[
  {
    "path": "DEVELOPMENT.md",
    "content": "### How to specify calibration parameters for RealSense cameras\n\nAfter exploring possibility to implement JavaScript API that would fetch calibration parameters from camera ([link to outdated specification for the reference](https://www.w3.org/TR/2017/WD-mediacapture-depth-20170328/)), that approach got abandoned calibration parameters are instead, specified in JavaScript code here, in [depth-camera.js](https://github.com/01org/depth-camera-web-demo/blob/926fd23c535e3a5a07fcfb94bf9afea0e31a9dc4/depth-camera.js#L149) file. Given that all RealSense cameras of the same model are factory calibrated to the same values and that firmware update (so far) doesn't change calibration parameters, specifying constant values in depth-camera.js and lookup based on camera label worked fine,... so far.\n\nThe section here explains where from, and how to, add numerical values to depth-camera.js file. This work is required for new camera models or if you want to support depth or color stream track resolutions that are not yet specified in depth-camera.js.\n\nWe would need [rs-enumerate-devices](https://github.com/IntelRealSense/librealsense/tree/master/tools/enumerate-devices) tool. It is part of RealSense SDK. Install SDK binary [binary or build it from source code](https://github.com/IntelRealSense/librealsense/). Connect the camera and run ```rs-enumerate-devices -c``` to get the calibration data printed out to terminal. Copy values from there to [depth-camera.js](https://github.com/01org/depth-camera-web-demo/blob/926fd23c535e3a5a07fcfb94bf9afea0e31a9dc4/depth-camera.js#L274) following the example:\n\n```\n    } else if (cameraName === \"SR300\")  {\n      result =  {\n```\n\nRun `rs-enumerate-devices -o` - depthScale value is in a row containing `Depth Units` label. \n\n```\n        depthScale: 0.0001249866472790017724,\n```\n\nProvide depth intrinstics for resolutions you plan to use. `rs-enumerate-devices -c` prints out this:\n\n```\nIntrinsic of \"Depth\"      640x480         Z16\nWidth:          640\nHeight:         480\nPPX:            307.147125244141\nPPY:            245.624420166016\nFx:             474.499542236328\nFy:             474.499420166016\nDistortion:     Inverse Brown Conrady\nCoeffs:         0.126395508646965       0.0701233819127083      0.00355594046413898     0.00548861175775528     0.103697031736374\n```\n\nFrom the output,  we just copy values to `getDepthIntrinsics` and `depthDistortionModel` below. `getColorIntrinsics`data is populated following the same pattern - note that there multiple resolutions (Intrinsic of \"Color\" 640x480, Intrinsic of \"Color\" 1280x720, ...) supported with different constants to be copied from `rs-enumerate-devices -c` output. \n\n```\n        getDepthIntrinsics: function(width, height) {\n          if (width == 640 && height == 480) {\n            return {\n              offset: [307.147125244141, 245.624420166016],\n              focalLength: [474.499542236328, 474.499420166016],\n            };\n          } else {\n            throwUnsupportedSizeError();\n          }\n        },\n        getColorIntrinsics: function(width, height) {\n          if (width == 640 && height == 480) {\n            return {\n              offset: [305.502166748047, 247.462982177734],\n              focalLength: [618.239440917969, 618.239562988281],\n            };\n          } else if (width == 1280 && height == 720) {\n            return {\n              offset: [618.253234863281, 371.194458007812],\n              focalLength: [927.359130859375, 927.359313964844],\n            };\n          } else if (width == 1920 && height == 1080) {\n            return {\n              offset: [927.3798828125, 556.791687011719],\n              focalLength: [1391.03869628906, 1391.03894042969],\n            };\n          } else {\n            throwUnsupportedSizeError();\n          }\n        },\n        colorOffset: new Float32Array(\n          [305.502166748047, 247.462982177734]\n        ),\n        colorFocalLength: new Float32Array(\n          [618.239440917969, 618.239562988281]\n        ),\n        \n```\n\ndepthToColor values are copied from `rs-enumerate-devices -c` `Extrinsic from \"Depth\" To \"Color\"` section.\n\n```\nExtrinsic from \"Depth\"    To      \"Color\" :\nRotation Matrix:\n0.99999        0.0034401      -0.0016265\n-0.003436      0.99999        0.0024992\n0.0016351      -0.0024936     1\n\nTranslation Vector: 0.0256999991834164  0.00126673700287938  0.00358582031913102\n```\n\nNote how the command output is column major compared to depthToColor layout below - three elements of the first printed row are the first three depthToColor column elements. We have patched [this line in rs-enumerate-devices](https://github.com/IntelRealSense/librealsense/blob/d0f0e5e5238ad8c729957c1d82297452c32e8d72/tools/enumerate-devices/rs-enumerate-devices.cpp#L26) to obtain higher precision values.\n\nThe fourth row of depthToColor matrix is populated from `Translation Vector`values.\n\n```\n\n        depthToColor: [\n          0.999992787837982, -0.00343602383509278, 0.00163511745631695, 0,\n          0.00344009511172771, 0.999990999698639, -0.00249356147833169, 0,\n          -0.00162653462029994, 0.00249916850589216, 0.999995589256287, 0,\n          0.0256999991834164, 0.00126673700287938, 0.00358582031913102, 1\n        ],\n        colorToDepth: [\n          0.999992787837982, -0.00343602383509278, 0.00163511745631695, 0,\n          0.00344009511172771, 0.999990999698639, -0.00249356147833169, 0,\n          -0.00162653462029994, 0.00249916850589216, 0.999995589256287, 0,\n          -0.0257013235241175, -0.00134619453456253, -0.00354716833680868, 1\n        ],        \n        depthDistortionModel: DistortionModel.INVERSE_BROWN_CONRADY,\n        depthDistortioncoeffs: [\n          0.126395508646965,\n          0.0701233819127083,\n          0.00355594046413898,\n          0.00548861175775528,\n          0.103697031736374,\n        ],\n        colorDistortionModel: DistortionModel.NONE,\n        colorDistortioncoeffs: [0, 0, 0, 0, 0],\n      };\n}\n\n```\n"
  },
  {
    "path": "LICENSE.md",
    "content": "# License\n\nEverything in this repo is BSD style license unless otherwise specified.\n\nCopyright (c) 2016 Intel Corporation. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n* Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n* Neither the name of Intel Corporation nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "DISCONTINUATION OF PROJECT\n\nThis project will no longer be maintained by Intel.\n\nIntel has ceased development and contributions including, but not limited to, maintenance, bug fixes, new releases, or updates, to this project.  \n\nIntel no longer accepts patches to this project.\n\nIf you have an ongoing need to use this project, are interested in independently developing it, or would like to maintain patches for the open source software community, please create your own fork of this project.  \n\nContact: webadmin@linux.intel.com\n# Depth camera capture in HTML5\n\n<table cellspacing=\"0\" cellpadding=\"0\" style=\"border-collapse: collapse; border: none;\">\n<tr>\n<td align=\"center\" valign=\"center\">\n<img src=\"gesture/joggling.gif\" alt=\"Video is not yet loaded.\" style=\"width:580px;\"/>\n<br />\n</td>\n<td align=\"center\" valign=\"center\">\n<img src=\"gesture/hands_interaction.gif\" alt=\"hands_interaction.gif is not yet loaded.\" style=\"width:556px;\"/>\n<br />\n</td>\n</tr>\n<tr>\n<td align=\"center\" valign=\"center\" colspan=\"2\">\n</br><p>Moving boxes using hands (or a paper) demo shows live depth captured mesh interaction with scene objects; combining 3D world and depth captured hands (or other objects) rendering and Bullet Physics. <a href=\"https://intel.github.io/depth-camera-web-demo/gesture/index.html\">Run live demo</a>.</br></br>\n</p>\n</td>\n</tr>\n<tr>\n</tr>\n<tr>\n<td align=\"center\" valign=\"center\">\n<img src=\"backgroundremoval.gif\" alt=\"backgroundremoval.gif is not yet loaded.\"/>\n<br />\n<p>Simple background removal implemented as flood-fill of background color to similarly colored pixels. Works only with simple backgrounds - e.g. room walls on the demo gif. Check the <a href=\"https://01.org/node/28902\">tutorial article</a> and <a href=\"https://intel.github.io/depth-camera-web-demo/depthdemo.html\">run live demo</a>.</p>\n</td>\n<td align=\"center\" valign=\"center\">\n<img src=\"typing_in_the_air/typing_in_the_air.gif\" alt=\"typing_in_the_air.gif is not yet loaded.\"/>\n<br />\n<p>Typing in the air tutorial shows how to use depth stream and WebGL transform feedback to do simple gesture recognition. Check the <a href=\"https://software.intel.com/en-us/blogs/2017/06/22/tutorial-typing-in-the-air-using-depth-camera-chrome-javascript-and-webgl-transform\">tutorial article</a> and <a href=\"https://intel.github.io/depth-camera-web-demo/typing_in_the_air/front_capture_typing.html\">run live demo</a>.</p>\n</td>\n</tr>\n<tr>\n<td align=\"center\" valign=\"center\">\n<img src=\"https://github.com/01org/depthcamera-pointcloud-web-demo/raw/master/recording.gif\" alt=\"https://github.com/01org/depthcamera-pointcloud-web-demo/raw/master/recording.gif is not yet loaded.\" style=\"width:362px;\"/>\n<br />\n<p>3D point cloud rendering demo shows how to render and synchronize depth and color video on GPU. Check the <a href=\"https://01.org/node/10446\">tutorial article</a> and <a href=\"https://intel.github.io/depthcamera-pointcloud-web-demo/\">run live demo</a>.</p>\n</td>\n<td align=\"center\" valign=\"center\">\n<img src=\"how_the_demo_looks.gif\" alt=\"how_the_demo_looks.gif is not yet loaded.\" style=\"height:400px;width:452px;\"/>\n<br />\n<p>HTML5 Depth Capture tutorial shows how to access depth stream, check the <a href=\"https://01.org/node/5101\">tutorial article</a> and <a href=\"https://intel.github.io/depth-camera-web-demo/depthdemo.html\">run live demo</a>.</p>\n</td>\n</tr>\n</table>\n\nTo capture and manipulate depth camera stream in HTML5, you'll need:\n* Chrome browser version 62 or later (the official release and no need for additional extensions),\n* Intel® RealSense™ 3D camera plugged to USB 3.0 port\n     * SR300 (and related cameras like Razer Stargazer or Creative BlasterX\nSenz3D) or R200,\n* Windows, Linux or ChromeOS PC.\n\nThese are the constraints of current implementation. The plan is to support other depth cameras and OSX and Android, too.\n\n## Articles related to the demos:\n* [Depth Camera Capture in HTML5](https://01.org/node/5101),\n* [Typing in the air using depth camera, Chrome, JavaScript, and WebGL transform feedback](https://software.intel.com/en-us/blogs/2017/06/22/tutorial-typing-in-the-air-using-depth-camera-chrome-javascript-and-webgl-transform)\n* [AR marker detection on GPU using WebGL](https://01.org/node/26012)\n* [Background removal with Intel® RealSense™ Depth Camera, WebRTC*, and WebGL*](https://01.org/node/28902)\n* [Background removal using TensorFlow.js](https://01.org/node/29971)\n\n\n\n\n"
  },
  {
    "path": "depth-camera.js",
    "content": "/*jshint esversion: 6 */\n\n// Copyright 2017 Intel Corporation.\n//\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  class DepthCamera {\n\n    constructor() {\n    }\n\n    static async getDepthStream() {\n      if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices ||\n        !navigator.mediaDevices.getUserMedia) {\n        throw new Error(\"Your browser doesn't support the required mediaDevices APIs.\");\n      }\n\n      // Use videoKind if it is supported. At the moment it is experimental; to\n      // use it. Chrome needs to be started with command line argument:\n      // --enable-blink-features=MediaCaptureDepthVideoKind\n      const supported_constraints = navigator.mediaDevices.getSupportedConstraints();\n      if (supported_constraints.videoKind) {\n        let stream = await navigator.mediaDevices.getUserMedia({\n          video: {\n            videoKind: {exact: \"depth\"},\n            frameRate: {exact: 60}\n          }\n        });\n        const track = stream.getVideoTracks()[0];\n        let settings = track.getSettings ? track.getSettings() : null;\n        // TODO: following is a browser bug if happening.\n        if (settings.videoKind != \"depth\")\n          throw new Error(\"No RealSense depth camera connected.\");\n        return stream;\n      }\n\n      // We cannot use videoKind yet, so try to make a constraint that would\n      // most likely resolve to a depth camera. Later, we use camera label to\n      // check if we really got a depth track.\n      const constraints = {\n        audio: false,\n        video: {\n          // videoKind: {exact: \"depth\"}, R200 related hack: prefer\n          // depth (width = 628) to IR (width = 641) stream.\n          width: {ideal: 628},\n\n          // SR300 depth camera enables capture at 110 frames per second.\n          frameRate: {ideal: 110},\n        }\n      }\n\n      let stream = await navigator.mediaDevices.getUserMedia(constraints);\n      let track = stream.getVideoTracks()[0];\n      if (track.label.indexOf(\"RealSense\") == -1) {\n        throw new Error(chromeVersion() < 58 ?\n          \"Your browser version is too old. Get Chrome version 58 or later.\" :\n          \"No RealSense camera connected.\");\n      }\n\n      if (track.getSettings && track.getSettings().frameRate > 60) {\n        // After Chrome 59, returned track is scaled to 628 and frameCount 110.\n        // We got the deviceId, so we the deviceId to select the stream with\n        // default resolution and frameRate.\n        track.stop();\n\n        const constraints = {\n          audio: false,\n          video: {\n            deviceId: {exact: track.getSettings().deviceId},\n            frameRate: {exact: 60}\n          }\n        }\n        stream = await navigator.mediaDevices.getUserMedia(constraints);\n      }\n      return stream;\n    }\n\n  // Call the method after getting depth_stream using getDepthStream.\n  static async getColorStreamForDepthStream(depthStream, w = 640, h = 480) {\n    // To get color stream from the same physical device providing the depth\n    // stream, we will use groupId, once it is implemented:\n    // See https://crbug.com/627793\n    // For now, enumerate devices based on label.\n    // Note: depth_stream is not used, for now, but deliberately added as a\n    // parameter to mandate the need for previous call to getDepthStream.\n\n    let depth_device_id = null;\n    const depth = depthStream.getVideoTracks()[0];\n\n    // Chrome, starting with version 59, implements getSettings() API.\n    if (depth.getSettings) {\n      depth_device_id = depth.getSettings().deviceId;\n    } else if (idealWidth) {\n      console.warn(`Not able to set ideal width for color video as\n        MediaStreamTrack getSettings() API is not available. Try\n        with Chromium version > 59.`);\n    }\n\n    var all_devices = await navigator.mediaDevices.enumerateDevices();\n    let devices = all_devices.filter((device) => (\n        device.kind == 'videoinput' &&\n        device.label.includes('RealSense') &&\n        device.label.includes('RGB') &&\n        (device.label != depth.label ||\n         device.deviceId != depth_device_id)));\n    if (devices.length < 1) {\n      throw new Error(\"No RealSense camera connected.\");\n    } else if (devices.length > 1) {\n      devices = devices.sort((a, b) => {\n        // Heuristics, as everything else in this method: pick camera with\n        // 'RGB' at the end\n        return b.label.lastIndexOf('RGB') - a.label.lastIndexOf('RGB');\n      });\n    }\n\n    // Select stream the id, so that some other camera doesn't get selected\n    // (e.g. if the user has another rgb camera).\n    const id = devices[0].deviceId;\n\n    // Select color stream.\n    const constraints = {\n      video: {\n        width: w,\n        height: h,\n        deviceId: {exact: id},\n      }\n    };\n    return navigator.mediaDevices.getUserMedia(constraints);\n  }\n\n  // Figure out the camera intristics and extrinsics based on the depth stream\n  // camera model.\n  //\n  // This should be rewritten once the MediaCapture-Depth API works - don't\n  // hardcode the values based on camera model, but query it from the API.\n  //\n  // See the documentation at\n  // https://w3c.github.io/mediacapture-depth/#synchronizing-depth-and-color-video-rendering\n  static getCameraCalibration(depth_stream) {\n    const label = depth_stream.getVideoTracks()[0].label;\n    const cameraName = label.includes(\"R200\") ? \"R200\"\n        : (label.includes(\"Camera S\") || label.includes(\"SR300\")) ? \"SR300\"\n        : label.includes(\"ZR300\") ? \"ZR300\"\n        : label.includes(\"415\") ? \"D415\"\n        : label.includes(\"430\") ? \"D435\"\n        : label.includes(\"435i\") ? \"D435i\"\n        : label.includes(\"435\") ? \"D435\"\n        : label.includes(\") 4\") ? \"generic4\"\n        : label;\n\n    const DistortionModel = {\n      NONE: 0,\n      MODIFIED_BROWN_CONRADY: 1,\n      INVERSE_BROWN_CONRADY: 2,\n    };\n\n    function throwUnsupportedSizeError() {\n      const error = new Error(\"Depth intrinsics for size \" + width + \"x\" +\n                               height + \" are not available.\");\n      error.name = \"UnsupportedSizeError\";\n      throw error;\n    }\n\n    let result;\n    if (cameraName === \"R200\")  {\n      result = {\n        depthScale: 0.001,\n        getDepthIntrinsics: function(width, height) {\n          if (width == 628 && height == 469) {\n            return {\n              offset: [305.558075, 233.5],\n              focalLength: [582.154968, 582.154968],\n            };\n          } else if (width == 628 && height == 361) {\n            return {\n              offset: [233.3975067138671875, 179.2618865966796875],\n              focalLength: [447.320953369140625, 447.320953369140625],\n            };\n          } else {\n            throwUnsupportedSizeError();\n          }\n        },\n        colorOffset: new Float32Array(\n          [311.841033935546875, 229.7513275146484375]\n        ),\n        colorFocalLength: new Float32Array(\n          [627.9630126953125, 634.02410888671875]\n        ),\n        // Rotation [0..2] goes to 1st column, [3..6] to second, etc. The\n        // row at the bottom is translation.\n        depthToColor: [\n          0.99998325109481811523, 0.002231199527159333229, 0.00533978315070271492, 0,\n          -0.0021383403800427913666, 0.99984747171401977539, -0.017333013936877250671, 0,\n          -0.0053776423446834087372, 0.017321307212114334106, 0.99983555078506469727, 0,\n          -0.058898702263832092285, -0.00020283895719330757856, -0.0001998419174924492836, 1\n        ],\n        depthDistortionModel: DistortionModel.NONE,\n        depthDistortioncoeffs: [0, 0, 0, 0, 0],\n        colorDistortionModel: DistortionModel.MODIFIED_BROWN_CONRADY,\n        colorDistortioncoeffs: [\n          -0.078357703983783721924,\n          0.041351985186338424683,\n          -0.00025565386749804019928,\n          0.0012357287341728806496,\n          0\n        ],\n      };\n    } else if (cameraName === \"SR300 Senz3D\")  {\n      result =  {\n        depthScale: 0.0001249866472790017724,\n        getDepthIntrinsics: function(width, height) {\n          if (width == 640 && height == 480) {\n            return {\n              offset: [310.743988037109375, 245.1811676025390625],\n              focalLength: [475.900726318359375, 475.900726318359375],\n            };\n          } else {\n            throwUnsupportedSizeError();\n          }\n        },\n        getColorIntrinsics: function(width, height) {\n          if (width == 640 && height == 480) {\n            return {\n              offset: [312.073974609375, 241.969329833984375],\n              focalLength: [617.65087890625, 617.65093994140625],\n            };\n          } else if (width == 1280 && height == 720) {\n            return {\n              offset: [628.110961914062, 362.953979492188],\n              focalLength: [926.476318359375, 926.476440429688],\n            };\n          } else if (width == 1920 && height == 1080) {\n            return {\n              offset: [942.166442871094, 544.430969238281],\n              focalLength: [1389.71447753906, 1389.71472167969],\n            };\n          } else {\n            throwUnsupportedSizeError();\n          }\n        },\n        colorOffset: new Float32Array(\n          [312.073974609375, 241.969329833984375]\n        ),\n        colorFocalLength: new Float32Array(\n          [617.65087890625, 617.65093994140625]\n        ),\n        depthToColor: [\n          0.99998641014099121094, -0.0051436689682304859161, 0.00084982655243948101997, 0,\n          0.0051483912393450737, 0.99997079372406005859, -0.005651625804603099823, 0,\n          -0.00082073162775486707687, 0.0056559243239462375641, 0.99998366832733154297, 0,\n          0.025699997320771217346, -0.00073326355777680873871, 0.0039400043897330760956, 1\n        ],\n        depthDistortionModel: DistortionModel.INVERSE_BROWN_CONRADY,\n        depthDistortioncoeffs: [\n          0.14655706286430358887,\n          0.078352205455303192139,\n          0.0026113723870366811752,\n          0.0029218809213489294052,\n          0.066788062453269958496,\n        ],\n        colorDistortionModel: DistortionModel.NONE,\n        colorDistortioncoeffs: [0, 0, 0, 0, 0],\n      };\n    } else if (cameraName === \"SR300\")  {\n      result =  {\n        depthScale: 0.0001249866472790017724,\n        getDepthIntrinsics: function(width, height) {\n          if (width == 640 && height == 480) {\n            return {\n              offset: [307.147125244141, 245.624420166016],\n              focalLength: [474.499542236328, 474.499420166016],\n            };\n          } else {\n            throwUnsupportedSizeError();\n          }\n        },\n        getColorIntrinsics: function(width, height) {\n          if (width == 640 && height == 480) {\n            return {\n              offset: [305.502166748047, 247.462982177734],\n              focalLength: [618.239440917969, 618.239562988281],\n            };\n          } else if (width == 1280 && height == 720) {\n            return {\n              offset: [618.253234863281, 371.194458007812],\n              focalLength: [927.359130859375, 927.359313964844],\n            };\n          } else if (width == 1920 && height == 1080) {\n            return {\n              offset: [927.3798828125, 556.791687011719],\n              focalLength: [1391.03869628906, 1391.03894042969],\n            };\n          } else {\n            throwUnsupportedSizeError();\n          }\n        },\n        colorOffset: new Float32Array(\n          [305.502166748047, 247.462982177734]\n        ),\n        colorFocalLength: new Float32Array(\n          [618.239440917969, 618.239562988281]\n        ),\n        depthToColor: [\n          0.999992787837982, -0.00343602383509278, 0.00163511745631695, 0,\n          0.00344009511172771, 0.999990999698639, -0.00249356147833169, 0,\n          -0.00162653462029994, 0.00249916850589216, 0.999995589256287, 0,\n          0.0256999991834164, 0.00126673700287938, 0.00358582031913102, 1\n        ],\n        colorToDepth: [\n          0.999992787837982, -0.00343602383509278, 0.00163511745631695, 0,\n          0.00344009511172771, 0.999990999698639, -0.00249356147833169, 0,\n          -0.00162653462029994, 0.00249916850589216, 0.999995589256287, 0,\n          -0.0257013235241175, -0.00134619453456253, -0.00354716833680868, 1\n        ],        \n        depthDistortionModel: DistortionModel.INVERSE_BROWN_CONRADY,\n        depthDistortioncoeffs: [\n          0.126395508646965,\n          0.0701233819127083,\n          0.00355594046413898,\n          0.00548861175775528,\n          0.103697031736374,\n        ],\n        colorDistortionModel: DistortionModel.NONE,\n        colorDistortioncoeffs: [0, 0, 0, 0, 0],\n      };\n    } else if (cameraName === \"ZR300\")  {\n      result = {\n        depthScale: 0.00100000005,\n        getDepthIntrinsics: function(width, height) {\n          if (width == 628 && height == 469) {\n            return {\n              offset: [309.912567, 234.410904],\n              focalLength: [575.729980, 575.729980],\n            };\n          } else if (width == 628 && height == 361) {\n            return {\n              offset: [238.683838, 180.205521],\n              focalLength: [445.920288, 445.920288],\n            };\n          } else {\n            throwUnsupportedSizeError();\n          }\n        },\n        colorOffset: new Float32Array(\n          [312.271545, 233.118652]\n        ),\n        colorFocalLength: new Float32Array(\n          [616.316895, 617.343323]\n        ),\n        depthToColor: [\n          0.999995947, 0.00140406948, 0.00246621366, 0,\n          -0.00140700850, 0.999998271, 0.00119038881, 0,\n          -0.00246453821, -0.00119385391, 0.999996245, 0,\n          -0.0587307774, 7.03283295e-05, 0.000553227146, 1\n        ],\n        depthDistortionModel: DistortionModel.NONE,\n        depthDistortioncoeffs: [0, 0, 0, 0, 0],\n        colorDistortionModel: DistortionModel.MODIFIED_BROWN_CONRADY,\n        colorDistortioncoeffs: [\n          0.0727398321,\n          -0.138192296,\n          0.000800351670,\n          0.000444319186,\n          0\n        ],\n      };\n    } else if (cameraName === \"D415\")  {\n      result =  {\n        depthScale: 0.00100000005,\n        getDepthIntrinsics: function(width, height) {\n          if (width == 640 && height == 480) {\n            return {\n              offset: [315.847442626953, 241.684616088867],\n              focalLength: [643.142272949219, 643.142272949219],\n            };\n          } else if (width == 1280 && height == 720) {\n            return {\n              offset: [633.771179199219, 362.526947021484],\n              focalLength: [964.713439941406, 964.713439941406],\n            };\n          } else {\n            throwUnsupportedSizeError();\n          }\n        },\n        getColorIntrinsics: function(width, height) {\n          if (width == 640 && height == 480) {\n            return {\n              offset: [321.308288574219, 231.349639892578],\n              focalLength: [617.459838867188, 617.65087890625],\n            };\n          } else if (width == 1280 && height == 720) {\n            return {\n              offset: [641.96240234375, 347.024475097656],\n              focalLength: [926.189697265625, 926.476257324219],\n            };\n          } else if (width == 1920 && height == 1080) {\n            return {\n              offset: [962.943664550781, 520.536682128906],\n              focalLength: [1389.28454589844, 1389.71447753906],\n            };\n          } else {\n            throwUnsupportedSizeError();\n          }\n        },\n        colorOffset: new Float32Array(\n          [321.308288574219, 231.349639892578]\n        ),\n        colorFocalLength: new Float32Array(\n          [617.459838867188, 617.65087890625]\n        ),\n        colorToDepth: [\n          0.999988317489624, -0.000426474376581609, 0.00481635145843029, 0,\n          0.000353455223375931, 0.999885141849518, 0.0151513637974858, 0,\n          -0.00482225976884365, -0.0151494843885303, 0.999873638153076, 0,\n          -0.0150478817522526, 0.0000661657468299381, 0.000241686851950362, 1\n        ],\n        depthToColor: [\n          0.999988317489624, 0.000353455223375931, -0.00482225976884365, 0,\n          -0.000426474376581609, 0.999885141849518, -0.0151494843885303, 0,\n          0.00481635145843029, 0.0151513637974858, 0.999873638153076, 0,\n          0.0150465695187449, -0.0000645012842142023, -0.00031321871210821, 1,\n        ],\n        depthDistortionModel: DistortionModel.NONE,\n        depthDistortioncoeffs: [0, 0, 0, 0, 0],\n        colorDistortionModel: DistortionModel.NONE,\n        colorDistortioncoeffs: [0, 0, 0, 0, 0],\n      };\n    } else if (cameraName === \"D435\")  {\n      result =  {\n        depthScale: 0.00100000005,\n        getDepthIntrinsics: function(width, height) {\n          if (width == 640 && height == 480) {\n            return {\n              offset: [318.229400634766, 239.944534301758],\n              focalLength: [381.902008056641, 381.902008056641],\n            };\n          } else if (width == 1280 && height == 720) {\n            return {\n              offset: [637.048950195312, 359.907562255859],\n              focalLength: [636.503356933594, 636.503356933594],\n            };\n          } else {\n            throwUnsupportedSizeError();\n          }\n        },\n        getColorIntrinsics: function(width, height) {\n          if (width == 640 && height == 480) {\n            return {\n              offset: [324.276763916016, 233.025253295898],\n              focalLength: [616.862121582031, 617.127319335938],\n            };\n          } else if (width == 1280 && height == 720) {\n            return {\n              offset: [646.415161132812, 349.537872314453],\n              focalLength: [925.293212890625, 925.691040039062],\n            };\n          } else if (width == 1920 && height == 1080) {\n            return {\n              offset: [969.622741699219, 524.306823730469],\n              focalLength: [1387.93981933594, 1388.53649902344],\n            };\n          } else {\n            throwUnsupportedSizeError();\n          }\n        },\n        colorOffset: new Float32Array(\n          [324.276763916016, 233.025253295898]\n        ),\n        colorFocalLength: new Float32Array(\n          [616.862121582031, 617.127319335938]\n        ),\n        depthToColor: [\n          0.999992370605469, 0.000624090549536049, -0.00385748990811408, 0,\n          -0.000635052449069917, 0.999995768070221, -0.00284114643000066, 0,\n          0.00385570037178695, 0.00284357438795269, 0.999988496303558, 0,\n          0.0149379102513194, 0.000216223328607157, 0.000277608894975856, 1,\n        ],\n        colorToDepth: [\n          0.999992370605469, -0.000635052449069917, 0.00385570037178695, 0,\n          0.000624090549536049, 0.999995768070221, 0.00284357438795269, 0,\n          -0.00385748990811408, -0.00284114643000066, 0.999988496303558, 0,\n          -0.0149368597194552, -0.000205947319045663, -0.000335816672304645, 1\n        ],       \n        depthDistortionModel: DistortionModel.NONE,\n        depthDistortioncoeffs: [0, 0, 0, 0, 0],\n        colorDistortionModel: DistortionModel.NONE,\n        colorDistortioncoeffs: [0, 0, 0, 0, 0],\n      };\n    } else if (cameraName === \"D435i\")  {\n      result =  {\n        depthScale: 0.00100000005,\n        getDepthIntrinsics: function(width, height) {\n          if (width == 640 && height == 480) {\n            return {\n              offset: [319.640411376953, 234.501083374023],\n              focalLength: [383.972534179688, 383.972534179688],\n            };\n          } else if (width == 1280 && height == 720) {\n            return {\n              offset: [639.400695800781, 350.835144042969],\n              focalLength: [639.954223632812, 639.954223632812],\n            };\n          } else {\n            throwUnsupportedSizeError();\n          }\n        },\n        getColorIntrinsics: function(width, height) {\n          if (width == 640 && height == 480) {\n            return {\n              offset: [326.527374267578, 241.035064697266],\n              focalLength: [613.288269042969, 613.207214355469],\n            };\n          } else if (width == 1280 && height == 720) {\n            return {\n              offset: [649.791015625, 361.552581787109],\n              focalLength: [919.932373046875, 919.810852050781],\n            };\n          } else {\n            throwUnsupportedSizeError();\n          }\n        },\n        colorOffset: new Float32Array(\n          [326.527374267578, 241.035064697266]\n        ),\n        colorFocalLength: new Float32Array(\n          [613.288269042969, 613.207214355469]\n        ),\n        depthToColor: [\n          0.999998152256012, 0.000072939285018947, -0.00191376695875078, 0,\n          -0.0000624307940597646, 0.999984920024872, 0.00549048557877541, 0,\n          0.00191413855645806, -0.00549035612493753, 0.999983072280884, 0,\n          0.0145636992529035, 0.0000774716536398046, 0.00038804262294434, 1,\n        ],\n        colorToDepth: [\n          0.999998152256012, -0.0000624307940597646, 0.00191413855645806, 0,\n          0.000072939285018947, 0.999984920024872, -0.00549035612493753, 0,\n          -0.00191376695875078, 0.00549048557877541, 0.999983072280884, 0,\n          -0.0145629355683923, -0.0000786918026278727, -0.000415487680584192, 1\n        ],\n        depthDistortionModel: DistortionModel.MODIFIED_BROWN_CONRADY,\n        depthDistortioncoeffs: [0, 0, 0, 0, 0],\n        colorDistortionModel: DistortionModel.MODIFIED_BROWN_CONRADY,\n        colorDistortioncoeffs: [0, 0, 0, 0, 0],\n      };\n    } else if (cameraName === \"generic4\")  {\n      result = {\n        depthScale: 0.00100000005,\n        getDepthIntrinsics: function(width, height) {\n          if (width == 640 && height == 480) {\n            return {\n              offset: [321.17535400390625, 248.4362640380859375],\n              focalLength: [402.60308837890625, 402.60308837890625],\n            };\n          } else {\n            throwUnsupportedSizeError();\n          }\n        },\n        colorOffset: new Float32Array(\n          [331.870422363281, 242.991546630859]\n        ),\n        colorFocalLength: new Float32Array(\n          [629.172912597656, 628.130920410156]\n        ),\n        depthToColor: [\n          0.999902248382, 0.010088876821, 0.009682051837, 0,\n          -0.010075648315, 0.9999482631683, -0.001414125669, 0,\n          0.009695817716, 0.001316434470, 0.99995213747, 0,\n          0.036090422422,  0.000611198542174, -0.00184865354, 1\n        ],\n        depthDistortionModel: DistortionModel.NONE,\n        depthDistortioncoeffs: [0, 0, 0, 0, 0],\n        colorDistortionModel: DistortionModel.NONE,\n        colorDistortioncoeffs: [0, 0, 0, 0, 0],\n      };\n    } else {\n      throw {\n        name: \"CameraNotSupported\",\n        message: \"Sorry, your camera '\" + cameraName + \"' is not supported\",\n      };\n    }\n    // This also de-normalizes the depth value (it's originally a 16-bit\n    // integer normalized into a float between 0 and 1).\n    result.depthScale = result.depthScale * 65535;\n    result.cameraName = cameraName;\n    return result;\n  }\n}\n\nfunction chromeVersion() {\n  const raw = navigator.userAgent.match(/Chrom(e|ium)\\/([0-9]+)\\./);\n  return raw ? parseInt(raw[2], 10) : false;\n}\n"
  },
  {
    "path": "depth-to-color-sync-render.js",
    "content": "/*jshint esversion: 6 */\n/*\n * Copyright (c) 2018, Intel Corporation\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n *  * Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Intel Corporation nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\nconst REDUCE_BLACK_PASSES = 7;\n\nclass DepthToColorSyncRender {\n  constructor(canvas) {\n    let gl;\n    try {\n        gl = canvas.getContext('webgl2', {antialias: false});\n    } catch (e) {\n        console.error('Your browser doesn\\'t support WebGL2.');\n        throw new Error(`Could not create WebGL2 context: ${e}`);\n    }\n    this.gl = gl;\n    this.programs = this.setupPrograms(gl);\n    gl.getExtension('EXT_color_buffer_float');\n    gl.getExtension('OES_texture_float_linear');\n    this.PAUSE_REQUESTED = 1;\n    this.PAUSED = 2;\n  }\n\n  createVideo(w = 640, h = 480) { \n    var video = document.createElement(\"video\");\n    video.crossOrigin = \"anonymous\";\n    video.width = w;\n    video.height = h;\n    video.autoplay = true;\n    video.loop = true;\n    video.oncanplay = function(){\n      video.video_loaded=true;\n    };  \n    return video;\n  }\n                                \n  async setupCamera(depth_video = null) {\n    if (depth_video)\n      this.depthVideo = depth_video;\n    if (!this.depthVideo)\n      this.depthVideo = this.createVideo();\n    if (!this.colorVideo)\n      this.colorVideo = this.createVideo(this.gl.canvas.width, this.gl.canvas.height);\n\n    if (!this.depthVideo.srcObject)\n      this.depthVideo.srcObject = await DepthCamera.getDepthStream();\n    const depthStream = this.depthVideo.srcObject;\n\n    const calibration = DepthCamera.getCameraCalibration(depthStream);\n    // Supported only for D400-Series Depth Cameras\n    if (calibration.cameraName.indexOf('D4') == -1) {\n      throw new Error('Background removal is supported only for Intel\\u00ae RealSense\\u2122 D400-Series Depth Cameras.');\n    }\n    if (!this.colorVideo.srcObject) {\n        const colorStream =\n            await DepthCamera.getColorStreamForDepthStream(depthStream, this.colorVideo.width, this.colorVideo.height);\n        this.colorVideo.srcObject = colorStream;\n    }\n    return calibration;\n  }\n\n  showBackgroundColor(on) {\n    this.backgroundColor = on;\n  }\n\n  showBackgroundVideo(on) {\n    this.backgroundVideo = on;\n    if (!this.backgroundVideoElement) {\n      const video = this.createVideo();\n      this.backgroundVideoElement = video;\n      video.src = \"res/landscape.mp4\";\n    }\n    if (on)\n      this.backgroundVideoElement.play();\n    else\n      this.backgroundVideoElement.pause();\n  }\n\n  // Create textures into which the camera output will be stored.\n  setupTextures(gl, programs, width, height, colorwidth, colorheight) {\n    let lastTextureId = 0;\n    function createTexture2D(format, w, h, filter = gl.NEAREST) {\n      gl.activeTexture(gl[`TEXTURE${lastTextureId}`]);\n      const texture = gl.createTexture();\n      gl.bindTexture(gl.TEXTURE_2D, texture);\n      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter);\n      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter);\n      gl.texStorage2D(\n          gl.TEXTURE_2D,\n          1, // number of mip-map levels\n          format, // internal format\n          w,\n          h,\n      );\n      texture.unit = lastTextureId++;\n      texture.w = w;\n      texture.h = h;\n      return texture;\n    }\n\n    const depth0 = createTexture2D(gl.R32F, width, height);\n    const depth1 = createTexture2D(gl.R32F, width, height);    \n    const color = createTexture2D(gl.RGBA8, colorwidth, colorheight);\n    const colorFilter = createTexture2D(gl.RGBA8, colorwidth, colorheight);\n    const noHoles = createTexture2D(gl.RGBA8, colorwidth, colorheight);\n    const reduceBlack = [createTexture2D(gl.RGBA8, colorwidth, colorheight),\n                         createTexture2D(gl.RGBA8, colorwidth, colorheight),\n                         createTexture2D(gl.RGBA8, colorwidth, colorheight),\n                         createTexture2D(gl.RGBA8, colorwidth, colorheight),\n                         createTexture2D(gl.RGBA8, colorwidth, colorheight),\n                         createTexture2D(gl.RGBA8, colorwidth, colorheight),\n                         createTexture2D(gl.RGBA8, colorwidth, colorheight)];\n    const background = createTexture2D(gl.RGBA8, colorwidth, colorheight);\n    const previousBackground = createTexture2D(gl.RGBA8, colorwidth, colorheight);\n    const cleanup = createTexture2D(gl.RGBA8, colorwidth, colorheight);\n    const backgroundVideo = createTexture2D(gl.RGBA8, 1920, 1080, gl.LINEAR);\n\n    return {\n        depth: depth0,\n        previousDepth: depth1,        \n        color: color,\n        colorFilter: colorFilter,\n        noHoles: noHoles,\n        reduceBlack: reduceBlack,\n        background: background,\n        previousBackground: previousBackground,\n        cleanup: cleanup,\n        backgroundVideo: backgroundVideo\n    };\n  }\n\n  setupPrograms(gl) {\n    this.vao = gl.createVertexArray();\n    gl.bindVertexArray(this.vao);\n    const vertex_buffer = gl.createBuffer();\n    this.vertex_buffer = vertex_buffer;\n    gl.bindBuffer(gl.ARRAY_BUFFER, this.vertex_buffer);\n    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0,0,1,0,1,1,0,1]), gl.STATIC_DRAW);\n\n    this.index_buffer= gl.createBuffer();\n    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.index_buffer);\n    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([0,1,2,0,2,3]), gl.STATIC_DRAW);\n    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n    \n    const noHolesVertex = `#version 300 es\n      in vec2 v;\n      out vec2 t;\n\n      void main(){\n        gl_Position = vec4(v.x * 2.0 - 1.0, v.y * 2.0 - 1.0, 0, 1);\n        t = v;\n      }`;\n    const noHolesPixel = `#version 300 es\n      precision highp float;\n\n      layout(location = 0) out vec4 fragColor;\n      layout(location = 1) out vec4 backgroundColor;\n      in vec2 t;\n      \n      uniform sampler2D sDepth;\n      uniform sampler2D sPreviousDepth;\n      uniform sampler2D sColor;\n      uniform sampler2D sPreviousBackground;\n      uniform vec3 dd; // vec3(1/w, 1/h, 0)\n      uniform vec3 ddDepth; // vec3(1/w, 1/h, 0)\n      uniform float depthScale;\n      uniform vec2 depthOffset;\n      uniform vec2 colorOffset;\n      uniform vec2 depthFocalLength;\n      uniform vec2 colorFocalLengthInv;\n      uniform mat4 colorToDepth;\n\n      const vec4 rgbmask = vec4(1.0, 1.0, 1.0, 0.0);\n      const float range = 0.9;\n                  \n      vec4 normalizeRG(vec4 c) {\n        float sum = dot(c, rgbmask);\n        return vec4(c.rgb / sum, c.a);\n      } \n\n      vec4 colorDeproject(vec2 index, float z) {\n        vec2 position2d = (index - colorOffset) * colorFocalLengthInv;\n        return vec4(position2d * z, z, 1.0);\n      }\n\n      float nonZeroDepth(sampler2D s, vec2 v) {\n        // If the depth is 0, return 1.0. We return 1.0 only because it is max\n        // value and we use it to find minimum among neighbour values.\n        vec4 c = texture(s, v);\n        return (c.r == 0.0) ? 1.0 : c.r;\n      }\n\n      void main(){\n        fragColor = texture(sColor, t);\n        vec4 backColor = texture(sPreviousBackground, t);\n        // Get the depth for color pixel.\n        vec4 colorPos = colorDeproject(t, 0.5);\n        vec4 depthPos = colorToDepth * colorPos;\n        vec2 position2d = depthPos.xy / depthPos.z;\n        vec2 v = position2d * depthFocalLength + depthOffset;\n        float z = texture(sDepth, v).r;\n        float z_around = min(min(nonZeroDepth(sDepth, v + ddDepth.rb),\n                                 nonZeroDepth(sDepth, v - ddDepth.rb)),\n                             min(texture(sDepth, v + ddDepth.bg).r, //deliberatelly\n                                 nonZeroDepth(sDepth, v - ddDepth.bg)));\n        z = (z == 1.0) ? 0.0 : z;\n\n        z *= depthScale;\n        z_around *= depthScale;\n        // As depth and color are not sampled in the same time, prevent overlap\n        // during (moderate) movement. Overlap would render foreground to be\n        // transparent for a frame and we mitigate it by checking pixels around.\n        // z = min(z, z_around);\n        z = z_around < z ? z_around : z;\n\n        backColor = z > range ? vec4(fragColor.rgb, z) : backColor;\n        backgroundColor = backColor;\n\n        // TODO: use previous depth frame to get depth value if not defined\n        // float z1 = texture(sPreviousDepth, v).r;\n        // z1 = (z1 == 1.0) ? 0.0 : z1;\n        // z = (z == 0.0) ? z1 * depthScale : z;\n        \n        // clamp up to 0.95 for expressing value using color alpha channel.\n        // [0-0.9] would express foreground, [0.9-0.95] background from depth\n        // camera and [0.95-1] computed background based on color fill.\n        z = (z > 0.95) ? 0.95 : z;\n        \n        // TODO: use background map to fix edges.\n        /*\n        vec4 distN = normalizeRG(fragColor) - normalizeRG(backColor);\n        vec4 dist = fragColor - backColor;\n        z = (z == 0.0 && dot(distN.rgb, distN.rgb) < 0.003 &&\n            dot(dist.rgb, dist.rgb) < 0.008 && backColor.a > 0.9) ? backColor.a : z;\n        z = (z > 0.95) ? 0.95 : z;\n        */\n        fragColor.rgb = sqrt(fragColor.rgb); // gamma correction aproximation.\n        fragColor.a = z;\n      }`;\n\n    const reduceBlackVertex = `#version 300 es\n      in vec2 v;\n      out vec2 t;\n\n      void main(){\n        gl_Position = vec4(v.x * 2.0 - 1.0, v.y * 2.0 - 1.0, 0, 1);\n        t = v;\n      }`;\n    const reduceBlackPixel = `#version 300 es\n      precision mediump float;\n      uniform sampler2D s;\n      uniform vec4 samplingStep;\n      vec4 bckgndThreshold = vec4(0.9);\n      in vec2 t;\n      out vec4 fragColor;\n\n      void main(){\n        vec4 c = texture(s, t);\n        fragColor = c;\n        if (c.a > 0.9)\n          return;\n\n        const vec4 similarThreshold = vec4(0.011);\n        const float k = similarThreshold.r / 0.035;\n\n        vec4 dd3 = samplingStep;\n        vec4 dd4 = dd3 * 1.414213562;\n        vec4 dd6 = 3.0 * dd3;\n        vec4 dd8 = 3.0 * dd4;\n        vec4 dd1 = 0.3333 * dd3;\n        vec4 dd2 = 0.3333 * dd4;\n\n        vec4 c11 = texture(s, t - dd3.rg);\n        vec4 c15 = texture(s, t + dd3.rg);\n        vec4 c13 = texture(s, t - dd3.bg);\n        vec4 c17 = texture(s, t + dd3.bg);\n        vec4 c12 = texture(s, t - dd4.ag);\n        vec4 c16 = texture(s, t + dd4.ag);\n        vec4 c18 = texture(s, t - dd4.ra);\n        vec4 c14 = texture(s, t + dd4.ra);\n\n        vec4 c21 = texture(s, t - dd6.rg);\n        vec4 c25 = texture(s, t + dd6.rg);\n        vec4 c23 = texture(s, t - dd6.bg);\n        vec4 c27 = texture(s, t + dd6.bg);\n        vec4 c22 = texture(s, t - dd8.ag);\n        vec4 c26 = texture(s, t + dd8.ag);\n        vec4 c28 = texture(s, t - dd8.ra);\n        vec4 c24 = texture(s, t + dd8.ra);\n\n        vec4 c01 = texture(s, t - dd1.rg);\n        vec4 c05 = texture(s, t + dd1.rg);\n        vec4 c03 = texture(s, t - dd1.bg);\n        vec4 c07 = texture(s, t + dd1.bg);\n        vec4 c02 = texture(s, t - dd2.ag);\n        vec4 c06 = texture(s, t + dd2.ag);\n        vec4 c08 = texture(s, t - dd2.ra);\n        vec4 c04 = texture(s, t + dd2.ra);\n\n        \n        // ci1 and ci5, ci2 and ci6,... are opposite. From z01 and z02, which\n        // contain depth of the nearest 8 pixels, to z21 and z22 for the\n        // furthest pixels.\n        vec4 z01 = vec4(c01.a, c02.a, c03.a, c04.a);\n        vec4 z02 = vec4(c05.a, c06.a, c07.a, c08.a);\n        vec4 z11 = vec4(c11.a, c12.a, c13.a, c14.a);\n        vec4 z12 = vec4(c15.a, c16.a, c17.a, c18.a);\n        vec4 z21 = vec4(c21.a, c22.a, c23.a, c24.a);\n        vec4 z22 = vec4(c25.a, c26.a, c27.a, c28.a);\n        \n        vec4 background01 = vec4(greaterThan(z01, bckgndThreshold));\n        vec4 background02 = vec4(greaterThan(z02, bckgndThreshold));\n        vec4 background11 = vec4(greaterThan(z11, bckgndThreshold));\n        vec4 background12 = vec4(greaterThan(z12, bckgndThreshold));\n        vec4 background21 = vec4(greaterThan(z21, bckgndThreshold));\n        vec4 background22 = vec4(greaterThan(z22, bckgndThreshold));\n\n        // Current pixel values, packed for parallel diff.\n        vec4 rn = vec4(c.r);\n        vec4 gn = vec4(c.g);\n        vec4 bn = vec4(c.b);\n        \n        // Use naive RGB diff for first prototype to evaluate similar colors.\n        vec4 r01 = vec4(c01.r, c02.r, c03.r, c04.r);\n        vec4 r02 = vec4(c05.r, c06.r, c07.r, c08.r);\n        vec4 g01 = vec4(c01.g, c02.g, c03.g, c04.g);\n        vec4 g02 = vec4(c05.g, c06.g, c07.g, c08.g);\n        vec4 b01 = vec4(c01.b, c02.b, c03.b, c04.b);\n        vec4 b02 = vec4(c05.b, c06.b, c07.b, c08.b);\n        vec4 diffr1 = abs(r01 - rn - g01 + gn);\n        vec4 diffr2 = abs(r02 - rn - g02 + gn);\n        vec4 diffg1 = max(abs(g01 - gn - b01 + bn), abs(r01 - rn) * k);\n        vec4 diffg2 = max(abs(g02 - gn - b02 + bn), abs(r02 - rn) * k);\n        vec4 diffb1 = max(abs(b01 - bn), abs(g01 - gn)) * k;\n        vec4 diffb2 = max(abs(b02 - bn), abs(g02 - gn)) * k;\n        vec4 sim01 = vec4(lessThan(max(max(diffr1, diffg1), diffb1), similarThreshold));\n        vec4 sim02 = vec4(lessThan(max(max(diffr2, diffg2), diffb2), similarThreshold));\n\n        vec4 r11 = vec4(c11.r, c12.r, c13.r, c14.r);\n        vec4 r12 = vec4(c15.r, c16.r, c17.r, c18.r);\n        vec4 g11 = vec4(c11.g, c12.g, c13.g, c14.g);\n        vec4 g12 = vec4(c15.g, c16.g, c17.g, c18.g);\n        vec4 b11 = vec4(c11.b, c12.b, c13.b, c14.b);\n        vec4 b12 = vec4(c15.b, c16.b, c17.b, c18.b);\n        diffr1 = abs(r11 - rn - g11 + gn);\n        diffr2 = abs(r12 - rn - g12 + gn);\n        diffg1 = max(abs(g11 - gn - b11 + bn), abs(r11 - rn) * k);\n        diffg2 = max(abs(g12 - gn - b12 + bn), abs(r12 - rn) * k);\n        diffb1 = max(abs(b11 - bn), abs(g11 - gn)) * k;\n        diffb2 = max(abs(b12 - bn), abs(g12 - gn)) * k;\n        vec4 sim11 = vec4(lessThan(max(max(diffr1, diffg1), diffb1), similarThreshold));\n        vec4 sim12 = vec4(lessThan(max(max(diffr2, diffg2), diffb2), similarThreshold));\n\n        vec4 r21 = vec4(c21.r, c22.r, c23.r, c24.r);\n        vec4 r22 = vec4(c25.r, c26.r, c27.r, c28.r);\n        vec4 g21 = vec4(c21.g, c22.g, c23.g, c24.g);\n        vec4 g22 = vec4(c25.g, c26.g, c27.g, c28.g);\n        vec4 b21 = vec4(c21.b, c22.b, c23.b, c24.b);\n        vec4 b22 = vec4(c25.b, c26.b, c27.b, c28.b);\n        diffr1 = abs(r21 - rn - g21 + gn);\n        diffr2 = abs(r22 - rn - g22 + gn);\n        diffg1 = max(abs(g21 - gn - b21 + bn), abs(r21 - rn) * k);\n        diffg2 = max(abs(g22 - gn - b22 + bn), abs(r22 - rn) * k);\n        diffb1 = max(abs(b21 - bn), abs(g21 - gn)) * k;\n        diffb2 = max(abs(b22 - bn), abs(g22 - gn)) * k;\n        vec4 sim21 = vec4(lessThan(max(max(diffr1, diffg1), diffb1), similarThreshold));\n        vec4 sim22 = vec4(lessThan(max(max(diffr2, diffg2), diffb2), similarThreshold));\n\n        vec4 sb11 = sim11 * background11;\n        vec4 sb12 = sim12 * background12;\n        vec4 sb01 = sim01 * background01;\n        vec4 sb02 = sim02 * background02;        \n        vec4 sdocfodbz1 = sim01 * background01 + sim11 * (background11 + sim21 * background21);\n        vec4 sdocfodbz2 = sim02 * background02 + sim12 * (background12 + sim22 * background22);\n        if (dot(sdocfodbz1, sdocfodbz1) + dot(sdocfodbz2, sdocfodbz2) > 0.0) {\n          float coef = 0.3;\n          float count1 = dot(sb11, sb11) + dot(sb12, sb12) + coef;\n          float count0 = dot(sb01, sb01) + dot(sb02, sb02) + coef;\n          vec3 ch = c.rgb * coef;\n          if (count0 > coef) {\n            float rf = dot(sb01, r01) + dot(sb02, r02);\n            float gf = dot(sb01, g01) + dot(sb02, g02);\n            float bf = dot(sb01, b01) + dot(sb02, b02);\n            ch = (ch + vec3(rf, gf, bf)) / count0;\n            fragColor = vec4(ch, 0.9804); // 0.9804 is for debugging.\n            return;\n          }\n          float rf = dot(sb11, r11) + dot(sb12, r12);\n          float gf = dot(sb11, g11) + dot(sb12, g12);\n          float bf = dot(sb11, b11) + dot(sb12, b12);\n          ch = (ch + vec3(rf, gf, bf)) / count1;\n          fragColor = vec4(ch, count1 > coef ? 0.9804 : 1.0);\n          return;\n        }    \n      }`;\n   \n    const cleanupVertex = `#version 300 es\n      in vec2 v;\n      out vec2 t;\n\n      void main(){\n        gl_Position = vec4(v.x * 2.0 - 1.0, v.y * 2.0 - 1.0, 0, 1);\n        t = v;\n      }`;\n    const cleanupPixel = `#version 300 es\n      precision mediump float;\n      uniform sampler2D s;\n      uniform vec4 dd;\n      uniform vec4 mappedRectangle;\n\n      in vec2 t;\n      out vec4 fragColor;\n      const vec4 range = vec4(0.9);\n\n      void main(){\n        vec4 c = texture(s, t);\n        vec4 d1 = vec4(texture(s, t + dd.ra).a,\n                       texture(s, t + dd.rg).a,\n                       texture(s, t + dd.ag).a,\n                       texture(s, t + dd.bg).a);\n        vec4 d2 = vec4(texture(s, t - dd.ra).a,\n                       texture(s, t - dd.rg).a,\n                       texture(s, t - dd.ag).a,\n                       texture(s, t - dd.bg).a);\n        d1 = vec4(lessThan(d1, range));\n        d2 = vec4(lessThan(d2, range));\n        float count = dot(d1, d1) + dot(d2, d2);\n        c.a = (c.a < range.x) ? (count <= 3.0 ? 0.01 : count <= 6.0 ? 0.03 : c.a) :\n                                (c.a > range.x && count >= 5.0) ? 0.5 : c.a;\n\n        float a = t.x < mappedRectangle.x ? 1.0 : c.a;\n        fragColor = vec4(c.rgb, a);\n      }`;\n\n    const renderVertex = `\n      attribute vec2 v;\n      varying vec2 t;\n\n      void main(){\n        gl_Position = vec4(v.x * 2.0 - 1.0, -v.y * 2.0 + 1.0, 0, 1);\n        t = v;\n      }`;\n    const renderPixel = `\n      precision mediump float;\n      uniform sampler2D s;\n      uniform sampler2D sBackground;\n      uniform float backgroundMode;\n      uniform sampler2D backgroundVideo;\n      uniform vec2 backgroundVideoScale;      \n      varying vec2 t;\n\n      const vec4 rgbmask = vec4(1.0, 1.0, 1.0, 0.0);\n      const float range = 0.9;            \n\n      void main(){\n        vec4 tex = texture2D(s, t);\n        vec2 bs = t * backgroundVideoScale + (vec2(1.0) - backgroundVideoScale) * 0.5;\n        vec4 video = texture2D(backgroundVideo, bs);\n\n        gl_FragColor = (tex.a < range) ? tex : vec4(0.0);\n        float alpha = tex.a > 0.0 ? tex.a < 0.015 ? 0.0 : (tex.a < 0.0350 ? 0.3 : 1.0) : 1.0;\n        vec4 background = vec4(0.0);\n        if (tex.a == 1.0) {\n          background = vec4(1.0, 0.6, 0.1, 1.0);;\n        } else if (tex.a > 0.99) \n          background = vec4(1.0, 0.5, 0.5, 1.0);\n        else if (tex.a > 0.9803) \n          background = vec4(0.3, 0.8, 1.0, 1.0);\n        else if (tex.a > 0.972) \n          background = vec4(0.5, 0.5, 0.7, 1.0);\n        else if (tex.a == 0.0) \n           background = vec4(1.0, 1.0, 0.0, 1.0);\n        else if (tex.a > range) \n          background = vec4(0.0, 1.0, 1.0, 1.0);\n        else if (tex.a > 0.035 && tex.a < 0.05) \n          background = vec4(1.0, 0.0, 0.0, 1.0);\n        \n        \n        background = vec4(0.0, 1.0, 1.0, 1.0);\n        background = backgroundMode == 2.0 ? video : background;\n        alpha = backgroundMode == 0.0 ? 1.0 : tex.a > range ? 0.0 : alpha;\n        // Square the RGB values to revert noHolesPixel's gamma approximation.\n        gl_FragColor = mix(background, vec4(tex.rgb * tex.rgb, 1.0), alpha);\n      }`; \n\n    function createProgram(gl, vs, ps) {\n      var vertex_shader = gl.createShader(gl.VERTEX_SHADER);\n      gl.shaderSource(vertex_shader, vs);\n      gl.compileShader(vertex_shader);\n\n      var pixel_shader = gl.createShader(gl.FRAGMENT_SHADER);\n      gl.shaderSource(pixel_shader, ps);\n      gl.compileShader(pixel_shader);\n\n      var program  = gl.createProgram();\n      gl.attachShader(program, vertex_shader);\n      gl.attachShader(program, pixel_shader);\n      gl.linkProgram(program);\n      const vinfo = gl.getShaderInfoLog(vertex_shader);\n      const pinfo = gl.getShaderInfoLog(pixel_shader);\n      if (vinfo.length > 0)\n        console.error(vinfo);\n      if (pinfo.length > 0)\n        console.error(pinfo);\n\n      gl.useProgram(program);\n\n      const vertex_location = gl.getAttribLocation(program, \"v\");\n      if (vertex_location == -1)\n        return program;\n      gl.enableVertexAttribArray(vertex_location);\n      program.vertex_location = vertex_location;\n      gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);\n      gl.vertexAttribPointer(vertex_location, 2, gl.FLOAT, false, 0, 0);\n      return program;\n    }\n\n    return {\n      noHoles: createProgram(gl, noHolesVertex, noHolesPixel),\n      reduceBlack: createProgram(gl, reduceBlackVertex, reduceBlackPixel),      \n      cleanup: createProgram(gl, cleanupVertex, cleanupPixel),\n      render: createProgram(gl, renderVertex, renderPixel),\n    }\n  }\n   \n  setup(gl, cameraParams, depthW, depthH, colorW, colorH) {\n    const createFramebuffer2D = (gl, textureList) => {\n      const framebuffer = gl.createFramebuffer();\n      const drawBuffers = [];\n      gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);\n      for (let i = 0; i < textureList.length; i += 1) {\n        const texture = textureList[i];\n        drawBuffers.push(gl[`COLOR_ATTACHMENT${i}`]);\n        gl.framebufferTexture2D(\n          gl.FRAMEBUFFER,\n          gl[`COLOR_ATTACHMENT${i}`],\n          gl.TEXTURE_2D,\n          texture,\n          0, // mip-map level\n        );\n      }\n      gl.drawBuffers(drawBuffers);\n      return framebuffer;\n    }\n\n    if (!this.textures)\n      this.textures = this.setupTextures(gl, this.programs, depthW, depthH, colorW, colorH);\n    this.initUniforms(gl, cameraParams, depthW, depthH);\n\n    const textures = this.textures;\n    const sk = 11;\n    const push = 32;\n    // init passes with framebuffers\n    if (!this.passes) {\n      this.passes = [{\n        framebuffer: createFramebuffer2D(gl, [textures.noHoles, textures.background]),\n        program: this.programs.noHoles,\n      }, {\n        in: textures.noHoles,\n        samplingStep: [sk / colorW, sk / colorH, -sk / colorW, 0.0],\n        framebuffer: createFramebuffer2D(gl, [textures.reduceBlack[0]]),\n        program: this.programs.reduceBlack,\n      }, {\n        in: textures.reduceBlack[0],\n        samplingStep: [sk / colorW, sk / colorH, -sk / colorW, 0.0],\n        framebuffer: createFramebuffer2D(gl, [textures.reduceBlack[1]]),\n        program: this.programs.reduceBlack,\n      }, {\n        in: textures.reduceBlack[1],\n        samplingStep: [(sk - 2) / colorW, (sk - 2) / colorH, -(sk - 2) / colorW, 0.0],\n        framebuffer: createFramebuffer2D(gl, [textures.reduceBlack[2]]),\n        program: this.programs.reduceBlack,\n      }, {\n        in: textures.reduceBlack[2],\n        samplingStep: [(sk - 4) / colorW, (sk - 4) / colorH, -(sk - 4) / colorW, 0.0],\n        framebuffer: createFramebuffer2D(gl, [textures.reduceBlack[3]]),\n        program: this.programs.reduceBlack,\n      }, {\n        in: textures.reduceBlack[3],\n        samplingStep: [(sk - 5) / colorW, (sk - 5) / colorH, -(sk - 5) / colorW, 0.0],\n        framebuffer: createFramebuffer2D(gl, [textures.reduceBlack[4]]),\n        program: this.programs.reduceBlack,\n      }, {\n        in: textures.reduceBlack[4],\n        samplingStep: [(sk - 7) / colorW, (sk - 7) / colorH, -(sk - 7) / colorW, 0.0],\n        framebuffer: createFramebuffer2D(gl, [textures.reduceBlack[5]]),\n        program: this.programs.reduceBlack,\n      }, {\n        in: textures.reduceBlack[5],\n        samplingStep: [(sk - 7) / colorW, (sk - 7) / colorH, -(sk - 7) / colorW, 0.0],\n        framebuffer: createFramebuffer2D(gl, [textures.reduceBlack[6]]),\n        program: this.programs.reduceBlack,\n      }, {\n        samplingStep: [2 / colorW, 2 / colorH, -2 / colorW, 0.0],\n        framebuffer: createFramebuffer2D(gl, [textures.cleanup]),\n        program: this.programs.cleanup,\n      }, {\n        framebuffer: null,\n        program: this.programs.render\n      }];\n    }\n    this.initAttributes(gl);\n  }\n\n  initAttributes(gl) {\n    gl.bindVertexArray(this.vao);\n    gl.useProgram(this.programs.render);\n    gl.bindBuffer(gl.ARRAY_BUFFER, this.vertex_buffer);\n    gl.vertexAttribPointer(this.programs.render.vertex_location, 2, gl.FLOAT, false, 0, 0);\n    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.index_buffer);    \n  }\n\n\n  initUniforms(gl, cameraParams, width, height) {\n    const textures = this.textures;\n    const color = textures.color;\n    const intrin = cameraParams.getDepthIntrinsics(width, height);\n    const colorIntrin = cameraParams.getColorIntrinsics(color.w, color.h);\n    const offsetx = (intrin.offset[0] / width);\n    const offsety = (intrin.offset[1] / height);\n    const focalxinv = width / intrin.focalLength[0];\n    const focalyinv = height / intrin.focalLength[1];\n    const focalx = intrin.focalLength[0] / width;\n    const focaly = intrin.focalLength[1] / height;\n    const coloroffsetx = colorIntrin.offset[0] / color.w;\n    const coloroffsety = colorIntrin.offset[1] / color.h;\n    const colorfocalx = colorIntrin.focalLength[0] / color.w;\n    const colorfocaly = colorIntrin.focalLength[1] / color.h;\n    const colorfocalxinv = color.w / colorIntrin.focalLength[0];\n    const colorfocalyinv = color.h / colorIntrin.focalLength[1];\n\n    // Shaders asume const range up to 0.9, in order to express the depth using\n    // color alpha channel.\n    const range = 1.5; // meaning 1.1 meters away from camera should be hidden.\n    const scale = cameraParams.depthScale * 0.9 / range;\n\n    const noHoles = this.programs.noHoles;\n    gl.useProgram(noHoles);\n\n    noHoles.sDepth = gl.getUniformLocation(noHoles, \"sDepth\");\n    noHoles.sPreviousDepth = gl.getUniformLocation(noHoles, \"sPreviousDepth\");\n    noHoles.sColor = gl.getUniformLocation(noHoles, \"sColor\");\n    noHoles.sPreviousBackground = gl.getUniformLocation(noHoles, \"sPreviousBackground\");\n\n    gl.uniform3f(gl.getUniformLocation(noHoles, 'ddDepth'), 5 / width, 5 / height, 0);\n    gl.uniform3f(gl.getUniformLocation(noHoles, 'dd'), 1 / color.w, 1 / color.h, 0);\n    gl.uniform1f(gl.getUniformLocation(noHoles, 'depthScale'), scale);\n    gl.uniform2f(gl.getUniformLocation(noHoles, 'depthFocalLength'), focalx, focaly);\n    gl.uniform2f(gl.getUniformLocation(noHoles, 'depthOffset'), offsetx, offsety);\n    gl.uniform2f(gl.getUniformLocation(noHoles, 'colorFocalLengthInv'), colorfocalxinv, colorfocalyinv);\n    gl.uniform2f(gl.getUniformLocation(noHoles, 'colorOffset'), coloroffsetx, coloroffsety);\n    gl.uniformMatrix4fv(gl.getUniformLocation(noHoles, \"colorToDepth\"), false, cameraParams.colorToDepth);\n\n    const reduceBlack = this.programs.reduceBlack;\n    gl.useProgram(reduceBlack);\n    reduceBlack.s = gl.getUniformLocation(reduceBlack, \"s\");\n    reduceBlack.samplingStep = gl.getUniformLocation(reduceBlack, \"samplingStep\");\n\n    const cleanup = this.programs.cleanup;\n    gl.useProgram(cleanup);\n    const last = textures.reduceBlack[REDUCE_BLACK_PASSES - 1];\n    gl.uniform1i(gl.getUniformLocation(cleanup, \"s\"), last.unit);\n    gl.uniform4f(gl.getUniformLocation(cleanup, 'mappedRectangle'), cameraParams.cameraName == \"D415\" ? 0.08 : 0, 0, 1, 1);\n    gl.uniform4f(gl.getUniformLocation(cleanup, 'dd'), 1 / color.w, 1 / color.h, -1 / color.w, 0);\n\n    const render = this.programs.render;\n    gl.useProgram(render);\n    gl.uniform1i(gl.getUniformLocation(render, \"s\"), textures.cleanup.unit);\n    gl.uniform1i(gl.getUniformLocation(render, \"backgroundVideo\"), textures.backgroundVideo.unit);\n    gl.uniform2f(gl.getUniformLocation(render, \"backgroundVideoScale\"), \n        (textures.backgroundVideo.h / color.h) / (textures.backgroundVideo.w / color.w) , 1.0);\n    render.backgroundMode = gl.getUniformLocation(render, \"backgroundMode\");    \n    render.sBackground = gl.getUniformLocation(render, \"sBackground\");\n  }\n\n  // it is loaded externally.\n  setDepthVideo(video) {\n    this.depthVideo = video;\n    if (video.videoWidth > 2) {\n      this.depthVideo.video_loaded = true;\n      return;\n    }\n    video.oncanplay = function() {\n      video.video_loaded=true;\n    }\n  }\n\n  async play() {\n    const cameraParams = await this.setupCamera(this.depthVideo).catch((error) => {\n      console.error(error);\n    });    \n    let frame = 0;\n    let textures;\n    const colorVideo = this.colorVideo;\n    const depthVideo = this.depthVideo;\n    const programs = this.programs;\n    const renderer = this;\n    const gl = renderer.gl;\n    let width = 0;\n    let height = 0;\n    let currentDepthTime = 0;\n    let currentColorTime = 0;\n    let currentBackgroundVideoTime = 0;\n    let this_ = this;\n\n    if (this.paused == this.PAUSE_REQUESTED) {\n      // if we get new play before paused is fulfilled, avoid second\n      // requestAnimationFrame issue;\n      this.paused = 0;\n      return;\n    } else if (this.paused == 0) {\n      console.error(\"DCHECK failed on paused\");\n      return;\n    }\n\n    // Run for each frame. Will do nothing if the camera is not ready yet.\n    const animate = function () {\n      if (depthVideo.video_loaded && colorVideo.video_loaded) {\n        if (frame === 0) {\n          width = depthVideo.videoWidth;\n          height = depthVideo.videoHeight;\n          renderer.setup(gl, cameraParams, width, height, colorVideo.videoWidth, colorVideo.videoHeight);\n          textures = renderer.textures;\n        }\n        try {\n          if (depthVideo.currentTime != currentDepthTime) {\n            const temp = textures.depth;\n            textures.depth = textures.previousDepth;\n            textures.previousDepth = temp;\n            currentDepthTime = depthVideo.currentTime;\n            gl.activeTexture(gl[`TEXTURE${textures.depth.unit}`]);\n            gl.bindTexture(gl.TEXTURE_2D, textures.depth);\n            gl.texSubImage2D(\n              gl.TEXTURE_2D,\n              0, // mip-map level\n              0, // x-offset\n              0, // y-offset\n              width,\n              height,\n              gl.RED,\n              gl.FLOAT,\n              depthVideo,\n            );\n          }\n          if (colorVideo.currentTime != currentColorTime) {\n            const temp = textures.background;\n            textures.previousBackground = textures.background;\n            textures.background = textures.previousBackground;\n            gl.bindFramebuffer(gl.FRAMEBUFFER, renderer.passes[0].framebuffer);\n            gl.framebufferTexture2D(\n              gl.FRAMEBUFFER,\n              gl.COLOR_ATTACHMENT1,\n              gl.TEXTURE_2D,\n              textures.background,\n              0, // mip-map level\n            );\n            currentColorTime = colorVideo.currentTime;\n            gl.activeTexture(gl[`TEXTURE${textures.color.unit}`]);\n            gl.bindTexture(gl.TEXTURE_2D, textures.color);\n            gl.texSubImage2D(\n              gl.TEXTURE_2D,\n              0, // mip-map level\n              0, // x-offset\n              0, // y-offset\n              colorVideo.videoWidth,\n              colorVideo.videoHeight,\n              gl.RGBA,\n              gl.UNSIGNED_BYTE,\n              colorVideo,\n            );\n          }\n          const back = this_.backgroundVideoElement;\n          if (this_.backgroundVideo && currentBackgroundVideoTime != back.currentTime) {\n            currentBackgroundVideoTime = back.currentTime;\n            gl.activeTexture(gl[`TEXTURE${textures.backgroundVideo.unit}`]);\n            gl.bindTexture(gl.TEXTURE_2D, textures.backgroundVideo);\n            gl.texSubImage2D(\n              gl.TEXTURE_2D,\n              0, // mip-map level\n              0, // x-offset\n              0, // y-offset\n              back.videoWidth,\n              back.videoHeight,\n              gl.RGBA,\n              gl.UNSIGNED_BYTE,\n              back,\n            );            \n          }\n        } catch (e) {\n          console.error(`Error uploading video to WebGL:\n                        ${e.name}, ${e.message}`);\n        }\n\n      \n        let l;\n        let program;\n        gl.bindVertexArray(renderer.vao);  \n        for (let i = 0; i < renderer.passes.length; ++i) {\n          const pass = renderer.passes[i];\n          // comment previous two lines and uncomment following to measure\n          // latency of rendering only\n          // { const pass = gl.passes[6];\n          gl.useProgram(pass.program);\n          if (pass.in && pass.program.s)\n            gl.uniform1i(pass.program.s, pass.in.unit);\n          if (pass.samplingStep && pass.program.samplingStep)\n            gl.uniform4fv(pass.program.samplingStep, pass.samplingStep);\n          if (pass.program.sDepth)\n            gl.uniform1i(pass.program.sDepth, textures.depth.unit);\n          if (pass.program.sPreviousDepth)\n            gl.uniform1i(pass.program.sPreviousDepth, textures.previousDepth.unit);\n          if (pass.program.sColor)\n            gl.uniform1i(pass.program.sColor, textures.color.unit);\n          if (pass.program.sPreviousBackground)\n             gl.uniform1i(pass.program.sPreviousBackground, textures.previousBackground.unit);\n          if (pass.program.sBackground)\n             gl.uniform1i(pass.program.sBackground, textures.background.unit);\n          if (pass.program.backgroundMode) {\n             gl.uniform1f(pass.program.backgroundMode, this_.backgroundColor ?\n                          1 : this_.backgroundVideo ? 2 : 0);\n          }\n\n          gl.bindFramebuffer(gl.FRAMEBUFFER, pass.framebuffer);\n          gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);              \n        }\n\n        frame += 1;\n      }\n      if (renderer.paused == renderer.PAUSE_REQUESTED) {\n        renderer.paused = renderer.PAUSED;\n        return;\n      }\n       window.requestAnimationFrame(animate);\n    };\n    animate();\n  }\n\n  pause() {\n    this.paused = 2;\n  }\n}"
  },
  {
    "path": "depthdemo.html",
    "content": "<html>\n<head>\n</head>\n\n<style>\n  body {\n    display: flex;\n    flex-direction: column;\n    font-family: 'Roboto', 'Noto', sans-serif;\n    line-height: 1.5;\n    background-color: #fbfbfb;\n    margin: 20px;\n  }\n\n  .select {\n    margin: 16px 0px;\n    display: flex;\n    flex-direction: column;\n    max-width: 400px;\n  }\n\n  select {\n    background-color: transparent;\n    width: 100%;\n    padding: 4px 0;\n    font-size: 16px;\n    color: rgba(0,0,0, 0.26);\n    border: none;\n    border-bottom: 1px solid rgba(0,0,0, 0.12);\n  }\n\n  select:focus {\n    outline: none;\n  }\n\n  .select > label {\n    font-size: 10pt;\n    color: gray;\n  }\n\n  #console {\n    color: red;\n    font-size: 150%;\n  }\n\n  canvas {\n    border: 1px solid #cccccd;\n    background-color: white;\n  }\n\n  #tabcontainer {\n    margin: 16px 0px;\n  }\n\n  #tabcontainer input {\n    height: 35px;\n    visibility: hidden;\n  }\n\n  label[for=tab1], label[for=tab2] {\n    color: gray;\n    cursor: pointer;\n    display: block;\n    float: left;\n    height, : 40px;\n    line-height: 40px;\n    margin-right: 5px;\n    padding: 0 20px;\n    text-align: center;\n  }\n  \n  #tabcontainer input:hover + label {\n    background: lightgray;\n    color: gray;\n  }\n\n  #tabcontainer input:checked + label {\n    background: #f0f0f0;\n    color: dimgray;\n    position: relative;\n    z-index: 6;\n  }\n\n  #tabcontent1, #tabcontent2 {\n    background: #f0f0f0;\n    opacity: 0;\n    position: absolute;\n    z-index: -100;\n  }\n\n  #tabcontainer input#tab1:checked ~ #tabcontent #tabcontent1,\n  #tabcontainer input#tab2:checked ~ #tabcontent #tabcontent2 {\n      opacity: 1;\n      z-index: 100;\n  }\n\n  input.visible {\n    visibility: visible !important;\n  }\n\n\n  video-stream {\n    color: dimgray;\n  }\n\n  #synctab {\n    margin: 16px;\n    padding:0px;\n    color: dimgray;\n  }\n\n  label[for=synccanvas] {\n    display:block;    \n  }\n\n  #show-background-video {\n    position: absolute;\n    bottom: 50px;\n    right: 25px;\n    color: gray;\n    z-index: 5;\n    height: 20px;\n    text-align: right;\n  }\n  #show-background-color {\n    position: absolute;\n    bottom: 30px;\n    right: 25px;\n    color: gray;\n    z-index: 5;\n    height: 20px;\n    text-align: right;\n  }\n  #show-video-toggle, #show-color-toggle {\n    visibility: visible !important;\n    height: 15px !important;\n    vertical-align:middle;\n  }\n</style>\n\n<template id=\"video-stream\">\n  <style>\n    :host {\n      display: flex;\n      flex-flow: row wrap;\n    }\n\n    canvas {\n      align-self: center;\n    }\n\n    div {\n      margin: 16px;\n    }\n\n    label {\n      display: block;\n    }\n  </style>\n  <div>\n    <label>WebGL canvas with depth video frame texture:</label>\n    <canvas id=\"canvasGL\" width=\"640\" height=\"480\"></canvas>\n  </div>\n  <div>\n    <label><input type=\"checkbox\" onchange=\"readAndShowPixels(this)\"></input>gl.readPixels and show in 2D canvas</label>\n    <canvas id=\"canvas2D\" width=\"640\" height=\"480\"></canvas>\n  </div>\n</template>\n\n<body onload=\"onLoad()\">\n  <h2>Depth Capture Demo</h2>\n  <div id=\"console\">\n    <!-- Print error messages here. -->\n  </div>\n  <div class=\"select\">\n    <label for=\"selectVideoDevice\">Capture device with depth stream</label>\n    <select id=\"selectVideoDevice\"></select>\n  </div>\n  <div id=\"tabcontainer\">\n    <input id=\"tab1\" type=\"radio\" name=\"tabs\" value=\"basic\" checked=\"checked\" data-ontaboff=\"stopBasicTab\" data-ontabon=\"startBasicTab\"/>\n    <label for=\"tab1\">Render depth</label>\n    <input id=\"tab2\" type=\"radio\" name=\"tabs\" value=\"sync\" data-ontaboff=\"stopSyncTab\" data-ontabon=\"startSyncTab\"/>\n    <label for=\"tab2\">Background removal</label>\n    <div id=\"tabcontent\">\n      <div id = tabcontent1>\n        <video-stream></video-stream>\n      </div>\n      <div id=\"tabcontent2\">\n        <div id=\"synctab\">\n          <label for=\"synccanvas\">Color stream is displayed over depth that is aligned to color:</label>\n          <div id=\"show-background-video\">background video <input id=\"show-video-toggle\" type=\"checkbox\">\n          </div>\n          <div id=\"show-background-color\">background color <input id=\"show-color-toggle\" type=\"checkbox\">\n          </div>\n          <canvas id=\"synccanvas\" width=\"640px\" height=\"480px\"\n                  style=\"background-color: black;\">\n          </canvas>\n        </div>\n      </div>\n    </div>\n  </div>\n</body>\n\n<script src=\"depth-camera.js\"></script>\n<script src=\"depth-to-color-sync-render.js\"></script>\n<script>\n  let readAndShowDepthPixels = false;\n  let error = window.console.error;\n  window.console.error = (message, ...rest) => {\n    let target = document.querySelector('#console');\n    error.call(window.console, message, ...rest);\n\n    if (message instanceof Error) {\n      message = `${message.name}: ${message.message}`;\n    }\n\n    target.innerHTML += `${message}<br>`;\n  }\n\n  function readAndShowPixels(element) {\n    readAndShowDepthPixels = element.checked;   \n  }\n\n\n  let tabs = document.getElementsByName(\"tabs\");\n  let videos = {depth: null, color: null};\n  let syncrender = new DepthToColorSyncRender(document.querySelector(\"#synccanvas\"));\n  let selectedtab = tabs[0];\n  for(let i = 0; i < tabs.length; i++) {\n    tabs[i].onclick = function() {\n      if(this !== selectedtab) {\n        window[selectedtab.dataset.ontaboff](); \n        selectedtab = this;\n        window[selectedtab.dataset.ontabon](); \n      }\n    };\n  }\n  \n  function stopVideo(video) {\n    if (video && video.srcObject) {\n      const cs = video.srcObject;\n      for (let track of cs.getTracks()) {\n        track.stop();\n      }\n      video.srcObject = null;\n    }\n  }\n\n  function startBasicTab() {\n    const videoStreamEl = document.querySelector('video-stream');\n    videoStreamEl.play();    \n  }\n\n  function stopBasicTab() {\n    const videoStreamEl = document.querySelector('video-stream');\n    videoStreamEl.pause();\n  }\n\n  async function startSyncTab() {\n    syncrender.setDepthVideo(videos.depth);\n    await syncrender.play();\n    videos.color = syncrender.colorVideo;\n    videos.depth = syncrender.depthVideo;    \n  }\n\n  function stopSyncTab() {\n    syncrender.pause();\n    stopVideo(videos.color);\n  }\n\n  const videoToggle = document.getElementById(\"show-video-toggle\");\n  const colorToggle = document.getElementById(\"show-color-toggle\");\n\n  videoToggle.addEventListener(\"change\", function() {\n    if (this.checked)\n      colorToggle.checked = false;\n    syncrender.showBackgroundColor(false);\n    syncrender.showBackgroundVideo(this.checked);\n  });\n  colorToggle.addEventListener(\"change\", function() {\n    if (this.checked)\n      videoToggle.checked = false;\n    syncrender.showBackgroundVideo(false);\n    syncrender.showBackgroundColor(this.checked);\n  });\n\n  customElements.define('video-stream', class extends HTMLElement {\n    constructor() {\n      super();\n      const template = document.querySelector('#video-stream');\n      const clone = document.importNode(template.content, true);\n      const shadowRoot = this.attachShadow({ mode: 'open' });\n      this.shadowRoot.appendChild(clone);\n\n      this._frameLoop = this._frameLoop.bind(this);\n\n      this.readBuffer = null;\n      this.readFormat = null;\n    }\n\n\n    connectedCallback() {\n      this.gl = this._configureGLContext();\n\n      const canvas = this.shadowRoot.getElementById(\"canvas2D\");\n      this.ctx2d = canvas.getContext(\"2d\");\n\n      this.frameAvailable = false;\n\n      this.video = this._createOffscreenVideo();\n      this.video.oncanplay = _ => { this.frameAvailable = true; }\n      this.video.addEventListener(\"play\", this._frameLoop);\n\n      let hasTouchListeners = false;\n      const onVideoTouchStart = _ => {\n        hasTouchListeners = false;\n        window.removeEventListener(\"touchstart\", onVideoTouchStart, true);\n        this.video.play();\n      }\n\n      if (this.video && this.video.paused && !hasTouchListeners) {\n        hasTouchListeners = true;\n        window.addEventListener(\"touchstart\", onVideoTouchStart, true);\n      }\n    }\n\n    _createOffscreenVideo() {\n      return Object.assign(document.createElement(\"video\"), {\n        autoplay: true,\n        loop: true,\n        crossOrigin: \"anonymous\",\n        width: 640,\n        height: 480\n      });\n    }\n    \n    _frameLoop() {\n      const gl = this.gl;\n\n      gl.activeTexture(gl.TEXTURE0);\n      gl.bindTexture(gl.TEXTURE_2D, gl.depth_texture);\n\n      if (this.frameAvailable) {\n        // Upload the video frame to texture.\n        if (gl.color_buffer_float_ext) {\n          gl.texImage2D(gl.TEXTURE_2D, 0, gl.R32F, gl.RED, gl.FLOAT, this.video);\n        } else {\n          gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA32F, gl.RGBA, gl.FLOAT, this.video);\n        }\n\n        if (readAndShowDepthPixels) {\n          // Read it back to buffer.\n          this._readPixels();\n\n          // TODO: process pixels.\n          // Put read and processed pixels to 2D canvas.\n          // Note: This is just one of scenarios for the demo. You can directly\n          // bind video to 2D canvas without using WebGL as intermediate step.\n          this._putReadPixelsTo2DCanvas();          \n        }\n      }\n      gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertex_buffer);\n      gl.vertexAttribPointer(gl.vertex_location, 2, gl.FLOAT, false, 0, 0);\n\n      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.index_buffer);\n      gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);\n      if (!this.paused)\n        window.requestAnimationFrame(this._frameLoop);\n    }\n\n    pause() {\n      this.paused = true;\n    }\n\n    play() {\n      this.paused = false;\n      window.requestAnimationFrame(this._frameLoop);\n    }\n\n    _readPixels() {\n      const gl = this.gl;\n      // Bind the framebuffer the texture is color-attached to.\n      gl.bindFramebuffer(gl.FRAMEBUFFER, gl.framebuffer);\n\n      if (!this.readBuffer) {\n        this.readFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);\n        if (this.readFormat == gl.RED && gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE) == gl.FLOAT) {\n          this.readBuffer = new Float32Array(this.video.width * this.video.height);\n        } else {\n          this.readFormat = gl.RGBA;\n          this.readBuffer = new Float32Array(this.video.width * this.video.height * 4);\n        }\n      }\n      gl.readPixels(0, 0, this.video.width, this.video.height, this.readFormat, gl.FLOAT, this.readBuffer);\n      gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n    }\n\n    _putReadPixelsTo2DCanvas() {\n      const img = this.ctx2d.getImageData(0, 0, this.video.width, this.video.height);\n      const data = img.data;\n      const stride = (this.readFormat === this.gl.RED) ? 1 : 4;\n      for (let i = 0, j = 0; i < data.length; i += 4, j += stride) {\n        data[i] = this.readBuffer[j] * 255;\n        data[i+3] = 255;\n      }\n      this.ctx2d.putImageData(img, 0, 0);\n    }\n\n    // Creates WebGL/WebGL2 context used to upload depth video to texture,\n    // read the pixels to Float buffer and optionElally render the texture.\n    _configureGLContext() {\n      const canvas = this.shadowRoot.getElementById(\"canvasGL\");\n      const gl = canvas.getContext(\"webgl2\");\n      if (gl) {\n        // The extension tells us if we can use single component R32F texture format.\n        gl.color_buffer_float_ext = gl.getExtension('EXT_color_buffer_float');\n      } else {\n        gl = canvas.getContext(\"webgl\");\n        gl.getExtension(\"OES_texture_float\");\n      }\n\n      gl.enable(gl.BLEND);\n      gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);\n\n      // Shaders and program are needed only if rendering depth texture.\n      var vertex_shader = gl.createShader(gl.VERTEX_SHADER);\n      gl.shaderSource(vertex_shader, `\n        attribute vec2 v;\n        varying vec2 t;\n\n        void main(){\n          gl_Position = vec4(v.x * 2.0 - 1.0, 1.0 - v.y * 2.0, 0, 1);\n          t = v;\n        }`);\n      gl.compileShader(vertex_shader);\n\n      var pixel_shader = gl.createShader(gl.FRAGMENT_SHADER);\n      gl.shaderSource(pixel_shader, `\n        precision mediump float;\n        uniform sampler2D s;\n        varying vec2 t;\n\n        void main(){\n          vec4 tex = texture2D(s, t) * vec4(10.0, 10.0, 10.0, 1.0);\n          gl_FragColor = tex.rrra;\n        }`);\n      gl.compileShader(pixel_shader);\n\n      var program  = gl.createProgram();\n      gl.attachShader(program, vertex_shader);\n      gl.attachShader(program, pixel_shader);\n      gl.linkProgram(program);\n      gl.useProgram(program);\n\n      var vertex_location = gl.getAttribLocation(program, \"v\");\n      gl.enableVertexAttribArray(vertex_location);\n      gl.uniform1i(gl.getUniformLocation(program, \"s\"), 0);\n\n      var vertex_buffer = gl.createBuffer();\n      gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);\n      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0,0,1,0,1,1,0,1]), gl.STATIC_DRAW);\n\n      var index_buffer= gl.createBuffer();\n      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);\n      gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([0,1,2,0,2,3]), gl.STATIC_DRAW);\n\n      var depth_texture = gl.createTexture();\n      gl.bindTexture(gl.TEXTURE_2D, depth_texture);\n      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n\n      // Framebuffer for reading back the texture.\n      var framebuffer = gl.createFramebuffer();\n      gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);\n      gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, depth_texture, 0);\n      gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\n      gl.vertex_buffer = vertex_buffer;\n      gl.vertex_location = vertex_location;\n      gl.index_buffer = index_buffer;\n      gl.depth_texture = depth_texture;\n      gl.framebuffer = framebuffer;\n\n      return gl;\n    }\n\n    async loadStream(deviceId) {\n      stopVideo(videos.depth);\n      stopVideo(videos.color);\n\n      // If the item in drop-down list is selected, use it.\n      const getUserMedia = () => {\n        // add ?allow=all to URL to allow listing all devices (incl. those not supporting depth).\n        if (!deviceId && (new URL(window.location)).searchParams.get(\"allow\") !== \"all\") {\n          return DepthCamera.getDepthStream();\n        }\n\n        const constraints = {\n          video: {\n            deviceId: deviceId ? { exact: deviceId } : {}\n          }\n        }\n\n        return navigator.mediaDevices.getUserMedia(constraints);\n      }\n\n      try {\n        const stream = await getUserMedia();\n        this.video.srcObject = stream;\n        videos.depth = this.video;\n\n        // Chrome, starting with version 59, implements getSettings() API.\n        const track = stream.getVideoTracks()[0];\n        if (track.getSettings) {\n          this.depthDeviceId = track.getSettings().deviceId;\n        }\n      } catch (err) {\n        console.error(err);\n      }\n    }\n  });\n\n  function populateSelectElement(devices) {\n    const selectEl = document.querySelector('#selectVideoDevice');\n    const videoStreamEl = document.querySelector('video-stream');\n\n    let selected = selectEl.value;\n\n    while (selectEl.firstChild) {\n      selectEl.removeChild(selectEl.firstChild);\n    }\n\n    let selectedDeviceStillExists = false;\n    for (let i = 0; i < devices.length; ++i) {\n      const info = devices[i];\n      if (info.kind !== 'videoinput') {\n        continue;\n      }\n\n      const optionEl = document.createElement('option');\n      optionEl.value = info.deviceId;\n      optionEl.text = info.label || 'camera ' + (selectEl.length + 1);\n      selectEl.appendChild(optionEl);\n\n      if (optionEl.value === selected) {\n        selectedDeviceStillExists = true;\n      }\n    }\n\n    if (selectedDeviceStillExists) {\n      selectEl.value = selected;\n    } else if (!selected) {\n      // If no other device is selected, set the initial selection to depth device.\n      if (videoStreamEl.depthDeviceId) {\n        selectEl.value = videoStreamEl.depthDeviceId;\n      }\n    }\n\n\n  }\n\n  function onLoad() {\n    const videoStreamEl = document.querySelector('video-stream');\n    const selectEl = document.querySelector('#selectVideoDevice');\n\n    selectEl.onchange = async event => {\n      selectEl.disabled = true;\n      const deviceId = event.target.value;\n\n      await videoStreamEl.loadStream(deviceId);\n\n      const devices = await navigator.mediaDevices.enumerateDevices();\n      populateSelectElement(devices);\n      if (selectedtab.value != \"basic\") {\n        // It is on by default; stop rendering it if not visible.\n        stopBasicTab();\n      }\n      window[selectedtab.dataset.ontabon]();\n\n      selectEl.disabled = false;\n    };\n    selectEl.dispatchEvent(new Event('change', { 'bubbles': true }))\n  }\n</script>\n</html>\n"
  },
  {
    "path": "gesture/depth_and_segments.js",
    "content": "/*jshint esversion: 6 */\r\n\r\n// Copyright 2017 Intel Corporation.\r\n//\r\n// Licensed under the Apache License, Version 2.0 (the \"License\");\r\n// you may not use this file except in compliance with the License.\r\n// You may obtain a copy of the License at\r\n//\r\n//     http://www.apache.org/licenses/LICENSE-2.0\r\n//\r\n// Unless required by applicable law or agreed to in writing, software\r\n// distributed under the License is distributed on an \"AS IS\" BASIS,\r\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n// See the License for the specific language governing permissions and\r\n// limitations under the License.\r\n\r\nconst INTERPOLATE_INV = 1 / 20.0; // interpolate depth physics at 20 pixels.\r\n\r\nclass DepthAndSegments {\r\n  constructor(gl, drawGL = null) {\r\n    this.gl = gl;\r\n    gl.depth_tex_unit = gl.depth_tex_unit | gl.TEXTURE0;\r\n    initGL(gl, drawGL);\r\n    reload();\r\n    // this.createDepthInfoCanvas();\r\n    this.out = {};\r\n    this.out1 = {};\r\n    this.out.segment_data = {};\r\n    this.out1.segment_data = {};\r\n    this.transform_feedback_draw_done = false;\r\n    this.gbsd_async_ready = false;\r\n    this.width = 640;\r\n    this.height = 480;\r\n  }\r\n\r\n  // In case when we use one WebGL context for processing (WebGL 2.0) and \r\n  // another |drawGL| for rendering depth, we upload depth texture to both.\r\n  // \r\n  process(drawGL) {\r\n    if (!video_loaded)\r\n      return false;\r\n    if (!init_done) {\r\n      this.videoLoaded(video, window.stream);\r\n      init_done = true;\r\n    }\r\n    const gl = this.gl; \r\n    if (this.transform_feedback_draw_done) {\r\n      // This is used only when WEBGL_get_buffer_sub_data_async extension is not\r\n      // available. \r\n      gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, gl.tf_bo);\r\n      gl.getBufferSubData(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tf_output, 0, tf_output.length);\r\n      gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, null);\r\n      processOnCPU();\r\n      this.identifyJointsAndFixNoise(out.segment_data);\r\n\r\n      this.out1 = this.out;\r\n      this.out = out;\r\n\r\n      putReadPixelsToTestCanvas(this.testContext);\r\n      this.transform_feedback_draw_done = false;\r\n      return true;\r\n    }\r\n    let processed = false;\r\n    if (this.gbsd_async_ready) {\r\n      // gbsd = getBufferSubData. Process the results from the previous frame\r\n      // make asynchronous request for this frame data below. \r\n      this.gbsd_async_ready = false;\r\n      processOnCPU();\r\n      this.identifyJointsAndFixNoise(out.segment_data);\r\n\r\n      this.out1 = this.out;\r\n      this.out = out;\r\n\r\n      putReadPixelsToTestCanvas(this.testContext);   \r\n      processed = true;\r\n    }\r\n\r\n    if (video_last_upload_time == video.currentTime) {\r\n      return processed;\r\n    }\r\n    video_last_upload_time = video.currentTime;\r\n    gl.activeTexture(gl.depth_tex_unit);\r\n    gl.bindTexture(gl.TEXTURE_2D, gl.depth_texture);\r\n\r\n    // Upload the video frame to texture.\r\n    if (gl.color_buffer_float_ext) {\r\n      gl.texImage2D(gl.TEXTURE_2D, 0, gl.R32F, gl.RED, gl.FLOAT, video);\r\n    } else {\r\n      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA32F, gl.RGBA, gl.FLOAT, video);\r\n    }\r\n    \r\n    if (drawGL && drawGL != gl) {\r\n      drawGL.activeTexture(gl.depth_tex_unit);\r\n      drawGL.bindTexture(gl.TEXTURE_2D, drawGL.depth_texture);\r\n      drawGL.texImage2D(drawGL.TEXTURE_2D, 0, drawGL.RGBA, drawGL.RGBA, drawGL.FLOAT, video);     \r\n    }\r\n\r\n    gl.enable(gl.RASTERIZER_DISCARD);\r\n    gl.useProgram(gl.compute_program);\r\n    gl.bindVertexArray(gl.depth_vao);\r\n    gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, gl.transform_feedback)\r\n    gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, gl.tf_bo)\r\n    gl.beginTransformFeedback(gl.POINTS);\r\n    gl.drawArrays(gl.POINTS, 0, tf_output.length);\r\n    gl.endTransformFeedback();\r\n    gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, null);\r\n    gl.bindVertexArray(null);\r\n\r\n    gl.disable(gl.RASTERIZER_DISCARD);\r\n    this.transform_feedback_draw_done = !gl.WEBGL_get_buffer_sub_data_async;\r\n\r\n    if (gl.WEBGL_get_buffer_sub_data_async) {\r\n      gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, gl.tf_bo);\r\n      this.gbsd_async_ready = false;\r\n      const this_ = this;\r\n\r\n      gl.WEBGL_get_buffer_sub_data_async.getBufferSubDataAsync(\r\n          gl.TRANSFORM_FEEDBACK_BUFFER, 0, tf_output, 0, tf_output.length).\r\n          then(function(buffer) {\r\n            this_.gbsd_async_ready = true;\r\n          });\r\n      gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, null);\r\n    }\r\n    return processed;\r\n  }\r\n\r\n  getMVPMatrix() {\r\n    return getMvpMatrix(window.innerWidth, window.innerHeight);\r\n  }\r\n\r\n  draw(mvp = null, lightmvp, light_position, shadow_map_unit) {\r\n    const gl = this.gl;\r\n    if (!video_loaded)\r\n      return;\r\n\r\n    gl.useProgram(gl.render_program);\r\n    \r\n    gl.uniformMatrix4fv(gl.render_u_mvp, false, mvp || this.getMVPMatrix());\r\n    const point_size = ((window.innerHeight / height) | 0) + 1;\r\n    gl.uniform1f(gl.render_u_pointSize, point_size);\r\n    if (lightmvp) {\r\n      gl.uniformMatrix4fv(gl.u_mvp_from_light, false, lightmvp);\r\n      gl.uniform1f(gl.u_draw_lighting, 1.0);\r\n      gl.uniform1i(gl.render_u_shadow_map, shadow_map_unit);\r\n    } else {\r\n      // TODO: separate program for shadow rendering.\r\n      gl.uniform1f(gl.u_draw_lighting, 0);\r\n      // shadow map texture is bound to framebuffer. prevent loop as we use the\r\n      // same program for lighting and read from the same texture. \r\n      gl.uniform1i(gl.render_u_shadow_map, shadow_map_unit + 1);\r\n    }\r\n\r\n    if (light_position)\r\n      gl.uniform3fv(gl.render_u_light_position, light_position);\r\n\r\n    gl.bindVertexArray(gl.depth_vao);\r\n    gl.activeTexture(gl.depth_tex_unit);\r\n    gl.bindTexture(gl.TEXTURE_2D, gl.depth_texture);\r\n    gl.drawArrays(gl.POINTS, 0, width * height);\r\n    gl.bindVertexArray(null);\r\n  }\r\n\r\n  createDepthInfoCanvas() {\r\n    var canvas = document.createElement('canvas');\r\n    canvas.id = \"testCanvas2D\";\r\n    canvas.width = 640;\r\n    canvas.height = 480;\r\n    canvas.style.zIndex = 8;\r\n    canvas.style.position = \"absolute\";\r\n    canvas.style.border = \"1px solid\";\r\n    var body = document.getElementsByTagName(\"body\")[0];\r\n    body.appendChild(canvas);\r\n    this.testContext = canvas.getContext(\"2d\");\r\n  }\r\n\r\n  videoLoaded(video, stream) {\r\n    const gl = this.gl;\r\n    gl.bindBuffer(gl.ARRAY_BUFFER, gl.tf_bo);\r\n    tf_output = new Float32Array(video.videoWidth * video.videoHeight);\r\n    gl.bufferData(gl.ARRAY_BUFFER, tf_output.length * 4, gl.DYNAMIC_READ);\r\n    gl.bindBuffer(gl.ARRAY_BUFFER, null);\r\n    links = new Array(video.videoWidth * video.videoHeight).fill(-1);\r\n\r\n    width = video.videoWidth;\r\n    height = video.videoHeight;\r\n    this.width = width;\r\n    this.height = height;\r\n    try {\r\n      this.setCameraParameters(DepthCamera.getCameraCalibration(stream));\r\n    } catch(e) {\r\n      return handleError(e);\r\n    }\r\n    if (this.depthVideoLoadedCallback)\r\n      this.depthVideoLoadedCallback();\r\n  }\r\n\r\n  setCameraParameters(parameters) {\r\n    const gl = this.gl;    \r\n    const nearplane = 0.0;\r\n    const farplane = 0.75 / parameters.depthScale;\r\n    const program = gl.render_program;\r\n    gl.useProgram(program);\r\n    let shaderVar = gl.getUniformLocation(program, \"u_depth_scale\");\r\n    gl.uniform1f(shaderVar, parameters.depthScale);\r\n    const depthIntrinsics = parameters.getDepthIntrinsics(width, height);\r\n    shaderVar = gl.getUniformLocation(program, \"u_depth_focal_length_inv\");\r\n    const inv_focal_length = [1 / depthIntrinsics.focalLength[0], 1 / depthIntrinsics.focalLength[1]];\r\n    gl.uniform2fv(shaderVar, inv_focal_length);\r\n    shaderVar = gl.getUniformLocation(program, \"u_depth_offset\");\r\n    gl.uniform2fv(shaderVar, depthIntrinsics.offset);\r\n    gl.uniform2f(gl.getUniformLocation(program, \"u_depth_texture_size\"), width, height);\r\n    var shaderDepthTexture = gl.getUniformLocation(program, \"u_depth_texture\");\r\n    gl.uniform1i(shaderDepthTexture, gl.depth_tex_unit - gl.TEXTURE0);\r\n\r\n    this.depth_focal_inv = [1 / depthIntrinsics.focalLength[0],\r\n                            1 / depthIntrinsics.focalLength[1]];\r\n    this.depth_offset = depthIntrinsics.offset;\r\n    this.depth_scale = parameters.depthScale;\r\n\r\n    gl.useProgram(gl.compute_program);\r\n    gl.uniform2f(gl.getUniformLocation(gl.compute_program, \"u_plane\"), nearplane, farplane);\r\n    gl.uniform2f(gl.getUniformLocation(gl.compute_program, \"u_depth_size\"), width, height);\r\n\r\n    \r\n    // Coefficient is used to calculate the width of finger (in pixels) on given\r\n    // distance (depth) from camera. Assume that finger is wider than 0.6 cm.\r\n    const finger_half_width = 0.0027 * depthIntrinsics.focalLength[0] / parameters.depthScale;\r\n    gl.uniform1f(gl.getUniformLocation(gl.compute_program, \"finger_half_width\"), finger_half_width);\r\n    // 5 cm for longest finger segment. Fingers usually have 2-3 of those.\r\n    segment_coef = 0.05 * depthIntrinsics.focalLength[0] / parameters.depthScale;\r\n    this.depth_coef = this.depth_scale * this.depth_focal_inv[0]; // cache the computed\r\n  }\r\n\r\n  setXZFlip(value) {\r\n    const gl = this.gl; \r\n    gl.useProgram(gl.render_program);\r\n    gl.uniform1f(gl.render_u_xz_flip, value ? 0.0 : 1.0);\r\n    gl.useProgram(gl.compute_program);\r\n    gl.uniform1f(gl.compute_u_xz_flip, value ? 0.0 : 1.0);\r\n  }\r\n\r\n  identifyJointsAndFixNoise(segment_data) {\r\n    // in segment data, identify end points that are joints.\r\n    let keys = Object.keys(segment_data);\r\n\r\n    function square(p) { return p * p; }\r\n    function pointsNear(p, seg1, coef, scale) {\r\n      const distance = square(coef * (seg1.x - p.x)) + square(coef * (seg1.y - p.y))\r\n                     + square(scale * (seg1.depth - p.depth));\r\n      return distance < 0.0009;                \r\n    }\r\n\r\n    for (let k = 0; k < keys.length; k++) {\r\n      const seg0 = segment_data[keys[k]];\r\n      const fl = seg0.far_left;\r\n      const fr = seg0.far_right;\r\n      for (let l = k + 1; l < keys.length; l++) {\r\n        const seg1 = segment_data[keys[l]];\r\n        // rough/fast estimation on arbitrary threshold.\r\n        const coef = seg1.depth * this.depth_coef;\r\n        const scale = this.depth_scale;\r\n        if (pointsNear(fl, seg1, coef, scale)) {\r\n          fl.joint = seg1.index;\r\n          seg1.joint = fl.index;\r\n        }\r\n        if (pointsNear(fr, seg1, coef, scale)) {\r\n          fr.joint = seg1.index;\r\n          seg1.joint = fr.index;\r\n        }\r\n      }\r\n      // check the special cases: vertical and horizontal orientation.\r\n      const maxy = Math.max(fr.y, fl.y);\r\n      if (fr.x - fl.x < 0.3 * (maxy - seg0.y)) {\r\n        // vertical thing, use the furthest one.\r\n        const in_the_middle = (fr.y < fl.y) ? fr : fl;\r\n        in_the_middle.joint = in_the_middle.index;\r\n      } else {\r\n        const ignore = seg0.count_right < seg0.count_left ? fr : fl;\r\n        ignore.joint = ignore.index;\r\n      }\r\n    }\r\n\r\n    // For endpoints that are not joints, we average using center points where\r\n    // available.\r\n    function useCenterIfAvailable(p) {\r\n      if (p.center.x == -1)\r\n        return;\r\n      p.x_original = p.x;\r\n      p.y_original = p.y;\r\n      p.x = p.center.x;\r\n      p.y = p.center.y;\r\n      p.index = p.x + p.y * width;\r\n      p.depth = modf(tf_output[p.index]);\r\n    }\r\n\r\n    function moveAwayFromEdge(p, to) {\r\n      // Limit the movement to 5mm.\r\n      const pixels = segment_coef_5mm / p.depth;\r\n      let xstep = 1;\r\n      let ystep = 1;\r\n      let steps = pixels;\r\n      const xdiff = Math.abs(p.x - to.x);\r\n      const ydiff = Math.abs(p.y - to.y);\r\n      if (xdiff < 2 && ydiff < 2)\r\n        return;\r\n      const hypotenuse = Math.sqrt(xdiff * xdiff + ydiff * ydiff);\r\n      if (xdiff > ydiff) {\r\n        xstep = Math.sign(p.x - to.x);\r\n        ystep = (p.y - to.y) / hypotenuse;\r\n        steps = pixels * xdiff / hypotenuse;\r\n      } else {\r\n        ystep = Math.sign(p.y - to.y);\r\n        xstep = (p.x - to.x) / hypotenuse;\r\n        steps = pixels * ydiff / hypotenuse;\r\n      }\r\n      let hitedge = false;\r\n      let x = p.x + 0.5;\r\n      let y = p.y + 0.5;\r\n      let i = 1;\r\n      while (i < steps) {\r\n        x += xstep;\r\n        y += ystep;\r\n        if (tf_output[(y | 0) * width + (x | 0)] == 0) {\r\n          break;\r\n        }\r\n        i++;\r\n      }\r\n      if (i >= steps)\r\n        return;\r\n      x = p.x - xstep * (steps - i);\r\n      y = p.y - ystep * (steps - i);\r\n      p.x = (x + 0.5) | 0;\r\n      p.y = (y + 0.5) | 0;\r\n    }\r\n\r\n    const segment_coef_5mm = segment_coef * 0.12;\r\n    for (let k = 0; k < keys.length; k++) {\r\n      const seg0 = segment_data[keys[k]];\r\n      if (!seg0.far_left.hasOwnProperty(\"joint\"))\r\n        useCenterIfAvailable(seg0.far_left);\r\n      if (!seg0.far_right.hasOwnProperty(\"joint\"))\r\n        useCenterIfAvailable(seg0.far_right);\r\n      // Move ends away from the edge.\r\n      const end = seg0.far_left.hasOwnProperty(\"joint\") ? seg0.far_right : seg0.far_left;\r\n      if (!end.hasOwnProperty(\"joint\"))\r\n        moveAwayFromEdge(end, seg0);\r\n      if (!seg0.hasOwnProperty(\"joint\"))\r\n        moveAwayFromEdge(seg0, end);\r\n    }\r\n  }\r\n\r\n  // Non skeleton means that client knows the depth value is not on skeleton and\r\n  // here we know it is encoded as negative. Saves one abs - premature optimization :)\r\n  getDepthNonSkeleton(x, y) {\r\n    return modf(-tf_output[y * width + x]);\r\n  }\r\n\r\n  getSegmentInterpolatedCount(segment) {\r\n    const end = this.getSegmentEnd(segment);\r\n    return (end.distance2D * INTERPOLATE_INV) | 0;  \r\n  }\r\n\r\n  // vec is float[3]: x, y in pixels define the screen point and depth is the captured\r\n  // value at the point.\r\n  getInterpolatedPoint(vec, segment, i) {\r\n    const end = this.getSegmentEnd(segment);\r\n    const coef = (i + 1) / (end.distance2D * INTERPOLATE_INV);\r\n    vec[0] = (segment.x + coef * (end.x - segment.x)) | 0;\r\n    vec[1] = (segment.y + coef * (end.y - segment.y)) | 0;\r\n    vec[2] = segment.depth + coef * (end.depth - segment.depth);\r\n  }\r\n\r\n  getSegmentEnd(seg) {\r\n    // TODO: move this to identifyJoints if used always.\r\n    let end = (seg.count_left > seg.count_right) ? seg.far_left : seg.far_right;\r\n    const jl = seg.far_left.hasOwnProperty(\"joint\");\r\n    const jr = seg.far_right.hasOwnProperty(\"joint\");\r\n    if (jl && !jr)\r\n      end = seg.far_right;\r\n    else if (jr && !jl)\r\n      end = seg.far_left;\r\n    if (!end.distance2D) {\r\n      const x = end.x - seg.x;\r\n      const y = end.y - seg.y;\r\n      end.distance2D = Math.sqrt(x * x + y * y);\r\n    }\r\n    return end;\r\n  }\r\n}\r\n\r\nvar video_loaded = false;\r\n\r\nfunction handleError(error) {\r\n  if (error.name == 'TrackStartError' || error.name == 'UnsupportedSizeError') {\r\n    return reload();\r\n  }\r\n  if (error.name == \"OverconstrainedError\" && error.constraint == \"videoKind\")\r\n    return console.error(\"No device with \\\"videoKind == depth\\\" capture available.\");\r\n  console.error(error);\r\n}\r\n\r\n// Offscreen |video| we use to upload depth content to WebGL texture.\r\nlet init_done = false;\r\nlet video_last_upload_time = -1;\r\nlet video = createDepthVideo();\r\n\r\nfunction createDepthVideo() {\r\n  var video = document.createElement(\"video\");\r\n  video.autoplay = true;\r\n  video.loop = true;\r\n  video.crossOrigin = \"anonymous\";\r\n  video.width = 640;\r\n  video.height = 480;\r\n  video.oncanplay = function(){\r\n    video_loaded=true;\r\n    init_done = false;\r\n  };  \r\n  return video;\r\n}\r\n\r\nfunction reload() {\r\n  if (window.stream) {\r\n    window.stream.getTracks().forEach(function(track) {\r\n      track.stop();\r\n    });\r\n  }\r\n\r\n  function streamOpened(stream) {\r\n    video.srcObject = stream;\r\n    window.stream = stream;\r\n    video_loaded = false;\r\n    init_done = false;\r\n    retrycount = 2;\r\n  };\r\n\r\n  DepthCamera.getDepthStream().then(streamOpened).catch(handleError);\r\n}\r\n\r\nfunction putReadPixelsToTestCanvas(testContext) {\r\n  if (testContext == undefined)\r\n    return;\r\n  const img = testContext.getImageData(0, 0, video.width, video.height);\r\n  const data = img.data;\r\n  const segment_data = out.segment_data;\r\n\r\n  for (let i = 0, j = 0; i < data.length; i += 4) {\r\n    let val = tf_output[i / 4];\r\n    let depth = val > 0.0 ? 110 : (modf(-val) * 1200);\r\n    if (val < 0 && links[i / 4] != -1)\r\n      depth = 60; // visited points.\r\n    data[i] = depth;\r\n    data[i + 1] = depth;\r\n    data[i + 1] = depth;\r\n    if (val > -1)\r\n      data[i + 2] = depth;\r\n    else\r\n      data[i + 2] = 0;\r\n    data[i+3] = 255;\r\n  }\r\n\r\n  testContext.putImageData(img, 0, 0);\r\n\r\n  // draw the connected segments\r\n  testContext.strokeStyle=\"#00FF00\";\r\n  let keys = Object.keys(segment_data);\r\n  for (let k = 0; k < keys.length; k++) {\r\n    const keystring = keys[k];\r\n    const segment = segment_data[keystring];\r\n    const index = parseInt(keystring);\r\n\r\n    let strokeStyle = \"#00FF00\";\r\n    if (segment.hasOwnProperty(\"discarded\"))\r\n      strokeStyle=\"#FF0000\";\r\n\r\n    const column = index % width;\r\n    const row = Math.floor(index / width);\r\n    if (column !== segment.x && row !== segment.y)\r\n      console.log(\"error column/row wrong\");\r\n\r\n    let item = segment.far_left;\r\n    if (item.index !== undefined) {\r\n      if (item.hasOwnProperty(\"joint\"))\r\n        testContext.strokeStyle = \"#AAAA00\";\r\n      else\r\n        testContext.strokeStyle = strokeStyle;\r\n      testContext.beginPath();\r\n      testContext.fillStyle=\"#FFFF00\";\r\n      testContext.fillRect(column, row, 2, 2);\r\n      if (item.hasOwnProperty(\"x_original\")) {\r\n        testContext.fillStyle=\"#007F7F\";\r\n        testContext.fillRect(item.x_original, item.y_original, 2, 2);\r\n        testContext.fillStyle=\"#FFFFFF\";        \r\n      } else {\r\n        testContext.fillStyle=\"#0000FF\";\r\n      }\r\n      testContext.fillRect(item.x, item.y, 2, 2);\r\n      testContext.moveTo(column, row);\r\n      testContext.lineTo(item.x, item.y);\r\n      testContext.stroke();      \r\n    }\r\n\r\n    item = segment.far_right;\r\n    if (item.index !== undefined) {\r\n      if (item.hasOwnProperty(\"joint\"))\r\n        testContext.strokeStyle=\"#AAAA00\";\r\n      else\r\n        testContext.strokeStyle = strokeStyle;\r\n      testContext.beginPath();\r\n      testContext.moveTo(column, row);\r\n      testContext.lineTo(item.x, item.y);\r\n      if (item.hasOwnProperty(\"x_original\")) {\r\n        testContext.fillStyle=\"#7F7F00\";\r\n        testContext.fillRect(item.x_original, item.y_original, 2, 2);\r\n        testContext.fillStyle=\"#FFFFFF\";        \r\n      } else {\r\n        testContext.fillStyle=\"#FF0000\";        \r\n      }\r\n      testContext.fillRect(item.x, item.y, 2, 2);\r\n\r\n      testContext.stroke();      \r\n    }\r\n\r\n    // Draw joints\r\n    \r\n//    testContext.fillStyle=\"#FF0000\";\r\n//    testContext.fillRect(column, row, 2, 2);\r\n//    testContext.stroke();\r\n  }\r\n  const img1 = testContext.getImageData(0, 0, video.width, video.height);\r\n  testContext.putImageData(img1, 0, 0);\r\n\r\n}\r\n\r\n// Creates WebGL/WebGL2 context used to upload depth video to texture.\r\nfunction initGL(gl, drawGL) {\r\n  // EXT_color_buffer_float to use single component R32F texture format.\r\n  gl.color_buffer_float_ext = gl.getExtension('EXT_color_buffer_float');\r\n  gl.WEBGL_get_buffer_sub_data_async = gl.getExtension(\"WEBGL_get_buffer_sub_data_async\");\r\n  if (drawGL) {\r\n    drawGL.color_buffer_float_ext = drawGL.getExtension('EXT_color_buffer_float') ||\r\n                                    drawGL.getExtension('OES_texture_float');\r\n  }\r\n\r\n  if (!gl || !gl.color_buffer_float_ext) {\r\n    alert(\"The depth capture demo doesn't run because it requires WebGL2 support with EXT_color_buffer_float.\");\r\n    return;\r\n  }\r\n\r\n  gl.enable(gl.BLEND);\r\n  gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);\r\n\r\n  // Transform feedback vertex shader is used for detecting \"finger skeleton\"\r\n  // candidate points. Passes the result as \"out depth\": if depth is > 1.0 then\r\n  // the CPU side of algorithm collects nearby skeleton points to segments.  \r\n  var tf_vertex_shader = gl.createShader(gl.VERTEX_SHADER);\r\n  gl.shaderSource(tf_vertex_shader, `#version 300 es\r\n    uniform sampler2D s_depth;\r\n    uniform vec2 u_depth_size;\r\n    uniform vec2 u_plane;\r\n    uniform float finger_half_width;\r\n    uniform float xz_flip;\r\n    out float depth;\r\n\r\n    void main() {\r\n      vec2 depth_pixel;\r\n      depth_pixel.x = mod(float(gl_VertexID), u_depth_size.x) + 0.5;\r\n      depth_pixel.y = clamp(floor(float(gl_VertexID) / u_depth_size.x),\r\n                            0.0, u_depth_size.y) + 0.5;\r\n      vec2 tex_pos = depth_pixel / u_depth_size;\r\n\r\n      // If camera faces towards user, mirror the display.\r\n      if (xz_flip != 0.0)\r\n        tex_pos.x = 1.0 - tex_pos.x;\r\n\r\n      depth = texture(s_depth, tex_pos).r;\r\n      if (depth <= u_plane.x || depth >= u_plane.y) {\r\n      \tdepth = 0.0;\r\n        return;\r\n      }\r\n\r\n      vec2 step = vec2(1.0, 1.0) / u_depth_size;\r\n\r\n      float d_0;\r\n      float d_90;\r\n      float d_180;\r\n      float d_270;\r\n\r\n      // Calculate max_width of the finger at the given distance. Asuming that finger is\r\n      // wider than ~0.6cm, min_width_half is width (in pixels) related to 0.3 cm.\r\n      float min_width_half = finger_half_width / depth;\r\n      float max_width_half = min_width_half * 6.0;\r\n\r\n      // Sample around and increase the distance of samples to the point.\r\n      // The idea is that on distance D all the samples are inside the area\r\n      // but on the distance D + 3, 3 or 4 out of 4 are outside the area. This\r\n      // would make the point \"fingertip point\" (e.g part of the skeleton) for\r\n      // the area.\r\n      float width_step = min_width_half * 0.8;\r\n      float inside_count = 4.0;\r\n\r\n      float k = 0.0; \r\n      float s_y = 1.0;\r\n      float s_x = 1.0;\r\n      float i = max(min_width_half * 0.19, 1.0); // 0.19 + 0.8 = 0.99, check k.\r\n\r\n      for (; i < max_width_half; i += width_step, k++) {\r\n        d_0   =  texture(s_depth, tex_pos + vec2( i, 0.0) * step).r;\r\n        d_90  =  texture(s_depth, tex_pos - vec2( 0.0, i) * step).r;\r\n        d_180 =  texture(s_depth, tex_pos - vec2( i, 0.0) * step).r;\r\n        d_270 =  texture(s_depth, tex_pos + vec2( 0.0, i) * step).r;\r\n        if (d_0 * d_90 * d_180 * d_270 == 0.0) {\r\n          s_x = sign(d_0) + sign(d_180);\r\n          s_y = sign(d_90) + sign(d_270);                    \r\n          inside_count = s_x + s_y;\r\n          break;\r\n        }\r\n      }\r\n\r\n      // k > 2.0 serves to eliminate \"thin\" areas. We pass depth > 0 through\r\n      // transform feedback, so that CPU side of algorithm would understands\r\n      // that this point is \"part of finger bone\" point and process it further.\r\n      if (k > 2.0 && inside_count <= 1.0) {\r\n        depth = depth + k;\r\n        return;\r\n      } else if (k > 2.0 && inside_count == 2.0 && (s_x * s_y == 0.0))\r\n        return;\r\n\r\n      // We also need large areas info as they are modeled using circles - as a\r\n      // net of pearls.\r\n      depth = -depth;\r\n      if (inside_count > 3.0)\r\n        depth -= 1.0;\r\n    }`\r\n  );\r\n  gl.compileShader(tf_vertex_shader);\r\n\r\n  var tf_dummy_pixel_shader = gl.createShader(gl.FRAGMENT_SHADER);\r\n  gl.shaderSource(tf_dummy_pixel_shader, `#version 300 es\r\n  \tprecision mediump float;\r\n    in float depth;\r\n    void main() {\r\n    }`\r\n  );\r\n  gl.compileShader(tf_dummy_pixel_shader);\r\n\r\n  var compute_program = gl.createProgram();\r\n  gl.attachShader(compute_program, tf_vertex_shader);\r\n  gl.attachShader(compute_program, tf_dummy_pixel_shader);\r\n  gl.transformFeedbackVaryings(compute_program, [\"depth\"], gl.SEPARATE_ATTRIBS);\r\n  gl.linkProgram(compute_program);\r\n  console.log(gl.getShaderInfoLog(tf_vertex_shader));\r\n  gl.useProgram(compute_program);\r\n  gl.depth_vao = gl.createVertexArray();\r\n  gl.bindVertexArray(gl.depth_vao);\r\n  // To restore state of vertex attrib arrays\r\n  const vattrib_count = Math.min(32, gl.getParameter(gl.MAX_VERTEX_ATTRIBS));\r\n  for (let i = 0; i < vattrib_count; i++)\r\n    gl.disableVertexAttribArray(i); \r\n  gl.bindVertexArray(null);\r\n  var tf_bo = gl.createBuffer();\r\n  gl.bindBuffer(gl.ARRAY_BUFFER, tf_bo);\r\n  var transform_feedback = gl.createTransformFeedback();\r\n  gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, transform_feedback)\r\n\r\n  gl.uniform1i(gl.getUniformLocation(compute_program, \"s_depth\"), gl.depth_tex_unit - gl.TEXTURE0);\r\n  gl.compute_u_xz_flip = gl.getUniformLocation(compute_program, \"xz_flip\");\r\n  gl.uniform1i(gl.compute_u_xz_flip, 0);\r\n\r\n  // 3D Pointcloud rendering.\r\n  var vertex_shader = gl.createShader(gl.VERTEX_SHADER);\r\n  gl.shaderSource(vertex_shader, `#version 300 es\r\n    precision mediump float;\r\n    // Run a vertex shader instance for each depth data point to create\r\n    // 3D model of the data (pointcloud).\r\n\r\n    ////////////////////////////////////////////////////////////////////\r\n    // Parameters of the currently used camera, see\r\n    // https://github.com/IntelRealSense/librealsense/blob/master/doc/projection.md\r\n    // and the documentation at\r\n    // https://w3c.github.io/mediacapture-depth/#synchronizing-depth-and-color-video-rendering\r\n\r\n\r\n    // Used to convert the raw depth data into meters.\r\n    // Corresponds to rs_get_device_depth_scale() in librealsense.\r\n    uniform float u_depth_scale;\r\n    // Center of projection of the depth camera data.\r\n    uniform vec2 u_depth_offset;\r\n    // Focal length of the depth data.\r\n    uniform vec2 u_depth_focal_length_inv;\r\n    ////////////////////////////////////////////////////////////////////\r\n\r\n    // Model-View-Projection matrix.\r\n    uniform mat4 u_mvp;\r\n    uniform mat4 u_mvp_from_light;\r\n\r\n    uniform float u_draw_lighting;\r\n    uniform float u_pointSize;\r\n    uniform float xz_flip;\r\n\r\n    uniform sampler2D u_depth_texture;\r\n\r\n    // Width and height of the depth data.\r\n    uniform vec2 u_depth_texture_size;\r\n    out vec3 v_normal;\r\n    out vec3 v_position;\r\n    out vec4 v_position_from_light;\r\n\r\n    // Convert the index of the depth data (ranged from [0, 0] to\r\n    // [u_depth_texture_size.x, u_depth_texture_size.y]) into a position\r\n    // in 3D space. The depth parameter needs to be in meters.\r\n    // This should be equivalent to what rs_deproject_pixel_to_point()\r\n    // in librealsense does.\r\n    vec4 depth_deproject(vec2 index, float depth) {\r\n        vec2 position2d = (index - u_depth_offset) * u_depth_focal_length_inv;\r\n        return vec4(position2d * depth, depth, 1.0);\r\n    }\r\n\r\n    void main() {\r\n        // Get the texture coordinates in range from [0, 0] to [1, 1]\r\n        vec2 depth_pixel;\r\n        depth_pixel.x = mod(float(gl_VertexID), u_depth_texture_size.x) + 0.5;\r\n        depth_pixel.y = clamp(floor(float(gl_VertexID) / u_depth_texture_size.x),\r\n                              0.0, u_depth_texture_size.y) + 0.5;\r\n        vec2 depth_texture_coord = depth_pixel / u_depth_texture_size;\r\n        if (xz_flip != 0.0)\r\n          depth_texture_coord.x = 1.0 - depth_texture_coord.x;\r\n        // The values of R, G and B should be equal, so we can just\r\n        // select any of them.\r\n        float depth = texture(u_depth_texture,\r\n                              depth_texture_coord).r;\r\n        if (depth == 0.0)\r\n          return;\r\n\r\n        // For example, a value of 1.5 means the current point is 1.5\r\n        // meters away.\r\n        float depth_scaled = u_depth_scale * depth;\r\n        // X and Y are the position within the depth texture (adjusted\r\n        // so that it matches the position of the RGB texture), Z is\r\n        // the depth.\r\n        vec4 position = depth_deproject(depth_pixel,\r\n                                        depth_scaled);\r\n        if (u_draw_lighting != 0.0) {\r\n          // Calculate normal based on surrounding pixels.\r\n          vec2 stepx = vec2(1.0, 0.0) / u_depth_texture_size;\r\n          vec2 stepy = vec2(0.0, 1.0) / u_depth_texture_size;\r\n          float d_0 = texture(u_depth_texture, depth_texture_coord + stepx).r;\r\n          float d_90 = texture(u_depth_texture, depth_texture_coord + stepy).r;\r\n          float d_180 = texture(u_depth_texture, depth_texture_coord - stepx).r;\r\n          float d_270 = texture(u_depth_texture, depth_texture_coord - stepy).r;\r\n\r\n          // Edges are tricky, for 0 depth pixels on edges, don't render.\r\n          // if (d_0 * d_90 * d_180 * d_270 == 0.0)\r\n          //   return;\r\n          float ddx = (d_0 - d_180) * 0.5;\r\n          float ddy = (d_90 - d_270) * 0.5;\r\n          v_normal = vec3(ddx, ddy, depth * u_depth_focal_length_inv.x);\r\n          v_position_from_light = u_mvp_from_light * position;\r\n        }\r\n\r\n        v_position = vec3(position);\r\n        gl_Position = u_mvp * position;\r\n        gl_PointSize = u_pointSize;\r\n    }`\r\n  );\r\n  gl.compileShader(vertex_shader);\r\n\r\n  var pixel_shader = gl.createShader(gl.FRAGMENT_SHADER);\r\n  gl.shaderSource(pixel_shader, `#version 300 es\r\n  \tprecision mediump float;\r\n    precision highp sampler2DShadow;\r\n    uniform sampler2DShadow u_shadow_map;\r\n\r\n    uniform float u_draw_lighting;\r\n    uniform vec3 u_light_position;\r\n\r\n    in vec3 v_normal;\r\n    in vec3 v_position;\r\n    in vec4 v_position_from_light;\r\n    out vec4 fragColor;\r\n    void main() {\r\n      if (u_draw_lighting != 1.0)\r\n        return;\r\n      vec3 s = (v_position_from_light.xyz / v_position_from_light.w) * 0.5 + 0.49;\r\n      float shadow = texture(u_shadow_map, s);\r\n      vec3 normal = normalize(v_normal);\r\n      vec3 to_eye = normalize(-v_position); // eye is in 0,0,0\r\n      // TODO: to_eye shouldnt be hardcoded.\r\n      vec3 to_light = normalize(vec3(0.7, -3.0, 1.0) - v_position);\r\n      // no specular component for hands.\r\n      float diffuse = shadow * max(dot(to_light, normal), 0.0) * 0.7;\r\n      float ambient = 0.3;   \r\n      fragColor = vec4(vec3(0.9, 0.9, 0.9) * (diffuse + ambient), 1.0);\r\n    }`\r\n  );\r\n  gl.compileShader(pixel_shader);\r\n\r\n  var program  = gl.createProgram();\r\n  gl.attachShader(program, vertex_shader);\r\n  gl.attachShader(program, pixel_shader);\r\n  gl.linkProgram(program);\r\n  console.log(gl.getShaderInfoLog(vertex_shader));\r\n  console.log(gl.getShaderInfoLog(pixel_shader));\r\n  console.log(gl.getProgramInfoLog(program));\r\n  gl.useProgram(program);\r\n\r\n  gl.uniform1i(gl.getUniformLocation(program, \"u_depth_texture\"), 0);\r\n\r\n  gl.render_u_mvp = gl.getUniformLocation(program, \"u_mvp\");\r\n  gl.u_mvp_from_light = gl.getUniformLocation(program, \"u_mvp_from_light\");\r\n  gl.u_draw_lighting = gl.getUniformLocation(program, \"u_draw_lighting\");  \r\n  gl.render_u_pointSize = gl.getUniformLocation(program, \"u_pointSize\");\r\n  gl.render_u_light_position = gl.getUniformLocation(program, \"u_light_position\");\r\n  gl.render_u_shadow_map = gl.getUniformLocation(program, \"u_shadow_map\");\r\n  gl.render_u_xz_flip = gl.getUniformLocation(program, \"xz_flip\");\r\n  gl.uniform1i(gl.render_u_xz_flip, 0);\r\n  \r\n  function createDepthTexture(gl) {\r\n    var depth_texture = gl.createTexture();\r\n    gl.bindTexture(gl.TEXTURE_2D, depth_texture);\r\n    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\r\n    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\r\n    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\r\n    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\r\n    return depth_texture;  \r\n  };\r\n  // Upload the latest depth frame to this texture.\r\n  gl.depth_texture = createDepthTexture(gl);\r\n  if (drawGL)\r\n    drawGL.depth_texture = createDepthTexture(drawGL);\r\n\r\n  gl.render_program = program;\r\n  gl.compute_program = compute_program;\r\n  gl.transform_feedback = transform_feedback;\r\n  gl.tf_bo = tf_bo;\r\n}\r\n\r\nfunction getMvpMatrix(screenwidth, screenheight) {\r\n    var model = new mat4.create();\r\n    var view = new mat4.create();\r\n    mat4.lookAt(view,\r\n        vec3.fromValues(0, 0, 0),   // eye\r\n        vec3.fromValues(0, 0, 0.4),   // target\r\n        vec3.fromValues(0, -1, 0));  // up\r\n\r\n    var aspect = screenwidth / screenheight;\r\n    var projection = new mat4.create();\r\n    mat4.perspective(projection, glMatrix.toRadian(60.0), aspect, 0.1, 20.0);\r\n\r\n    var mv = mat4.create();\r\n    mat4.multiply(mv, view, model);\r\n\r\n    var mvp = mat4.create();\r\n    mat4.multiply(mvp, projection, mv);\r\n    mat4.scale(mvp, mvp, [1.1, 1.1, 1]);\r\n    return mvp;\r\n}\r\n\r\nlet u_plane;\r\nlet tf_output;\r\n\r\n// Analysis intermediate data.\r\n// If != -1, marking that the point is connected to subsegment starting point,\r\n// and the value is sub-segment starting point's index. Only skeleton points\r\n// are procesed in the algorithm (speed concern) and only those have the values\r\n// != -1 - see markConnectedPoints.\r\nlet links;\r\n\r\n\r\nlet out;\r\nlet out1;\r\nlet out2;\r\nlet width;\r\nlet height;\r\n// The max length of a finger segment - determines the radius of circular\r\n// propagation using generate_concentric_circles_indices.js (5 cm)\r\nlet segment_coef;\r\n\r\nfunction processOnCPU() {\r\n  links.fill(-1);\r\n  segment_farthest_point_map_left = {};\r\n  segment_farthest_point_map_right = {};\r\n  const segment_data = {};\r\n  const net_inv = INTERPOLATE_INV;\r\n  const netw = Math.ceil(width * net_inv);\r\n  const neth = Math.ceil(height * net_inv);\r\n  const net = (out ? out.net : new Array(netw * neth)).fill(-1);\r\n\r\n  // We limit the gesture processing to area of the screen with margins 60 for\r\n  // screen size 640x480. This is to avoid the need of checking against the\r\n  // screen bounds.\r\n  const x_offset = Math.min(radius_offset.length, (width * 0.1) | 0, (height * 0.125) | 0);\r\n  const y_offset = x_offset;\r\n  const max_radius = x_offset;\r\n  let x_count = width - (2 * x_offset);\r\n  let y_end = height - y_offset;\r\n  for (let row = y_offset; row < y_end; row++) {\r\n    const row_offset = row * width;\r\n    let x = row_offset + x_offset;\r\n    const x_end = x + x_count;\r\n    for (; x < x_end; ++x) {\r\n      const value = tf_output[x];\r\n      if (value < -1) {\r\n        // Maintain the net of wide areas.\r\n        const column = x - row_offset;\r\n        const ncol = (column * net_inv) | 0;\r\n        const nrow = (row * net_inv) | 0;\r\n        const ni = netw * nrow + ncol;\r\n        if (net[ni] == -1)\r\n          net[ni] = (column << 16) | row;\r\n        continue;\r\n      } else if (value <= 0.0) {\r\n        continue; // Far away pixel if 0, or pixel that is not on a bone if < 0.\r\n      }\r\n      if (links[x] > -1)\r\n        continue; // If already on a segment.\r\n      const depth = modf(value);  \r\n      // Convert hand size from cm to pixels on given depth.\r\n      const radius = Math.min(max_radius, segment_coef / depth * 0.8);\r\n      markConnectedPoints(x, x - row_offset, row, radius, segment_data);\r\n    }\r\n  }\r\n  out2 = out1;\r\n  out1 = out;\r\n  out = {segment_data: segment_data, net: net, netw: netw, neth: neth};\r\n}\r\n\r\nfunction markConnectedPoints(index, column, row, radius, segment_data) {\r\n  connected.fill(false);\r\n  connected[0] = true;\r\n  links[index] = index;\r\n\r\n  // farthest index left and right.\r\n  let farthest_index_left = {index: index, x: column, y: row, center: {x: -1, y: -1}};\r\n  let farthest_index_right = {index: index, x: column, y: row, center: {x: -1, y: -1}};\r\n  let count_left = 0;\r\n  let count_right = 0;\r\n\r\n  for (var j = 1; j < radius; j++) {\r\n    let had_connection_on_radius = false;  // Don't go further if there are no points to connect.\r\n    const count_on_this_radius = count_per_radius[j];\r\n    // generate_concentric_circles_indices.js generates full circle, and we want\r\n    // to only go through lower half of the circle.\r\n    const r_start = radius_offset[j] + (count_on_this_radius >> 2);\r\n    const r_end = r_start + 1 + (count_on_this_radius >> 1);\r\n    for (var i = r_start; i < r_end; i++) {\r\n      const element_towards_center = towards_center[i];\r\n      // We get the index of element towards center. If the point is not\r\n      // connected to the center, don't bother analyzing it.\r\n      if (!connected[element_towards_center])\r\n        continue;\r\n      let elem = index + xs[i] + ys[i] * width;\r\n      const x_offset = xs[i];\r\n      const y_offset = ys[i];\r\n      let l = tf_output[elem];\r\n      if (l != 0.0) {\r\n        connected[i] = true;\r\n        had_connection_on_radius = true;\r\n        const x = column + x_offset;\r\n        const y = row + y_offset;\r\n        if (links[elem] > -1) {\r\n          // continue as the point is already allocated to other segment.\r\n          continue;\r\n        }\r\n        links[elem] = index;\r\n        if (l < 0.0)\r\n          continue; // The pixel is not on the finger bone. \r\n        // Track the farthest indices to the left and to the right.\r\n        if (x_offset < 0) {\r\n          if (l > 1.0) {\r\n            farthest_index_left.center.x = x;\r\n            farthest_index_left.center.y = y;\r\n          }\r\n          farthest_index_left.index = elem;\r\n          farthest_index_left.x = x;\r\n          farthest_index_left.y = y;\r\n          count_left++;\r\n        } else {\r\n          if (l > 1.0) {\r\n            farthest_index_right.center.x = x;\r\n            farthest_index_right.center.y = y;\r\n          }\r\n          farthest_index_right.index = elem;\r\n          farthest_index_right.x = x;\r\n          farthest_index_right.y = y;\r\n          count_right++;\r\n        }\r\n      }\r\n    }\r\n    if (!had_connection_on_radius)\r\n      break;\r\n  }\r\n\r\n  let data = {x:column, y:row, index: index, far_left: farthest_index_left,\r\n              far_right: farthest_index_right, count_left: count_left,\r\n              count_right: count_right, depth: modf(tf_output[index])};\r\n  farthest_index_left.depth = modf(tf_output[farthest_index_left.index]);\r\n  farthest_index_right.depth = modf(tf_output[farthest_index_right.index]);\r\n\r\n  segment_data[index] = data;\r\n}\r\n\r\nfunction modf(v) {\r\n  return v - (v | 0);\r\n}\r\n\r\n// Generated using generate_concentric_circles_indices.js for kernel 60.\r\n// This is used to enumerate through points on the same distance from the center,\r\n// similar to spreading of vawes of concentric circles and for each point of\r\n// the circle, use towards_center to calculate if the point is connected to the\r\n// center.\r\nvar xs = [0,0,1,1,1,0,-1,-1,-1,0,1,2,2,2,2,2,1,0,-1,-2,-2,-2,-2,-2,-1,0,1,2,3,3,3,3,3,2,1,0,-1,-2,-3,-3,-3,-3,-3,-2,-1,0,1,2,3,4,4,4,4,4,3,2,1,0,-1,-2,-3,-4,-4,-4,-4,-4,-3,-2,-1,0,1,2,3,3,4,4,5,5,5,5,5,5,5,4,4,3,3,2,1,0,-1,-2,-3,-3,-4,-4,-5,-5,-5,-5,-5,-5,-5,-4,-4,-3,-3,-2,-1,0,1,2,3,4,5,6,6,6,6,6,6,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-6,-6,-6,-6,-6,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,5,6,6,7,7,7,7,7,7,7,6,6,5,5,4,3,2,1,0,-1,-2,-3,-4,-5,-5,-6,-6,-7,-7,-7,-7,-7,-7,-7,-6,-6,-5,-5,-4,-3,-2,-1,0,1,2,3,4,4,5,6,7,7,8,8,8,8,8,8,8,8,8,7,7,6,5,4,4,3,2,1,0,-1,-2,-3,-4,-4,-5,-6,-7,-7,-8,-8,-8,-8,-8,-8,-8,-8,-8,-7,-7,-6,-5,-4,-4,-3,-2,-1,0,1,2,3,4,5,6,7,7,8,9,9,9,9,9,9,9,9,9,8,7,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-7,-8,-9,-9,-9,-9,-9,-9,-9,-9,-9,-8,-7,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,6,7,8,8,9,9,10,10,10,10,10,10,10,10,10,9,9,8,8,7,6,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-6,-7,-8,-8,-9,-9,-10,-10,-10,-10,-10,-10,-10,-10,-10,-9,-9,-8,-8,-7,-6,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,10,11,11,11,11,11,11,11,11,11,10,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-10,-11,-11,-11,-11,-11,-11,-11,-11,-11,-10,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,8,9,9,10,10,11,11,12,12,12,12,12,12,12,12,12,11,11,10,10,9,9,8,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-8,-9,-9,-10,-10,-11,-11,-12,-12,-12,-12,-12,-12,-12,-12,-12,-11,-11,-10,-10,-9,-9,-8,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,5,6,7,7,8,9,10,11,11,12,12,12,13,13,13,13,13,13,13,13,13,13,13,12,12,12,11,11,10,9,8,7,7,6,5,5,4,3,2,1,0,-1,-2,-3,-4,-5,-5,-6,-7,-7,-8,-9,-10,-11,-11,-12,-12,-12,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-12,-12,-12,-11,-11,-10,-9,-8,-7,-7,-6,-5,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,10,11,11,12,13,13,14,14,14,14,14,14,14,14,14,14,14,13,13,12,11,11,10,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-10,-11,-11,-12,-13,-13,-14,-14,-14,-14,-14,-14,-14,-14,-14,-14,-14,-13,-13,-12,-11,-11,-10,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,9,10,11,12,12,13,13,14,14,15,15,15,15,15,15,15,15,15,15,15,14,14,13,13,12,12,11,10,9,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-9,-10,-11,-12,-12,-13,-13,-14,-14,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-14,-14,-13,-13,-12,-12,-11,-10,-9,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,12,13,14,14,15,15,16,16,16,16,16,16,16,16,16,16,16,15,15,14,14,13,12,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-12,-13,-14,-14,-15,-15,-16,-16,-16,-16,-16,-16,-16,-16,-16,-16,-16,-15,-15,-14,-14,-13,-12,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,8,9,10,11,11,12,13,13,14,14,15,15,16,16,16,17,17,17,17,17,17,17,17,17,17,17,16,16,16,15,15,14,14,13,13,12,11,11,10,9,8,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-8,-9,-10,-11,-11,-12,-13,-13,-14,-14,-15,-15,-16,-16,-16,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-16,-16,-16,-15,-15,-14,-14,-13,-13,-12,-11,-11,-10,-9,-8,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,6,7,8,9,10,10,11,12,13,14,15,15,16,16,17,17,17,18,18,18,18,18,18,18,18,18,18,18,18,18,17,17,17,16,16,15,15,14,13,12,11,10,10,9,8,7,6,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-6,-7,-8,-9,-10,-10,-11,-12,-13,-14,-15,-15,-16,-16,-17,-17,-17,-18,-18,-18,-18,-18,-18,-18,-18,-18,-18,-18,-18,-18,-17,-17,-17,-16,-16,-15,-15,-14,-13,-12,-11,-10,-10,-9,-8,-7,-6,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,13,14,14,15,15,16,17,17,18,18,19,19,19,19,19,19,19,19,19,19,19,19,19,18,18,17,17,16,15,15,14,14,13,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-13,-14,-14,-15,-15,-16,-17,-17,-18,-18,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-18,-18,-17,-17,-16,-15,-15,-14,-14,-13,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,12,13,14,15,16,16,17,17,18,18,19,19,20,20,20,20,20,20,20,20,20,20,20,20,20,19,19,18,18,17,17,16,16,15,14,13,12,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-12,-13,-14,-15,-16,-16,-17,-17,-18,-18,-19,-19,-20,-20,-20,-20,-20,-20,-20,-20,-20,-20,-20,-20,-20,-19,-19,-18,-18,-17,-17,-16,-16,-15,-14,-13,-12,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,9,10,11,11,12,13,14,15,15,16,16,17,18,18,19,19,19,20,20,20,21,21,21,21,21,21,21,21,21,21,21,21,21,20,20,20,19,19,19,18,18,17,16,16,15,15,14,13,12,11,11,10,9,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-9,-10,-11,-11,-12,-13,-14,-15,-15,-16,-16,-17,-18,-18,-19,-19,-19,-20,-20,-20,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-20,-20,-20,-19,-19,-19,-18,-18,-17,-16,-16,-15,-15,-14,-13,-12,-11,-11,-10,-9,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,14,15,16,17,17,18,18,19,20,20,21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,21,21,21,20,20,19,18,18,17,17,16,15,14,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-14,-15,-16,-17,-17,-18,-18,-19,-20,-20,-21,-21,-21,-22,-22,-22,-22,-22,-22,-22,-22,-22,-22,-22,-22,-22,-21,-21,-21,-20,-20,-19,-18,-18,-17,-17,-16,-15,-14,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,13,14,15,16,17,18,19,19,20,20,21,21,22,22,22,23,23,23,23,23,23,23,23,23,23,23,23,23,22,22,22,21,21,20,20,19,19,18,17,16,15,14,13,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-13,-14,-15,-16,-17,-18,-19,-19,-20,-20,-21,-21,-22,-22,-22,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-22,-22,-22,-21,-21,-20,-20,-19,-19,-18,-17,-16,-15,-14,-13,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,17,17,18,18,19,19,20,21,21,22,22,23,23,23,24,24,24,24,24,24,24,24,24,24,24,24,24,23,23,23,22,22,21,21,20,19,19,18,18,17,17,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-16,-17,-17,-18,-18,-19,-19,-20,-21,-21,-22,-22,-23,-23,-23,-24,-24,-24,-24,-24,-24,-24,-24,-24,-24,-24,-24,-24,-23,-23,-23,-22,-22,-21,-21,-20,-19,-19,-18,-18,-17,-17,-16,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,7,8,9,10,11,12,12,13,14,15,15,16,17,18,19,20,20,21,21,22,22,23,23,23,24,24,24,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,24,24,24,23,23,23,22,22,21,21,20,20,19,18,17,16,15,15,14,13,12,12,11,10,9,8,7,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-7,-8,-9,-10,-11,-12,-12,-13,-14,-15,-15,-16,-17,-18,-19,-20,-20,-21,-21,-22,-22,-23,-23,-23,-24,-24,-24,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-24,-24,-24,-23,-23,-23,-22,-22,-21,-21,-20,-20,-19,-18,-17,-16,-15,-15,-14,-13,-12,-12,-11,-10,-9,-8,-7,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,10,11,12,13,14,14,15,16,17,18,18,19,19,20,20,21,22,22,23,23,24,24,24,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,25,25,25,24,24,24,23,23,22,22,21,20,20,19,19,18,18,17,16,15,14,14,13,12,11,10,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-10,-11,-12,-13,-14,-14,-15,-16,-17,-18,-18,-19,-19,-20,-20,-21,-22,-22,-23,-23,-24,-24,-24,-25,-25,-25,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-24,-24,-24,-23,-23,-22,-22,-21,-20,-20,-19,-19,-18,-18,-17,-16,-15,-14,-14,-13,-12,-11,-10,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,17,18,19,20,21,21,22,22,23,24,24,25,25,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,26,26,26,25,25,24,24,23,22,22,21,21,20,19,18,17,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-17,-18,-19,-20,-21,-21,-22,-22,-23,-24,-24,-25,-25,-26,-26,-26,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-26,-26,-26,-25,-25,-24,-24,-23,-22,-22,-21,-21,-20,-19,-18,-17,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,17,18,19,20,21,22,23,23,24,24,25,25,26,26,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,27,27,27,26,26,25,25,24,24,23,23,22,21,20,19,18,17,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-16,-17,-18,-19,-20,-21,-22,-23,-23,-24,-24,-25,-25,-26,-26,-27,-27,-27,-28,-28,-28,-28,-28,-28,-28,-28,-28,-28,-28,-28,-28,-28,-28,-27,-27,-27,-26,-26,-25,-25,-24,-24,-23,-23,-22,-21,-20,-19,-18,-17,-16,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,13,14,15,16,17,18,19,19,20,20,21,21,22,22,23,23,24,25,25,26,26,27,27,27,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,28,28,28,27,27,27,26,26,25,25,24,23,23,22,22,21,21,20,20,19,19,18,17,16,15,14,13,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-13,-14,-15,-16,-17,-18,-19,-19,-20,-20,-21,-21,-22,-22,-23,-23,-24,-25,-25,-26,-26,-27,-27,-27,-28,-28,-28,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-28,-28,-28,-27,-27,-27,-26,-26,-25,-25,-24,-23,-23,-22,-22,-21,-21,-20,-20,-19,-19,-18,-17,-16,-15,-14,-13,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15,16,17,18,18,19,20,21,22,23,24,24,25,25,26,26,27,27,28,28,28,29,29,29,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,29,29,29,28,28,28,27,27,26,26,25,25,24,24,23,22,21,20,19,18,18,17,16,15,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-15,-16,-17,-18,-18,-19,-20,-21,-22,-23,-24,-24,-25,-25,-26,-26,-27,-27,-28,-28,-28,-29,-29,-29,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-29,-29,-29,-28,-28,-28,-27,-27,-26,-26,-25,-25,-24,-24,-23,-22,-21,-20,-19,-18,-18,-17,-16,-15,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,11,12,13,14,15,16,17,17,18,19,20,21,21,22,22,23,23,24,24,25,26,26,27,27,28,28,29,29,29,30,30,30,30,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,30,30,30,30,29,29,29,28,28,27,27,26,26,25,24,24,23,23,22,22,21,21,20,19,18,17,17,16,15,14,13,12,11,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-11,-12,-13,-14,-15,-16,-17,-17,-18,-19,-20,-21,-21,-22,-22,-23,-23,-24,-24,-25,-26,-26,-27,-27,-28,-28,-29,-29,-29,-30,-30,-30,-30,-31,-31,-31,-31,-31,-31,-31,-31,-31,-31,-31,-31,-31,-31,-31,-30,-30,-30,-30,-29,-29,-29,-28,-28,-27,-27,-26,-26,-25,-24,-24,-23,-23,-22,-22,-21,-21,-20,-19,-18,-17,-17,-16,-15,-14,-13,-12,-11,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,8,9,10,11,12,13,14,15,16,17,18,19,20,20,21,22,23,24,25,25,26,26,27,28,28,29,29,30,30,31,31,31,31,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,31,31,31,31,30,30,29,29,28,28,27,26,26,25,25,24,23,22,21,20,20,19,18,17,16,15,14,13,12,11,10,9,8,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-20,-21,-22,-23,-24,-25,-25,-26,-26,-27,-28,-28,-29,-29,-30,-30,-31,-31,-31,-31,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-31,-31,-31,-31,-30,-30,-29,-29,-28,-28,-27,-26,-26,-25,-25,-24,-23,-22,-21,-20,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,19,20,21,22,23,23,24,24,25,25,26,27,27,28,28,29,29,30,30,31,31,32,32,32,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,32,32,32,31,31,30,30,29,29,28,28,27,27,26,25,25,24,24,23,23,22,21,20,19,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-19,-20,-21,-22,-23,-23,-24,-24,-25,-25,-26,-27,-27,-28,-28,-29,-29,-30,-30,-31,-31,-32,-32,-32,-33,-33,-33,-33,-33,-33,-33,-33,-33,-33,-33,-33,-33,-33,-33,-33,-33,-32,-32,-32,-31,-31,-30,-30,-29,-29,-28,-28,-27,-27,-26,-25,-25,-24,-24,-23,-23,-22,-21,-20,-19,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,14,15,16,16,17,18,18,19,20,21,22,22,23,24,25,26,26,27,27,28,29,29,30,30,30,31,31,31,32,32,32,33,33,33,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,33,33,33,32,32,32,31,31,31,30,30,30,29,29,28,27,27,26,26,25,24,23,22,22,21,20,19,18,18,17,16,16,15,14,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-14,-15,-16,-16,-17,-18,-18,-19,-20,-21,-22,-22,-23,-24,-25,-26,-26,-27,-27,-28,-29,-29,-30,-30,-30,-31,-31,-31,-32,-32,-32,-33,-33,-33,-34,-34,-34,-34,-34,-34,-34,-34,-34,-34,-34,-34,-34,-34,-34,-34,-34,-33,-33,-33,-32,-32,-32,-31,-31,-31,-30,-30,-30,-29,-29,-28,-27,-27,-26,-26,-25,-24,-23,-22,-22,-21,-20,-19,-18,-18,-17,-16,-16,-15,-14,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,21,22,23,24,25,26,27,28,28,29,29,30,31,31,32,32,33,33,33,34,34,34,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,34,34,34,33,33,33,32,32,31,31,30,29,29,28,28,27,26,25,24,23,22,21,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-21,-22,-23,-24,-25,-26,-27,-28,-28,-29,-29,-30,-31,-31,-32,-32,-33,-33,-33,-34,-34,-34,-35,-35,-35,-35,-35,-35,-35,-35,-35,-35,-35,-35,-35,-35,-35,-35,-35,-34,-34,-34,-33,-33,-33,-32,-32,-31,-31,-30,-29,-29,-28,-28,-27,-26,-25,-24,-23,-22,-21,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,20,21,22,23,24,24,25,25,26,26,27,27,28,28,29,30,30,31,31,32,32,33,33,34,34,34,35,35,35,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,35,35,35,34,34,34,33,33,32,32,31,31,30,30,29,28,28,27,27,26,26,25,25,24,24,23,22,21,20,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-20,-21,-22,-23,-24,-24,-25,-25,-26,-26,-27,-27,-28,-28,-29,-30,-30,-31,-31,-32,-32,-33,-33,-34,-34,-34,-35,-35,-35,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-35,-35,-35,-34,-34,-34,-33,-33,-32,-32,-31,-31,-30,-30,-29,-28,-28,-27,-27,-26,-26,-25,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,12,13,14,15,16,17,18,19,20,21,22,23,23,24,25,26,27,28,29,29,30,30,31,32,32,33,33,34,34,35,35,35,36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,36,36,36,35,35,35,34,34,33,33,32,32,31,30,30,29,29,28,27,26,25,24,23,23,22,21,20,19,18,17,16,15,14,13,12,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-23,-24,-25,-26,-27,-28,-29,-29,-30,-30,-31,-32,-32,-33,-33,-34,-34,-35,-35,-35,-36,-36,-36,-36,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-36,-36,-36,-36,-35,-35,-35,-34,-34,-33,-33,-32,-32,-31,-30,-30,-29,-29,-28,-27,-26,-25,-24,-23,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,17,18,19,19,20,21,22,22,23,24,25,26,26,27,27,28,28,29,29,30,31,31,32,32,33,33,34,34,34,35,35,35,36,36,37,37,37,37,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,37,37,37,37,36,36,35,35,35,34,34,34,33,33,32,32,31,31,30,29,29,28,28,27,27,26,26,25,24,23,22,22,21,20,19,19,18,17,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-17,-18,-19,-19,-20,-21,-22,-22,-23,-24,-25,-26,-26,-27,-27,-28,-28,-29,-29,-30,-31,-31,-32,-32,-33,-33,-34,-34,-34,-35,-35,-35,-36,-36,-37,-37,-37,-37,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-37,-37,-37,-37,-36,-36,-35,-35,-35,-34,-34,-34,-33,-33,-32,-32,-31,-31,-30,-29,-29,-28,-28,-27,-27,-26,-26,-25,-24,-23,-22,-22,-21,-20,-19,-19,-18,-17,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15,16,17,18,19,20,21,21,22,23,24,25,25,26,27,28,29,30,30,31,31,32,33,33,34,34,35,35,36,36,36,37,37,37,38,38,38,38,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,38,38,38,38,37,37,37,36,36,36,35,35,34,34,33,33,32,31,31,30,30,29,28,27,26,25,25,24,23,22,21,21,20,19,18,17,16,15,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-15,-16,-17,-18,-19,-20,-21,-21,-22,-23,-24,-25,-25,-26,-27,-28,-29,-30,-30,-31,-31,-32,-33,-33,-34,-34,-35,-35,-36,-36,-36,-37,-37,-37,-38,-38,-38,-38,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-38,-38,-38,-38,-37,-37,-37,-36,-36,-36,-35,-35,-34,-34,-33,-33,-32,-31,-31,-30,-30,-29,-28,-27,-26,-25,-25,-24,-23,-22,-21,-21,-20,-19,-18,-17,-16,-15,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,24,25,26,27,28,29,30,31,32,32,33,33,34,35,35,36,36,37,37,38,38,38,39,39,39,39,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,39,39,39,39,38,38,38,37,37,36,36,35,35,34,33,33,32,32,31,30,29,28,27,26,25,24,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-24,-25,-26,-27,-28,-29,-30,-31,-32,-32,-33,-33,-34,-35,-35,-36,-36,-37,-37,-38,-38,-38,-39,-39,-39,-39,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-39,-39,-39,-39,-38,-38,-38,-37,-37,-36,-36,-35,-35,-34,-33,-33,-32,-32,-31,-30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,23,24,25,26,27,27,28,28,29,29,30,30,31,31,32,32,33,34,34,35,35,36,36,37,37,38,38,39,39,39,40,40,40,40,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,40,40,40,40,39,39,39,38,38,37,37,36,36,35,35,34,34,33,32,32,31,31,30,30,29,29,28,28,27,27,26,25,24,23,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-23,-24,-25,-26,-27,-27,-28,-28,-29,-29,-30,-30,-31,-31,-32,-32,-33,-34,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-39,-39,-40,-40,-40,-40,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-40,-40,-40,-40,-39,-39,-39,-38,-38,-37,-37,-36,-36,-35,-35,-34,-34,-33,-32,-32,-31,-31,-30,-30,-29,-29,-28,-28,-27,-27,-26,-25,-24,-23,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,18,19,20,20,21,22,23,24,25,26,26,27,28,29,30,31,32,33,33,34,34,35,36,36,37,37,38,38,38,39,39,39,40,40,40,41,41,41,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,41,41,41,40,40,40,39,39,39,38,38,38,37,37,36,36,35,34,34,33,33,32,31,30,29,28,27,26,26,25,24,23,22,21,20,20,19,18,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-18,-19,-20,-20,-21,-22,-23,-24,-25,-26,-26,-27,-28,-29,-30,-31,-32,-33,-33,-34,-34,-35,-36,-36,-37,-37,-38,-38,-38,-39,-39,-39,-40,-40,-40,-41,-41,-41,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-41,-41,-41,-40,-40,-40,-39,-39,-39,-38,-38,-38,-37,-37,-36,-36,-35,-34,-34,-33,-33,-32,-31,-30,-29,-28,-27,-26,-26,-25,-24,-23,-22,-21,-20,-20,-19,-18,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,13,14,15,16,17,18,19,20,21,22,22,23,24,25,25,26,27,28,29,29,30,30,31,31,32,32,33,33,34,35,35,36,36,37,37,38,38,39,39,40,40,40,41,41,41,42,42,42,42,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,42,42,42,42,41,41,41,40,40,40,39,39,38,38,37,37,36,36,35,35,34,33,33,32,32,31,31,30,30,29,29,28,27,26,25,25,24,23,22,22,21,20,19,18,17,16,15,14,13,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-22,-23,-24,-25,-25,-26,-27,-28,-29,-29,-30,-30,-31,-31,-32,-32,-33,-33,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-39,-40,-40,-40,-41,-41,-41,-42,-42,-42,-42,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-42,-42,-42,-42,-41,-41,-41,-40,-40,-40,-39,-39,-38,-38,-37,-37,-36,-36,-35,-35,-34,-33,-33,-32,-32,-31,-31,-30,-30,-29,-29,-28,-27,-26,-25,-25,-24,-23,-22,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,17,18,19,20,21,22,23,24,24,25,26,27,28,28,29,30,31,32,33,34,34,35,35,36,37,37,38,38,39,39,40,40,41,41,41,42,42,42,43,43,43,43,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,43,43,43,43,42,42,42,41,41,41,40,40,39,39,38,38,37,37,36,35,35,34,34,33,32,31,30,29,28,28,27,26,25,24,24,23,22,21,20,19,18,17,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-16,-17,-18,-19,-20,-21,-22,-23,-24,-24,-25,-26,-27,-28,-28,-29,-30,-31,-32,-33,-34,-34,-35,-35,-36,-37,-37,-38,-38,-39,-39,-40,-40,-41,-41,-41,-42,-42,-42,-43,-43,-43,-43,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-43,-43,-43,-43,-42,-42,-42,-41,-41,-41,-40,-40,-39,-39,-38,-38,-37,-37,-36,-35,-35,-34,-34,-33,-32,-31,-30,-29,-28,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-19,-18,-17,-16,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,27,28,29,30,31,32,32,33,33,34,35,36,36,37,37,38,39,39,40,40,41,41,42,42,43,43,43,44,44,44,44,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,44,44,44,44,43,43,43,42,42,41,41,40,40,39,39,38,37,37,36,36,35,34,33,33,32,32,31,30,29,28,27,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-27,-28,-29,-30,-31,-32,-32,-33,-33,-34,-35,-36,-36,-37,-37,-38,-39,-39,-40,-40,-41,-41,-42,-42,-43,-43,-43,-44,-44,-44,-44,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-44,-44,-44,-44,-43,-43,-43,-42,-42,-41,-41,-40,-40,-39,-39,-38,-37,-37,-36,-36,-35,-34,-33,-33,-32,-32,-31,-30,-29,-28,-27,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,21,22,23,24,25,26,26,27,28,29,30,30,31,31,32,33,34,34,35,35,36,36,37,38,38,39,39,40,40,41,41,42,42,42,43,43,44,44,44,45,45,45,45,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,45,45,45,45,44,44,44,43,43,42,42,42,41,41,40,40,39,39,38,38,37,36,36,35,35,34,34,33,32,31,31,30,30,29,28,27,26,26,25,24,23,22,21,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-21,-22,-23,-24,-25,-26,-26,-27,-28,-29,-30,-30,-31,-31,-32,-33,-34,-34,-35,-35,-36,-36,-37,-38,-38,-39,-39,-40,-40,-41,-41,-42,-42,-42,-43,-43,-44,-44,-44,-45,-45,-45,-45,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-45,-45,-45,-45,-44,-44,-44,-43,-43,-42,-42,-42,-41,-41,-40,-40,-39,-39,-38,-38,-37,-36,-36,-35,-35,-34,-34,-33,-32,-31,-31,-30,-30,-29,-28,-27,-26,-26,-25,-24,-23,-22,-21,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,19,20,21,22,23,23,24,25,26,27,28,29,29,30,31,32,33,34,35,36,37,37,38,38,39,40,40,41,41,42,42,43,43,43,44,44,44,45,45,45,46,46,46,46,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,46,46,46,46,45,45,45,44,44,44,43,43,43,42,42,41,41,40,40,39,38,38,37,37,36,35,34,33,32,31,30,29,29,28,27,26,25,24,23,23,22,21,20,19,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-19,-20,-21,-22,-23,-23,-24,-25,-26,-27,-28,-29,-29,-30,-31,-32,-33,-34,-35,-36,-37,-37,-38,-38,-39,-40,-40,-41,-41,-42,-42,-43,-43,-43,-44,-44,-44,-45,-45,-45,-46,-46,-46,-46,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-46,-46,-46,-46,-45,-45,-45,-44,-44,-44,-43,-43,-43,-42,-42,-41,-41,-40,-40,-39,-38,-38,-37,-37,-36,-35,-34,-33,-32,-31,-30,-29,-29,-28,-27,-26,-25,-24,-23,-23,-22,-21,-20,-19,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,25,26,27,28,28,29,30,31,32,32,33,33,34,34,35,35,36,36,37,37,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,45,46,46,46,47,47,47,47,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,47,47,47,47,46,46,46,45,45,45,44,44,43,43,42,42,41,41,40,40,39,39,38,37,37,36,36,35,35,34,34,33,33,32,32,31,30,29,28,28,27,26,25,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-25,-26,-27,-28,-28,-29,-30,-31,-32,-32,-33,-33,-34,-34,-35,-35,-36,-36,-37,-37,-38,-39,-39,-40,-40,-41,-41,-42,-42,-43,-43,-44,-44,-45,-45,-45,-46,-46,-46,-47,-47,-47,-47,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-47,-47,-47,-47,-46,-46,-46,-45,-45,-45,-44,-44,-43,-43,-42,-42,-41,-41,-40,-40,-39,-39,-38,-37,-37,-36,-36,-35,-35,-34,-34,-33,-33,-32,-32,-31,-30,-29,-28,-28,-27,-26,-25,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,17,18,19,20,21,22,23,24,25,26,27,27,28,29,30,31,31,32,33,34,35,36,37,38,38,39,39,40,41,41,42,42,43,43,44,44,45,45,46,46,46,47,47,47,47,48,48,48,48,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,48,48,48,48,47,47,47,47,46,46,46,45,45,44,44,43,43,42,42,41,41,40,39,39,38,38,37,36,35,34,33,32,31,31,30,29,28,27,27,26,25,24,23,22,21,20,19,18,17,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-27,-28,-29,-30,-31,-31,-32,-33,-34,-35,-36,-37,-38,-38,-39,-39,-40,-41,-41,-42,-42,-43,-43,-44,-44,-45,-45,-46,-46,-46,-47,-47,-47,-47,-48,-48,-48,-48,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-48,-48,-48,-48,-47,-47,-47,-47,-46,-46,-46,-45,-45,-44,-44,-43,-43,-42,-42,-41,-41,-40,-39,-39,-38,-38,-37,-36,-35,-34,-33,-32,-31,-31,-30,-29,-28,-27,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,10,11,12,13,14,14,15,16,17,18,19,20,21,22,22,23,24,25,26,27,28,29,30,30,31,32,33,34,34,35,35,36,36,37,37,38,38,39,40,40,41,41,42,43,43,44,44,45,45,46,46,46,47,47,48,48,48,48,49,49,49,49,49,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,49,49,49,49,49,48,48,48,48,47,47,46,46,46,45,45,44,44,43,43,42,41,41,40,40,39,38,38,37,37,36,36,35,35,34,34,33,32,31,30,30,29,28,27,26,25,24,23,22,22,21,20,19,18,17,16,15,14,14,13,12,11,10,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-10,-11,-12,-13,-14,-14,-15,-16,-17,-18,-19,-20,-21,-22,-22,-23,-24,-25,-26,-27,-28,-29,-30,-30,-31,-32,-33,-34,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-40,-40,-41,-41,-42,-43,-43,-44,-44,-45,-45,-46,-46,-46,-47,-47,-48,-48,-48,-48,-49,-49,-49,-49,-49,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-49,-49,-49,-49,-49,-48,-48,-48,-48,-47,-47,-46,-46,-46,-45,-45,-44,-44,-43,-43,-42,-41,-41,-40,-40,-39,-38,-38,-37,-37,-36,-36,-35,-35,-34,-34,-33,-32,-31,-30,-30,-29,-28,-27,-26,-25,-24,-23,-22,-22,-21,-20,-19,-18,-17,-16,-15,-14,-14,-13,-12,-11,-10,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,24,25,26,26,27,28,29,29,30,31,32,33,33,34,35,36,37,38,39,39,40,40,41,42,42,43,43,44,44,45,45,45,46,46,47,47,47,48,48,49,49,49,50,50,50,50,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,50,50,50,50,49,49,49,48,48,47,47,47,46,46,45,45,45,44,44,43,43,42,42,41,40,40,39,39,38,37,36,35,34,33,33,32,31,30,29,29,28,27,26,26,25,24,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-24,-25,-26,-26,-27,-28,-29,-29,-30,-31,-32,-33,-33,-34,-35,-36,-37,-38,-39,-39,-40,-40,-41,-42,-42,-43,-43,-44,-44,-45,-45,-45,-46,-46,-47,-47,-47,-48,-48,-49,-49,-49,-50,-50,-50,-50,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-50,-50,-50,-50,-49,-49,-49,-48,-48,-47,-47,-47,-46,-46,-45,-45,-45,-44,-44,-43,-43,-42,-42,-41,-40,-40,-39,-39,-38,-37,-36,-35,-34,-33,-33,-32,-31,-30,-29,-29,-28,-27,-26,-26,-25,-24,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,20,21,22,23,24,25,26,27,28,29,30,31,32,32,33,34,35,36,37,38,39,40,41,41,42,42,43,44,44,45,46,46,47,47,48,48,48,49,49,49,50,50,50,51,51,51,51,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,51,51,51,51,50,50,50,49,49,49,48,48,48,47,47,46,46,45,44,44,43,42,42,41,41,40,39,38,37,36,35,34,33,32,32,31,30,29,28,27,26,25,24,23,22,21,20,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-20,-21,-22,-23,-24,-25,-26,-27,-28,-29,-30,-31,-32,-32,-33,-34,-35,-36,-37,-38,-39,-40,-41,-41,-42,-42,-43,-44,-44,-45,-46,-46,-47,-47,-48,-48,-48,-49,-49,-49,-50,-50,-50,-51,-51,-51,-51,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-51,-51,-51,-51,-50,-50,-50,-49,-49,-49,-48,-48,-48,-47,-47,-46,-46,-45,-44,-44,-43,-42,-42,-41,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,28,29,30,31,31,32,33,34,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,43,43,44,44,45,45,46,46,47,47,48,48,49,49,50,50,50,51,51,51,52,52,52,52,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,52,52,52,52,51,51,51,50,50,50,49,49,48,48,47,47,46,46,45,45,44,44,43,43,42,41,41,40,40,39,39,38,38,37,37,36,36,35,35,34,33,32,31,31,30,29,28,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-28,-28,-29,-30,-31,-31,-32,-33,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-39,-40,-40,-41,-41,-42,-43,-43,-44,-44,-45,-45,-46,-46,-47,-47,-48,-48,-49,-49,-50,-50,-50,-51,-51,-51,-52,-52,-52,-52,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-52,-52,-52,-52,-51,-51,-51,-50,-50,-50,-49,-49,-48,-48,-47,-47,-46,-46,-45,-45,-44,-44,-43,-43,-42,-41,-41,-40,-40,-39,-39,-38,-38,-37,-37,-36,-36,-35,-35,-34,-33,-32,-31,-31,-30,-29,-28,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,30,31,32,33,34,34,35,36,37,38,39,40,41,42,42,43,43,44,45,45,46,46,47,47,48,48,49,49,50,50,51,51,51,52,52,52,53,53,53,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,53,53,53,52,52,52,51,51,51,50,50,49,49,48,48,47,47,46,46,45,45,44,43,43,42,42,41,40,39,38,37,36,35,34,34,33,32,31,30,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-28,-29,-30,-30,-31,-32,-33,-34,-34,-35,-36,-37,-38,-39,-40,-41,-42,-42,-43,-43,-44,-45,-45,-46,-46,-47,-47,-48,-48,-49,-49,-50,-50,-51,-51,-51,-52,-52,-52,-53,-53,-53,-53,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-53,-53,-53,-53,-52,-52,-52,-51,-51,-51,-50,-50,-49,-49,-48,-48,-47,-47,-46,-46,-45,-45,-44,-43,-43,-42,-42,-41,-40,-39,-38,-37,-36,-35,-34,-34,-33,-32,-31,-30,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,18,19,20,21,22,23,23,24,25,25,26,27,27,28,29,30,31,32,33,33,34,35,36,37,37,38,38,39,39,40,40,41,41,42,42,43,44,44,45,45,46,47,47,48,48,49,49,49,50,50,50,51,51,51,52,52,52,53,53,53,53,54,54,54,54,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,54,54,54,54,53,53,53,53,52,52,52,51,51,51,50,50,50,49,49,49,48,48,47,47,46,45,45,44,44,43,42,42,41,41,40,40,39,39,38,38,37,37,36,35,34,33,33,32,31,30,29,28,27,27,26,25,25,24,23,23,22,21,20,19,18,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-18,-19,-20,-21,-22,-23,-23,-24,-25,-25,-26,-27,-27,-28,-29,-30,-31,-32,-33,-33,-34,-35,-36,-37,-37,-38,-38,-39,-39,-40,-40,-41,-41,-42,-42,-43,-44,-44,-45,-45,-46,-47,-47,-48,-48,-49,-49,-49,-50,-50,-50,-51,-51,-51,-52,-52,-52,-53,-53,-53,-53,-54,-54,-54,-54,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-54,-54,-54,-54,-53,-53,-53,-53,-52,-52,-52,-51,-51,-51,-50,-50,-50,-49,-49,-49,-48,-48,-47,-47,-46,-45,-45,-44,-44,-43,-42,-42,-41,-41,-40,-40,-39,-39,-38,-38,-37,-37,-36,-35,-34,-33,-33,-32,-31,-30,-29,-28,-27,-27,-26,-25,-25,-24,-23,-23,-22,-21,-20,-19,-18,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,29,30,31,32,32,33,34,35,36,36,37,38,39,40,41,42,43,43,44,44,45,46,46,47,47,48,48,49,49,50,50,51,51,52,52,52,53,53,54,54,54,54,55,55,55,55,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,55,55,55,55,54,54,54,54,53,53,52,52,52,51,51,50,50,49,49,48,48,47,47,46,46,45,44,44,43,43,42,41,40,39,38,37,36,36,35,34,33,32,32,31,30,29,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-28,-29,-29,-30,-31,-32,-32,-33,-34,-35,-36,-36,-37,-38,-39,-40,-41,-42,-43,-43,-44,-44,-45,-46,-46,-47,-47,-48,-48,-49,-49,-50,-50,-51,-51,-52,-52,-52,-53,-53,-54,-54,-54,-54,-55,-55,-55,-55,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-55,-55,-55,-55,-54,-54,-54,-54,-53,-53,-52,-52,-52,-51,-51,-50,-50,-49,-49,-48,-48,-47,-47,-46,-46,-45,-44,-44,-43,-43,-42,-41,-40,-39,-38,-37,-36,-36,-35,-34,-33,-32,-32,-31,-30,-29,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15,16,17,18,19,20,21,21,22,23,24,25,26,27,28,29,30,31,31,32,33,34,35,35,36,37,38,39,40,41,41,42,43,44,45,45,46,46,47,48,48,49,49,50,50,51,51,52,52,53,53,53,54,54,54,55,55,55,55,56,56,56,56,56,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,56,56,56,56,56,55,55,55,55,54,54,54,53,53,53,52,52,51,51,50,50,49,49,48,48,47,46,46,45,45,44,43,42,41,41,40,39,38,37,36,35,35,34,33,32,31,31,30,29,28,27,26,25,24,23,22,21,21,20,19,18,17,16,15,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-15,-16,-17,-18,-19,-20,-21,-21,-22,-23,-24,-25,-26,-27,-28,-29,-30,-31,-31,-32,-33,-34,-35,-35,-36,-37,-38,-39,-40,-41,-41,-42,-43,-44,-45,-45,-46,-46,-47,-48,-48,-49,-49,-50,-50,-51,-51,-52,-52,-53,-53,-53,-54,-54,-54,-55,-55,-55,-55,-56,-56,-56,-56,-56,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-56,-56,-56,-56,-56,-55,-55,-55,-55,-54,-54,-54,-53,-53,-53,-52,-52,-51,-51,-50,-50,-49,-49,-48,-48,-47,-46,-46,-45,-45,-44,-43,-42,-41,-41,-40,-39,-38,-37,-36,-35,-35,-34,-33,-32,-31,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-21,-20,-19,-18,-17,-16,-15,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,34,35,36,37,38,38,39,39,40,40,41,42,42,43,43,44,44,45,45,46,47,47,48,48,49,50,50,51,51,52,52,53,53,54,54,55,55,55,56,56,56,57,57,57,57,57,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,57,57,57,57,57,56,56,56,55,55,55,54,54,53,53,52,52,51,51,50,50,49,48,48,47,47,46,45,45,44,44,43,43,42,42,41,40,40,39,39,38,38,37,36,35,34,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-28,-29,-30,-31,-32,-33,-34,-34,-35,-36,-37,-38,-38,-39,-39,-40,-40,-41,-42,-42,-43,-43,-44,-44,-45,-45,-46,-47,-47,-48,-48,-49,-50,-50,-51,-51,-52,-52,-53,-53,-54,-54,-55,-55,-55,-56,-56,-56,-57,-57,-57,-57,-57,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-57,-57,-57,-57,-57,-56,-56,-56,-55,-55,-55,-54,-54,-53,-53,-52,-52,-51,-51,-50,-50,-49,-48,-48,-47,-47,-46,-45,-45,-44,-44,-43,-43,-42,-42,-41,-40,-40,-39,-39,-38,-38,-37,-36,-35,-34,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,26,27,28,28,29,30,31,32,33,33,34,35,36,37,37,38,39,40,41,42,43,44,45,46,46,47,47,48,49,49,50,50,51,51,52,52,53,53,53,54,54,54,55,55,56,56,56,57,57,57,58,58,58,58,58,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,58,58,58,58,58,57,57,57,56,56,56,55,55,54,54,54,53,53,53,52,52,51,51,50,50,49,49,48,47,47,46,46,45,44,43,42,41,40,39,38,37,37,36,35,34,33,33,32,31,30,29,28,28,27,26,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-26,-27,-28,-28,-29,-30,-31,-32,-33,-33,-34,-35,-36,-37,-37,-38,-39,-40,-41,-42,-43,-44,-45,-46,-46,-47,-47,-48,-49,-49,-50,-50,-51,-51,-52,-52,-53,-53,-53,-54,-54,-54,-55,-55,-56,-56,-56,-57,-57,-57,-58,-58,-58,-58,-58,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-58,-58,-58,-58,-58,-57,-57,-57,-56,-56,-56,-55,-55,-54,-54,-54,-53,-53,-53,-52,-52,-51,-51,-50,-50,-49,-49,-48,-47,-47,-46,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-37,-36,-35,-34,-33,-33,-32,-31,-30,-29,-28,-28,-27,-26,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1];\r\nvar ys = [0,-1,-1,0,1,1,1,0,-1,-2,-2,-2,-1,0,1,2,2,2,2,2,1,0,-1,-2,-2,-3,-3,-3,-2,-1,0,1,2,3,3,3,3,3,2,1,0,-1,-2,-3,-3,-4,-4,-4,-3,-2,-1,0,1,2,3,4,4,4,4,4,3,2,1,0,-1,-2,-3,-4,-4,-5,-5,-5,-5,-4,-4,-3,-3,-2,-1,0,1,2,3,3,4,4,5,5,5,5,5,5,5,4,4,3,3,2,1,0,-1,-2,-3,-3,-4,-4,-5,-5,-5,-6,-6,-6,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,6,6,6,6,6,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-6,-6,-7,-7,-7,-7,-6,-6,-5,-5,-4,-3,-2,-1,0,1,2,3,4,5,5,6,6,7,7,7,7,7,7,7,6,6,5,5,4,3,2,1,0,-1,-2,-3,-4,-5,-5,-6,-6,-7,-7,-7,-8,-8,-8,-8,-8,-7,-7,-6,-5,-4,-4,-3,-2,-1,0,1,2,3,4,4,5,6,7,7,8,8,8,8,8,8,8,8,8,7,7,6,5,4,4,3,2,1,0,-1,-2,-3,-4,-4,-5,-6,-7,-7,-8,-8,-8,-8,-9,-9,-9,-9,-9,-8,-7,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,7,8,9,9,9,9,9,9,9,9,9,8,7,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-7,-8,-9,-9,-9,-9,-10,-10,-10,-10,-10,-9,-9,-8,-8,-7,-6,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,6,7,8,8,9,9,10,10,10,10,10,10,10,10,10,9,9,8,8,7,6,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-6,-7,-8,-8,-9,-9,-10,-10,-10,-10,-11,-11,-11,-11,-11,-10,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,10,11,11,11,11,11,11,11,11,11,10,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-10,-11,-11,-11,-11,-12,-12,-12,-12,-12,-11,-11,-10,-10,-9,-9,-8,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,8,9,9,10,10,11,11,12,12,12,12,12,12,12,12,12,11,11,10,10,9,9,8,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-8,-9,-9,-10,-10,-11,-11,-12,-12,-12,-12,-13,-13,-13,-13,-13,-13,-12,-12,-12,-11,-11,-10,-9,-8,-7,-7,-6,-5,-5,-4,-3,-2,-1,0,1,2,3,4,5,5,6,7,7,8,9,10,11,11,12,12,12,13,13,13,13,13,13,13,13,13,13,13,12,12,12,11,11,10,9,8,7,7,6,5,5,4,3,2,1,0,-1,-2,-3,-4,-5,-5,-6,-7,-7,-8,-9,-10,-11,-11,-12,-12,-12,-13,-13,-13,-13,-13,-14,-14,-14,-14,-14,-14,-13,-13,-12,-11,-11,-10,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,10,11,11,12,13,13,14,14,14,14,14,14,14,14,14,14,14,13,13,12,11,11,10,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-10,-11,-11,-12,-13,-13,-14,-14,-14,-14,-14,-15,-15,-15,-15,-15,-15,-14,-14,-13,-13,-12,-12,-11,-10,-9,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,9,10,11,12,12,13,13,14,14,15,15,15,15,15,15,15,15,15,15,15,14,14,13,13,12,12,11,10,9,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-9,-10,-11,-12,-12,-13,-13,-14,-14,-15,-15,-15,-15,-15,-16,-16,-16,-16,-16,-16,-15,-15,-14,-14,-13,-12,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,12,13,14,14,15,15,16,16,16,16,16,16,16,16,16,16,16,15,15,14,14,13,12,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-12,-13,-14,-14,-15,-15,-16,-16,-16,-16,-16,-17,-17,-17,-17,-17,-17,-16,-16,-16,-15,-15,-14,-14,-13,-13,-12,-11,-11,-10,-9,-8,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,8,9,10,11,11,12,13,13,14,14,15,15,16,16,16,17,17,17,17,17,17,17,17,17,17,17,16,16,16,15,15,14,14,13,13,12,11,11,10,9,8,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-8,-9,-10,-11,-11,-12,-13,-13,-14,-14,-15,-15,-16,-16,-16,-17,-17,-17,-17,-17,-18,-18,-18,-18,-18,-18,-18,-17,-17,-17,-16,-16,-15,-15,-14,-13,-12,-11,-10,-10,-9,-8,-7,-6,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,6,7,8,9,10,10,11,12,13,14,15,15,16,16,17,17,17,18,18,18,18,18,18,18,18,18,18,18,18,18,17,17,17,16,16,15,15,14,13,12,11,10,10,9,8,7,6,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-6,-7,-8,-9,-10,-10,-11,-12,-13,-14,-15,-15,-16,-16,-17,-17,-17,-18,-18,-18,-18,-18,-18,-19,-19,-19,-19,-19,-19,-19,-18,-18,-17,-17,-16,-15,-15,-14,-14,-13,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,13,14,14,15,15,16,17,17,18,18,19,19,19,19,19,19,19,19,19,19,19,19,19,18,18,17,17,16,15,15,14,14,13,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-13,-14,-14,-15,-15,-16,-17,-17,-18,-18,-19,-19,-19,-19,-19,-19,-20,-20,-20,-20,-20,-20,-20,-19,-19,-18,-18,-17,-17,-16,-16,-15,-14,-13,-12,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,12,13,14,15,16,16,17,17,18,18,19,19,20,20,20,20,20,20,20,20,20,20,20,20,20,19,19,18,18,17,17,16,16,15,14,13,12,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-12,-13,-14,-15,-16,-16,-17,-17,-18,-18,-19,-19,-20,-20,-20,-20,-20,-20,-21,-21,-21,-21,-21,-21,-21,-20,-20,-20,-19,-19,-19,-18,-18,-17,-16,-16,-15,-15,-14,-13,-12,-11,-11,-10,-9,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,9,10,11,11,12,13,14,15,15,16,16,17,18,18,19,19,19,20,20,20,21,21,21,21,21,21,21,21,21,21,21,21,21,20,20,20,19,19,19,18,18,17,16,16,15,15,14,13,12,11,11,10,9,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-9,-10,-11,-11,-12,-13,-14,-15,-15,-16,-16,-17,-18,-18,-19,-19,-19,-20,-20,-20,-21,-21,-21,-21,-21,-21,-22,-22,-22,-22,-22,-22,-22,-21,-21,-21,-20,-20,-19,-18,-18,-17,-17,-16,-15,-14,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,14,15,16,17,17,18,18,19,20,20,21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,21,21,21,20,20,19,18,18,17,17,16,15,14,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-14,-15,-16,-17,-17,-18,-18,-19,-20,-20,-21,-21,-21,-22,-22,-22,-22,-22,-22,-23,-23,-23,-23,-23,-23,-23,-22,-22,-22,-21,-21,-20,-20,-19,-19,-18,-17,-16,-15,-14,-13,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,13,14,15,16,17,18,19,19,20,20,21,21,22,22,22,23,23,23,23,23,23,23,23,23,23,23,23,23,22,22,22,21,21,20,20,19,19,18,17,16,15,14,13,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-13,-14,-15,-16,-17,-18,-19,-19,-20,-20,-21,-21,-22,-22,-22,-23,-23,-23,-23,-23,-23,-24,-24,-24,-24,-24,-24,-24,-23,-23,-23,-22,-22,-21,-21,-20,-19,-19,-18,-18,-17,-17,-16,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,17,17,18,18,19,19,20,21,21,22,22,23,23,23,24,24,24,24,24,24,24,24,24,24,24,24,24,23,23,23,22,22,21,21,20,19,19,18,18,17,17,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-16,-17,-17,-18,-18,-19,-19,-20,-21,-21,-22,-22,-23,-23,-23,-24,-24,-24,-24,-24,-24,-25,-25,-25,-25,-25,-25,-25,-25,-24,-24,-24,-23,-23,-23,-22,-22,-21,-21,-20,-20,-19,-18,-17,-16,-15,-15,-14,-13,-12,-12,-11,-10,-9,-8,-7,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,7,8,9,10,11,12,12,13,14,15,15,16,17,18,19,20,20,21,21,22,22,23,23,23,24,24,24,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,24,24,24,23,23,23,22,22,21,21,20,20,19,18,17,16,15,15,14,13,12,12,11,10,9,8,7,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-7,-8,-9,-10,-11,-12,-12,-13,-14,-15,-15,-16,-17,-18,-19,-20,-20,-21,-21,-22,-22,-23,-23,-23,-24,-24,-24,-25,-25,-25,-25,-25,-25,-25,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-24,-24,-24,-23,-23,-22,-22,-21,-20,-20,-19,-19,-18,-18,-17,-16,-15,-14,-14,-13,-12,-11,-10,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,10,11,12,13,14,14,15,16,17,18,18,19,19,20,20,21,22,22,23,23,24,24,24,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,25,25,25,24,24,24,23,23,22,22,21,20,20,19,19,18,18,17,16,15,14,14,13,12,11,10,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-10,-11,-12,-13,-14,-14,-15,-16,-17,-18,-18,-19,-19,-20,-20,-21,-22,-22,-23,-23,-24,-24,-24,-25,-25,-25,-26,-26,-26,-26,-26,-26,-26,-27,-27,-27,-27,-27,-27,-27,-27,-26,-26,-26,-25,-25,-24,-24,-23,-22,-22,-21,-21,-20,-19,-18,-17,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,17,18,19,20,21,21,22,22,23,24,24,25,25,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,26,26,26,25,25,24,24,23,22,22,21,21,20,19,18,17,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-17,-18,-19,-20,-21,-21,-22,-22,-23,-24,-24,-25,-25,-26,-26,-26,-27,-27,-27,-27,-27,-27,-27,-28,-28,-28,-28,-28,-28,-28,-28,-27,-27,-27,-26,-26,-25,-25,-24,-24,-23,-23,-22,-21,-20,-19,-18,-17,-16,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,17,18,19,20,21,22,23,23,24,24,25,25,26,26,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,27,27,27,26,26,25,25,24,24,23,23,22,21,20,19,18,17,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-16,-17,-18,-19,-20,-21,-22,-23,-23,-24,-24,-25,-25,-26,-26,-27,-27,-27,-28,-28,-28,-28,-28,-28,-28,-29,-29,-29,-29,-29,-29,-29,-29,-28,-28,-28,-27,-27,-27,-26,-26,-25,-25,-24,-23,-23,-22,-22,-21,-21,-20,-20,-19,-19,-18,-17,-16,-15,-14,-13,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,13,14,15,16,17,18,19,19,20,20,21,21,22,22,23,23,24,25,25,26,26,27,27,27,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,28,28,28,27,27,27,26,26,25,25,24,23,23,22,22,21,21,20,20,19,19,18,17,16,15,14,13,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-13,-14,-15,-16,-17,-18,-19,-19,-20,-20,-21,-21,-22,-22,-23,-23,-24,-25,-25,-26,-26,-27,-27,-27,-28,-28,-28,-29,-29,-29,-29,-29,-29,-29,-30,-30,-30,-30,-30,-30,-30,-30,-29,-29,-29,-28,-28,-28,-27,-27,-26,-26,-25,-25,-24,-24,-23,-22,-21,-20,-19,-18,-18,-17,-16,-15,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15,16,17,18,18,19,20,21,22,23,24,24,25,25,26,26,27,27,28,28,28,29,29,29,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,29,29,29,28,28,28,27,27,26,26,25,25,24,24,23,22,21,20,19,18,18,17,16,15,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-15,-16,-17,-18,-18,-19,-20,-21,-22,-23,-24,-24,-25,-25,-26,-26,-27,-27,-28,-28,-28,-29,-29,-29,-30,-30,-30,-30,-30,-30,-30,-31,-31,-31,-31,-31,-31,-31,-31,-30,-30,-30,-30,-29,-29,-29,-28,-28,-27,-27,-26,-26,-25,-24,-24,-23,-23,-22,-22,-21,-21,-20,-19,-18,-17,-17,-16,-15,-14,-13,-12,-11,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,11,12,13,14,15,16,17,17,18,19,20,21,21,22,22,23,23,24,24,25,26,26,27,27,28,28,29,29,29,30,30,30,30,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,30,30,30,30,29,29,29,28,28,27,27,26,26,25,24,24,23,23,22,22,21,21,20,19,18,17,17,16,15,14,13,12,11,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-11,-12,-13,-14,-15,-16,-17,-17,-18,-19,-20,-21,-21,-22,-22,-23,-23,-24,-24,-25,-26,-26,-27,-27,-28,-28,-29,-29,-29,-30,-30,-30,-30,-31,-31,-31,-31,-31,-31,-31,-32,-32,-32,-32,-32,-32,-32,-32,-32,-31,-31,-31,-31,-30,-30,-29,-29,-28,-28,-27,-26,-26,-25,-25,-24,-23,-22,-21,-20,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,8,9,10,11,12,13,14,15,16,17,18,19,20,20,21,22,23,24,25,25,26,26,27,28,28,29,29,30,30,31,31,31,31,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,31,31,31,31,30,30,29,29,28,28,27,26,26,25,25,24,23,22,21,20,20,19,18,17,16,15,14,13,12,11,10,9,8,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-20,-21,-22,-23,-24,-25,-25,-26,-26,-27,-28,-28,-29,-29,-30,-30,-31,-31,-31,-31,-32,-32,-32,-32,-32,-32,-32,-32,-33,-33,-33,-33,-33,-33,-33,-33,-33,-32,-32,-32,-31,-31,-30,-30,-29,-29,-28,-28,-27,-27,-26,-25,-25,-24,-24,-23,-23,-22,-21,-20,-19,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,19,20,21,22,23,23,24,24,25,25,26,27,27,28,28,29,29,30,30,31,31,32,32,32,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,32,32,32,31,31,30,30,29,29,28,28,27,27,26,25,25,24,24,23,23,22,21,20,19,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-19,-20,-21,-22,-23,-23,-24,-24,-25,-25,-26,-27,-27,-28,-28,-29,-29,-30,-30,-31,-31,-32,-32,-32,-33,-33,-33,-33,-33,-33,-33,-33,-34,-34,-34,-34,-34,-34,-34,-34,-34,-33,-33,-33,-32,-32,-32,-31,-31,-31,-30,-30,-30,-29,-29,-28,-27,-27,-26,-26,-25,-24,-23,-22,-22,-21,-20,-19,-18,-18,-17,-16,-16,-15,-14,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,14,15,16,16,17,18,18,19,20,21,22,22,23,24,25,26,26,27,27,28,29,29,30,30,30,31,31,31,32,32,32,33,33,33,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,33,33,33,32,32,32,31,31,31,30,30,30,29,29,28,27,27,26,26,25,24,23,22,22,21,20,19,18,18,17,16,16,15,14,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-14,-15,-16,-16,-17,-18,-18,-19,-20,-21,-22,-22,-23,-24,-25,-26,-26,-27,-27,-28,-29,-29,-30,-30,-30,-31,-31,-31,-32,-32,-32,-33,-33,-33,-34,-34,-34,-34,-34,-34,-34,-34,-35,-35,-35,-35,-35,-35,-35,-35,-35,-34,-34,-34,-33,-33,-33,-32,-32,-31,-31,-30,-29,-29,-28,-28,-27,-26,-25,-24,-23,-22,-21,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,21,22,23,24,25,26,27,28,28,29,29,30,31,31,32,32,33,33,33,34,34,34,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,34,34,34,33,33,33,32,32,31,31,30,29,29,28,28,27,26,25,24,23,22,21,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-21,-22,-23,-24,-25,-26,-27,-28,-28,-29,-29,-30,-31,-31,-32,-32,-33,-33,-33,-34,-34,-34,-35,-35,-35,-35,-35,-35,-35,-35,-36,-36,-36,-36,-36,-36,-36,-36,-36,-35,-35,-35,-34,-34,-34,-33,-33,-32,-32,-31,-31,-30,-30,-29,-28,-28,-27,-27,-26,-26,-25,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,20,21,22,23,24,24,25,25,26,26,27,27,28,28,29,30,30,31,31,32,32,33,33,34,34,34,35,35,35,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,35,35,35,34,34,34,33,33,32,32,31,31,30,30,29,28,28,27,27,26,26,25,25,24,24,23,22,21,20,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-20,-21,-22,-23,-24,-24,-25,-25,-26,-26,-27,-27,-28,-28,-29,-30,-30,-31,-31,-32,-32,-33,-33,-34,-34,-34,-35,-35,-35,-36,-36,-36,-36,-36,-36,-36,-36,-37,-37,-37,-37,-37,-37,-37,-37,-37,-36,-36,-36,-36,-35,-35,-35,-34,-34,-33,-33,-32,-32,-31,-30,-30,-29,-29,-28,-27,-26,-25,-24,-23,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,12,13,14,15,16,17,18,19,20,21,22,23,23,24,25,26,27,28,29,29,30,30,31,32,32,33,33,34,34,35,35,35,36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,36,36,36,35,35,35,34,34,33,33,32,32,31,30,30,29,29,28,27,26,25,24,23,23,22,21,20,19,18,17,16,15,14,13,12,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-23,-24,-25,-26,-27,-28,-29,-29,-30,-30,-31,-32,-32,-33,-33,-34,-34,-35,-35,-35,-36,-36,-36,-36,-37,-37,-37,-37,-37,-37,-37,-37,-38,-38,-38,-38,-38,-38,-38,-38,-38,-37,-37,-37,-37,-36,-36,-35,-35,-35,-34,-34,-34,-33,-33,-32,-32,-31,-31,-30,-29,-29,-28,-28,-27,-27,-26,-26,-25,-24,-23,-22,-22,-21,-20,-19,-19,-18,-17,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,17,18,19,19,20,21,22,22,23,24,25,26,26,27,27,28,28,29,29,30,31,31,32,32,33,33,34,34,34,35,35,35,36,36,37,37,37,37,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,37,37,37,37,36,36,35,35,35,34,34,34,33,33,32,32,31,31,30,29,29,28,28,27,27,26,26,25,24,23,22,22,21,20,19,19,18,17,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-17,-18,-19,-19,-20,-21,-22,-22,-23,-24,-25,-26,-26,-27,-27,-28,-28,-29,-29,-30,-31,-31,-32,-32,-33,-33,-34,-34,-34,-35,-35,-35,-36,-36,-37,-37,-37,-37,-38,-38,-38,-38,-38,-38,-38,-38,-39,-39,-39,-39,-39,-39,-39,-39,-39,-38,-38,-38,-38,-37,-37,-37,-36,-36,-36,-35,-35,-34,-34,-33,-33,-32,-31,-31,-30,-30,-29,-28,-27,-26,-25,-25,-24,-23,-22,-21,-21,-20,-19,-18,-17,-16,-15,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15,16,17,18,19,20,21,21,22,23,24,25,25,26,27,28,29,30,30,31,31,32,33,33,34,34,35,35,36,36,36,37,37,37,38,38,38,38,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,38,38,38,38,37,37,37,36,36,36,35,35,34,34,33,33,32,31,31,30,30,29,28,27,26,25,25,24,23,22,21,21,20,19,18,17,16,15,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-15,-16,-17,-18,-19,-20,-21,-21,-22,-23,-24,-25,-25,-26,-27,-28,-29,-30,-30,-31,-31,-32,-33,-33,-34,-34,-35,-35,-36,-36,-36,-37,-37,-37,-38,-38,-38,-38,-39,-39,-39,-39,-39,-39,-39,-39,-40,-40,-40,-40,-40,-40,-40,-40,-40,-39,-39,-39,-39,-38,-38,-38,-37,-37,-36,-36,-35,-35,-34,-33,-33,-32,-32,-31,-30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,24,25,26,27,28,29,30,31,32,32,33,33,34,35,35,36,36,37,37,38,38,38,39,39,39,39,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,39,39,39,39,38,38,38,37,37,36,36,35,35,34,33,33,32,32,31,30,29,28,27,26,25,24,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-24,-25,-26,-27,-28,-29,-30,-31,-32,-32,-33,-33,-34,-35,-35,-36,-36,-37,-37,-38,-38,-38,-39,-39,-39,-39,-40,-40,-40,-40,-40,-40,-40,-40,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-40,-40,-40,-40,-39,-39,-39,-38,-38,-37,-37,-36,-36,-35,-35,-34,-34,-33,-32,-32,-31,-31,-30,-30,-29,-29,-28,-28,-27,-27,-26,-25,-24,-23,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,23,24,25,26,27,27,28,28,29,29,30,30,31,31,32,32,33,34,34,35,35,36,36,37,37,38,38,39,39,39,40,40,40,40,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,40,40,40,40,39,39,39,38,38,37,37,36,36,35,35,34,34,33,32,32,31,31,30,30,29,29,28,28,27,27,26,25,24,23,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-23,-24,-25,-26,-27,-27,-28,-28,-29,-29,-30,-30,-31,-31,-32,-32,-33,-34,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-39,-39,-40,-40,-40,-40,-41,-41,-41,-41,-41,-41,-41,-41,-41,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-41,-41,-41,-40,-40,-40,-39,-39,-39,-38,-38,-38,-37,-37,-36,-36,-35,-34,-34,-33,-33,-32,-31,-30,-29,-28,-27,-26,-26,-25,-24,-23,-22,-21,-20,-20,-19,-18,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,18,19,20,20,21,22,23,24,25,26,26,27,28,29,30,31,32,33,33,34,34,35,36,36,37,37,38,38,38,39,39,39,40,40,40,41,41,41,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,41,41,41,40,40,40,39,39,39,38,38,38,37,37,36,36,35,34,34,33,33,32,31,30,29,28,27,26,26,25,24,23,22,21,20,20,19,18,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-18,-19,-20,-20,-21,-22,-23,-24,-25,-26,-26,-27,-28,-29,-30,-31,-32,-33,-33,-34,-34,-35,-36,-36,-37,-37,-38,-38,-38,-39,-39,-39,-40,-40,-40,-41,-41,-41,-42,-42,-42,-42,-42,-42,-42,-42,-42,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-42,-42,-42,-42,-41,-41,-41,-40,-40,-40,-39,-39,-38,-38,-37,-37,-36,-36,-35,-35,-34,-33,-33,-32,-32,-31,-31,-30,-30,-29,-29,-28,-27,-26,-25,-25,-24,-23,-22,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,13,14,15,16,17,18,19,20,21,22,22,23,24,25,25,26,27,28,29,29,30,30,31,31,32,32,33,33,34,35,35,36,36,37,37,38,38,39,39,40,40,40,41,41,41,42,42,42,42,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,42,42,42,42,41,41,41,40,40,40,39,39,38,38,37,37,36,36,35,35,34,33,33,32,32,31,31,30,30,29,29,28,27,26,25,25,24,23,22,22,21,20,19,18,17,16,15,14,13,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-22,-23,-24,-25,-25,-26,-27,-28,-29,-29,-30,-30,-31,-31,-32,-32,-33,-33,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-39,-40,-40,-40,-41,-41,-41,-42,-42,-42,-42,-43,-43,-43,-43,-43,-43,-43,-43,-43,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-43,-43,-43,-43,-42,-42,-42,-41,-41,-41,-40,-40,-39,-39,-38,-38,-37,-37,-36,-35,-35,-34,-34,-33,-32,-31,-30,-29,-28,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-19,-18,-17,-16,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,17,18,19,20,21,22,23,24,24,25,26,27,28,28,29,30,31,32,33,34,34,35,35,36,37,37,38,38,39,39,40,40,41,41,41,42,42,42,43,43,43,43,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,43,43,43,43,42,42,42,41,41,41,40,40,39,39,38,38,37,37,36,35,35,34,34,33,32,31,30,29,28,28,27,26,25,24,24,23,22,21,20,19,18,17,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-16,-17,-18,-19,-20,-21,-22,-23,-24,-24,-25,-26,-27,-28,-28,-29,-30,-31,-32,-33,-34,-34,-35,-35,-36,-37,-37,-38,-38,-39,-39,-40,-40,-41,-41,-41,-42,-42,-42,-43,-43,-43,-43,-44,-44,-44,-44,-44,-44,-44,-44,-44,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-44,-44,-44,-44,-43,-43,-43,-42,-42,-41,-41,-40,-40,-39,-39,-38,-37,-37,-36,-36,-35,-34,-33,-33,-32,-32,-31,-30,-29,-28,-27,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,27,28,29,30,31,32,32,33,33,34,35,36,36,37,37,38,39,39,40,40,41,41,42,42,43,43,43,44,44,44,44,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,44,44,44,44,43,43,43,42,42,41,41,40,40,39,39,38,37,37,36,36,35,34,33,33,32,32,31,30,29,28,27,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-27,-28,-29,-30,-31,-32,-32,-33,-33,-34,-35,-36,-36,-37,-37,-38,-39,-39,-40,-40,-41,-41,-42,-42,-43,-43,-43,-44,-44,-44,-44,-45,-45,-45,-45,-45,-45,-45,-45,-45,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-45,-45,-45,-45,-44,-44,-44,-43,-43,-42,-42,-42,-41,-41,-40,-40,-39,-39,-38,-38,-37,-36,-36,-35,-35,-34,-34,-33,-32,-31,-31,-30,-30,-29,-28,-27,-26,-26,-25,-24,-23,-22,-21,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,21,22,23,24,25,26,26,27,28,29,30,30,31,31,32,33,34,34,35,35,36,36,37,38,38,39,39,40,40,41,41,42,42,42,43,43,44,44,44,45,45,45,45,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,45,45,45,45,44,44,44,43,43,42,42,42,41,41,40,40,39,39,38,38,37,36,36,35,35,34,34,33,32,31,31,30,30,29,28,27,26,26,25,24,23,22,21,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-21,-22,-23,-24,-25,-26,-26,-27,-28,-29,-30,-30,-31,-31,-32,-33,-34,-34,-35,-35,-36,-36,-37,-38,-38,-39,-39,-40,-40,-41,-41,-42,-42,-42,-43,-43,-44,-44,-44,-45,-45,-45,-45,-46,-46,-46,-46,-46,-46,-46,-46,-46,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-46,-46,-46,-46,-45,-45,-45,-44,-44,-44,-43,-43,-43,-42,-42,-41,-41,-40,-40,-39,-38,-38,-37,-37,-36,-35,-34,-33,-32,-31,-30,-29,-29,-28,-27,-26,-25,-24,-23,-23,-22,-21,-20,-19,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,19,20,21,22,23,23,24,25,26,27,28,29,29,30,31,32,33,34,35,36,37,37,38,38,39,40,40,41,41,42,42,43,43,43,44,44,44,45,45,45,46,46,46,46,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,46,46,46,46,45,45,45,44,44,44,43,43,43,42,42,41,41,40,40,39,38,38,37,37,36,35,34,33,32,31,30,29,29,28,27,26,25,24,23,23,22,21,20,19,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-19,-20,-21,-22,-23,-23,-24,-25,-26,-27,-28,-29,-29,-30,-31,-32,-33,-34,-35,-36,-37,-37,-38,-38,-39,-40,-40,-41,-41,-42,-42,-43,-43,-43,-44,-44,-44,-45,-45,-45,-46,-46,-46,-46,-47,-47,-47,-47,-47,-47,-47,-47,-47,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-47,-47,-47,-47,-46,-46,-46,-45,-45,-45,-44,-44,-43,-43,-42,-42,-41,-41,-40,-40,-39,-39,-38,-37,-37,-36,-36,-35,-35,-34,-34,-33,-33,-32,-32,-31,-30,-29,-28,-28,-27,-26,-25,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,25,26,27,28,28,29,30,31,32,32,33,33,34,34,35,35,36,36,37,37,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,45,46,46,46,47,47,47,47,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,47,47,47,47,46,46,46,45,45,45,44,44,43,43,42,42,41,41,40,40,39,39,38,37,37,36,36,35,35,34,34,33,33,32,32,31,30,29,28,28,27,26,25,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-25,-26,-27,-28,-28,-29,-30,-31,-32,-32,-33,-33,-34,-34,-35,-35,-36,-36,-37,-37,-38,-39,-39,-40,-40,-41,-41,-42,-42,-43,-43,-44,-44,-45,-45,-45,-46,-46,-46,-47,-47,-47,-47,-48,-48,-48,-48,-48,-48,-48,-48,-48,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-48,-48,-48,-48,-47,-47,-47,-47,-46,-46,-46,-45,-45,-44,-44,-43,-43,-42,-42,-41,-41,-40,-39,-39,-38,-38,-37,-36,-35,-34,-33,-32,-31,-31,-30,-29,-28,-27,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,17,18,19,20,21,22,23,24,25,26,27,27,28,29,30,31,31,32,33,34,35,36,37,38,38,39,39,40,41,41,42,42,43,43,44,44,45,45,46,46,46,47,47,47,47,48,48,48,48,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,48,48,48,48,47,47,47,47,46,46,46,45,45,44,44,43,43,42,42,41,41,40,39,39,38,38,37,36,35,34,33,32,31,31,30,29,28,27,27,26,25,24,23,22,21,20,19,18,17,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-27,-28,-29,-30,-31,-31,-32,-33,-34,-35,-36,-37,-38,-38,-39,-39,-40,-41,-41,-42,-42,-43,-43,-44,-44,-45,-45,-46,-46,-46,-47,-47,-47,-47,-48,-48,-48,-48,-49,-49,-49,-49,-49,-49,-49,-49,-49,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-49,-49,-49,-49,-49,-48,-48,-48,-48,-47,-47,-46,-46,-46,-45,-45,-44,-44,-43,-43,-42,-41,-41,-40,-40,-39,-38,-38,-37,-37,-36,-36,-35,-35,-34,-34,-33,-32,-31,-30,-30,-29,-28,-27,-26,-25,-24,-23,-22,-22,-21,-20,-19,-18,-17,-16,-15,-14,-14,-13,-12,-11,-10,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,10,11,12,13,14,14,15,16,17,18,19,20,21,22,22,23,24,25,26,27,28,29,30,30,31,32,33,34,34,35,35,36,36,37,37,38,38,39,40,40,41,41,42,43,43,44,44,45,45,46,46,46,47,47,48,48,48,48,49,49,49,49,49,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,49,49,49,49,49,48,48,48,48,47,47,46,46,46,45,45,44,44,43,43,42,41,41,40,40,39,38,38,37,37,36,36,35,35,34,34,33,32,31,30,30,29,28,27,26,25,24,23,22,22,21,20,19,18,17,16,15,14,14,13,12,11,10,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-10,-11,-12,-13,-14,-14,-15,-16,-17,-18,-19,-20,-21,-22,-22,-23,-24,-25,-26,-27,-28,-29,-30,-30,-31,-32,-33,-34,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-40,-40,-41,-41,-42,-43,-43,-44,-44,-45,-45,-46,-46,-46,-47,-47,-48,-48,-48,-48,-49,-49,-49,-49,-49,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-50,-50,-50,-50,-49,-49,-49,-48,-48,-47,-47,-47,-46,-46,-45,-45,-45,-44,-44,-43,-43,-42,-42,-41,-40,-40,-39,-39,-38,-37,-36,-35,-34,-33,-33,-32,-31,-30,-29,-29,-28,-27,-26,-26,-25,-24,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,24,25,26,26,27,28,29,29,30,31,32,33,33,34,35,36,37,38,39,39,40,40,41,42,42,43,43,44,44,45,45,45,46,46,47,47,47,48,48,49,49,49,50,50,50,50,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,50,50,50,50,49,49,49,48,48,47,47,47,46,46,45,45,45,44,44,43,43,42,42,41,40,40,39,39,38,37,36,35,34,33,33,32,31,30,29,29,28,27,26,26,25,24,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-24,-25,-26,-26,-27,-28,-29,-29,-30,-31,-32,-33,-33,-34,-35,-36,-37,-38,-39,-39,-40,-40,-41,-42,-42,-43,-43,-44,-44,-45,-45,-45,-46,-46,-47,-47,-47,-48,-48,-49,-49,-49,-50,-50,-50,-50,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-51,-51,-51,-51,-50,-50,-50,-49,-49,-49,-48,-48,-48,-47,-47,-46,-46,-45,-44,-44,-43,-42,-42,-41,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,20,21,22,23,24,25,26,27,28,29,30,31,32,32,33,34,35,36,37,38,39,40,41,41,42,42,43,44,44,45,46,46,47,47,48,48,48,49,49,49,50,50,50,51,51,51,51,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,51,51,51,51,50,50,50,49,49,49,48,48,48,47,47,46,46,45,44,44,43,42,42,41,41,40,39,38,37,36,35,34,33,32,32,31,30,29,28,27,26,25,24,23,22,21,20,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-20,-21,-22,-23,-24,-25,-26,-27,-28,-29,-30,-31,-32,-32,-33,-34,-35,-36,-37,-38,-39,-40,-41,-41,-42,-42,-43,-44,-44,-45,-46,-46,-47,-47,-48,-48,-48,-49,-49,-49,-50,-50,-50,-51,-51,-51,-51,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-52,-52,-52,-52,-51,-51,-51,-50,-50,-50,-49,-49,-48,-48,-47,-47,-46,-46,-45,-45,-44,-44,-43,-43,-42,-41,-41,-40,-40,-39,-39,-38,-38,-37,-37,-36,-36,-35,-35,-34,-33,-32,-31,-31,-30,-29,-28,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,28,29,30,31,31,32,33,34,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,43,43,44,44,45,45,46,46,47,47,48,48,49,49,50,50,50,51,51,51,52,52,52,52,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,52,52,52,52,51,51,51,50,50,50,49,49,48,48,47,47,46,46,45,45,44,44,43,43,42,41,41,40,40,39,39,38,38,37,37,36,36,35,35,34,33,32,31,31,30,29,28,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-28,-28,-29,-30,-31,-31,-32,-33,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-39,-40,-40,-41,-41,-42,-43,-43,-44,-44,-45,-45,-46,-46,-47,-47,-48,-48,-49,-49,-50,-50,-50,-51,-51,-51,-52,-52,-52,-52,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-53,-53,-53,-53,-52,-52,-52,-51,-51,-51,-50,-50,-49,-49,-48,-48,-47,-47,-46,-46,-45,-45,-44,-43,-43,-42,-42,-41,-40,-39,-38,-37,-36,-35,-34,-34,-33,-32,-31,-30,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,30,31,32,33,34,34,35,36,37,38,39,40,41,42,42,43,43,44,45,45,46,46,47,47,48,48,49,49,50,50,51,51,51,52,52,52,53,53,53,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,53,53,53,52,52,52,51,51,51,50,50,49,49,48,48,47,47,46,46,45,45,44,43,43,42,42,41,40,39,38,37,36,35,34,34,33,32,31,30,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-28,-29,-30,-30,-31,-32,-33,-34,-34,-35,-36,-37,-38,-39,-40,-41,-42,-42,-43,-43,-44,-45,-45,-46,-46,-47,-47,-48,-48,-49,-49,-50,-50,-51,-51,-51,-52,-52,-52,-53,-53,-53,-53,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-54,-54,-54,-54,-53,-53,-53,-53,-52,-52,-52,-51,-51,-51,-50,-50,-50,-49,-49,-49,-48,-48,-47,-47,-46,-45,-45,-44,-44,-43,-42,-42,-41,-41,-40,-40,-39,-39,-38,-38,-37,-37,-36,-35,-34,-33,-33,-32,-31,-30,-29,-28,-27,-27,-26,-25,-25,-24,-23,-23,-22,-21,-20,-19,-18,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,18,19,20,21,22,23,23,24,25,25,26,27,27,28,29,30,31,32,33,33,34,35,36,37,37,38,38,39,39,40,40,41,41,42,42,43,44,44,45,45,46,47,47,48,48,49,49,49,50,50,50,51,51,51,52,52,52,53,53,53,53,54,54,54,54,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,54,54,54,54,53,53,53,53,52,52,52,51,51,51,50,50,50,49,49,49,48,48,47,47,46,45,45,44,44,43,42,42,41,41,40,40,39,39,38,38,37,37,36,35,34,33,33,32,31,30,29,28,27,27,26,25,25,24,23,23,22,21,20,19,18,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-18,-19,-20,-21,-22,-23,-23,-24,-25,-25,-26,-27,-27,-28,-29,-30,-31,-32,-33,-33,-34,-35,-36,-37,-37,-38,-38,-39,-39,-40,-40,-41,-41,-42,-42,-43,-44,-44,-45,-45,-46,-47,-47,-48,-48,-49,-49,-49,-50,-50,-50,-51,-51,-51,-52,-52,-52,-53,-53,-53,-53,-54,-54,-54,-54,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-55,-55,-55,-55,-54,-54,-54,-54,-53,-53,-52,-52,-52,-51,-51,-50,-50,-49,-49,-48,-48,-47,-47,-46,-46,-45,-44,-44,-43,-43,-42,-41,-40,-39,-38,-37,-36,-36,-35,-34,-33,-32,-32,-31,-30,-29,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,29,30,31,32,32,33,34,35,36,36,37,38,39,40,41,42,43,43,44,44,45,46,46,47,47,48,48,49,49,50,50,51,51,52,52,52,53,53,54,54,54,54,55,55,55,55,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,55,55,55,55,54,54,54,54,53,53,52,52,52,51,51,50,50,49,49,48,48,47,47,46,46,45,44,44,43,43,42,41,40,39,38,37,36,36,35,34,33,32,32,31,30,29,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-28,-29,-29,-30,-31,-32,-32,-33,-34,-35,-36,-36,-37,-38,-39,-40,-41,-42,-43,-43,-44,-44,-45,-46,-46,-47,-47,-48,-48,-49,-49,-50,-50,-51,-51,-52,-52,-52,-53,-53,-54,-54,-54,-54,-55,-55,-55,-55,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-56,-56,-56,-56,-56,-55,-55,-55,-55,-54,-54,-54,-53,-53,-53,-52,-52,-51,-51,-50,-50,-49,-49,-48,-48,-47,-46,-46,-45,-45,-44,-43,-42,-41,-41,-40,-39,-38,-37,-36,-35,-35,-34,-33,-32,-31,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-21,-20,-19,-18,-17,-16,-15,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15,16,17,18,19,20,21,21,22,23,24,25,26,27,28,29,30,31,31,32,33,34,35,35,36,37,38,39,40,41,41,42,43,44,45,45,46,46,47,48,48,49,49,50,50,51,51,52,52,53,53,53,54,54,54,55,55,55,55,56,56,56,56,56,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,56,56,56,56,56,55,55,55,55,54,54,54,53,53,53,52,52,51,51,50,50,49,49,48,48,47,46,46,45,45,44,43,42,41,41,40,39,38,37,36,35,35,34,33,32,31,31,30,29,28,27,26,25,24,23,22,21,21,20,19,18,17,16,15,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-15,-16,-17,-18,-19,-20,-21,-21,-22,-23,-24,-25,-26,-27,-28,-29,-30,-31,-31,-32,-33,-34,-35,-35,-36,-37,-38,-39,-40,-41,-41,-42,-43,-44,-45,-45,-46,-46,-47,-48,-48,-49,-49,-50,-50,-51,-51,-52,-52,-53,-53,-53,-54,-54,-54,-55,-55,-55,-55,-56,-56,-56,-56,-56,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-57,-57,-57,-57,-57,-56,-56,-56,-55,-55,-55,-54,-54,-53,-53,-52,-52,-51,-51,-50,-50,-49,-48,-48,-47,-47,-46,-45,-45,-44,-44,-43,-43,-42,-42,-41,-40,-40,-39,-39,-38,-38,-37,-36,-35,-34,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,34,35,36,37,38,38,39,39,40,40,41,42,42,43,43,44,44,45,45,46,47,47,48,48,49,50,50,51,51,52,52,53,53,54,54,55,55,55,56,56,56,57,57,57,57,57,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,57,57,57,57,57,56,56,56,55,55,55,54,54,53,53,52,52,51,51,50,50,49,48,48,47,47,46,45,45,44,44,43,43,42,42,41,40,40,39,39,38,38,37,36,35,34,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-28,-29,-30,-31,-32,-33,-34,-34,-35,-36,-37,-38,-38,-39,-39,-40,-40,-41,-42,-42,-43,-43,-44,-44,-45,-45,-46,-47,-47,-48,-48,-49,-50,-50,-51,-51,-52,-52,-53,-53,-54,-54,-55,-55,-55,-56,-56,-56,-57,-57,-57,-57,-57,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-58,-58,-58,-58,-58,-57,-57,-57,-56,-56,-56,-55,-55,-54,-54,-54,-53,-53,-53,-52,-52,-51,-51,-50,-50,-49,-49,-48,-47,-47,-46,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-37,-36,-35,-34,-33,-33,-32,-31,-30,-29,-28,-28,-27,-26,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,26,27,28,28,29,30,31,32,33,33,34,35,36,37,37,38,39,40,41,42,43,44,45,46,46,47,47,48,49,49,50,50,51,51,52,52,53,53,53,54,54,54,55,55,56,56,56,57,57,57,58,58,58,58,58,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,58,58,58,58,58,57,57,57,56,56,56,55,55,54,54,54,53,53,53,52,52,51,51,50,50,49,49,48,47,47,46,46,45,44,43,42,41,40,39,38,37,37,36,35,34,33,33,32,31,30,29,28,28,27,26,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-26,-27,-28,-28,-29,-30,-31,-32,-33,-33,-34,-35,-36,-37,-37,-38,-39,-40,-41,-42,-43,-44,-45,-46,-46,-47,-47,-48,-49,-49,-50,-50,-51,-51,-52,-52,-53,-53,-53,-54,-54,-54,-55,-55,-56,-56,-56,-57,-57,-57,-58,-58,-58,-58,-58,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59];\r\nvar towards_center = [0,0,0,0,0,0,0,0,0,1,1,2,3,3,3,4,5,5,5,6,7,7,7,8,1,9,9,10,12,13,13,13,14,16,17,17,17,18,20,21,21,21,22,24,9,25,25,26,11,29,30,30,30,31,15,34,35,35,35,36,19,39,40,40,40,41,23,44,25,45,45,46,47,27,48,28,49,50,51,51,51,52,53,32,54,33,55,56,57,57,57,58,59,37,60,38,61,62,63,63,63,64,65,42,66,43,67,68,45,69,69,70,71,73,75,77,78,79,79,79,80,81,83,85,87,88,89,89,89,90,91,93,95,97,98,99,99,99,100,101,103,105,107,108,69,109,109,110,111,72,113,74,114,76,116,117,118,118,118,119,120,82,122,84,123,86,125,126,127,127,127,128,129,92,131,94,132,96,134,135,136,136,136,137,138,102,140,104,141,106,143,144,109,145,145,146,147,148,112,149,151,153,115,154,155,156,157,157,157,158,159,160,121,161,163,165,124,166,167,168,169,169,169,170,171,172,130,173,175,177,133,178,179,180,181,181,181,182,183,184,139,185,187,189,142,190,191,192,145,193,193,194,195,196,198,150,200,152,202,204,205,206,207,207,207,208,209,210,212,162,214,164,216,218,219,220,221,221,221,222,223,224,226,174,228,176,230,232,233,234,235,235,235,236,237,238,240,186,242,188,244,246,247,248,193,249,249,250,251,252,197,254,199,255,257,201,258,203,260,261,262,263,263,263,264,265,266,211,268,213,269,271,215,272,217,274,275,276,277,277,277,278,279,280,225,282,227,283,285,229,286,231,288,289,290,291,291,291,292,293,294,239,296,241,297,299,243,300,245,302,303,304,249,305,305,306,307,308,253,310,312,256,315,317,259,319,320,321,322,322,322,323,324,325,267,327,329,270,332,334,273,336,337,338,339,339,339,340,341,342,281,344,346,284,349,351,287,353,354,355,356,356,356,357,358,359,295,361,363,298,366,368,301,370,371,372,305,373,373,374,375,376,309,378,311,380,313,381,314,382,316,384,318,386,387,388,389,389,389,390,391,392,326,394,328,396,330,397,331,398,333,400,335,402,403,404,405,405,405,406,407,408,343,410,345,412,347,413,348,414,350,416,352,418,419,420,421,421,421,422,423,424,360,426,362,428,364,429,365,430,367,432,369,434,435,436,373,437,437,438,439,440,441,377,442,443,379,444,446,448,450,383,451,452,385,453,454,455,456,457,457,457,458,459,460,461,393,462,463,395,464,466,468,470,399,471,472,401,473,474,475,476,477,477,477,478,479,480,481,409,482,483,411,484,486,488,490,415,491,492,417,493,494,495,496,497,497,497,498,499,500,501,425,502,503,427,504,506,508,510,431,511,512,433,513,514,515,516,437,517,517,518,519,520,521,523,524,526,445,528,447,529,449,531,533,534,536,537,538,539,540,540,540,541,542,543,544,546,547,549,465,551,467,552,469,554,556,557,559,560,561,562,563,563,563,564,565,566,567,569,570,572,485,574,487,575,489,577,579,580,582,583,584,585,586,586,586,587,588,589,590,592,593,595,505,597,507,598,509,600,602,603,605,606,607,608,517,609,609,610,611,612,613,522,615,525,617,527,618,620,622,530,623,532,625,535,627,628,629,630,631,631,631,632,633,634,635,545,637,548,639,550,640,642,644,553,645,555,647,558,649,650,651,652,653,653,653,654,655,656,657,568,659,571,661,573,662,664,666,576,667,578,669,581,671,672,673,674,675,675,675,676,677,678,679,591,681,594,683,596,684,686,688,599,689,601,691,604,693,694,695,696,609,697,697,698,699,700,701,614,703,616,705,707,619,709,621,711,713,624,715,626,717,718,719,720,721,721,721,722,723,724,725,636,727,638,729,731,641,733,643,735,737,646,739,648,741,742,743,744,745,745,745,746,747,748,749,658,751,660,753,755,663,757,665,759,761,668,763,670,765,766,767,768,769,769,769,770,771,772,773,680,775,682,777,779,685,781,687,783,785,690,787,692,789,790,791,792,697,793,793,794,795,796,797,702,799,800,704,801,706,803,708,804,806,710,807,712,809,714,810,811,716,813,814,815,816,817,817,817,818,819,820,821,726,823,824,728,825,730,827,732,828,830,734,831,736,833,738,834,835,740,837,838,839,840,841,841,841,842,843,844,845,750,847,848,752,849,754,851,756,852,854,758,855,760,857,762,858,859,764,861,862,863,864,865,865,865,866,867,868,869,774,871,872,776,873,778,875,780,876,878,782,879,784,881,786,882,883,788,885,886,887,888,793,889,889,890,891,892,893,894,798,895,896,898,899,802,900,902,805,905,907,808,908,909,911,912,812,913,914,915,916,917,918,918,918,919,920,921,922,923,822,924,925,927,928,826,929,931,829,934,936,832,937,938,940,941,836,942,943,944,945,946,947,947,947,948,949,950,951,952,846,953,954,956,957,850,958,960,853,963,965,856,966,967,969,970,860,971,972,973,974,975,976,976,976,977,978,979,980,981,870,982,983,985,986,874,987,989,877,992,994,880,995,996,998,999,884,1000,1001,1002,1003,1004,889,1005,1005,1006,1007,1008,1009,1010,1012,1013,897,1015,1017,901,1019,903,1020,904,1021,906,1023,1025,910,1027,1028,1030,1031,1032,1033,1034,1035,1035,1035,1036,1037,1038,1039,1040,1042,1043,926,1045,1047,930,1049,932,1050,933,1051,935,1053,1055,939,1057,1058,1060,1061,1062,1063,1064,1065,1065,1065,1066,1067,1068,1069,1070,1072,1073,955,1075,1077,959,1079,961,1080,962,1081,964,1083,1085,968,1087,1088,1090,1091,1092,1093,1094,1095,1095,1095,1096,1097,1098,1099,1100,1102,1103,984,1105,1107,988,1109,990,1110,991,1111,993,1113,1115,997,1117,1118,1120,1121,1122,1123,1124,1005,1125,1125,1126,1127,1128,1129,1130,1011,1132,1014,1134,1016,1136,1018,1137,1139,1141,1143,1022,1144,1024,1146,1026,1148,1029,1150,1151,1152,1153,1154,1155,1155,1155,1156,1157,1158,1159,1160,1041,1162,1044,1164,1046,1166,1048,1167,1169,1171,1173,1052,1174,1054,1176,1056,1178,1059,1180,1181,1182,1183,1184,1185,1185,1185,1186,1187,1188,1189,1190,1071,1192,1074,1194,1076,1196,1078,1197,1199,1201,1203,1082,1204,1084,1206,1086,1208,1089,1210,1211,1212,1213,1214,1215,1215,1215,1216,1217,1218,1219,1220,1101,1222,1104,1224,1106,1226,1108,1227,1229,1231,1233,1112,1234,1114,1236,1116,1238,1119,1240,1241,1242,1243,1244,1125,1245,1245,1246,1247,1248,1249,1250,1131,1252,1253,1133,1254,1255,1135,1256,1258,1138,1260,1140,1261,1142,1263,1265,1145,1266,1267,1147,1268,1269,1149,1271,1272,1273,1274,1275,1276,1276,1276,1277,1278,1279,1280,1281,1161,1283,1284,1163,1285,1286,1165,1287,1289,1168,1291,1170,1292,1172,1294,1296,1175,1297,1298,1177,1299,1300,1179,1302,1303,1304,1305,1306,1307,1307,1307,1308,1309,1310,1311,1312,1191,1314,1315,1193,1316,1317,1195,1318,1320,1198,1322,1200,1323,1202,1325,1327,1205,1328,1329,1207,1330,1331,1209,1333,1334,1335,1336,1337,1338,1338,1338,1339,1340,1341,1342,1343,1221,1345,1346,1223,1347,1348,1225,1349,1351,1228,1353,1230,1354,1232,1356,1358,1235,1359,1360,1237,1361,1362,1239,1364,1365,1366,1367,1368,1245,1369,1369,1370,1371,1372,1373,1374,1251,1376,1377,1379,1380,1382,1257,1384,1259,1385,1387,1389,1262,1390,1264,1392,1394,1395,1397,1398,1270,1400,1401,1402,1403,1404,1405,1405,1405,1406,1407,1408,1409,1410,1282,1412,1413,1415,1416,1418,1288,1420,1290,1421,1423,1425,1293,1426,1295,1428,1430,1431,1433,1434,1301,1436,1437,1438,1439,1440,1441,1441,1441,1442,1443,1444,1445,1446,1313,1448,1449,1451,1452,1454,1319,1456,1321,1457,1459,1461,1324,1462,1326,1464,1466,1467,1469,1470,1332,1472,1473,1474,1475,1476,1477,1477,1477,1478,1479,1480,1481,1482,1344,1484,1485,1487,1488,1490,1350,1492,1352,1493,1495,1497,1355,1498,1357,1500,1502,1503,1505,1506,1363,1508,1509,1510,1511,1512,1369,1513,1513,1514,1515,1516,1517,1518,1375,1520,1521,1378,1523,1381,1525,1383,1526,1528,1386,1388,1532,1534,1391,1535,1393,1537,1396,1539,1540,1399,1542,1543,1544,1545,1546,1547,1547,1547,1548,1549,1550,1551,1552,1411,1554,1555,1414,1557,1417,1559,1419,1560,1562,1422,1424,1566,1568,1427,1569,1429,1571,1432,1573,1574,1435,1576,1577,1578,1579,1580,1581,1581,1581,1582,1583,1584,1585,1586,1447,1588,1589,1450,1591,1453,1593,1455,1594,1596,1458,1460,1600,1602,1463,1603,1465,1605,1468,1607,1608,1471,1610,1611,1612,1613,1614,1615,1615,1615,1616,1617,1618,1619,1620,1483,1622,1623,1486,1625,1489,1627,1491,1628,1630,1494,1496,1634,1636,1499,1637,1501,1639,1504,1641,1642,1507,1644,1645,1646,1647,1648,1513,1649,1649,1650,1651,1652,1653,1654,1519,1656,1657,1522,1659,1524,1661,1663,1527,1665,1529,1666,1530,1667,1531,1668,1533,1670,1672,1536,1674,1538,1676,1677,1541,1679,1680,1681,1682,1683,1684,1684,1684,1685,1686,1687,1688,1689,1553,1691,1692,1556,1694,1558,1696,1698,1561,1700,1563,1701,1564,1702,1565,1703,1567,1705,1707,1570,1709,1572,1711,1712,1575,1714,1715,1716,1717,1718,1719,1719,1719,1720,1721,1722,1723,1724,1587,1726,1727,1590,1729,1592,1731,1733,1595,1735,1597,1736,1598,1737,1599,1738,1601,1740,1742,1604,1744,1606,1746,1747,1609,1749,1750,1751,1752,1753,1754,1754,1754,1755,1756,1757,1758,1759,1621,1761,1762,1624,1764,1626,1766,1768,1629,1770,1631,1771,1632,1772,1633,1773,1635,1775,1777,1638,1779,1640,1781,1782,1643,1784,1785,1786,1787,1788,1649,1789,1789,1790,1791,1792,1793,1794,1795,1655,1796,1797,1658,1799,1800,1660,1801,1662,1803,1664,1804,1806,1808,1810,1812,1669,1813,1671,1815,1673,1816,1817,1675,1819,1820,1678,1821,1822,1823,1824,1825,1826,1827,1827,1827,1828,1829,1830,1831,1832,1833,1690,1834,1835,1693,1837,1838,1695,1839,1697,1841,1699,1842,1844,1846,1848,1850,1704,1851,1706,1853,1708,1854,1855,1710,1857,1858,1713,1859,1860,1861,1862,1863,1864,1865,1865,1865,1866,1867,1868,1869,1870,1871,1725,1872,1873,1728,1875,1876,1730,1877,1732,1879,1734,1880,1882,1884,1886,1888,1739,1889,1741,1891,1743,1892,1893,1745,1895,1896,1748,1897,1898,1899,1900,1901,1902,1903,1903,1903,1904,1905,1906,1907,1908,1909,1760,1910,1911,1763,1913,1914,1765,1915,1767,1917,1769,1918,1920,1922,1924,1926,1774,1927,1776,1929,1778,1930,1931,1780,1933,1934,1783,1935,1936,1937,1938,1939,1940,1789,1941,1941,1942,1943,1944,1945,1946,1947,1949,1950,1951,1798,1952,1953,1955,1956,1802,1957,1959,1805,1961,1807,1962,1809,1963,1811,1965,1967,1814,1968,1969,1971,1972,1818,1973,1974,1975,1977,1978,1979,1980,1981,1982,1983,1983,1983,1984,1985,1986,1987,1988,1989,1991,1992,1993,1836,1994,1995,1997,1998,1840,1999,2001,1843,2003,1845,2004,1847,2005,1849,2007,2009,1852,2010,2011,2013,2014,1856,2015,2016,2017,2019,2020,2021,2022,2023,2024,2025,2025,2025,2026,2027,2028,2029,2030,2031,2033,2034,2035,1874,2036,2037,2039,2040,1878,2041,2043,1881,2045,1883,2046,1885,2047,1887,2049,2051,1890,2052,2053,2055,2056,1894,2057,2058,2059,2061,2062,2063,2064,2065,2066,2067,2067,2067,2068,2069,2070,2071,2072,2073,2075,2076,2077,1912,2078,2079,2081,2082,1916,2083,2085,1919,2087,1921,2088,1923,2089,1925,2091,2093,1928,2094,2095,2097,2098,1932,2099,2100,2101,2103,2104,2105,2106,2107,2108,1941,2109,2109,2110,2111,2112,2113,2114,2115,1948,2117,2118,2120,2121,1954,2123,2125,1958,2127,1960,2128,2130,2132,2134,1964,2135,1966,2137,2139,1970,2141,2142,2144,2145,1976,2147,2148,2149,2150,2151,2152,2153,2153,2153,2154,2155,2156,2157,2158,2159,1990,2161,2162,2164,2165,1996,2167,2169,2000,2171,2002,2172,2174,2176,2178,2006,2179,2008,2181,2183,2012,2185,2186,2188,2189,2018,2191,2192,2193,2194,2195,2196,2197,2197,2197,2198,2199,2200,2201,2202,2203,2032,2205,2206,2208,2209,2038,2211,2213,2042,2215,2044,2216,2218,2220,2222,2048,2223,2050,2225,2227,2054,2229,2230,2232,2233,2060,2235,2236,2237,2238,2239,2240,2241,2241,2241,2242,2243,2244,2245,2246,2247,2074,2249,2250,2252,2253,2080,2255,2257,2084,2259,2086,2260,2262,2264,2266,2090,2267,2092,2269,2271,2096,2273,2274,2276,2277,2102,2279,2280,2281,2282,2283,2284,2109,2285,2285,2286,2287,2288,2289,2290,2291,2116,2293,2294,2119,2296,2122,2298,2124,2300,2126,2301,2303,2129,2131,2133,2308,2310,2136,2311,2138,2313,2140,2315,2143,2317,2318,2146,2320,2321,2322,2323,2324,2325,2326,2326,2326,2327,2328,2329,2330,2331,2332,2160,2334,2335,2163,2337,2166,2339,2168,2341,2170,2342,2344,2173,2175,2177,2349,2351,2180,2352,2182,2354,2184,2356,2187,2358,2359,2190,2361,2362,2363,2364,2365,2366,2367,2367,2367,2368,2369,2370,2371,2372,2373,2204,2375,2376,2207,2378,2210,2380,2212,2382,2214,2383,2385,2217,2219,2221,2390,2392,2224,2393,2226,2395,2228,2397,2231,2399,2400,2234,2402,2403,2404,2405,2406,2407,2408,2408,2408,2409,2410,2411,2412,2413,2414,2248,2416,2417,2251,2419,2254,2421,2256,2423,2258,2424,2426,2261,2263,2265,2431,2433,2268,2434,2270,2436,2272,2438,2275,2440,2441,2278,2443,2444,2445,2446,2447,2448,2285,2449,2449,2450,2451,2452,2453,2454,2455,2292,2457,2458,2295,2460,2461,2297,2462,2299,2464,2466,2302,2468,2304,2469,2305,2470,2306,2471,2307,2472,2309,2474,2476,2312,2478,2314,2479,2480,2316,2482,2483,2319,2485,2486,2487,2488,2489,2490,2491,2491,2491,2492,2493,2494,2495,2496,2497,2333,2499,2500,2336,2502,2503,2338,2504,2340,2506,2508,2343,2510,2345,2511,2346,2512,2347,2513,2348,2514,2350,2516,2518,2353,2520,2355,2521,2522,2357,2524,2525,2360,2527,2528,2529,2530,2531,2532,2533,2533,2533,2534,2535,2536,2537,2538,2539,2374,2541,2542,2377,2544,2545,2379,2546,2381,2548,2550,2384,2552,2386,2553,2387,2554,2388,2555,2389,2556,2391,2558,2560,2394,2562,2396,2563,2564,2398,2566,2567,2401,2569,2570,2571,2572,2573,2574,2575,2575,2575,2576,2577,2578,2579,2580,2581,2415,2583,2584,2418,2586,2587,2420,2588,2422,2590,2592,2425,2594,2427,2595,2428,2596,2429,2597,2430,2598,2432,2600,2602,2435,2604,2437,2605,2606,2439,2608,2609,2442,2611,2612,2613,2614,2615,2616,2449,2617,2617,2618,2619,2620,2621,2622,2623,2456,2625,2626,2459,2628,2629,2631,2632,2463,2633,2465,2635,2467,2636,2638,2640,2642,2644,2646,2473,2647,2475,2649,2477,2650,2651,2653,2654,2481,2656,2657,2484,2659,2660,2661,2662,2663,2664,2665,2665,2665,2666,2667,2668,2669,2670,2671,2498,2673,2674,2501,2676,2677,2679,2680,2505,2681,2507,2683,2509,2684,2686,2688,2690,2692,2694,2515,2695,2517,2697,2519,2698,2699,2701,2702,2523,2704,2705,2526,2707,2708,2709,2710,2711,2712,2713,2713,2713,2714,2715,2716,2717,2718,2719,2540,2721,2722,2543,2724,2725,2727,2728,2547,2729,2549,2731,2551,2732,2734,2736,2738,2740,2742,2557,2743,2559,2745,2561,2746,2747,2749,2750,2565,2752,2753,2568,2755,2756,2757,2758,2759,2760,2761,2761,2761,2762,2763,2764,2765,2766,2767,2582,2769,2770,2585,2772,2773,2775,2776,2589,2777,2591,2779,2593,2780,2782,2784,2786,2788,2790,2599,2791,2601,2793,2603,2794,2795,2797,2798,2607,2800,2801,2610,2803,2804,2805,2806,2807,2808,2617,2809,2809,2810,2811,2812,2813,2814,2815,2624,2817,2818,2819,2627,2820,2821,2630,2823,2825,2826,2634,2827,2829,2637,2831,2639,2832,2641,2833,2643,2834,2645,2836,2838,2648,2839,2840,2842,2652,2844,2845,2655,2846,2847,2848,2658,2850,2851,2852,2853,2854,2855,2856,2856,2856,2857,2858,2859,2860,2861,2862,2672,2864,2865,2866,2675,2867,2868,2678,2870,2872,2873,2682,2874,2876,2685,2878,2687,2879,2689,2880,2691,2881,2693,2883,2885,2696,2886,2887,2889,2700,2891,2892,2703,2893,2894,2895,2706,2897,2898,2899,2900,2901,2902,2903,2903,2903,2904,2905,2906,2907,2908,2909,2720,2911,2912,2913,2723,2914,2915,2726,2917,2919,2920,2730,2921,2923,2733,2925,2735,2926,2737,2927,2739,2928,2741,2930,2932,2744,2933,2934,2936,2748,2938,2939,2751,2940,2941,2942,2754,2944,2945,2946,2947,2948,2949,2950,2950,2950,2951,2952,2953,2954,2955,2956,2768,2958,2959,2960,2771,2961,2962,2774,2964,2966,2967,2778,2968,2970,2781,2972,2783,2973,2785,2974,2787,2975,2789,2977,2979,2792,2980,2981,2983,2796,2985,2986,2799,2987,2988,2989,2802,2991,2992,2993,2994,2995,2996,2809,2997,2997,2998,2999,3000,3001,3002,3003,3004,2816,3005,3006,3007,3009,3010,2822,3012,2824,3014,3016,2828,3018,2830,3019,3021,3023,3025,3027,2835,3028,2837,3030,3032,2841,3034,2843,3036,3037,3039,3040,3041,2849,3042,3043,3044,3045,3046,3047,3048,3049,3049,3049,3050,3051,3052,3053,3054,3055,3056,2863,3057,3058,3059,3061,3062,2869,3064,2871,3066,3068,2875,3070,2877,3071,3073,3075,3077,3079,2882,3080,2884,3082,3084,2888,3086,2890,3088,3089,3091,3092,3093,2896,3094,3095,3096,3097,3098,3099,3100,3101,3101,3101,3102,3103,3104,3105,3106,3107,3108,2910,3109,3110,3111,3113,3114,2916,3116,2918,3118,3120,2922,3122,2924,3123,3125,3127,3129,3131,2929,3132,2931,3134,3136,2935,3138,2937,3140,3141,3143,3144,3145,2943,3146,3147,3148,3149,3150,3151,3152,3153,3153,3153,3154,3155,3156,3157,3158,3159,3160,2957,3161,3162,3163,3165,3166,2963,3168,2965,3170,3172,2969,3174,2971,3175,3177,3179,3181,3183,2976,3184,2978,3186,3188,2982,3190,2984,3192,3193,3195,3196,3197,2990,3198,3199,3200,3201,3202,3203,3204,2997,3205,3205,3206,3207,3208,3209,3210,3211,3212,3214,3215,3216,3008,3218,3011,3220,3013,3222,3015,3224,3017,3225,3227,3020,3229,3022,3230,3024,3231,3026,3233,3235,3029,3236,3031,3238,3033,3240,3035,3242,3038,3244,3245,3246,3248,3249,3250,3251,3252,3253,3254,3255,3255,3255,3256,3257,3258,3259,3260,3261,3262,3264,3265,3266,3060,3268,3063,3270,3065,3272,3067,3274,3069,3275,3277,3072,3279,3074,3280,3076,3281,3078,3283,3285,3081,3286,3083,3288,3085,3290,3087,3292,3090,3294,3295,3296,3298,3299,3300,3301,3302,3303,3304,3305,3305,3305,3306,3307,3308,3309,3310,3311,3312,3314,3315,3316,3112,3318,3115,3320,3117,3322,3119,3324,3121,3325,3327,3124,3329,3126,3330,3128,3331,3130,3333,3335,3133,3336,3135,3338,3137,3340,3139,3342,3142,3344,3345,3346,3348,3349,3350,3351,3352,3353,3354,3355,3355,3355,3356,3357,3358,3359,3360,3361,3362,3364,3365,3366,3164,3368,3167,3370,3169,3372,3171,3374,3173,3375,3377,3176,3379,3178,3380,3180,3381,3182,3383,3385,3185,3386,3187,3388,3189,3390,3191,3392,3194,3394,3395,3396,3398,3399,3400,3401,3402,3403,3404,3205,3405,3405,3406,3407,3408,3409,3410,3411,3412,3213,3414,3415,3217,3417,3418,3219,3419,3420,3221,3421,3422,3223,3423,3425,3226,3427,3228,3428,3430,3432,3434,3232,3435,3234,3437,3439,3237,3440,3441,3239,3442,3443,3241,3444,3445,3243,3447,3448,3247,3450,3451,3452,3453,3454,3455,3456,3457,3457,3457,3458,3459,3460,3461,3462,3463,3464,3263,3466,3467,3267,3469,3470,3269,3471,3472,3271,3473,3474,3273,3475,3477,3276,3479,3278,3480,3482,3484,3486,3282,3487,3284,3489,3491,3287,3492,3493,3289,3494,3495,3291,3496,3497,3293,3499,3500,3297,3502,3503,3504,3505,3506,3507,3508,3509,3509,3509,3510,3511,3512,3513,3514,3515,3516,3313,3518,3519,3317,3521,3522,3319,3523,3524,3321,3525,3526,3323,3527,3529,3326,3531,3328,3532,3534,3536,3538,3332,3539,3334,3541,3543,3337,3544,3545,3339,3546,3547,3341,3548,3549,3343,3551,3552,3347,3554,3555,3556,3557,3558,3559,3560,3561,3561,3561,3562,3563,3564,3565,3566,3567,3568,3363,3570,3571,3367,3573,3574,3369,3575,3576,3371,3577,3578,3373,3579,3581,3376,3583,3378,3584,3586,3588,3590,3382,3591,3384,3593,3595,3387,3596,3597,3389,3598,3599,3391,3600,3601,3393,3603,3604,3397,3606,3607,3608,3609,3610,3611,3612,3405,3613,3613,3614,3615,3616,3617,3618,3619,3620,3413,3622,3623,3416,3625,3626,3628,3629,3631,3632,3634,3424,3636,3426,3637,3639,3429,3431,3433,3644,3646,3436,3647,3438,3649,3651,3652,3654,3655,3657,3658,3446,3660,3661,3449,3663,3664,3665,3666,3667,3668,3669,3670,3670,3670,3671,3672,3673,3674,3675,3676,3677,3465,3679,3680,3468,3682,3683,3685,3686,3688,3689,3691,3476,3693,3478,3694,3696,3481,3483,3485,3701,3703,3488,3704,3490,3706,3708,3709,3711,3712,3714,3715,3498,3717,3718,3501,3720,3721,3722,3723,3724,3725,3726,3727,3727,3727,3728,3729,3730,3731,3732,3733,3734,3517,3736,3737,3520,3739,3740,3742,3743,3745,3746,3748,3528,3750,3530,3751,3753,3533,3535,3537,3758,3760,3540,3761,3542,3763,3765,3766,3768,3769,3771,3772,3550,3774,3775,3553,3777,3778,3779,3780,3781,3782,3783,3784,3784,3784,3785,3786,3787,3788,3789,3790,3791,3569,3793,3794,3572,3796,3797,3799,3800,3802,3803,3805,3580,3807,3582,3808,3810,3585,3587,3589,3815,3817,3592,3818,3594,3820,3822,3823,3825,3826,3828,3829,3602,3831,3832,3605,3834,3835,3836,3837,3838,3839,3840,3613,3841,3841,3842,3843,3844,3845,3846,3847,3848,3621,3850,3851,3624,3853,3854,3627,3856,3630,3858,3633,3860,3635,3861,3863,3638,3865,3640,3866,3641,3867,3642,3868,3643,3869,3645,3871,3873,3648,3874,3650,3876,3653,3878,3656,3880,3881,3659,3883,3884,3662,3886,3887,3888,3889,3890,3891,3892,3893,3893,3893,3894,3895,3896,3897,3898,3899,3900,3678,3902,3903,3681,3905,3906,3684,3908,3687,3910,3690,3912,3692,3913,3915,3695,3917,3697,3918,3698,3919,3699,3920,3700,3921,3702,3923,3925,3705,3926,3707,3928,3710,3930,3713,3932,3933,3716,3935,3936,3719,3938,3939,3940,3941,3942,3943,3944,3945,3945,3945,3946,3947,3948,3949,3950,3951,3952,3735,3954,3955,3738,3957,3958,3741,3960,3744,3962,3747,3964,3749,3965,3967,3752,3969,3754,3970,3755,3971,3756,3972,3757,3973,3759,3975,3977,3762,3978,3764,3980,3767,3982,3770,3984,3985,3773,3987,3988,3776,3990,3991,3992,3993,3994,3995,3996,3997,3997,3997,3998,3999,4000,4001,4002,4003,4004,3792,4006,4007,3795,4009,4010,3798,4012,3801,4014,3804,4016,3806,4017,4019,3809,4021,3811,4022,3812,4023,3813,4024,3814,4025,3816,4027,4029,3819,4030,3821,4032,3824,4034,3827,4036,4037,3830,4039,4040,3833,4042,4043,4044,4045,4046,4047,4048,3841,4049,4049,4050,4051,4052,4053,4054,4055,4056,3849,4058,4059,4060,3852,4061,4062,3855,4064,3857,4066,3859,4068,4070,3862,4072,3864,4073,4075,4077,4079,4081,4083,3870,4084,3872,4086,4088,3875,4090,3877,4092,3879,4094,4095,3882,4096,4097,4098,3885,4100,4101,4102,4103,4104,4105,4106,4107,4107,4107,4108,4109,4110,4111,4112,4113,4114,3901,4116,4117,4118,3904,4119,4120,3907,4122,3909,4124,3911,4126,4128,3914,4130,3916,4131,4133,4135,4137,4139,4141,3922,4142,3924,4144,4146,3927,4148,3929,4150,3931,4152,4153,3934,4154,4155,4156,3937,4158,4159,4160,4161,4162,4163,4164,4165,4165,4165,4166,4167,4168,4169,4170,4171,4172,3953,4174,4175,4176,3956,4177,4178,3959,4180,3961,4182,3963,4184,4186,3966,4188,3968,4189,4191,4193,4195,4197,4199,3974,4200,3976,4202,4204,3979,4206,3981,4208,3983,4210,4211,3986,4212,4213,4214,3989,4216,4217,4218,4219,4220,4221,4222,4223,4223,4223,4224,4225,4226,4227,4228,4229,4230,4005,4232,4233,4234,4008,4235,4236,4011,4238,4013,4240,4015,4242,4244,4018,4246,4020,4247,4249,4251,4253,4255,4257,4026,4258,4028,4260,4262,4031,4264,4033,4266,4035,4268,4269,4038,4270,4271,4272,4041,4274,4275,4276,4277,4278,4279,4280,4049,4281,4281,4282,4283,4284,4285,4286,4287,4288,4057,4290,4291,4292,4294,4295,4063,4297,4298,4065,4299,4300,4067,4301,4069,4303,4071,4304,4306,4074,4308,4076,4309,4078,4310,4080,4311,4082,4313,4315,4085,4316,4087,4318,4089,4319,4320,4091,4321,4322,4093,4324,4325,4327,4328,4329,4099,4331,4332,4333,4334,4335,4336,4337,4338,4338,4338,4339,4340,4341,4342,4343,4344,4345,4115,4347,4348,4349,4351,4352,4121,4354,4355,4123,4356,4357,4125,4358,4127,4360,4129,4361,4363,4132,4365,4134,4366,4136,4367,4138,4368,4140,4370,4372,4143,4373,4145,4375,4147,4376,4377,4149,4378,4379,4151,4381,4382,4384,4385,4386,4157,4388,4389,4390,4391,4392,4393,4394,4395,4395,4395,4396,4397,4398,4399,4400,4401,4402,4173,4404,4405,4406,4408,4409,4179,4411,4412,4181,4413,4414,4183,4415,4185,4417,4187,4418,4420,4190,4422,4192,4423,4194,4424,4196,4425,4198,4427,4429,4201,4430,4203,4432,4205,4433,4434,4207,4435,4436,4209,4438,4439,4441,4442,4443,4215,4445,4446,4447,4448,4449,4450,4451,4452,4452,4452,4453,4454,4455,4456,4457,4458,4459,4231,4461,4462,4463,4465,4466,4237,4468,4469,4239,4470,4471,4241,4472,4243,4474,4245,4475,4477,4248,4479,4250,4480,4252,4481,4254,4482,4256,4484,4486,4259,4487,4261,4489,4263,4490,4491,4265,4492,4493,4267,4495,4496,4498,4499,4500,4273,4502,4503,4504,4505,4506,4507,4508,4281,4509,4509,4510,4511,4512,4513,4514,4515,4516,4289,4518,4519,4520,4293,4522,4523,4296,4524,4525,4527,4528,4530,4531,4302,4532,4534,4305,4536,4307,4537,4539,4541,4543,4545,4312,4546,4314,4548,4550,4317,4551,4552,4554,4555,4557,4558,4323,4559,4560,4326,4562,4563,4564,4330,4566,4567,4568,4569,4570,4571,4572,4573,4573,4573,4574,4575,4576,4577,4578,4579,4580,4346,4582,4583,4584,4350,4586,4587,4353,4588,4589,4591,4592,4594,4595,4359,4596,4598,4362,4600,4364,4601,4603,4605,4607,4609,4369,4610,4371,4612,4614,4374,4615,4616,4618,4619,4621,4622,4380,4623,4624,4383,4626,4627,4628,4387,4630,4631,4632,4633,4634,4635,4636,4637,4637,4637,4638,4639,4640,4641,4642,4643,4644,4403,4646,4647,4648,4407,4650,4651,4410,4652,4653,4655,4656,4658,4659,4416,4660,4662,4419,4664,4421,4665,4667,4669,4671,4673,4426,4674,4428,4676,4678,4431,4679,4680,4682,4683,4685,4686,4437,4687,4688,4440,4690,4691,4692,4444,4694,4695,4696,4697,4698,4699,4700,4701,4701,4701,4702,4703,4704,4705,4706,4707,4708,4460,4710,4711,4712,4464,4714,4715,4467,4716,4717,4719,4720,4722,4723,4473,4724,4726,4476,4728,4478,4729,4731,4733,4735,4737,4483,4738,4485,4740,4742,4488,4743,4744,4746,4747,4749,4750,4494,4751,4752,4497,4754,4755,4756,4501,4758,4759,4760,4761,4762,4763,4764,4509,4765,4765,4766,4767,4768,4769,4770,4771,4772,4517,4774,4775,4776,4521,4778,4779,4781,4782,4526,4784,4529,4786,4788,4533,4790,4535,4791,4793,4538,4540,4542,4544,4799,4801,4547,4802,4549,4804,4806,4553,4808,4556,4810,4811,4813,4814,4561,4816,4817,4818,4565,4820,4821,4822,4823,4824,4825,4826,4827,4827,4827,4828,4829,4830,4831,4832,4833,4834,4581,4836,4837,4838,4585,4840,4841,4843,4844,4590,4846,4593,4848,4850,4597,4852,4599,4853,4855,4602,4604,4606,4608,4861,4863,4611,4864,4613,4866,4868,4617,4870,4620,4872,4873,4875,4876,4625,4878,4879,4880,4629,4882,4883,4884,4885,4886,4887,4888,4889,4889,4889,4890,4891,4892,4893,4894,4895,4896,4645,4898,4899,4900,4649,4902,4903,4905,4906,4654,4908,4657,4910,4912,4661,4914,4663,4915,4917,4666,4668,4670,4672,4923,4925,4675,4926,4677,4928,4930,4681,4932,4684,4934,4935,4937,4938,4689,4940,4941,4942,4693,4944,4945,4946,4947,4948,4949,4950,4951,4951,4951,4952,4953,4954,4955,4956,4957,4958,4709,4960,4961,4962,4713,4964,4965,4967,4968,4718,4970,4721,4972,4974,4725,4976,4727,4977,4979,4730,4732,4734,4736,4985,4987,4739,4988,4741,4990,4992,4745,4994,4748,4996,4997,4999,5000,4753,5002,5003,5004,4757,5006,5007,5008,5009,5010,5011,5012,4765,5013,5013,5014,5015,5016,5017,5018,5019,5020,5021,4773,5022,5023,5024,4777,5026,5027,4780,5029,4783,5031,4785,5033,4787,5035,4789,5036,5038,4792,5040,4794,5041,4795,5042,4796,5043,4797,5044,4798,5045,4800,5047,5049,4803,5050,4805,5052,4807,5054,4809,5056,4812,5058,5059,4815,5061,5062,5063,4819,5064,5065,5066,5067,5068,5069,5070,5071,5072,5072,5072,5073,5074,5075,5076,5077,5078,5079,5080,4835,5081,5082,5083,4839,5085,5086,4842,5088,4845,5090,4847,5092,4849,5094,4851,5095,5097,4854,5099,4856,5100,4857,5101,4858,5102,4859,5103,4860,5104,4862,5106,5108,4865,5109,4867,5111,4869,5113,4871,5115,4874,5117,5118,4877,5120,5121,5122,4881,5123,5124,5125,5126,5127,5128,5129,5130,5131,5131,5131,5132,5133,5134,5135,5136,5137,5138,5139,4897,5140,5141,5142,4901,5144,5145,4904,5147,4907,5149,4909,5151,4911,5153,4913,5154,5156,4916,5158,4918,5159,4919,5160,4920,5161,4921,5162,4922,5163,4924,5165,5167,4927,5168,4929,5170,4931,5172,4933,5174,4936,5176,5177,4939,5179,5180,5181,4943,5182,5183,5184,5185,5186,5187,5188,5189,5190,5190,5190,5191,5192,5193,5194,5195,5196,5197,5198,4959,5199,5200,5201,4963,5203,5204,4966,5206,4969,5208,4971,5210,4973,5212,4975,5213,5215,4978,5217,4980,5218,4981,5219,4982,5220,4983,5221,4984,5222,4986,5224,5226,4989,5227,4991,5229,4993,5231,4995,5233,4998,5235,5236,5001,5238,5239,5240,5005,5241,5242,5243,5244,5245,5246,5247,5248,5013,5249,5249,5250,5251,5252,5253,5254,5255,5256,5257,5259,5260,5261,5025,5263,5264,5028,5266,5267,5030,5268,5269,5032,5270,5034,5272,5274,5037,5276,5039,5277,5279,5281,5283,5285,5287,5289,5046,5290,5048,5292,5294,5051,5296,5053,5297,5298,5055,5299,5300,5057,5302,5303,5060,5305,5306,5307,5309,5310,5311,5312,5313,5314,5315,5316,5317,5317,5317,5318,5319,5320,5321,5322,5323,5324,5325,5327,5328,5329,5084,5331,5332,5087,5334,5335,5089,5336,5337,5091,5338,5093,5340,5342,5096,5344,5098,5345,5347,5349,5351,5353,5355,5357,5105,5358,5107,5360,5362,5110,5364,5112,5365,5366,5114,5367,5368,5116,5370,5371,5119,5373,5374,5375,5377,5378,5379,5380,5381,5382,5383,5384,5385,5385,5385,5386,5387,5388,5389,5390,5391,5392,5393,5395,5396,5397,5143,5399,5400,5146,5402,5403,5148,5404,5405,5150,5406,5152,5408,5410,5155,5412,5157,5413,5415,5417,5419,5421,5423,5425,5164,5426,5166,5428,5430,5169,5432,5171,5433,5434,5173,5435,5436,5175,5438,5439,5178,5441,5442,5443,5445,5446,5447,5448,5449,5450,5451,5452,5453,5453,5453,5454,5455,5456,5457,5458,5459,5460,5461,5463,5464,5465,5202,5467,5468,5205,5470,5471,5207,5472,5473,5209,5474,5211,5476,5478,5214,5480,5216,5481,5483,5485,5487,5489,5491,5493,5223,5494,5225,5496,5498,5228,5500,5230,5501,5502,5232,5503,5504,5234,5506,5507,5237,5509,5510,5511,5513,5514,5515,5516,5517,5518,5519,5520,5249,5521,5521,5522,5523,5524,5525,5526,5527,5528,5529,5258,5531,5532,5533,5262,5534,5535,5265,5537,5538,5540,5541,5543,5544,5271,5545,5273,5547,5275,5548,5550,5278,5552,5280,5553,5282,5554,5284,5555,5286,5556,5288,5558,5560,5291,5561,5293,5563,5295,5564,5565,5567,5568,5570,5571,5301,5573,5574,5304,5575,5576,5577,5308,5579,5580,5581,5582,5583,5584,5585,5586,5587,5587,5587,5588,5589,5590,5591,5592,5593,5594,5595,5326,5597,5598,5599,5330,5600,5601,5333,5603,5604,5606,5607,5609,5610,5339,5611,5341,5613,5343,5614,5616,5346,5618,5348,5619,5350,5620,5352,5621,5354,5622,5356,5624,5626,5359,5627,5361,5629,5363,5630,5631,5633,5634,5636,5637,5369,5639,5640,5372,5641,5642,5643,5376,5645,5646,5647,5648,5649,5650,5651,5652,5653,5653,5653,5654,5655,5656,5657,5658,5659,5660,5661,5394,5663,5664,5665,5398,5666,5667,5401,5669,5670,5672,5673,5675,5676,5407,5677,5409,5679,5411,5680,5682,5414,5684,5416,5685,5418,5686,5420,5687,5422,5688,5424,5690,5692,5427,5693,5429,5695,5431,5696,5697,5699,5700,5702,5703,5437,5705,5706,5440,5707,5708,5709,5444,5711,5712,5713,5714,5715,5716,5717,5718,5719,5719,5719,5720,5721,5722,5723,5724,5725,5726,5727,5462,5729,5730,5731,5466,5732,5733,5469,5735,5736,5738,5739,5741,5742,5475,5743,5477,5745,5479,5746,5748,5482,5750,5484,5751,5486,5752,5488,5753,5490,5754,5492,5756,5758,5495,5759,5497,5761,5499,5762,5763,5765,5766,5768,5769,5505,5771,5772,5508,5773,5774,5775,5512,5777,5778,5779,5780,5781,5782,5783,5784,5521,5785,5785,5786,5787,5788,5789,5790,5791,5792,5793,5530,5795,5796,5797,5799,5800,5801,5536,5802,5803,5539,5805,5542,5807,5809,5810,5546,5811,5813,5549,5815,5551,5816,5818,5820,5822,5824,5826,5557,5827,5559,5829,5831,5562,5832,5833,5835,5566,5837,5569,5839,5840,5572,5841,5842,5843,5845,5846,5847,5578,5849,5850,5851,5852,5853,5854,5855,5856,5857,5857,5857,5858,5859,5860,5861,5862,5863,5864,5865,5596,5867,5868,5869,5871,5872,5873,5602,5874,5875,5605,5877,5608,5879,5881,5882,5612,5883,5885,5615,5887,5617,5888,5890,5892,5894,5896,5898,5623,5899,5625,5901,5903,5628,5904,5905,5907,5632,5909,5635,5911,5912,5638,5913,5914,5915,5917,5918,5919,5644,5921,5922,5923,5924,5925,5926,5927,5928,5929,5929,5929,5930,5931,5932,5933,5934,5935,5936,5937,5662,5939,5940,5941,5943,5944,5945,5668,5946,5947,5671,5949,5674,5951,5953,5954,5678,5955,5957,5681,5959,5683,5960,5962,5964,5966,5968,5970,5689,5971,5691,5973,5975,5694,5976,5977,5979,5698,5981,5701,5983,5984,5704,5985,5986,5987,5989,5990,5991,5710,5993,5994,5995,5996,5997,5998,5999,6000,6001,6001,6001,6002,6003,6004,6005,6006,6007,6008,6009,5728,6011,6012,6013,6015,6016,6017,5734,6018,6019,5737,6021,5740,6023,6025,6026,5744,6027,6029,5747,6031,5749,6032,6034,6036,6038,6040,6042,5755,6043,5757,6045,6047,5760,6048,6049,6051,5764,6053,5767,6055,6056,5770,6057,6058,6059,6061,6062,6063,5776,6065,6066,6067,6068,6069,6070,6071,6072,5785,6073,6073,6074,6075,6076,6077,6078,6079,6080,6081,5794,6083,6084,6085,5798,6087,6088,6090,6091,5804,6093,5806,6095,5808,6097,6099,5812,6101,5814,6102,6104,5817,5819,6107,5821,6108,5823,5825,6111,6113,5828,6114,5830,6116,6118,5834,6120,5836,6122,5838,6124,6125,6127,6128,5844,6130,6131,6132,5848,6134,6135,6136,6137,6138,6139,6140,6141,6142,6142,6142,6143,6144,6145,6146,6147,6148,6149,6150,5866,6152,6153,6154,5870,6156,6157,6159,6160,5876,6162,5878,6164,5880,6166,6168,5884,6170,5886,6171,6173,5889,5891,6176,5893,6177,5895,5897,6180,6182,5900,6183,5902,6185,6187,5906,6189,5908,6191,5910,6193,6194,6196,6197,5916,6199,6200,6201,5920,6203,6204,6205,6206,6207,6208,6209,6210,6211,6211,6211,6212,6213,6214,6215,6216,6217,6218,6219,5938,6221,6222,6223,5942,6225,6226,6228,6229,5948,6231,5950,6233,5952,6235,6237,5956,6239,5958,6240,6242,5961,5963,6245,5965,6246,5967,5969,6249,6251,5972,6252,5974,6254,6256,5978,6258,5980,6260,5982,6262,6263,6265,6266,5988,6268,6269,6270,5992,6272,6273,6274,6275,6276,6277,6278,6279,6280,6280,6280,6281,6282,6283,6284,6285,6286,6287,6288,6010,6290,6291,6292,6014,6294,6295,6297,6298,6020,6300,6022,6302,6024,6304,6306,6028,6308,6030,6309,6311,6033,6035,6314,6037,6315,6039,6041,6318,6320,6044,6321,6046,6323,6325,6050,6327,6052,6329,6054,6331,6332,6334,6335,6060,6337,6338,6339,6064,6341,6342,6343,6344,6345,6346,6347,6348,6073,6349,6349,6350,6351,6352,6353,6354,6355,6356,6357,6082,6359,6360,6361,6086,6363,6364,6089,6366,6092,6368,6369,6094,6370,6096,6372,6098,6374,6100,6375,6377,6103,6379,6105,6380,6106,6381,6383,6385,6109,6386,6110,6387,6112,6389,6391,6115,6392,6117,6394,6119,6396,6121,6397,6398,6123,6400,6126,6402,6403,6129,6405,6406,6407,6133,6409,6410,6411,6412,6413,6414,6415,6416,6417,6417,6417,6418,6419,6420,6421,6422,6423,6424,6425,6151,6427,6428,6429,6155,6431,6432,6158,6434,6161,6436,6437,6163,6438,6165,6440,6167,6442,6169,6443,6445,6172,6447,6174,6448,6175,6449,6451,6453,6178,6454,6179,6455,6181,6457,6459,6184,6460,6186,6462,6188,6464,6190,6465,6466,6192,6468,6195,6470,6471,6198,6473,6474,6475,6202,6477,6478,6479,6480,6481,6482,6483,6484,6485,6485,6485,6486,6487,6488,6489,6490,6491,6492,6493,6220,6495,6496,6497,6224,6499,6500,6227,6502,6230,6504,6505,6232,6506,6234,6508,6236,6510,6238,6511,6513,6241,6515,6243,6516,6244,6517,6519,6521,6247,6522,6248,6523,6250,6525,6527,6253,6528,6255,6530,6257,6532,6259,6533,6534,6261,6536,6264,6538,6539,6267,6541,6542,6543,6271,6545,6546,6547,6548,6549,6550,6551,6552,6553,6553,6553,6554,6555,6556,6557,6558,6559,6560,6561,6289,6563,6564,6565,6293,6567,6568,6296,6570,6299,6572,6573,6301,6574,6303,6576,6305,6578,6307,6579,6581,6310,6583,6312,6584,6313,6585,6587,6589,6316,6590,6317,6591,6319,6593,6595,6322,6596,6324,6598,6326,6600,6328,6601,6602,6330,6604,6333,6606,6607,6336,6609,6610,6611,6340,6613,6614,6615,6616,6617,6618,6619,6620,6349,6621,6621,6622,6623,6624,6625,6626,6627,6628,6629,6358,6631,6632,6633,6362,6635,6636,6365,6638,6639,6367,6640,6641,6643,6644,6371,6645,6373,6647,6649,6376,6651,6378,6652,6654,6656,6382,6384,6660,6662,6664,6388,6665,6390,6667,6669,6393,6671,6395,6672,6673,6675,6676,6399,6677,6678,6401,6680,6681,6404,6683,6684,6685,6408,6687,6688,6689,6690,6691,6692,6693,6694,6695,6695,6695,6696,6697,6698,6699,6700,6701,6702,6703,6426,6705,6706,6707,6430,6709,6710,6433,6712,6713,6435,6714,6715,6717,6718,6439,6719,6441,6721,6723,6444,6725,6446,6726,6728,6730,6450,6452,6734,6736,6738,6456,6739,6458,6741,6743,6461,6745,6463,6746,6747,6749,6750,6467,6751,6752,6469,6754,6755,6472,6757,6758,6759,6476,6761,6762,6763,6764,6765,6766,6767,6768,6769,6769,6769,6770,6771,6772,6773,6774,6775,6776,6777,6494,6779,6780,6781,6498,6783,6784,6501,6786,6787,6503,6788,6789,6791,6792,6507,6793,6509,6795,6797,6512,6799,6514,6800,6802,6804,6518,6520,6808,6810,6812,6524,6813,6526,6815,6817,6529,6819,6531,6820,6821,6823,6824,6535,6825,6826,6537,6828,6829,6540,6831,6832,6833,6544,6835,6836,6837,6838,6839,6840,6841,6842,6843,6843,6843,6844,6845,6846,6847,6848,6849,6850,6851,6562,6853,6854,6855,6566,6857,6858,6569,6860,6861,6571,6862,6863,6865,6866,6575,6867,6577,6869,6871,6580,6873,6582,6874,6876,6878,6586,6588,6882,6884,6886,6592,6887,6594,6889,6891,6597,6893,6599,6894,6895,6897,6898,6603,6899,6900,6605,6902,6903,6608,6905,6906,6907,6612,6909,6910,6911,6912,6913,6914,6915,6916,6621,6917,6917,6918,6919,6920,6921,6922,6923,6924,6925,6630,6927,6928,6929,6634,6931,6932,6637,6934,6935,6937,6938,6642,6940,6942,6943,6646,6944,6648,6946,6650,6947,6949,6653,6951,6655,6952,6657,6953,6658,6954,6659,6955,6661,6956,6663,6958,6960,6666,6961,6668,6963,6670,6964,6965,6967,6674,6969,6970,6972,6973,6679,6975,6976,6682,6978,6979,6980,6686,6982,6983,6984,6985,6986,6987,6988,6989,6990,6990,6990,6991,6992,6993,6994,6995,6996,6997,6998,6704,7000,7001,7002,6708,7004,7005,6711,7007,7008,7010,7011,6716,7013,7015,7016,6720,7017,6722,7019,6724,7020,7022,6727,7024,6729,7025,6731,7026,6732,7027,6733,7028,6735,7029,6737,7031,7033,6740,7034,6742,7036,6744,7037,7038,7040,6748,7042,7043,7045,7046,6753,7048,7049,6756,7051,7052,7053,6760,7055,7056,7057,7058,7059,7060,7061,7062,7063,7063,7063,7064,7065,7066,7067,7068,7069,7070,7071,6778,7073,7074,7075,6782,7077,7078,6785,7080,7081,7083,7084,6790,7086,7088,7089,6794,7090,6796,7092,6798,7093,7095,6801,7097,6803,7098,6805,7099,6806,7100,6807,7101,6809,7102,6811,7104,7106,6814,7107,6816,7109,6818,7110,7111,7113,6822,7115,7116,7118,7119,6827,7121,7122,6830,7124,7125,7126,6834,7128,7129,7130,7131,7132,7133,7134,7135,7136,7136,7136,7137,7138,7139,7140,7141,7142,7143,7144,6852,7146,7147,7148,6856,7150,7151,6859,7153,7154,7156,7157,6864,7159,7161,7162,6868,7163,6870,7165,6872,7166,7168,6875,7170,6877,7171,6879,7172,6880,7173,6881,7174,6883,7175,6885,7177,7179,6888,7180,6890,7182,6892,7183,7184,7186,6896,7188,7189,7191,7192,6901,7194,7195,6904,7197,7198,7199,6908,7201,7202,7203,7204,7205,7206,7207,7208,6917,7209,7209,7210,7211,7212,7213,7214,7215,7216,7217,6926,7219,7220,7221,6930,7223,7224,7225,6933,7226,7227,6936,7229,6939,7231,6941,7233,7235,7236,6945,7237,7239,6948,7241,6950,7242,7244,7246,7248,7250,7252,7254,6957,7255,6959,7257,7259,6962,7260,7261,7263,6966,7265,6968,7267,6971,7269,7270,6974,7271,7272,7273,6977,7275,7276,7277,6981,7279,7280,7281,7282,7283,7284,7285,7286,7287,7287,7287,7288,7289,7290,7291,7292,7293,7294,7295,6999,7297,7298,7299,7003,7301,7302,7303,7006,7304,7305,7009,7307,7012,7309,7014,7311,7313,7314,7018,7315,7317,7021,7319,7023,7320,7322,7324,7326,7328,7330,7332,7030,7333,7032,7335,7337,7035,7338,7339,7341,7039,7343,7041,7345,7044,7347,7348,7047,7349,7350,7351,7050,7353,7354,7355,7054,7357,7358,7359,7360,7361,7362,7363,7364,7365,7365,7365,7366,7367,7368,7369,7370,7371,7372,7373,7072,7375,7376,7377,7076,7379,7380,7381,7079,7382,7383,7082,7385,7085,7387,7087,7389,7391,7392,7091,7393,7395,7094,7397,7096,7398,7400,7402,7404,7406,7408,7410,7103,7411,7105,7413,7415,7108,7416,7417,7419,7112,7421,7114,7423,7117,7425,7426,7120,7427,7428,7429,7123,7431,7432,7433,7127,7435,7436,7437,7438,7439,7440,7441,7442,7443,7443,7443,7444,7445,7446,7447,7448,7449,7450,7451,7145,7453,7454,7455,7149,7457,7458,7459,7152,7460,7461,7155,7463,7158,7465,7160,7467,7469,7470,7164,7471,7473,7167,7475,7169,7476,7478,7480,7482,7484,7486,7488,7176,7489,7178,7491,7493,7181,7494,7495,7497,7185,7499,7187,7501,7190,7503,7504,7193,7505,7506,7507,7196,7509,7510,7511,7200,7513,7514,7515,7516,7517,7518,7519,7520,7209,7521,7521,7522,7523,7524,7525,7526,7527,7528,7529,7530,7218,7531,7532,7533,7534,7222,7535,7536,7537,7539,7540,7228,7542,7543,7230,7544,7232,7546,7234,7548,7550,7238,7552,7240,7553,7555,7243,7557,7245,7558,7247,7559,7249,7560,7251,7561,7253,7563,7565,7256,7566,7258,7568,7570,7262,7572,7264,7574,7266,7575,7576,7268,7578,7579,7581,7582,7583,7274,7584,7585,7586,7587,7278,7588,7589,7590,7591,7592,7593,7594,7595,7596,7597,7597,7597,7598,7599,7600,7601,7602,7603,7604,7605,7606,7296,7607,7608,7609,7610,7300,7611,7612,7613,7615,7616,7306,7618,7619,7308,7620,7310,7622,7312,7624,7626,7316,7628,7318,7629,7631,7321,7633,7323,7634,7325,7635,7327,7636,7329,7637,7331,7639,7641,7334,7642,7336,7644,7646,7340,7648,7342,7650,7344,7651,7652,7346,7654,7655,7657,7658,7659,7352,7660,7661,7662,7663,7356,7664,7665,7666,7667,7668,7669,7670,7671,7672,7673,7673,7673,7674,7675,7676,7677,7678,7679,7680,7681,7682,7374,7683,7684,7685,7686,7378,7687,7688,7689,7691,7692,7384,7694,7695,7386,7696,7388,7698,7390,7700,7702,7394,7704,7396,7705,7707,7399,7709,7401,7710,7403,7711,7405,7712,7407,7713,7409,7715,7717,7412,7718,7414,7720,7722,7418,7724,7420,7726,7422,7727,7728,7424,7730,7731,7733,7734,7735,7430,7736,7737,7738,7739,7434,7740,7741,7742,7743,7744,7745,7746,7747,7748,7749,7749,7749,7750,7751,7752,7753,7754,7755,7756,7757,7758,7452,7759,7760,7761,7762,7456,7763,7764,7765,7767,7768,7462,7770,7771,7464,7772,7466,7774,7468,7776,7778,7472,7780,7474,7781,7783,7477,7785,7479,7786,7481,7787,7483,7788,7485,7789,7487,7791,7793,7490,7794,7492,7796,7798,7496,7800,7498,7802,7500,7803,7804,7502,7806,7807,7809,7810,7811,7508,7812,7813,7814,7815,7512,7816,7817,7818,7819,7820,7821,7822,7823,7824,7521,7825,7825,7826,7827,7828,7829,7830,7831,7832,7833,7834,7836,7837,7838,7839,7841,7842,7843,7538,7845,7541,7847,7848,7850,7851,7545,7852,7853,7547,7854,7549,7856,7551,7857,7859,7554,7861,7556,7862,7864,7866,7868,7870,7872,7562,7873,7564,7875,7877,7567,7878,7569,7880,7571,7881,7882,7573,7883,7884,7886,7887,7577,7889,7580,7891,7892,7893,7895,7896,7897,7898,7900,7901,7902,7903,7904,7905,7906,7907,7908,7909,7909,7909,7910,7911,7912,7913,7914,7915,7916,7917,7918,7920,7921,7922,7923,7925,7926,7927,7614,7929,7617,7931,7932,7934,7935,7621,7936,7937,7623,7938,7625,7940,7627,7941,7943,7630,7945,7632,7946,7948,7950,7952,7954,7956,7638,7957,7640,7959,7961,7643,7962,7645,7964,7647,7965,7966,7649,7967,7968,7970,7971,7653,7973,7656,7975,7976,7977,7979,7980,7981,7982,7984,7985,7986,7987,7988,7989,7990,7991,7992,7993,7993,7993,7994,7995,7996,7997,7998,7999,8000,8001,8002,8004,8005,8006,8007,8009,8010,8011,7690,8013,7693,8015,8016,8018,8019,7697,8020,8021,7699,8022,7701,8024,7703,8025,8027,7706,8029,7708,8030,8032,8034,8036,8038,8040,7714,8041,7716,8043,8045,7719,8046,7721,8048,7723,8049,8050,7725,8051,8052,8054,8055,7729,8057,7732,8059,8060,8061,8063,8064,8065,8066,8068,8069,8070,8071,8072,8073,8074,8075,8076,8077,8077,8077,8078,8079,8080,8081,8082,8083,8084,8085,8086,8088,8089,8090,8091,8093,8094,8095,7766,8097,7769,8099,8100,8102,8103,7773,8104,8105,7775,8106,7777,8108,7779,8109,8111,7782,8113,7784,8114,8116,8118,8120,8122,8124,7790,8125,7792,8127,8129,7795,8130,7797,8132,7799,8133,8134,7801,8135,8136,8138,8139,7805,8141,7808,8143,8144,8145,8147,8148,8149,8150,8152,8153,8154,8155,8156,8157,8158,8159,8160,7825,8161,8161,8162,8163,8164,8165,8166,8167,8168,8169,8170,7835,8172,8173,8174,7840,8176,8177,7844,8179,8180,7846,8181,8182,7849,8184,8186,8187,8189,7855,8191,8193,7858,8195,7860,8196,8198,7863,7865,7867,7869,7871,8205,8207,7874,8208,7876,8210,8212,7879,8214,8216,8217,8219,7885,8221,8222,7888,8223,8224,7890,8226,8227,7894,8229,8230,8231,7899,8233,8234,8235,8236,8237,8238,8239,8240,8241,8242,8242,8242,8243,8244,8245,8246,8247,8248,8249,8250,8251,7919,8253,8254,8255,7924,8257,8258,7928,8260,8261,7930,8262,8263,7933,8265,8267,8268,8270,7939,8272,8274,7942,8276,7944,8277,8279,7947,7949,7951,7953,7955,8286,8288,7958,8289,7960,8291,8293,7963,8295,8297,8298,8300,7969,8302,8303,7972,8304,8305,7974,8307,8308,7978,8310,8311,8312,7983,8314,8315,8316,8317,8318,8319,8320,8321,8322,8323,8323,8323,8324,8325,8326,8327,8328,8329,8330,8331,8332,8003,8334,8335,8336,8008,8338,8339,8012,8341,8342,8014,8343,8344,8017,8346,8348,8349,8351,8023,8353,8355,8026,8357,8028,8358,8360,8031,8033,8035,8037,8039,8367,8369,8042,8370,8044,8372,8374,8047,8376,8378,8379,8381,8053,8383,8384,8056,8385,8386,8058,8388,8389,8062,8391,8392,8393,8067,8395,8396,8397,8398,8399,8400,8401,8402,8403,8404,8404,8404,8405,8406,8407,8408,8409,8410,8411,8412,8413,8087,8415,8416,8417,8092,8419,8420,8096,8422,8423,8098,8424,8425,8101,8427,8429,8430,8432,8107,8434,8436,8110,8438,8112,8439,8441,8115,8117,8119,8121,8123,8448,8450,8126,8451,8128,8453,8455,8131,8457,8459,8460,8462,8137,8464,8465,8140,8466,8467,8142,8469,8470,8146,8472,8473,8474,8151,8476,8477,8478,8479,8480,8481,8482,8483,8484,8161,8485,8485,8486,8487,8488,8489,8490,8491,8492,8493,8494,8171,8496,8497,8498,8175,8500,8501,8178,8503,8504,8506,8507,8183,8509,8185,8511,8188,8513,8190,8514,8192,8516,8194,8517,8519,8197,8521,8199,8522,8200,8523,8201,8524,8202,8525,8203,8526,8204,8527,8206,8529,8531,8209,8532,8211,8534,8213,8535,8215,8537,8218,8539,8220,8541,8542,8544,8545,8225,8547,8548,8228,8550,8551,8552,8232,8554,8555,8556,8557,8558,8559,8560,8561,8562,8563,8563,8563,8564,8565,8566,8567,8568,8569,8570,8571,8572,8252,8574,8575,8576,8256,8578,8579,8259,8581,8582,8584,8585,8264,8587,8266,8589,8269,8591,8271,8592,8273,8594,8275,8595,8597,8278,8599,8280,8600,8281,8601,8282,8602,8283,8603,8284,8604,8285,8605,8287,8607,8609,8290,8610,8292,8612,8294,8613,8296,8615,8299,8617,8301,8619,8620,8622,8623,8306,8625,8626,8309,8628,8629,8630,8313,8632,8633,8634,8635,8636,8637,8638,8639,8640,8641,8641,8641,8642,8643,8644,8645,8646,8647,8648,8649,8650,8333,8652,8653,8654,8337,8656,8657,8340,8659,8660,8662,8663,8345,8665,8347,8667,8350,8669,8352,8670,8354,8672,8356,8673,8675,8359,8677,8361,8678,8362,8679,8363,8680,8364,8681,8365,8682,8366,8683,8368,8685,8687,8371,8688,8373,8690,8375,8691,8377,8693,8380,8695,8382,8697,8698,8700,8701,8387,8703,8704,8390,8706,8707,8708,8394,8710,8711,8712,8713,8714,8715,8716,8717,8718,8719,8719,8719,8720,8721,8722,8723,8724,8725,8726,8727,8728,8414,8730,8731,8732,8418,8734,8735,8421,8737,8738,8740,8741,8426,8743,8428,8745,8431,8747,8433,8748,8435,8750,8437,8751,8753,8440,8755,8442,8756,8443,8757,8444,8758,8445,8759,8446,8760,8447,8761,8449,8763,8765,8452,8766,8454,8768,8456,8769,8458,8771,8461,8773,8463,8775,8776,8778,8779,8468,8781,8782,8471,8784,8785,8786,8475,8788,8789,8790,8791,8792,8793,8794,8795,8796,8485,8797,8797,8798,8799,8800,8801,8802,8803,8804,8805,8806,8495,8808,8809,8810,8499,8812,8813,8502,8815,8816,8505,8818,8508,8820,8510,8822,8512,8824,8826,8827,8515,8828,8830,8518,8832,8520,8833,8835,8837,8839,8841,8843,8845,8847,8528,8848,8530,8850,8852,8533,8853,8854,8856,8536,8858,8538,8860,8540,8862,8543,8864,8865,8546,8867,8868,8549,8870,8871,8872,8553,8874,8875,8876,8877,8878,8879,8880,8881,8882,8883,8883,8883,8884,8885,8886,8887,8888,8889,8890,8891,8892,8573,8894,8895,8896,8577,8898,8899,8580,8901,8902,8583,8904,8586,8906,8588,8908,8590,8910,8912,8913,8593,8914,8916,8596,8918,8598,8919,8921,8923,8925,8927,8929,8931,8933,8606,8934,8608,8936,8938,8611,8939,8940,8942,8614,8944,8616,8946,8618,8948,8621,8950,8951,8624,8953,8954,8627,8956,8957,8958,8631,8960,8961,8962,8963,8964,8965,8966,8967,8968,8969,8969,8969,8970,8971,8972,8973,8974,8975,8976,8977,8978,8651,8980,8981,8982,8655,8984,8985,8658,8987,8988,8661,8990,8664,8992,8666,8994,8668,8996,8998,8999,8671,9000,9002,8674,9004,8676,9005,9007,9009,9011,9013,9015,9017,9019,8684,9020,8686,9022,9024,8689,9025,9026,9028,8692,9030,8694,9032,8696,9034,8699,9036,9037,8702,9039,9040,8705,9042,9043,9044,8709,9046,9047,9048,9049,9050,9051,9052,9053,9054,9055,9055,9055,9056,9057,9058,9059,9060,9061,9062,9063,9064,8729,9066,9067,9068,8733,9070,9071,8736,9073,9074,8739,9076,8742,9078,8744,9080,8746,9082,9084,9085,8749,9086,9088,8752,9090,8754,9091,9093,9095,9097,9099,9101,9103,9105,8762,9106,8764,9108,9110,8767,9111,9112,9114,8770,9116,8772,9118,8774,9120,8777,9122,9123,8780,9125,9126,8783,9128,9129,9130,8787,9132,9133,9134,9135,9136,9137,9138,9139,9140,8797,9141,9141,9142,9143,9144,9145,9146,9147,9148,9149,9150,8807,9152,9153,9154,8811,9156,9157,9158,8814,9159,9160,8817,9162,9163,8819,9164,9165,8821,9166,9167,8823,9168,8825,9170,9172,8829,9174,8831,9175,9177,8834,9179,8836,9180,8838,9181,8840,9182,8842,9183,8844,9184,8846,9186,9188,8849,9189,8851,9191,9193,8855,9195,8857,9196,9197,8859,9198,9199,8861,9200,9201,8863,9203,9204,8866,9205,9206,9207,8869,9209,9210,9211,8873,9213,9214,9215,9216,9217,9218,9219,9220,9221,9222,9222,9222,9223,9224,9225,9226,9227,9228,9229,9230,9231,8893,9233,9234,9235,8897,9237,9238,9239,8900,9240,9241,8903,9243,9244,8905,9245,9246,8907,9247,9248,8909,9249,8911,9251,9253,8915,9255,8917,9256,9258,8920,9260,8922,9261,8924,9262,8926,9263,8928,9264,8930,9265,8932,9267,9269,8935,9270,8937,9272,9274,8941,9276,8943,9277,9278,8945,9279,9280,8947,9281,9282,8949,9284,9285,8952,9286,9287,9288,8955,9290,9291,9292,8959,9294,9295,9296,9297,9298,9299,9300,9301,9302,9303,9303,9303,9304,9305,9306,9307,9308,9309,9310,9311,9312,8979,9314,9315,9316,8983,9318,9319,9320,8986,9321,9322,8989,9324,9325,8991,9326,9327,8993,9328,9329,8995,9330,8997,9332,9334,9001,9336,9003,9337,9339,9006,9341,9008,9342,9010,9343,9012,9344,9014,9345,9016,9346,9018,9348,9350,9021,9351,9023,9353,9355,9027,9357,9029,9358,9359,9031,9360,9361,9033,9362,9363,9035,9365,9366,9038,9367,9368,9369,9041,9371,9372,9373,9045,9375,9376,9377,9378,9379,9380,9381,9382,9383,9384,9384,9384,9385,9386,9387,9388,9389,9390,9391,9392,9393,9065,9395,9396,9397,9069,9399,9400,9401,9072,9402,9403,9075,9405,9406,9077,9407,9408,9079,9409,9410,9081,9411,9083,9413,9415,9087,9417,9089,9418,9420,9092,9422,9094,9423,9096,9424,9098,9425,9100,9426,9102,9427,9104,9429,9431,9107,9432,9109,9434,9436,9113,9438,9115,9439,9440,9117,9441,9442,9119,9443,9444,9121,9446,9447,9124,9448,9449,9450,9127,9452,9453,9454,9131,9456,9457,9458,9459,9460,9461,9462,9463,9464,9141,9465,9465,9466,9467,9468,9469,9470,9471,9472,9473,9474,9151,9476,9477,9478,9155,9480,9481,9482,9484,9485,9161,9487,9488,9490,9491,9493,9494,9496,9497,9169,9498,9171,9500,9173,9501,9503,9176,9505,9178,9506,9508,9510,9512,9514,9516,9518,9185,9519,9187,9521,9523,9190,9524,9192,9526,9194,9527,9528,9530,9531,9533,9534,9536,9537,9202,9539,9540,9542,9543,9544,9208,9546,9547,9548,9212,9550,9551,9552,9553,9554,9555,9556,9557,9558,9559,9559,9559,9560,9561,9562,9563,9564,9565,9566,9567,9568,9232,9570,9571,9572,9236,9574,9575,9576,9578,9579,9242,9581,9582,9584,9585,9587,9588,9590,9591,9250,9592,9252,9594,9254,9595,9597,9257,9599,9259,9600,9602,9604,9606,9608,9610,9612,9266,9613,9268,9615,9617,9271,9618,9273,9620,9275,9621,9622,9624,9625,9627,9628,9630,9631,9283,9633,9634,9636,9637,9638,9289,9640,9641,9642,9293,9644,9645,9646,9647,9648,9649,9650,9651,9652,9653,9653,9653,9654,9655,9656,9657,9658,9659,9660,9661,9662,9313,9664,9665,9666,9317,9668,9669,9670,9672,9673,9323,9675,9676,9678,9679,9681,9682,9684,9685,9331,9686,9333,9688,9335,9689,9691,9338,9693,9340,9694,9696,9698,9700,9702,9704,9706,9347,9707,9349,9709,9711,9352,9712,9354,9714,9356,9715,9716,9718,9719,9721,9722,9724,9725,9364,9727,9728,9730,9731,9732,9370,9734,9735,9736,9374,9738,9739,9740,9741,9742,9743,9744,9745,9746,9747,9747,9747,9748,9749,9750,9751,9752,9753,9754,9755,9756,9394,9758,9759,9760,9398,9762,9763,9764,9766,9767,9404,9769,9770,9772,9773,9775,9776,9778,9779,9412,9780,9414,9782,9416,9783,9785,9419,9787,9421,9788,9790,9792,9794,9796,9798,9800,9428,9801,9430,9803,9805,9433,9806,9435,9808,9437,9809,9810,9812,9813,9815,9816,9818,9819,9445,9821,9822,9824,9825,9826,9451,9828,9829,9830,9455,9832,9833,9834,9835,9836,9837,9838,9839,9840,9465,9841,9841,9842,9843,9844,9845,9846,9847,9848,9849,9850,9475,9852,9853,9854,9855,9479,9856,9857,9858,9483,9860,9861,9486,9862,9863,9489,9865,9492,9867,9495,9869,9871,9872,9499,9873,9875,9502,9877,9504,9878,9880,9507,9509,9511,9884,9513,9515,9517,9888,9890,9520,9891,9522,9893,9895,9525,9896,9897,9899,9529,9901,9532,9903,9535,9905,9906,9538,9907,9908,9541,9910,9911,9912,9545,9913,9914,9915,9916,9549,9918,9919,9920,9921,9922,9923,9924,9925,9926,9927,9927,9927,9928,9929,9930,9931,9932,9933,9934,9935,9936,9569,9938,9939,9940,9941,9573,9942,9943,9944,9577,9946,9947,9580,9948,9949,9583,9951,9586,9953,9589,9955,9957,9958,9593,9959,9961,9596,9963,9598,9964,9966,9601,9603,9605,9970,9607,9609,9611,9974,9976,9614,9977,9616,9979,9981,9619,9982,9983,9985,9623,9987,9626,9989,9629,9991,9992,9632,9993,9994,9635,9996,9997,9998,9639,9999,10000,10001,10002,9643,10004,10005,10006,10007,10008,10009,10010,10011,10012,10013,10013,10013,10014,10015,10016,10017,10018,10019,10020,10021,10022,9663,10024,10025,10026,10027,9667,10028,10029,10030,9671,10032,10033,9674,10034,10035,9677,10037,9680,10039,9683,10041,10043,10044,9687,10045,10047,9690,10049,9692,10050,10052,9695,9697,9699,10056,9701,9703,9705,10060,10062,9708,10063,9710,10065,10067,9713,10068,10069,10071,9717,10073,9720,10075,9723,10077,10078,9726,10079,10080,9729,10082,10083,10084,9733,10085,10086,10087,10088,9737,10090,10091,10092,10093,10094,10095,10096,10097,10098,10099,10099,10099,10100,10101,10102,10103,10104,10105,10106,10107,10108,9757,10110,10111,10112,10113,9761,10114,10115,10116,9765,10118,10119,9768,10120,10121,9771,10123,9774,10125,9777,10127,10129,10130,9781,10131,10133,9784,10135,9786,10136,10138,9789,9791,9793,10142,9795,9797,9799,10146,10148,9802,10149,9804,10151,10153,9807,10154,10155,10157,9811,10159,9814,10161,9817,10163,10164,9820,10165,10166,9823,10168,10169,10170,9827,10171,10172,10173,10174,9831,10176,10177,10178,10179,10180,10181,10182,10183,10184,9841,10185,10185,10186,10187,10188,10189,10190,10191,10192,10193,10194,9851,10196,10197,10198,10199,10201,10202,10203,9859,10205,10206,10208,10209,9864,10211,9866,10213,9868,10215,9870,10217,10219,9874,10221,9876,10222,10224,9879,10226,9881,10227,9882,10228,9883,10229,10231,9885,10232,9886,10233,9887,10234,9889,10236,10238,9892,10239,9894,10241,10243,9898,10245,9900,10247,9902,10249,9904,10251,10252,10254,10255,9909,10257,10258,10259,10261,10262,10263,10264,9917,10266,10267,10268,10269,10270,10271,10272,10273,10274,10275,10275,10275,10276,10277,10278,10279,10280,10281,10282,10283,10284,9937,10286,10287,10288,10289,10291,10292,10293,9945,10295,10296,10298,10299,9950,10301,9952,10303,9954,10305,9956,10307,10309,9960,10311,9962,10312,10314,9965,10316,9967,10317,9968,10318,9969,10319,10321,9971,10322,9972,10323,9973,10324,9975,10326,10328,9978,10329,9980,10331,10333,9984,10335,9986,10337,9988,10339,9990,10341,10342,10344,10345,9995,10347,10348,10349,10351,10352,10353,10354,10003,10356,10357,10358,10359,10360,10361,10362,10363,10364,10365,10365,10365,10366,10367,10368,10369,10370,10371,10372,10373,10374,10023,10376,10377,10378,10379,10381,10382,10383,10031,10385,10386,10388,10389,10036,10391,10038,10393,10040,10395,10042,10397,10399,10046,10401,10048,10402,10404,10051,10406,10053,10407,10054,10408,10055,10409,10411,10057,10412,10058,10413,10059,10414,10061,10416,10418,10064,10419,10066,10421,10423,10070,10425,10072,10427,10074,10429,10076,10431,10432,10434,10435,10081,10437,10438,10439,10441,10442,10443,10444,10089,10446,10447,10448,10449,10450,10451,10452,10453,10454,10455,10455,10455,10456,10457,10458,10459,10460,10461,10462,10463,10464,10109,10466,10467,10468,10469,10471,10472,10473,10117,10475,10476,10478,10479,10122,10481,10124,10483,10126,10485,10128,10487,10489,10132,10491,10134,10492,10494,10137,10496,10139,10497,10140,10498,10141,10499,10501,10143,10502,10144,10503,10145,10504,10147,10506,10508,10150,10509,10152,10511,10513,10156,10515,10158,10517,10160,10519,10162,10521,10522,10524,10525,10167,10527,10528,10529,10531,10532,10533,10534,10175,10536,10537,10538,10539,10540,10541,10542,10543,10544,10185,10545,10545,10546,10547,10548,10549,10550,10551,10552,10553,10554,10195,10556,10557,10558,10559,10200,10561,10562,10204,10564,10565,10207,10567,10210,10569,10570,10212,10571,10572,10214,10573,10216,10575,10218,10577,10220,10578,10580,10223,10582,10225,10583,10585,10587,10589,10230,10592,10594,10596,10598,10235,10599,10237,10601,10603,10240,10604,10242,10606,10244,10608,10246,10609,10610,10248,10611,10612,10250,10614,10253,10616,10617,10256,10619,10620,10260,10622,10623,10624,10625,10265,10627,10628,10629,10630,10631,10632,10633,10634,10635,10636,10636,10636,10637,10638,10639,10640,10641,10642,10643,10644,10645,10285,10647,10648,10649,10650,10290,10652,10653,10294,10655,10656,10297,10658,10300,10660,10661,10302,10662,10663,10304,10664,10306,10666,10308,10668,10310,10669,10671,10313,10673,10315,10674,10676,10678,10680,10320,10683,10685,10687,10689,10325,10690,10327,10692,10694,10330,10695,10332,10697,10334,10699,10336,10700,10701,10338,10702,10703,10340,10705,10343,10707,10708,10346,10710,10711,10350,10713,10714,10715,10716,10355,10718,10719,10720,10721,10722,10723,10724,10725,10726,10727,10727,10727,10728,10729,10730,10731,10732,10733,10734,10735,10736,10375,10738,10739,10740,10741,10380,10743,10744,10384,10746,10747,10387,10749,10390,10751,10752,10392,10753,10754,10394,10755,10396,10757,10398,10759,10400,10760,10762,10403,10764,10405,10765,10767,10769,10771,10410,10774,10776,10778,10780,10415,10781,10417,10783,10785,10420,10786,10422,10788,10424,10790,10426,10791,10792,10428,10793,10794,10430,10796,10433,10798,10799,10436,10801,10802,10440,10804,10805,10806,10807,10445,10809,10810,10811,10812,10813,10814,10815,10816,10817,10818,10818,10818,10819,10820,10821,10822,10823,10824,10825,10826,10827,10465,10829,10830,10831,10832,10470,10834,10835,10474,10837,10838,10477,10840,10480,10842,10843,10482,10844,10845,10484,10846,10486,10848,10488,10850,10490,10851,10853,10493,10855,10495,10856,10858,10860,10862,10500,10865,10867,10869,10871,10505,10872,10507,10874,10876,10510,10877,10512,10879,10514,10881,10516,10882,10883,10518,10884,10885,10520,10887,10523,10889,10890,10526,10892,10893,10530,10895,10896,10897,10898,10535,10900,10901,10902,10903,10904,10905,10906,10907,10908,10545];\r\nvar count_per_radius = [1,8,16,20,24,40,36,48,56,56,68,64,80,92,88,96,96,116,120,120,124,144,136,140,152,168,176,164,168,192,188,208,200,208,228,208,232,228,256,248,236,272,264,288,276,272,296,292,312,304,336,324,312,344,324,376,344,360,364,368];\r\nvar radius_offset = [0,1,9,25,45,69,109,145,193,249,305,373,437,517,609,697,793,889,1005,1125,1245,1369,1513,1649,1789,1941,2109,2285,2449,2617,2809,2997,3205,3405,3613,3841,4049,4281,4509,4765,5013,5249,5521,5785,6073,6349,6621,6917,7209,7521,7825,8161,8485,8797,9141,9465,9841,10185,10545,10909];\r\n// End of generated.\r\n\r\nvar connected = new Array(towards_center.length).fill(true);\r\n"
  },
  {
    "path": "gesture/index.html",
    "content": "<!DOCTYPE html>\r\n<html>\r\n<head>\r\n  <title>Depth Capture Based Hand Interaction Demo</title>\r\n  <script src=\"../libs/ammo.js/ammo.js\"></script>\r\n  <script src=\"../libs/gl-matrix.js\"></script>\r\n  <script src=\"../libs/picogl.js/picogl.js\"></script>\r\n  <script src=\"../libs/picogl.js/utils.js\"></script>\r\n  <script src=\"../depth-camera.js\"></script>\r\n  <script src=\"depth_and_segments.js\"></script>\r\n</head>\r\n<style>\r\nhtml {\r\n  overflow: hidden;\r\n}\r\nbody {\r\n  display: flex;\r\n  flex-direction: column;\r\n  font-family: 'Roboto', 'Noto', sans-serif;\r\n  line-height: 1.5;\r\n  background-color: #fbfbfb;\r\n  margin: 0;\r\n  text-align:center;\r\n}\r\n.info {\r\n  position: absolute;\r\n  top: 0px; width: 100%;\r\n  padding: 5px;\r\n  color: gray;\r\n}\r\n#timer {\r\n  position: absolute;\r\n  bottom: 10px;\r\n  left: 10px;\r\n  color: white;\r\n}\r\n#rotate-control {\r\n  position: absolute;\r\n  bottom: 20px;\r\n  right: 20px;\r\n  color: black;\r\n  visibility: hidden; /*it isn't that usable*/\r\n}\r\n</style>\r\n<body>\r\n  <div class=\"info\">\r\n    Hand physics - depth camera capture demo.\r\n    <div>\r\n      <a href=\"https://github.com/01org/depth-camera-web-demo\">Source code on GitHub</a>\r\n    </div>\r\n    <div id=\"console\" style=\"color: red; font-size: x-large;\"></div>\r\n\r\n  </div>\r\n  <div id=\"rotate-control\">\r\n    Rotate - head mounted camera: <input id=\"rotate-toggle\" type=\"checkbox\" checked>\r\n  </div>  \r\n  <canvas id=\"gl-canvas\"></canvas>\r\n  <script id=\"shadow-vs\" type=\"x-vertex-shader\">\r\n    #version 300 es\r\n\r\n    layout(location=0) in vec4 aPosition;\r\n\r\n    uniform mat4 uMVP;\r\n    void main() {\r\n      gl_Position = uMVP * aPosition;\r\n    }\r\n  </script>\r\n  <script id=\"shadow-fs\" type=\"x-fragment-shader\">\r\n    #version 300 es\r\n    precision highp float;\r\n\r\n    void main() {\r\n    \r\n    }\r\n  </script> \r\n  <script id=\"main-vs\" type=\"x-vertex-shader\">\r\n    #version 300 es\r\n\r\n    layout(location=0) in vec4 aPosition;\r\n    layout(location=1) in vec3 aNormal;\r\n    layout(location=2) in vec2 aTexCoord;\r\n\r\n    uniform mat4 uModelMatrix;\r\n    uniform mat4 uMVP;\r\n    uniform mat4 uMVPFromLight;\r\n    \r\n    out vec3 vPosition;\r\n    out vec3 vNormal;\r\n    out vec2 vTexCoord;\r\n    out vec4 vPositionFromLight;\r\n    out vec3 vModelPosition;\r\n    void main() {\r\n      gl_Position = uMVP * aPosition;\r\n\r\n      vModelPosition = vec3(aPosition);\r\n      vPosition = vec3(uModelMatrix * aPosition);\r\n      vNormal = vec3(uModelMatrix * vec4(aNormal, 0.0));\r\n      vTexCoord = aTexCoord;\r\n\r\n      vPositionFromLight = uMVPFromLight * aPosition;\r\n    }\r\n  </script>\r\n  <script id=\"main-fs\" type=\"x-fragment-shader\">\r\n    #version 300 es\r\n    precision highp float;\r\n    precision highp sampler2DShadow;\r\n\r\n    uniform vec3 uLightPosition;\r\n    uniform vec3 uEyePosition;\r\n    uniform float opacity;\r\n    uniform sampler2D uTextureMap;\r\n    uniform sampler2DShadow uShadowMap;\r\n    uniform float uWithLighting;\r\n\r\n    in vec3 vPosition;\r\n    in vec3 vNormal;\r\n    in vec2 vTexCoord;\r\n    in vec4 vPositionFromLight;\r\n    in vec3 vModelPosition;\r\n\r\n    out vec4 fragColor;\r\n    void main() {\r\n      vec3 shadowCoord = (vPositionFromLight.xyz / vPositionFromLight.w) / 2.0 + 0.5;\r\n      shadowCoord.z -= 0.0015;\r\n      float shadow = texture(uShadowMap, shadowCoord);\r\n\r\n      vec4 baseColor = texture(uTextureMap, vTexCoord) * uWithLighting;\r\n      baseColor.a = opacity;\r\n\r\n      vec3 normal = normalize(vNormal);\r\n      vec3 eyeDirection = normalize(uEyePosition - vPosition);\r\n      vec3 lightDirection = normalize(uLightPosition - vPosition);\r\n      vec3 reflectionDirection = reflect(-lightDirection, normal);\r\n      float diffuse = shadow * max(dot(lightDirection, normal), 0.0) * 0.7;\r\n      float ambient = 0.3;\r\n      float specular = shadow * pow(max(dot(reflectionDirection, eyeDirection), 0.0), 20.0) * 0.7;\r\n\r\n      fragColor = vec4((ambient + diffuse + specular) * baseColor.rgb, baseColor.a);\r\n    }\r\n  </script> \r\n  <script type=\"text/javascript\">\r\n    \"use strict\";\r\n    let error = window.console.error;\r\n    window.console.error = (message, ...rest) => {\r\n      let target = document.querySelector('#console');\r\n      error.call(window.console, message, ...rest);\r\n\r\n      if (message instanceof Error) {\r\n        message = `${message.name}: ${message.message}`;\r\n      }\r\n\r\n      target.innerHTML += `${message}<br>`;\r\n    }\r\n\r\n    utils.addTimerElement();\r\n\r\n    var canvas = document.getElementById(\"gl-canvas\");\r\n    if (!utils.testWebGL2()) {\r\n      console.error(\"WebGL 2 not available\");\r\n      document.body.innerHTML = \"This example requires WebGL 2 which is unavailable on this system.\"\r\n    }\r\n\r\n    canvas.width = window.innerWidth;\r\n    canvas.height = window.innerHeight;\r\n    \r\n    var app = PicoGL.createApp(canvas, {alpha: true})\r\n    .clearColor(0.0, 0.0, 0.0, 1.0)\r\n    .depthTest()\r\n    .cullBackfaces();\r\n\r\n    let physics;\r\n    let depthseg = new DepthAndSegments(app.gl);\r\n    const DEBUG_DRAW_BONES = false;\r\n\r\n    document.getElementById(\"rotate-toggle\").addEventListener(\"change\", function() {\r\n      depthseg.setXZFlip(this.checked);\r\n    });\r\n\r\n    var timer = app.createTimer();\r\n\r\n    // SET UP SHADOW PROGRAM\r\n    var shadowVsSource =  document.getElementById(\"shadow-vs\").text.trim();\r\n    var shadowFsSource =  document.getElementById(\"shadow-fs\").text.trim();\r\n    var shadowProgram = app.createProgram(shadowVsSource, shadowFsSource);\r\n    var shadowBuffer = app.createFramebuffer().depthTarget({compareMode: PicoGL.COMPARE_REF_TO_TEXTURE,\r\n                                                            minFilter: app.gl.LINEAR,\r\n                                                            magFilter: app.gl.NEAREST_MIPMAP_LINEAR});\r\n\r\n    // SET UP MAIN PROGRAM\r\n    var vsSource =  document.getElementById(\"main-vs\").text.trim();\r\n    var fsSource =  document.getElementById(\"main-fs\").text.trim();\r\n    var mainProgram = app.createProgram(vsSource, fsSource);\r\n\r\n    // GEOMETRY\r\n    var box = utils.createBox({dimensions: [1.0, 1.0, 1.0]})\r\n    var positions = app.createVertexBuffer(PicoGL.FLOAT, 3, box.positions);\r\n    var normals = app.createVertexBuffer(PicoGL.FLOAT, 3, box.normals);\r\n    var uv = app.createVertexBuffer(PicoGL.FLOAT, 2, box.uvs);\r\n\r\n    var boxArray = app.createVertexArray()\r\n        .vertexAttributeBuffer(0, positions)\r\n        .vertexAttributeBuffer(1, normals)\r\n        .vertexAttributeBuffer(2, uv);\r\n\r\n    const sphere = utils.createSphere({longBands: 8, latBands: 8});\r\n    const spositions = app.createVertexBuffer(PicoGL.FLOAT, 3, sphere.positions);\r\n    const snormals = app.createVertexBuffer(PicoGL.FLOAT, 3, sphere.normals);\r\n    const suv = app.createVertexBuffer(PicoGL.FLOAT, 2, sphere.uvs);\r\n    const sindices = app.createIndexBuffer(PicoGL.UNSIGNED_SHORT, 3, sphere.indices);\r\n\r\n    const sphereArray = app.createVertexArray()\r\n        .vertexAttributeBuffer(0, spositions)\r\n        .vertexAttributeBuffer(1, snormals)\r\n        .vertexAttributeBuffer(2, suv)\r\n        .indexBuffer(sindices);    \r\n\r\n    const plane_uvs = box.uvs.slice(0);\r\n    // Tile them for ground tile.\r\n    for (let i = 0; i < plane_uvs.length; i++)\r\n      plane_uvs[i] = plane_uvs[i] * 12;\r\n    const plane_uv = app.createVertexBuffer(PicoGL.FLOAT, 2, plane_uvs);\r\n    const planeArray = app.createVertexArray()\r\n        .vertexAttributeBuffer(0, positions)\r\n        .vertexAttributeBuffer(1, normals)\r\n        .vertexAttributeBuffer(2, plane_uv);\r\n\r\n    // UNIFORMS\r\n    var projMatrix = mat4.create();\r\n    var viewMatrix = mat4.create();\r\n    var eyePosition = vec3.fromValues(0, 0.5, 0.3);\r\n    mat4.lookAt(viewMatrix, eyePosition, vec3.fromValues(0, 0, 0), vec3.fromValues(0, 1, 0));\r\n\r\n    var viewProjMatrix = mat4.create();\r\n    let inverseViewProjMatrix = mat4.create();\r\n    let depth_mvp = depthseg.getMVPMatrix();\r\n    const depth_to_world_transform = mat4.create();\r\n    const world_to_depth_transform = mat4.create();\r\n\r\n    var lightPosition = vec3.fromValues(0.6, 0.5, 0.1);\r\n    var lightViewMatrix = mat4.create();\r\n    var lightViewProjMatrix = mat4.create();\r\n    const light_position_depth = vec3.create();\r\n    mat4.lookAt(lightViewMatrix, lightPosition, vec3.fromValues(0, 0, 0), vec3.fromValues(0, 1, 0));\r\n    updateMatrices();    \r\n\r\n    function updateMatrices() {\r\n      mat4.perspective(projMatrix, Math.PI / 2, app.width / app.height, 0.1, 10.0);\r\n      mat4.multiply(viewProjMatrix, projMatrix, viewMatrix);\r\n      mat4.multiply(lightViewProjMatrix, projMatrix, lightViewMatrix);\r\n      mat4.invert(inverseViewProjMatrix, viewProjMatrix);\r\n      depth_mvp = depthseg.getMVPMatrix();\r\n      mat4.multiply(depth_to_world_transform, inverseViewProjMatrix, depth_mvp);\r\n      mat4.invert(world_to_depth_transform, depth_to_world_transform);\r\n      vec3.transformMat4(light_position_depth, lightPosition, world_to_depth_transform);\r\n    }\r\n\r\n    // OBJECT DESCRIPTIONS\r\n    var boxes = [\r\n      {\r\n        translate: [0, 0, 0],\r\n        quat: [0, 0, 0, 1],\r\n        scale: [3, 0.05, 3],\r\n        mvpMatrix: mat4.create(),\r\n        modelMatrix: mat4.create(),\r\n        lightMvpMatrix: mat4.create(),\r\n        mainDrawCall: null,\r\n        shadowDrawCall: null,\r\n        array: planeArray,\r\n        mass: 0, // ground\r\n        visible: true,\r\n        ground: 1,\r\n        opacity: 0.7\r\n      },\r\n      { // wall\r\n        translate: [0, 0, -0.4],\r\n        quat: [-0.1, 0, 0, 1],\r\n        scale: [3, 1, 0.05],\r\n        mvpMatrix: mat4.create(),\r\n        modelMatrix: mat4.create(),\r\n        lightMvpMatrix: mat4.create(),\r\n        mainDrawCall: null,\r\n        shadowDrawCall: null,\r\n        array: planeArray,\r\n        mass: 0, // ground\r\n        visible: true,\r\n        ground: 1,\r\n        opacity: 1\r\n      },\r\n      { // nearest wall\r\n        translate: [0, 0, 0.4],\r\n        quat: [0, 0, 0, 1],\r\n        scale: [3, 1, 0.05],\r\n        mvpMatrix: mat4.create(),\r\n        modelMatrix: mat4.create(),\r\n        lightMvpMatrix: mat4.create(),\r\n        mainDrawCall: null,\r\n        shadowDrawCall: null,\r\n        array: planeArray,\r\n        mass: 0, // ground\r\n        visible: true,\r\n        ground: 1,\r\n        opacity: 0.2\r\n      },\r\n      { // wall to the right, not visible to let the light in.\r\n        translate: [0.5, 0, 0],\r\n        quat: [0, -0.2, 0, 1],\r\n        scale: [0.05, 1, 3],\r\n        mvpMatrix: mat4.create(),\r\n        modelMatrix: mat4.create(),\r\n        lightMvpMatrix: mat4.create(),\r\n        mainDrawCall: null,\r\n        shadowDrawCall: null,\r\n        array: planeArray,\r\n        mass: 0, // ground\r\n        visible: false,\r\n        ground: 1,\r\n        opacity: 0.2\r\n      },\r\n      { // wall on the left.\r\n        translate: [-0.5, 0, 0],\r\n        quat: [0, 0.2, 0, 1],\r\n        scale: [0.05, 1, 3],\r\n        mvpMatrix: mat4.create(),\r\n        modelMatrix: mat4.create(),\r\n        lightMvpMatrix: mat4.create(),\r\n        mainDrawCall: null,\r\n        shadowDrawCall: null,\r\n        array: planeArray,\r\n        mass: 0, // ground\r\n        visible: true,\r\n        ground: 1,\r\n        opacity: 1\r\n      },\r\n      {\r\n        translate: [0.1, 0.075, 0],\r\n        quat: [0, 0, 0, 1],\r\n        scale: [0.1, 0.1, 0.1],\r\n        mvpMatrix: mat4.create(),\r\n        modelMatrix: mat4.create(),\r\n        lightMvpMatrix: mat4.create(),\r\n        mainDrawCall: null,\r\n        shadowDrawCall: null,\r\n        array: boxArray,\r\n        mass: 0.5,\r\n        visible: true,\r\n      },\r\n      {\r\n        translate: [0.3, 0.175, 0],\r\n        quat: [0, 0, 0, 1],\r\n        scale: [0.1, 0.1, 0.1],\r\n        mvpMatrix: mat4.create(),\r\n        modelMatrix: mat4.create(),\r\n        lightMvpMatrix: mat4.create(),\r\n        mainDrawCall: null,\r\n        shadowDrawCall: null,\r\n        array: boxArray,\r\n        mass: 0.5,\r\n        visible: true,\r\n      },\r\n      {\r\n        translate: [-0.1, 0.275, 0],\r\n        quat: [0, 0, 0, 1],\r\n        scale: [0.1, 0.1, 0.1],\r\n        mvpMatrix: mat4.create(),\r\n        modelMatrix: mat4.create(),\r\n        lightMvpMatrix: mat4.create(),\r\n        mainDrawCall: null,\r\n        shadowDrawCall: null,\r\n        array: boxArray,\r\n        mass: 0.5,\r\n        visible: true\r\n      },\r\n    ];\r\n\r\n    // Finger bones pool. Instantiate pool and hide them.\r\n    const POOL_OFFSET = boxes.length;\r\n    const box_pool = {};\r\n\r\n    const SPOOL_OFFSET = 2;\r\n    var spheres = [];\r\n    var netspheres = [];\r\n\r\n    window.onresize = function() {\r\n      app.resize(window.innerWidth, window.innerHeight);\r\n      shadowBuffer.resize();\r\n      updateMatrices();\r\n    };\r\n\r\n    let images = [];\r\n    let images_loaded = 0;\r\n    function image_onload() {\r\n      images_loaded++;\r\n      if (images_loaded < images.length)\r\n        return; // and wait for all to load.\r\n      allImagesLoaded();\r\n    }\r\n\r\n    function allImagesLoaded() {\r\n      let texture = app.createTexture2D(images[0], { flipY: true });\r\n      let grid = app.createTexture2D(images[1], {});\r\n      let bone = app.createTexture2D(images[2], {});\r\n      let redtex = app.createTexture2D(null, 1, 1, {});\r\n      redtex.data(Uint8Array.from([255, 0, 0, 255]));\r\n\r\n      function setupDraw(box) {\r\n        box.shadowDrawCall = app.createDrawCall(shadowProgram, box.array);\r\n        box.mainDrawCall = app.createDrawCall(mainProgram, box.array)\r\n        .uniform(\"uLightPosition\", lightPosition)\r\n        .uniform(\"uEyePosition\", eyePosition)\r\n        .uniform(\"opacity\", box.opacity || 1.0)\r\n        .texture(\"uTextureMap\", box.hasOwnProperty(\"frameid\") ? bone :\r\n                                box.hasOwnProperty(\"ground\") ? grid : texture)\r\n        .texture(\"uShadowMap\", shadowBuffer.depthTexture);\r\n      }\r\n\r\n      // DRAW CALLS\r\n      for (var i = 0, len = boxes.length; i < len; ++i) {\r\n        setupDraw(boxes[i]);\r\n      }\r\n\r\n      function addNewSphere(spheres) {\r\n        const sphere = {\r\n          translate: [0, 0, 0],\r\n          quat: [0, 0, 0, 1],\r\n          scale: [0.02, 0.02, 0.02],\r\n          mvpMatrix: mat4.create(),\r\n          modelMatrix: mat4.create(),\r\n          lightMvpMatrix: mat4.create(),\r\n          mainDrawCall: null,\r\n          shadowDrawCall: null,\r\n          array: sphereArray,\r\n          mass: 0,\r\n          visible: false,\r\n          frameid: 0\r\n        };\r\n        spheres.push(sphere);\r\n        return sphere;\r\n      };\r\n      \r\n      // SPOOL_OFFSET = 2 scene spheres.\r\n      for (let i = 0; i < SPOOL_OFFSET; ++i) {\r\n        const sphere = addNewSphere(spheres);\r\n        sphere.translate = [0.2 + i * 0.07, 0.08, 0.1 + i * 0.07];\r\n        sphere.scale = [0.04, 0.04, 0.04];\r\n        sphere.mass = 0.5;\r\n        sphere.visible = true;\r\n        delete sphere.frameid; // frame id is used for bones.\r\n        setupDraw(sphere);\r\n      }\r\n\r\n      for (let i = 0; i < 50; i++) {\r\n        setupDraw(addNewSphere(spheres));\r\n      }\r\n\r\n      // Physics setup\r\n      var collisionConfiguration = new Ammo.btDefaultCollisionConfiguration();\r\n      var dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration);\r\n      var pairCache = new Ammo.btDbvtBroadphase();\r\n      var solver = new Ammo.btSequentialImpulseConstraintSolver();\r\n      physics = new Ammo.btDiscreteDynamicsWorld(dispatcher, pairCache, solver,collisionConfiguration);\r\n      const gravity = new Ammo.btVector3(0, -9.81, 0);\r\n      physics.setGravity(gravity);\r\n      const bt_zero_vec3 = new Ammo.btVector3(0, 0, 0);\r\n      const bt_inertia = new Ammo.btVector3(0, 0, 0);\r\n      const btvec = new Ammo.btVector3(0, 0, 0);\r\n      const btquaternion = new Ammo.btQuaternion(0, 0, 0, 0);\r\n\r\n      let transform = new Ammo.btTransform();\r\n      let transform1 = new Ammo.btTransform();\r\n\r\n      // btCollisionObjects.h constants.\r\n      const ACTIVE_TAG = 1;\r\n      const DISABLE_DEACTIVATION = 4;\r\n      const WANTS_DEACTIVATION = 3;\r\n      const CF_KINEMATIC_OBJECT = 2;\r\n      const DISABLE_SIMULATION = 5;\r\n      const CF_STATIC_OBJECT = 1;\r\n      const CF_NO_CONTACT_RESPONSE = 4;\r\n      const CF_CUSTOM_MATERIAL_CALLBACK = 8;\r\n      const CF_CHARACTER_OBJECT = 16;\r\n      let frameid = 1;\r\n      let previous_frameid = 1;\r\n      const SPHERES_OFFSET = 1000; // range of sphares used for bones offset.\r\n      const NETSPHERES_OFFSET = 10000; // index mark the beginning of the offset\r\n      // of an index of sphere used for large areas, e.g. arm, physics modeling.\r\n\r\n      function createRigidBody(index) {\r\n        const box = boxes[index];\r\n        let shape = new Ammo.btBoxShape(new Ammo.btVector3(box.scale[0] * 0.5, box.scale[1] * 0.5, box.scale[2] * 0.5));\r\n        transform.setIdentity();\r\n        transform.setOrigin(new Ammo.btVector3(box.translate[0], box.translate[1], box.translate[2]));\r\n        transform.setRotation(new Ammo.btQuaternion(box.quat[0], box.quat[1], box.quat[2], box.quat[3]));\r\n        let motionState = new Ammo.btDefaultMotionState(transform);\r\n\r\n        let localInertia = new Ammo.btVector3(0, 0, 0);\r\n        shape.calculateLocalInertia(box.mass, localInertia);\r\n\r\n        let info = new Ammo.btRigidBodyConstructionInfo(box.mass, motionState, shape, localInertia);\r\n        const is_finger = box.hasOwnProperty(\"frameid\");\r\n        if (is_finger) \r\n          info.m_friction = 10.0; // high friction for hands.\r\n        let body = new Ammo.btRigidBody(info);\r\n        // if (box.hasOwnProperty(\"frameid\"))\r\n        //   body.setCollisionFlags(body.getCollisionFlags() | CF_KINEMATIC_OBJECT);\r\n        box.physics_body = body;\r\n        body.setUserPointer(box);\r\n        body.setUserIndex(index);\r\n        box.constraints = [];\r\n        box.holding_vector = null;\r\n        if (!box.visible)\r\n          body.forceActivationState(DISABLE_SIMULATION);\r\n        if (box.mass > 0) {\r\n          body.setActivationState(DISABLE_DEACTIVATION);\r\n        } else if (is_finger) {\r\n          body.setCollisionFlags(CF_NO_CONTACT_RESPONSE | CF_STATIC_OBJECT);\r\n          // body.setSleepingThresholds(0.2, 0.2);\r\n          // body.setAngularFactor(0.0);\r\n        }\r\n        physics.addRigidBody(body);\r\n      }\r\n\r\n      function createRigidBodySphere(sp, index) {\r\n        let shape = new Ammo.btSphereShape(sp.scale[0]);\r\n        transform.setIdentity();\r\n        btvec.setValue(sp.translate[0], sp.translate[1], sp.translate[2]);\r\n        btquaternion.setValue(sp.quat[0], sp.quat[1], sp.quat[2], sp.quat[3]);\r\n        transform.setOrigin(btvec);\r\n        transform.setRotation(btquaternion);\r\n        let motionState = new Ammo.btDefaultMotionState(transform);\r\n\r\n        bt_inertia.setValue(0, 0, 0);\r\n        shape.calculateLocalInertia(sp.mass, bt_inertia);\r\n\r\n        let info = new Ammo.btRigidBodyConstructionInfo(sp.mass, motionState, shape, bt_inertia);\r\n        info.m_friction = 10.0; // high friction for hands.\r\n        let body = new Ammo.btRigidBody(info);\r\n        sp.physics_body = body;\r\n        body.setUserPointer(sp);\r\n        body.setUserIndex(index);\r\n        if (!sp.visible)\r\n          body.forceActivationState(DISABLE_SIMULATION);\r\n        sp.constraints = [];\r\n        if (sp.mass > 0) {\r\n          body.setActivationState(DISABLE_DEACTIVATION);\r\n        } else if (sp.hasOwnProperty(\"frameid\")) {\r\n          body.setCollisionFlags(CF_NO_CONTACT_RESPONSE | CF_STATIC_OBJECT);\r\n        }\r\n        physics.addRigidBody(body);\r\n      }\r\n\r\n      function btToScene(s) {\r\n        let state = s.physics_body.getMotionState();\r\n        if (!state)\r\n          return;\r\n        state.getWorldTransform(transform);\r\n        let t = transform.getOrigin();\r\n        let q = transform.getRotation();\r\n        s.translate[0] = t.x();\r\n        s.translate[1] = t.y();\r\n        s.translate[2] = t.z();\r\n        s.quat[0] = q.x();\r\n        s.quat[1] = q.y();\r\n        s.quat[2] = q.z();\r\n        s.quat[3] = q.w();\r\n      }\r\n\r\n      function updatePhysics(time_delta) {\r\n        if ((boxes[1].constraints.length & 1) != 0 ||\r\n            (boxes[2].constraints.length & 1) != 0 ||\r\n            (boxes[3].constraints.length & 1) != 0)\r\n          console.error(\"expected even number of constraints\");\r\n        physics.stepSimulation(time_delta, 10);\r\n        for (let i = 1; i < boxes.length; i++)\r\n          btToScene(boxes[i]);\r\n        for (let i = 0; i < SPOOL_OFFSET; i++)\r\n          btToScene(spheres[i]);\r\n        addConnectionsForContacts();\r\n      }\r\n\r\n      const tip = new glMatrix.ARRAY_TYPE(3);\r\n      const base = new glMatrix.ARRAY_TYPE(3);\r\n      const subtract = new glMatrix.ARRAY_TYPE(3);\r\n      const quaternion = new glMatrix.ARRAY_TYPE(4);\r\n      const draw_transform = mat4.create();\r\n      const yUnitVec3 = vec3.fromValues(0,1,0);\r\n      const far_away = new Ammo.btTransform();\r\n      far_away.setOrigin(new Ammo.btVector3(-200, -200, -200));\r\n      const temp = new glMatrix.ARRAY_TYPE(3);\r\n      const temp1 = new glMatrix.ARRAY_TYPE(3);\r\n\r\n      function isAngleObtuse(a, b, c) {\r\n        vec3.subtract(temp, a, b);\r\n        vec3.subtract(temp1, c, b);\r\n        return (vec3.dot(temp, temp1) < 0);\r\n      }\r\n\r\n      const segbuffer = [];\r\n      function getSegBuffer(i) {\r\n        while(segbuffer.length <= i) {\r\n          segbuffer.push({world_tip: new glMatrix.ARRAY_TYPE(3), sp1: null,\r\n                          world_base: new glMatrix.ARRAY_TYPE(3), sp2: null,\r\n                          sp1_square: Number.MAX_VALUE,\r\n                          sp2_square: Number.MAX_VALUE});\r\n        }\r\n        return segbuffer[i];\r\n      }\r\n\r\n      // keep track of sphere ids that are touching the scene objects.\r\n      const contact_spheres = new Set();\r\n\r\n      function getBoxFromPool(length) {\r\n        const k = Math.max(20, Math.min((length * 1000) | 0, 69));\r\n        for (let i = k; i >= 20; i--) {\r\n          if (box_pool[i].frameid == frameid)\r\n            continue;\r\n          return box_pool[i];\r\n        }\r\n        for (let i = k + 1; i < 70; i++) {\r\n          if (box_pool[i].frameid == frameid)\r\n            continue;\r\n          return box_pool[i];\r\n        }\r\n        console.error(\"TODO: add boxes when not in pool\");\r\n      }\r\n\r\n      function getSphereFromPool() {\r\n        for (let i = SPOOL_OFFSET; i < spheres.length; i++) {\r\n          if (spheres[i].frameid == frameid)\r\n            continue;\r\n          return spheres[i];\r\n        }\r\n        const sphere = addNewSphere(spheres);\r\n        setupDraw(sphere);\r\n        createRigidBodySphere(sphere, SPHERES_OFFSET + spheres.length - 1);\r\n        return sphere;\r\n      }\r\n\r\n      // Convert scanned point values |p| to 3D |v|. For all of the points we\r\n      // assign spheres of radius 0.02 - this is the reason the offset is 0.014\r\n      // as the sphere center should be behind the surface.\r\n      function convertTo3D(v, x, y, d) {\r\n        const depth = depthseg.depth_scale * d + 0.014;\r\n        v[0] = depth * (x - depthseg.depth_offset[0]) * depthseg.depth_focal_inv[0];\r\n        v[1] = depth * (y - depthseg.depth_offset[1]) * depthseg.depth_focal_inv[1];          \r\n        v[2] = depth;\r\n      };\r\n\r\n      function initSegBuffer(seg, buffer) {\r\n        // TODO: fix horizontal orientation\r\n        // Convert segment endpoints to 3D world coordinates.\r\n        const p1 = seg;\r\n        const p2 = depthseg.getSegmentEnd(seg);         \r\n\r\n        convertTo3D(tip, p1.x, p1.y, p1.depth); \r\n        vec3.transformMat4(buffer.world_tip, tip, depth_to_world_transform);\r\n        convertTo3D(base, p2.x, p2.y, p2.depth); \r\n        vec3.transformMat4(buffer.world_base, base, depth_to_world_transform);\r\n\r\n        buffer.sp1 = null;\r\n        buffer.sp2 = null;\r\n        buffer.sp1_square = Number.MAX_VALUE;\r\n        buffer.sp2_square = Number.MAX_VALUE;\r\n        buffer.endpoint_base = !p2.hasOwnProperty(\"joint\");\r\n        buffer.endpoint_tip = !p1.hasOwnProperty(\"joint\");                   \r\n      };\r\n\r\n      const viewscale = 1;\r\n      const MATCH_SPHERE_LIMIT = 0.0004 * viewscale * viewscale; // 2cm\r\n      function getMatchingPreviousFrameSphere(world_center) {\r\n        let nearest = Number.MAX_VALUE;\r\n        let nearest_s = null;\r\n        for (let i = SPOOL_OFFSET, len = spheres.length; i < len; ++i) {\r\n          const s = spheres[i];\r\n          // If it wasn't used in previous frame or already allocated to\r\n          // other point, move to next.\r\n          if (s.frameid != previous_frameid || s.segment || s.contact == false)\r\n            continue;\r\n          const squared_distance = vec3.squaredDistance(s.translate, world_center);\r\n          if (squared_distance < nearest) {\r\n            nearest = squared_distance;\r\n            nearest_s = s;\r\n          }\r\n        }\r\n        if (nearest < MATCH_SPHERE_LIMIT)\r\n          return nearest_s;\r\n        return null;\r\n      }\r\n\r\n      // |force| is true for previous frame contact spheres - spheres that were\r\n      // holding the box. We map them to the nearest, so that the picked object\r\n      // wouldn't jump around.\r\n      // Except the potential contact points, the rest of depth segments\r\n      // endpoints are not mapped to previous frame's spheres, but always to\r\n      // a sphere not used in previous frame - cleaned history sphere from the\r\n      // pool is assigned for the depth point. \r\n      function assignContactSphereToSegmentEndPoint(buffer, spkey, segment, force) {\r\n        const sp = buffer[spkey];\r\n        if (sp == null)\r\n          return;\r\n        const c = (sp == buffer.sp1) ? buffer.world_tip : buffer.world_base;\r\n        sp.segment = segment;\r\n        sp.visible = DEBUG_DRAW_BONES;\r\n        // reposition the physics body\r\n        vec3.copy(sp.translate, c);\r\n        const body = sp.physics_body;\r\n        transform.setIdentity();\r\n        btvec.setValue(c[0], c[1], c[2]);\r\n        transform.setOrigin(btvec);\r\n        body.setWorldTransform(transform);\r\n        body.getMotionState().setWorldTransform(transform);\r\n        // if (sp.frameid == 0 || !contact) {\r\n          body.setLinearVelocity(bt_zero_vec3);\r\n          body.setAngularVelocity(bt_zero_vec3);\r\n          body.forceActivationState(ACTIVE_TAG);\r\n          body.setCollisionFlags(CF_STATIC_OBJECT);\r\n          body.updateInertiaTensor();\r\n        // }\r\n        // if contact is not forced, make it so that it happens only when fingers\r\n        // are well distinguished.\r\n        sp.contact = force || (((segment.far_left.distance2D | 0) +\r\n                                (segment.far_right.distance2D | 0) > 4) &&\r\n                               (segment.count_left + segment.count_right > 8));\r\n        sp.segment_id = segment.index; // debugging purpose only.\r\n        sp.frameid = frameid;\r\n        sp.buffer = buffer;\r\n      }\r\n\r\n      function dropObjectsHeldBySphere(sp, index) {\r\n        if (sp.constraints.length > 0)\r\n          contact_spheres.delete(index);\r\n        for (let j = 0; j < sp.constraints.length; j++) {\r\n          const constraint = sp.constraints[j];\r\n          // remove constraints holding the world object.\r\n          const wbox = boxes[constraint.world_item];\r\n          // TODO: remove constraints from other item.\r\n          const finger0 = wbox.constraints[0].finger_item;\r\n          const finger1 = wbox.constraints[1].finger_item;\r\n          \r\n          if (finger0 != index) {\r\n            const s0cons = spheres[finger0].constraints;\r\n            s0cons.splice(s0cons.indexOf(wbox.constraints[0]), 1);\r\n            if (s0cons.length == 0)\r\n              contact_spheres.delete(finger0);           \r\n          } else if (finger1 != index) {\r\n            const s0cons = spheres[finger1].constraints;\r\n            s0cons.splice(s0cons.indexOf(wbox.constraints[1]), 1);           \r\n            if (s0cons.length == 0)\r\n              contact_spheres.delete(finger1);           \r\n          }\r\n\r\n          if(wbox.constraints.indexOf(constraint) == -1)\r\n            console.error(\"wboxcindex == -1\");\r\n\r\n          wbox.physics_body.getCollisionShape().calculateLocalInertia(wbox.mass, bt_inertia);   \r\n          wbox.physics_body.setMassProps(wbox.mass, bt_inertia);\r\n          wbox.holding_vector_recent = [];\r\n           \r\n          wbox.constraints.length = 0;\r\n\r\n        }\r\n        sp.constraints.length = 0;\r\n      }\r\n\r\n      function filterOutNoise(v, list) {\r\n        // Filter position noise.\r\n        const p = list.length > 6 ? list.shift() : new glMatrix.ARRAY_TYPE(3);\r\n        vec3.copy(p, v);\r\n        list.push(p);\r\n\r\n        if (list.length < 5)\r\n          return;\r\n\r\n        vec3.copy(temp, v);\r\n        for (let i = 0; i < list.length - 1; i++)\r\n          vec3.add(temp, temp, list[i]);\r\n        vec3.normalize(temp1, temp);\r\n        \r\n        let maxdiffindex = 0;\r\n        let maxdiff = vec3.squaredDistance(temp1, list[0]);\r\n        for (let i = 1; i < list.length; i++) {\r\n          const diff = vec3.squaredDistance(temp1, list[i]);\r\n          if (diff > maxdiff) {\r\n            maxdiffindex = i;\r\n            maxdiff = diff;\r\n          }\r\n        }\r\n        // remove max diff from computation\r\n        vec3.subtract(temp, temp, list[maxdiffindex]);\r\n        vec3.normalize(v, temp);\r\n      }\r\n\r\n      function assignSphereToPoint(sp, x, y, d) {\r\n        const body = sp.physics_body;\r\n        convertTo3D(temp, x, y, d); \r\n        const c = sp.translate;\r\n        vec3.transformMat4(c, temp, depth_to_world_transform);\r\n        \r\n        sp.visible = DEBUG_DRAW_BONES;\r\n        // reposition the physics body\r\n        transform.setIdentity();\r\n        btvec.setValue(c[0], c[1], c[2]);\r\n        transform.setOrigin(btvec);\r\n        body.setWorldTransform(transform);\r\n        body.getMotionState().setWorldTransform(transform);\r\n        // if (sp.frameid == 0 || !contact) {\r\n          body.setLinearVelocity(bt_zero_vec3);\r\n          body.setAngularVelocity(bt_zero_vec3);\r\n          body.forceActivationState(ACTIVE_TAG);\r\n          body.setCollisionFlags(CF_STATIC_OBJECT);\r\n          body.updateInertiaTensor();\r\n        // }\r\n        sp.frameid = frameid;\r\n        sp.contact = false;\r\n      }\r\n\r\n      function updateNet() {\r\n        for (let i = netspheres.length; i < depthseg.out.net.length; i++) {\r\n          const sp = addNewSphere(netspheres);\r\n          setupDraw(sp);\r\n          createRigidBodySphere(sp, i + NETSPHERES_OFFSET);\r\n        }\r\n        const width = out.netw;\r\n        const height = out.neth;\r\n        const d = depthseg.getDepthNonSkeleton;\r\n        for (let j = 1; j < height - 1; j++) {\r\n          for (let i = 1 + j * width, end = i + width - 2; i < end; i++) {\r\n            const n = out.net[i];\r\n            const sp = netspheres[i];            \r\n            if (n == -1) {\r\n              // hide visible and physics.\r\n              sp.visible = false;\r\n              const body = sp.physics_body;\r\n              body.setLinearVelocity(bt_zero_vec3);\r\n              body.setAngularVelocity(bt_zero_vec3);\r\n              body.setCollisionFlags(CF_NO_CONTACT_RESPONSE | CF_STATIC_OBJECT);\r\n              body.setActivationState(DISABLE_SIMULATION);\r\n              continue;\r\n            }\r\n            const x = n >> 16, y = n & 0xFFFF;\r\n            assignSphereToPoint(sp, x, y, d(x, y));\r\n          }\r\n        }        \r\n      }        \r\n\r\n      function updateFingerSegments() {        \r\n        previous_frameid = frameid;\r\n        frameid = ((frameid + 1) & 0xFFFFFFFF) || 1;\r\n\r\n        // For all the segment endpoints calculate 3D values. We will use those\r\n        // in several traversals below.\r\n        const segment_data = depthseg.out.segment_data;\r\n        let keys = Object.keys(depthseg.out.segment_data);\r\n        for (let k = 0; k < keys.length; k++) {\r\n          const segment = segment_data[keys[k]];\r\n          const buffer = getSegBuffer(k);\r\n          initSegBuffer(segment, buffer);\r\n        }\r\n\r\n        // Identify endpoints (remove the points where two segments touch).\r\n        // We do this so there are less points that could cause tracking/mapping\r\n        // problems.\r\n        let endpoints = 0;\r\n        for (let k = 0; k < keys.length; k++) {\r\n          const buffer = getSegBuffer(k);\r\n          endpoints += ((buffer.endpoint_base ? 1 : 0) +\r\n                        (buffer.endpoint_tip ? 1 : 0));\r\n        }\r\n\r\n        // Start from previous frame contact points and get the closest points\r\n        // the latest segments to the previous frame contact points.\r\n        // Assign here means setting e.g. buffer.sp1.s(phere) and s.segment\r\n        let to_assign = Math.min(contact_spheres.size, endpoints);\r\n        while (to_assign > 0) {\r\n          for (i of contact_spheres) {\r\n            const s = spheres[i];\r\n            if (s.segment != null)\r\n              continue;\r\n            // Get the closest current segment endpoint.\r\n            let nearest = Number.MAX_VALUE;\r\n            let nearest_k = -1;\r\n            let nearest_key = \"sp1\";\r\n            for (let k = 0; k < keys.length; k++) {\r\n              const buffer = getSegBuffer(k);\r\n              let squared_distance = buffer.endpoint_tip ?\r\n                                     vec3.squaredDistance(s.translate, buffer.world_tip) :\r\n                                     Number.MAX_VALUE;\r\n              if (squared_distance < nearest && squared_distance < buffer.sp1_square) {\r\n                nearest = squared_distance;\r\n                nearest_k = k;\r\n                nearest_key = \"sp1\";\r\n              }\r\n              squared_distance = buffer.endpoint_base ?\r\n                                 vec3.squaredDistance(s.translate, buffer.world_base) :\r\n                                 Number.MAX_VALUE;\r\n              if (squared_distance < nearest && squared_distance < buffer.sp2_square) {\r\n                nearest = squared_distance;\r\n                nearest_k = k;\r\n                nearest_key = \"sp2\";\r\n              }\r\n            }\r\n            if (nearest_k == -1)\r\n              continue; // This one doesn't get assigned.\r\n            const buffer = getSegBuffer(nearest_k);\r\n            if (buffer[nearest_key] != null) {\r\n              // There is another sphere claiming it is the closest to the\r\n              // segment endpoint. Invalidate it and do that sphere again.\r\n              to_assign++;\r\n              buffer[nearest_key].segment = null;\r\n              buffer[nearest_key + \"_square\"] = Number.MAX_VALUE; \r\n            }\r\n            buffer[nearest_key] = s;\r\n            buffer[nearest_key + \"_square\"] = nearest; \r\n            to_assign--;\r\n            s.segment = segment_data[keys[nearest_k]];\r\n          }\r\n        }\r\n\r\n        // The final step in assigning previous joints - based on\r\n        // buffer.spX.s(phere), \r\n        function bothHoldsValidAssignment(key, buffer) {\r\n          // If both ends of one segment got assigned as contact points then\r\n          // we have an erroneous situation: contact points should be on\r\n          // different fingers, and previous frame fingertip is probably not\r\n          // visible in this frame so it got reassigned to the closest but\r\n          // wrong point. drop the box.\r\n          if (buffer.sp2 && buffer.sp1)\r\n            return false;\r\n          return buffer[key + \"_square\"] < 0.01;\r\n        }\r\n\r\n        for (let k = 0; k < keys.length; k++) {\r\n          const buffer = getSegBuffer(k);\r\n          // We need another sub-step here: check the distances and accept\r\n          // those that are the closest but not the ones that suddenly change\r\n          // the orientation. The idea is to avoid sudden jumps when finger is\r\n          // not visible. For now, drop the object as code bellow will not\r\n          // assign the sphere.\r\n          if (buffer.endpoint_tip && buffer.sp1 &&\r\n              bothHoldsValidAssignment(\"sp1\", buffer)) {\r\n            assignContactSphereToSegmentEndPoint(buffer, \"sp1\", buffer.sp1.segment, true);\r\n          }\r\n          if (buffer.endpoint_base && buffer.sp2 &&\r\n              bothHoldsValidAssignment(\"sp2\", buffer)) {\r\n            assignContactSphereToSegmentEndPoint(buffer, \"sp2\", buffer.sp2.segment, true);\r\n          }\r\n        }\r\n        \r\n        // Among other points, get the mapping to previous when they are nearby.\r\n        for (let k = 0; k < keys.length; k++) {\r\n          const segment = segment_data[keys[k]];\r\n          const buffer = getSegBuffer(k);\r\n          if (buffer.endpoint_tip && !buffer.sp1) {\r\n            buffer.sp1 = getMatchingPreviousFrameSphere(buffer.world_tip);\r\n            assignContactSphereToSegmentEndPoint(buffer, \"sp1\", segment);\r\n          }\r\n          if (buffer.endpoint_base && !buffer.sp2) {\r\n            buffer.sp2 = getMatchingPreviousFrameSphere(buffer.world_base);\r\n            assignContactSphereToSegmentEndPoint(buffer, \"sp2\", segment);\r\n          }\r\n        }\r\n\r\n        for (let k = 0; k < keys.length; k++) {\r\n          const segment = segment_data[keys[k]];\r\n          const buffer = getSegBuffer(k);\r\n          if (buffer.endpoint_tip && !buffer.sp1) {\r\n            // Get from the pool.\r\n            buffer.sp1 = getSphereFromPool();\r\n            assignContactSphereToSegmentEndPoint(buffer, \"sp1\", segment);\r\n          }\r\n          if (buffer.endpoint_base && !buffer.sp2) {\r\n            buffer.sp2 = getSphereFromPool();\r\n            assignContactSphereToSegmentEndPoint(buffer, \"sp2\", segment);\r\n          }\r\n        }\r\n\r\n        // If 2 fingers holding the object are not holding it anymore, drop the\r\n        // object.\r\n        for (let i = SPOOL_OFFSET, len = spheres.length; i < len; ++i) {\r\n          const sp = spheres[i];\r\n          const body = sp.physics_body;\r\n\r\n          if (sp.frameid == previous_frameid) {\r\n            body.setLinearVelocity(bt_zero_vec3);\r\n            body.setAngularVelocity(bt_zero_vec3);\r\n            // getBroadphaseProxy().masks and groups are not compiled in,\r\n            // DISABLE_SIMULATION is not honored so the way to avoid interaction\r\n            // of pool items is to add CF_NO_CONTACT_RESPONSE flag.\r\n            // As this means that the collision is still computed, we move the\r\n            // objects far away to get them processed out during broad phase.\r\n            body.setCollisionFlags(CF_NO_CONTACT_RESPONSE | CF_STATIC_OBJECT);\r\n            body.setActivationState(DISABLE_SIMULATION);\r\n            body.updateInertiaTensor();\r\n            // body.setWorldTransform(far_away);\r\n            // body.getMotionState().setWorldTransform(far_away);\r\n            // remove all the constraints this body has in the world.\r\n            dropObjectsHeldBySphere(sp, i);\r\n          }\r\n          sp.segment = null;\r\n          if (sp.frameid != frameid) {\r\n            sp.frameid = 0;\r\n            sp.visible = false; //sp.physics_body.isActive(); // false;\r\n            sp.buffer = null;\r\n          }\r\n        }\r\n\r\n        // Non contact areas get spheres assigned too.\r\n        for (let k = 0; k < keys.length; k++) {\r\n          const segment = segment_data[keys[k]];\r\n          const interpolated_count = depthseg.getSegmentInterpolatedCount(segment);\r\n          for (let i = 0; i < interpolated_count; i++) {\r\n            depthseg.getInterpolatedPoint(temp, segment, i);\r\n            const sp = getSphereFromPool();\r\n            assignSphereToPoint(sp, temp[0], temp[1], temp[2]);\r\n          }\r\n          if (segment.hasOwnProperty(\"joint\")) {\r\n            const sp = getSphereFromPool();\r\n            assignSphereToPoint(sp, segment.x, segment.y, segment.depth);            \r\n          }\r\n        }\r\n\r\n        // World objects that are hold are getting the rotation from position\r\n        // of fingers holding them.\r\n        for (let i = 0; i < boxes.length; i++) {\r\n          if (boxes[i].constraints.length == 1)\r\n            console.error(\"shouldnt be 1\");\r\n          if (boxes[i].constraints.length > 0) {\r\n            const wb = boxes[i];\r\n            const sp0 = spheres[wb.constraints[0].finger_item];\r\n            const sp1 = spheres[wb.constraints[1].finger_item];\r\n            vec3.subtract(subtract, sp1.translate, sp0.translate);\r\n            \r\n            // If length between fingers is > threshold * initial holding length,\r\n            // drop it.\r\n            const hold_length = vec3.length(subtract);\r\n            if (hold_length > 1.5 * wb.holding_length) {\r\n              // drop the box.\r\n              dropObjectsHeldBySphere(sp0, wb.constraints[0].finger_item);\r\n              continue;\r\n            }\r\n\r\n            //  normalize subtract:\r\n            vec3.scale(subtract, subtract, 1 / hold_length);\r\n\r\n            // average holding vector to filter out spikes.\r\n            wb.holding_vector_recent = wb.holding_vector_recent || [];\r\n            filterOutNoise(subtract, wb.holding_vector_recent);\r\n\r\n            quat.rotationTo(wb.quat, wb.holding_vector, subtract);\r\n            quat.multiply(wb.quat, wb.quat, wb.holding_quat);\r\n\r\n            const body = wb.physics_body;\r\n            transform.setIdentity();\r\n            vec3.lerp(subtract, sp0.translate, sp1.translate, 0.5);\r\n            vec3.add(wb.translate, subtract, wb.center_offset);\r\n            btvec.setValue(wb.translate[0], wb.translate[1], wb.translate[2]);\r\n            transform.setOrigin(btvec);\r\n            btquaternion.setValue(wb.quat[0], wb.quat[1], wb.quat[2], wb.quat[3]);\r\n            transform.setRotation(btquaternion);\r\n            body.setWorldTransform(transform);\r\n            body.getMotionState().setWorldTransform(transform);\r\n            // body.setLinearVelocity(bt_zero_vec3);\r\n            // body.setAngularVelocity(bt_zero_vec3);\r\n          }\r\n        }\r\n        updateNet();\r\n      }\r\n\r\n      // Can 2 manifolds hold the object? Both manifolds are on the same\r\n      // object, but different finger balls.\r\n      function canManifoldsHoldTheObject(con1, m2, ob, joint, finger) {\r\n        const m1 = con1.manifold;\r\n        const p1 = m1.getContactPoint(0);\r\n        const p2 = m2.getContactPoint(0);\r\n\r\n        // First, let's not allow picking objects from the lower side - to\r\n        // prevent this happening when carrying objects.\r\n        // It is box, so on.scale[0] is sufficient - otherwise, use the minimum.\r\n        const ymin = ob.translate[1] - ob.scale[0] * 0.5;\r\n        if (p1.get_m_positionWorldOnA().y() < ymin ||\r\n            p2.get_m_positionWorldOnA().y() < ymin) {\r\n          return false;\r\n        }\r\n        const pA1 = p1.get_m_localPointA();\r\n        const pB1 = p1.get_m_localPointB();\r\n        const pA2 = p2.get_m_localPointA();\r\n        const pB2 = p2.get_m_localPointB();\r\n\r\n        // As these are the boxes, holding if pBs are in the same.\r\n        // object to hold is a box, so simplify this so that we hold it on\r\n        // opposite sides of the box.\r\n        const xdiff = Math.abs(pA1.x() - pA2.x());\r\n        const ydiff = Math.abs(pA1.y() - pA2.y());\r\n        const zdiff = Math.abs(pA1.z() - pA2.z());\r\n        if (!(xdiff > 0.9 * ob.scale[0] || ydiff > 0.9 * ob.scale[1] ||\r\n            zdiff > 0.9 * ob.scale[2]))\r\n          return false;\r\n        // Some more math: the direction of the finger; towards or from within\r\n        // the box determines if fingers can hold the object.\r\n        const finger1 = spheres[con1.finger_item];\r\n        const joint1 = finger1.buffer.sp1 == finger1 ? finger1.buffer.world_base\r\n                                                     : finger1.buffer.world_tip;\r\n        // All together, we check 4 angles: joint - fingertip(contact) - center\r\n        // of object for both fingers and joint - fingertip(contact) - center of\r\n        // the grip between two points.\r\n        // If all angles are obtuse (> 90) then it can hold the box.\r\n        if (!isAngleObtuse(ob.translate, finger1.translate, joint1))\r\n          return false;\r\n\r\n        if (!isAngleObtuse(ob.translate, finger.translate, joint))\r\n          return false;\r\n\r\n        ob.center_offset = ob.center_offset || new glMatrix.ARRAY_TYPE(3);\r\n        vec3.lerp(ob.center_offset, finger.translate, finger1.translate, 0.5);\r\n\r\n        if (!isAngleObtuse(ob.center_offset, finger1.translate, joint1))\r\n          return false;\r\n\r\n        if (!isAngleObtuse(ob.center_offset, finger.translate, joint))\r\n          return false;\r\n\r\n        return true;\r\n      }\r\n\r\n      function processManifold(i0, i1, manifold) {\r\n        if (!manifold)\r\n            console.error(\"undefined manifold\");\r\n        i1 = i1 - SPHERES_OFFSET;\r\n        const ob = i0 < SPHERES_OFFSET ? boxes[i0] : spheres[i0 - SPHERES_OFFSET];\r\n        if (ob.constraints.length == 2 && ob.constraints[0].manifold == null)\r\n          return; // already two fingers holding the object, ignore other.\r\n        const finger = spheres[i1];\r\n        if (!finger.contact)\r\n          return;\r\n        const joint = finger.buffer.sp1 == finger ? finger.buffer.world_base\r\n                                                  : finger.buffer.world_tip;\r\n        for (let i = 0; i < ob.constraints.length; i++) {\r\n          const con1 = ob.constraints[i];\r\n          if (canManifoldsHoldTheObject(con1, manifold, ob, joint, finger)) {\r\n            // We found the pair, so create real joints and clear the rest.\r\n            // Create constraint from the manifold.                     \r\n            const body = ob.physics_body;\r\n                          \r\n            const finger1 = spheres[con1.finger_item];\r\n            const pt = con1.manifold.getContactPoint(0);\r\n            finger1.constraints.push(con1);\r\n            con1.manifold = null;\r\n\r\n            contact_spheres.add(con1.finger_item);\r\n\r\n            // The second finger:\r\n            const pt2 = manifold.getContactPoint(0);\r\n            const con2 = {world_item: i0, finger_item: i1, manifold: null};\r\n            ob.constraints = [con1, con2]; // remove all other\r\n            finger.constraints.push(con2);\r\n        \r\n            contact_spheres.add(i1);\r\n\r\n            ob.holding_vector = ob.holding_vector || new glMatrix.ARRAY_TYPE(3);\r\n            vec3.subtract(ob.holding_vector, finger.translate, finger1.translate);\r\n            ob.holding_length = vec3.length(ob.holding_vector);\r\n            vec3.scale(ob.holding_vector, ob.holding_vector, 1 / ob.holding_length);\r\n            ob.holding_quat = quat.clone(ob.quat);\r\n\r\n            vec3.lerp(ob.center_offset, finger.translate, finger1.translate, 0.5);\r\n            vec3.subtract(ob.center_offset, ob.translate, ob.center_offset);\r\n\r\n            body.getCollisionShape().calculateLocalInertia(0, bt_inertia);   \r\n            body.setMassProps(0, bt_inertia);\r\n            body.setLinearVelocity(bt_zero_vec3);\r\n            body.setAngularVelocity(bt_zero_vec3);\r\n            // body.setCollisionFlags(body.getCollisionFlags() | (CF_KINEMATIC_OBJECT | ~CF_STATIC_OBJECT));\r\n            body.updateInertiaTensor();\r\n            return;\r\n          }\r\n        }\r\n\r\n        // Since it is not possible to hold an object, cache the manifold.\r\n        const con = {world_item: i0, finger_item: i1, manifold: manifold};\r\n        ob.constraints.push(con);\r\n      }\r\n\r\n      function addConnectionsForContacts() {\r\n        const disp = physics.getDispatcher();\r\n        for (let i = 0, num = disp.getNumManifolds(); i < num; i++) {\r\n          const manifold = disp.getManifoldByIndexInternal(i);\r\n          const num_contacts = manifold.getNumContacts();\r\n          if (!num_contacts)\r\n            continue;\r\n          const i0 = manifold.getBody0().getUserIndex();\r\n          const i1 = manifold.getBody1().getUserIndex();\r\n          if(i0 > i1) throw \"first one should be less than the second\";\r\n          if (i0 >= SPHERES_OFFSET)\r\n            continue; // let's pick only boxes.\r\n          if (i1 < SPHERES_OFFSET + SPOOL_OFFSET)\r\n            continue;\r\n          if (i1 >= NETSPHERES_OFFSET)\r\n            continue;\r\n          if (!manifold.getBody1().isActive())\r\n            continue;\r\n          processManifold(i0, i1, manifold);\r\n        }\r\n\r\n        // reset back intermediate data.\r\n        for (let i = 1; i < POOL_OFFSET; i++) {\r\n          const cons = boxes[i].constraints;\r\n          if (cons.length != 0 && // don't reset if empty already\r\n              (cons.length != 2 || cons[0].manifold != null)) {\r\n            cons.length = 0;         \r\n          }\r\n          if (boxes[i].constraints.length > 0 && boxes[i].holding_vector == null)\r\n            console.error(\"TODO: remove this debug message\");\r\n        }\r\n      }      \r\n\r\n      for (var i = 0, len = boxes.length; i < len; ++i)\r\n        createRigidBody(i);\r\n      for (var i = 0, len = spheres.length; i < len; ++i)\r\n        createRigidBodySphere(spheres[i], i + SPHERES_OFFSET);      \r\n\r\n      let timestamp = performance.now();\r\n\r\n      function draw() {\r\n        if (timer.ready()) {\r\n          utils.updateTimerElement(timer.cpuTime, timer.gpuTime);\r\n        }\r\n\r\n        timer.start();\r\n        const gl = depthseg.gl;\r\n        gl.clear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT); \r\n        if (depthseg.process())\r\n          updateFingerSegments();\r\n\r\n        // Update physics.\r\n        const now = performance.now();\r\n        updatePhysics((now - timestamp) * 0.001);\r\n        timestamp = now;\r\n\r\n        // Update graphics.\r\n        function updateUniforms(item, withlight = 1.0) {\r\n          mat4.fromRotationTranslationScale(item.modelMatrix, item.quat, item.translate, item.scale);\r\n          mat4.multiply(item.mvpMatrix, viewProjMatrix, item.modelMatrix);\r\n          mat4.multiply(item.lightMvpMatrix, lightViewProjMatrix, item.modelMatrix);\r\n          \r\n          item.mainDrawCall.uniform(\"uMVP\", item.mvpMatrix)\r\n          .uniform(\"uModelMatrix\", item.modelMatrix)\r\n          .uniform(\"uMVPFromLight\", item.lightMvpMatrix)\r\n          .uniform(\"uWithLighting\", withlight);\r\n          item.shadowDrawCall.uniform(\"uMVP\", item.lightMvpMatrix);          \r\n        }\r\n        for (var i = 0, len = boxes.length; i < len; ++i) {\r\n          if (boxes[i].visible)\r\n            updateUniforms(boxes[i]);\r\n        }\r\n        for (var i = 0, len = spheres.length; i < len; ++i) {\r\n          if (spheres[i].visible)\r\n            updateUniforms(spheres[i], (spheres[i].contact || i < SPOOL_OFFSET) ? 1.0 : 0.0);\r\n        }\r\n        for (var i = 0, len = netspheres.length; i < len; ++i) {\r\n          if (netspheres[i].visible)\r\n            updateUniforms(netspheres[i], 0.3);\r\n        }\r\n\r\n        // Draw to shadow buffer.\r\n        app.drawFramebuffer(shadowBuffer).clear();\r\n        mat4.multiply(draw_transform, lightViewProjMatrix, depth_to_world_transform);\r\n        depthseg.draw(draw_transform, null, null, shadowBuffer.depthTexture.currentUnit);\r\n        for (var i = 0, len = boxes.length; i < len; ++i) {\r\n          if (boxes[i].visible)\r\n            boxes[i].shadowDrawCall.draw();\r\n        }\r\n        for (var i = 0, len = SPOOL_OFFSET; i < len; ++i) {\r\n          if (spheres[i].visible)\r\n            spheres[i].shadowDrawCall.draw();\r\n        }\r\n\r\n\r\n        // Draw to screen.\r\n        app.defaultDrawFramebuffer().clear();\r\n        depthseg.draw(depth_mvp, draw_transform, light_position_depth, shadowBuffer.depthTexture.currentUnit);\r\n        for (var i = 0, len = boxes.length; i < len; ++i) {\r\n          if (boxes[i].visible)\r\n            boxes[i].mainDrawCall.draw();\r\n        }\r\n        for (var i = 0, len = spheres.length; i < len; ++i) {\r\n          if (spheres[i].visible)\r\n            spheres[i].mainDrawCall.draw();\r\n        }\r\n        for (var i = 0, len = netspheres.length; i < len; ++i) {\r\n          if (netspheres[i].visible)\r\n            netspheres[i].mainDrawCall.draw();\r\n        }\r\n\r\n        timer.end();\r\n        requestAnimationFrame(draw);\r\n      }\r\n      requestAnimationFrame(draw);        \r\n    };\r\n \r\n    for (let i = 0; i < 3; i++) {\r\n      images.push(new Image());\r\n      images[i].onload = image_onload;\r\n    }\r\n    Ammo().then(function(Ammo) {\r\n      images[0].src = \"webgl.png\";\r\n      images[1].src = \"grid.png\";\r\n      images[2].src = \"bone.png\";\r\n    });\r\n  </script>\r\n</body>\r\n</html>\r\n\r\n<!--\r\nThis code is reusing some of the code from  picogl.js/examples/shadow.html, so \r\nincluding the license.\r\n-->\r\n<!--\r\n  The MIT License (MIT)\r\n\r\n  Copyright (c) 2017 Tarek Sherif\r\n\r\n  Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n  this software and associated documentation files (the \"Software\"), to deal in\r\n  the Software without restriction, including without limitation the rights to\r\n  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n  the Software, and to permit persons to whom the Software is furnished to do so,\r\n  subject to the following conditions:\r\n\r\n  The above copyright notice and this permission notice shall be included in all\r\n  copies or substantial portions of the Software.\r\n\r\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n-->"
  },
  {
    "path": "gesture/indexaframe.html",
    "content": "<!DOCTYPE html>\r\n<html>\r\n<head>\r\n  <title>Depth Capture Based Hand Interaction Demo</title>\r\n  <script src=\"../libs/ammo.js/ammo.js\"></script>\r\n  <script src=\"../libs/aframe/aframe-v0.8.0.js\"></script>\r\n  <script src=\"../libs/gl-matrix.js\"></script>\r\n  <script src=\"../libs/picogl.js/picogl.js\"></script>\r\n  <script src=\"../libs/picogl.js/utils.js\"></script>\r\n  <script src=\"../depth-camera.js\"></script>\r\n  <script src=\"depth_and_segments.js\"></script>\r\n</head>\r\n<style>\r\nhtml {\r\n  overflow: hidden;\r\n}\r\nbody {\r\n  display: flex;\r\n  flex-direction: column;\r\n  font-family: 'Roboto', 'Noto', sans-serif;\r\n  line-height: 1.5;\r\n  background-color: #fbfbfb;\r\n  margin: 0;\r\n  text-align:center;\r\n}\r\n.info {\r\n  position: absolute;\r\n  top: 0px; width: 100%;\r\n  padding: 5px;\r\n  color: gray;\r\n}\r\n#timer {\r\n  position: absolute;\r\n  bottom: 10px;\r\n  left: 10px;\r\n  color: white;\r\n}\r\n#rotate-control {\r\n  position: absolute;\r\n  bottom: 20px;\r\n  left: 20px;\r\n  color: black;\r\n  z-index: 5;\r\n}\r\n</style>\r\n<body>\r\n  <div id=\"rotate-control\">\r\n    Rotate - head mounted camera: <input id=\"rotate-toggle\" type=\"checkbox\" checked>\r\n  </div>\r\n\r\n  <script type=\"text/javascript\">\r\n    \"use strict\";\r\n    let error = window.console.error;\r\n    window.console.error = (message, ...rest) => {\r\n      let target = document.querySelector('#console');\r\n      error.call(window.console, message, ...rest);\r\n\r\n      if (message instanceof Error) {\r\n        message = `${message.name}: ${message.message}`;\r\n      }\r\n\r\n      target.innerHTML += `${message}<br>`;\r\n    }\r\n\r\n    utils.addTimerElement();\r\n\r\n    const canvas = document.createElement(\"canvas\");\r\n    canvas.width = window.innerWidth;\r\n    canvas.height = window.innerHeight;\r\n    const gl = canvas.getContext(\"webgl2\", {antialias: false});\r\n    if (gl) {\r\n      gl.color_buffer_float_ext = gl.getExtension('EXT_color_buffer_float');\r\n      gl.WEBGL_get_buffer_sub_data_async =\r\n          gl.getExtension(\"WEBGL_get_buffer_sub_data_async\");\r\n      gl.texture_float_linear = gl.getExtension(\"OES_texture_float_linear\");\r\n    }\r\n    if (!gl || !gl.color_buffer_float_ext) {\r\n      alert(\"The demo doesn't run because it requires WebGL2 support.\");\r\n      document.body.innerHTML = \"The demo doesn't run because it requires WebGL2 support.\"\r\n    }\r\n\r\n    let scene;\r\n    let camera;\r\n    const DEBUG_DRAW_BONES = false;\r\n\r\n    let physics;\r\n    const viewscale = 15.0;\r\n    let depthseg;\r\n    const boxes = [];\r\n\r\n\r\n    document.getElementById(\"rotate-toggle\").addEventListener(\"change\", function() {\r\n      depthseg.setXZFlip(this.checked);\r\n    });\r\n\r\n    const depth_to_world_transform = mat4.create();\r\n    const depth_mvp = mat4.create();\r\n    const viewMatrix = mat4.create();\r\n    const viewProjMatrix = mat4.create();\r\n    const inverseViewProjMatrix = mat4.create();\r\n\r\n    // UNIFORMS\r\n/*    var projMatrix = mat4.create();\r\n    var viewMatrix = mat4.create();\r\n    var eyePosition = vec3.fromValues(0, 0.3, 0.4);\r\n    mat4.lookAt(viewMatrix, eyePosition, vec3.fromValues(0, 0, 0), vec3.fromValues(0, 1, 0));\r\n\r\n    var viewProjMatrix = mat4.create();\r\n    let inverseViewProjMatrix = mat4.create();\r\n    let depth_mvp = depthseg.getMVPMatrix();\r\n    const depth_to_world_transform = mat4.create();\r\n    const world_to_depth_transform = mat4.create();\r\n\r\n    var lightPosition = vec3.fromValues(0.7, 0.5, 0.1); \r\n    var lightViewMatrix = mat4.create();\r\n    var lightViewProjMatrix = mat4.create();\r\n    const light_position_depth = vec3.create();\r\n    mat4.lookAt(lightViewMatrix, lightPosition, vec3.fromValues(0, 0, 0), vec3.fromValues(0, 1, 0));\r\n    updateMatrices();    \r\n\r\n    function updateMatrices() {\r\n      mat4.perspective(projMatrix, Math.PI / 2, window.innerWidth / window.innerHeight, 0.1, 10.0);\r\n      mat4.multiply(viewProjMatrix, projMatrix, viewMatrix);\r\n      mat4.multiply(lightViewProjMatrix, projMatrix, lightViewMatrix);\r\n      mat4.invert(inverseViewProjMatrix, viewProjMatrix);\r\n      depth_mvp = depthseg.getMVPMatrix();\r\n      mat4.multiply(depth_to_world_transform, inverseViewProjMatrix, depth_mvp);\r\n      mat4.invert(world_to_depth_transform, depth_to_world_transform);\r\n      vec3.transformMat4(light_position_depth, lightPosition, world_to_depth_transform);\r\n    }*/\r\n\r\n    const SPOOL_OFFSET = 0;\r\n    let spheres = [];\r\n    var netspheres = [];\r\n    let transform;\r\n\r\n    // Temporary variables, preallocated.\r\n    const temp = new glMatrix.ARRAY_TYPE(3);\r\n    const temp1 = new glMatrix.ARRAY_TYPE(3);\r\n    // keep track of sphere ids that are touching the scene objects.\r\n    const contact_spheres = new Set();\r\n\r\n    // btCollisionObjects.h constants.\r\n    const ACTIVE_TAG = 1;\r\n    const DISABLE_DEACTIVATION = 4;\r\n    const WANTS_DEACTIVATION = 3;\r\n    const CF_KINEMATIC_OBJECT = 2;\r\n    const DISABLE_SIMULATION = 5;\r\n    const CF_STATIC_OBJECT = 1;\r\n    const CF_NO_CONTACT_RESPONSE = 4;\r\n    const CF_CUSTOM_MATERIAL_CALLBACK = 8;\r\n    const CF_CHARACTER_OBJECT = 16;\r\n    let frameid = 1;\r\n    let previous_frameid = 1;\r\n    const SPHERES_OFFSET = 1000; // range of sphares used for bones offset.\r\n    const NETSPHERES_OFFSET = 10000; // index mark the beginning of the offset\r\n    // of an index of sphere used for large areas, e.g. arm, physics modeling.\r\n    let updateFingerSegments;\r\n    let updateMatrices;\r\n    \r\n    let camera3;\r\n    let bt_zero_vec3;\r\n    let bt_inertia;\r\n    let btvec;\r\n    let btquaternion;\r\n\r\n    window.onresize = function() {\r\n      if (camera3) // -> initialized\r\n        updateMatrices();\r\n    };\r\n\r\n    function sceneLoaded() {\r\n      depthseg = new DepthAndSegments(gl, scene.renderer.context);\r\n\r\n      bt_zero_vec3 = new Ammo.btVector3(0, 0, 0);\r\n      bt_inertia = new Ammo.btVector3(0, 0, 0);\r\n      btvec = new Ammo.btVector3(0, 0, 0);\r\n      btquaternion = new Ammo.btQuaternion(0, 0, 0, 0);\r\n\r\n      transform = transform || new Ammo.btTransform();\r\n      const children = scene.children;\r\n      for (let i = 0; i < children.length; i++) {\r\n        const child = children[i];\r\n        if (child.tagName == \"A-BOX\") {\r\n          boxes.push(child);\r\n        }\r\n      }\r\n\r\n      function addNewSphere(spheres) {\r\n        const sphere = {\r\n          translate: [0, 0, 0],\r\n          quat: [0, 0, 0, 1],\r\n          scale: [0.01 * viewscale, 0.01 * viewscale, 0.01 * viewscale],\r\n          mvpMatrix: mat4.create(),\r\n          modelMatrix: mat4.create(),\r\n          lightMvpMatrix: mat4.create(),\r\n          mass: 0,\r\n          visible: false,\r\n          frameid: 0\r\n        };\r\n        spheres.push(sphere);\r\n        return sphere;\r\n      };\r\n\r\n      for (let i = 0; i < 50; i++) {\r\n        addNewSphere(spheres);\r\n      }\r\n\r\n\r\n      function createRigidBodySphere(sp, index) {\r\n        let shape = new Ammo.btSphereShape(sp.scale[0]);\r\n        transform.setIdentity();\r\n        btvec.setValue(sp.translate[0], sp.translate[1], sp.translate[2]);\r\n        btquaternion.setValue(sp.quat[0], sp.quat[1], sp.quat[2], sp.quat[3]);\r\n        transform.setOrigin(btvec);\r\n        transform.setRotation(btquaternion);\r\n        let motionState = new Ammo.btDefaultMotionState(transform);\r\n\r\n        bt_inertia.setValue(0, 0, 0);\r\n        shape.calculateLocalInertia(sp.mass, bt_inertia);\r\n\r\n        let info = new Ammo.btRigidBodyConstructionInfo(sp.mass, motionState, shape, bt_inertia);\r\n        info.m_friction = 10.0; // high friction for hands.\r\n        let body = new Ammo.btRigidBody(info);\r\n        sp.physics_body = body;\r\n        body.setUserPointer(sp);\r\n        body.setUserIndex(index);\r\n        if (!sp.visible)\r\n          body.forceActivationState(DISABLE_SIMULATION);\r\n        sp.constraints = [];\r\n        if (sp.mass > 0) {\r\n          body.setActivationState(DISABLE_DEACTIVATION);\r\n        } else if (sp.hasOwnProperty(\"frameid\")) {\r\n          body.setCollisionFlags(CF_NO_CONTACT_RESPONSE | CF_STATIC_OBJECT);\r\n        }\r\n        physics.addRigidBody(body);\r\n      }\r\n\r\n      const tip = new glMatrix.ARRAY_TYPE(3);\r\n      const base = new glMatrix.ARRAY_TYPE(3);\r\n      const subtract = new glMatrix.ARRAY_TYPE(3);\r\n      const quaternion = new glMatrix.ARRAY_TYPE(4);\r\n      const draw_transform = mat4.create();\r\n      const yUnitVec3 = vec3.fromValues(0,1,0);\r\n      const far_away = new Ammo.btTransform();\r\n      far_away.setOrigin(new Ammo.btVector3(-200, -200, -200));\r\n\r\n      for (var i = 0, len = boxes.length; i < len; ++i)\r\n        createRigidBody(i);\r\n      for (var i = 0, len = spheres.length; i < len; ++i)\r\n        createRigidBodySphere(spheres[i], i + SPHERES_OFFSET);\r\n\r\n      const segbuffer = [];\r\n      function getSegBuffer(i) {\r\n        while(segbuffer.length <= i) {\r\n          segbuffer.push({world_tip: new glMatrix.ARRAY_TYPE(3), sp1: null,\r\n                          world_base: new glMatrix.ARRAY_TYPE(3), sp2: null,\r\n                          sp1_square: Number.MAX_VALUE,\r\n                          sp2_square: Number.MAX_VALUE});\r\n        }\r\n        return segbuffer[i];\r\n      }\r\n\r\n      function getSphereFromPool() {\r\n        for(let i = SPOOL_OFFSET; i < spheres.length; i++) {\r\n          if (spheres[i].frameid == frameid)\r\n            continue;\r\n          return spheres[i];\r\n        }\r\n        const sphere = addNewSphere(spheres);\r\n        createRigidBodySphere(sphere, SPHERES_OFFSET + spheres.length - 1);\r\n        return sphere;\r\n      }\r\n\r\n      // Convert scanned point values |p| to 3D |v|.\r\n      function convertTo3D(v, x, y, d) {\r\n        const depth = (depthseg.depth_scale * d + 0.007) * viewscale;\r\n        v[0] = depth * (x - depthseg.depth_offset[0]) * depthseg.depth_focal_inv[0];\r\n        v[1] = -depth * (y - depthseg.depth_offset[1]) * depthseg.depth_focal_inv[1];          \r\n        v[2] = -depth;\r\n      };\r\n\r\n      function initSegBuffer(seg, buffer) {\r\n        // TODO: fix horizontal orientation\r\n        // Convert segment endpoints to 3D world coordinates.\r\n        const p1 = seg;\r\n        const p2 = depthseg.getSegmentEnd(seg);         \r\n\r\n        convertTo3D(tip, p1.x, p1.y, p1.depth); \r\n        vec3.transformMat4(buffer.world_tip, tip, depth_to_world_transform);\r\n        convertTo3D(base, p2.x, p2.y, p2.depth); \r\n        vec3.transformMat4(buffer.world_base, base, depth_to_world_transform);\r\n\r\n        buffer.sp1 = null;\r\n        buffer.sp2 = null;\r\n        buffer.sp1_square = Number.MAX_VALUE;\r\n        buffer.sp2_square = Number.MAX_VALUE;\r\n        buffer.endpoint_base = !p2.hasOwnProperty(\"joint\");\r\n        buffer.endpoint_tip = !p1.hasOwnProperty(\"joint\");                   \r\n      };\r\n\r\n      const MATCH_SPHERE_LIMIT = 0.0004 * viewscale * viewscale; // 2cm\r\n      function getMatchingPreviousFrameSphere(world_center) {\r\n        let nearest = Number.MAX_VALUE;\r\n        let nearest_s = null;\r\n        for (let i = SPOOL_OFFSET, len = spheres.length; i < len; ++i) {\r\n          const s = spheres[i];\r\n          // If it wasn't used in previous frame or already allocated to\r\n          // other point, move to next.\r\n          if (s.frameid != previous_frameid || s.segment || s.contact == false)\r\n            continue;\r\n          const squared_distance = vec3.squaredDistance(s.translate, world_center);\r\n          if (squared_distance < nearest) {\r\n            nearest = squared_distance;\r\n            nearest_s = s;\r\n          }\r\n        }\r\n        if (nearest < MATCH_SPHERE_LIMIT)\r\n          return nearest_s;\r\n        return null;\r\n      }\r\n\r\n      // |force| is true for previous frame contact spheres - spheres that were\r\n      // holding the box. We map them to the nearest, so that the picked object\r\n      // wouldn't jump around.\r\n      // Except the potential contact points, the rest of depth segments\r\n      // endpoints are not mapped to previous frame's spheres, but always to\r\n      // a sphere not used in previous frame - cleaned history sphere from the\r\n      // pool is assigned for the depth point. \r\n      function assignContactSphereToSegmentEndPoint(buffer, spkey, segment, force) {\r\n        const sp = buffer[spkey];\r\n        if (sp == null)\r\n          return;\r\n        const c = (sp == buffer.sp1) ? buffer.world_tip : buffer.world_base;\r\n        sp.segment = segment;\r\n        sp.visible = DEBUG_DRAW_BONES;\r\n        // reposition the physics body\r\n        vec3.copy(sp.translate, c);\r\n        const body = sp.physics_body;\r\n        transform.setIdentity();\r\n        btvec.setValue(c[0], c[1], c[2]);\r\n        transform.setOrigin(btvec);\r\n        body.setWorldTransform(transform);\r\n        body.getMotionState().setWorldTransform(transform);\r\n        // if (sp.frameid == 0 || !contact) {\r\n          body.setLinearVelocity(bt_zero_vec3);\r\n          body.setAngularVelocity(bt_zero_vec3);\r\n          body.forceActivationState(ACTIVE_TAG);\r\n          body.setCollisionFlags(CF_STATIC_OBJECT);\r\n          body.updateInertiaTensor();\r\n        // }\r\n        // if contact is not forced, make it so that it happens only when fingers\r\n        // are well distinguished.\r\n        sp.contact = force || (((segment.far_left.distance2D | 0) +\r\n                                (segment.far_right.distance2D | 0) > 4) &&\r\n                               (segment.count_left + segment.count_right > 8));\r\n        sp.segment_id = segment.index; // debugging purpose only.\r\n        sp.frameid = frameid;\r\n        sp.buffer = buffer;\r\n      }\r\n\r\n      function dropObjectsHeldBySphere(sp, index) {\r\n        if (sp.constraints.length > 0)\r\n          contact_spheres.delete(index);\r\n        for (let j = 0; j < sp.constraints.length; j++) {\r\n          const constraint = sp.constraints[j];\r\n          // remove constraints holding the world object.\r\n          const wbox = boxes[constraint.world_item];\r\n          // TODO: remove constraints from other item.\r\n          const finger0 = wbox.constraints[0].finger_item;\r\n          const finger1 = wbox.constraints[1].finger_item;\r\n          \r\n          if (finger0 != index) {\r\n            const s0cons = spheres[finger0].constraints;\r\n            s0cons.splice(s0cons.indexOf(wbox.constraints[0]), 1);\r\n            if (s0cons.length == 0)\r\n              contact_spheres.delete(finger0);           \r\n          } else if (finger1 != index) {\r\n            const s0cons = spheres[finger1].constraints;\r\n            s0cons.splice(s0cons.indexOf(wbox.constraints[1]), 1);           \r\n            if (s0cons.length == 0)\r\n              contact_spheres.delete(finger1);           \r\n          }\r\n\r\n          if(wbox.constraints.indexOf(constraint) == -1)\r\n            console.error(\"wboxcindex == -1\");\r\n\r\n          wbox.physics_body.getCollisionShape().calculateLocalInertia(wbox.mass, bt_inertia);   \r\n          wbox.physics_body.setMassProps(wbox.mass, bt_inertia);\r\n          wbox.holding_vector_recent = [];\r\n           \r\n          wbox.constraints.length = 0;\r\n\r\n        }\r\n        sp.constraints.length = 0;\r\n      }\r\n\r\n      function filterOutNoise(v, list) {\r\n        // Filter position noise.\r\n        const p = list.length > 6 ? list.shift() : new glMatrix.ARRAY_TYPE(3);\r\n        vec3.copy(p, v);\r\n        list.push(p);\r\n\r\n        if (list.length < 5)\r\n          return;\r\n\r\n        vec3.copy(temp, v);\r\n        for (let i = 0; i < list.length - 1; i++)\r\n          vec3.add(temp, temp, list[i]);\r\n        vec3.normalize(temp1, temp);\r\n        \r\n        let maxdiffindex = 0;\r\n        let maxdiff = vec3.squaredDistance(temp1, list[0]);\r\n        for (let i = 1; i < list.length; i++) {\r\n          const diff = vec3.squaredDistance(temp1, list[i]);\r\n          if (diff > maxdiff) {\r\n            maxdiffindex = i;\r\n            maxdiff = diff;\r\n          }\r\n        }\r\n        // remove max diff from computation\r\n        vec3.subtract(temp, temp, list[maxdiffindex]);\r\n        vec3.normalize(v, temp);\r\n      }\r\n\r\n      function assignSphereToPoint(sp, x, y, d) {\r\n        const body = sp.physics_body;\r\n        convertTo3D(temp, x, y, d); \r\n        const c = sp.translate;\r\n        vec3.transformMat4(c, temp, depth_to_world_transform);\r\n        \r\n        sp.visible = DEBUG_DRAW_BONES;\r\n        // reposition the physics body\r\n        transform.setIdentity();\r\n        btvec.setValue(c[0], c[1], c[2]);\r\n        transform.setOrigin(btvec);\r\n        body.setWorldTransform(transform);\r\n        body.getMotionState().setWorldTransform(transform);\r\n        // if (sp.frameid == 0 || !contact) {\r\n          body.setLinearVelocity(bt_zero_vec3);\r\n          body.setAngularVelocity(bt_zero_vec3);\r\n          body.forceActivationState(ACTIVE_TAG);\r\n          body.setCollisionFlags(CF_STATIC_OBJECT);\r\n          body.updateInertiaTensor();\r\n        // }\r\n        sp.frameid = frameid;\r\n        sp.contact = false;\r\n      }\r\n\r\n      function updateNet() {\r\n        for (let i = netspheres.length; i < depthseg.out.net.length; i++) {\r\n          const sp = addNewSphere(netspheres);\r\n          createRigidBodySphere(sp, i + NETSPHERES_OFFSET);\r\n        }\r\n        const width = out.netw;\r\n        const height = out.neth;\r\n        const d = depthseg.getDepthNonSkeleton;\r\n        for (let j = 1; j < height - 1; j++) {\r\n          for (let i = 1 + j * width, end = i + width - 2; i < end; i++) {\r\n            const n = out.net[i];\r\n            const sp = netspheres[i];            \r\n            if (n == -1) {\r\n              // hide visible and physics.\r\n              sp.visible = false;\r\n              const body = sp.physics_body;\r\n              body.setLinearVelocity(bt_zero_vec3);\r\n              body.setAngularVelocity(bt_zero_vec3);\r\n              body.setCollisionFlags(CF_NO_CONTACT_RESPONSE | CF_STATIC_OBJECT);\r\n              body.setActivationState(DISABLE_SIMULATION);\r\n              continue;\r\n            }\r\n            const x = n >> 16, y = n & 0xFFFF;\r\n            assignSphereToPoint(sp, x, y, d(x, y));\r\n          }\r\n        }        \r\n      }        \r\n\r\n      updateMatrices = function() {\r\n        // TODO: update when changed only\r\n        camera3 = camera3 || camera.object3D.children[0];\r\n        if (!camera3.isPerspectiveCamera)\r\n          throw \"Perspective camera API access error\";\r\n\r\n        // TODO: remove multiplying by projmatrix.\r\n        const projMatrix = camera3.projectionMatrix.elements;\r\n        const viewMatrix = camera3.matrixWorldInverse.elements;\r\n        mat4.multiply(viewProjMatrix, projMatrix, viewMatrix);\r\n        mat4.invert(inverseViewProjMatrix, viewProjMatrix);\r\n        \r\n        mat4.multiply(depth_mvp, camera3.projectionMatrix.elements, depthMesh.modelViewMatrix.elements);\r\n        mat4.multiply(depth_to_world_transform, inverseViewProjMatrix, depth_mvp);\r\n      }\r\n\r\n      updateFingerSegments = function() {\r\n        updateMatrices();\r\n        previous_frameid = frameid;\r\n        frameid = ((frameid + 1) & 0xFFFFFFFF) || 1;\r\n\r\n        // For all the segment endpoints calculate 3D values. We will use those\r\n        // in several traversals below.\r\n        const segment_data = depthseg.out.segment_data;\r\n        let keys = Object.keys(depthseg.out.segment_data);\r\n        for (let k = 0; k < keys.length; k++) {\r\n          const segment = segment_data[keys[k]];\r\n          const buffer = getSegBuffer(k);\r\n          initSegBuffer(segment, buffer);\r\n        }\r\n\r\n        // Identify endpoints (remove the points where two segments touch).\r\n        // We do this so there are less points that could cause tracking/mapping\r\n        // problems.\r\n        let endpoints = 0;\r\n        for (let k = 0; k < keys.length; k++) {\r\n          const buffer = getSegBuffer(k);\r\n          endpoints += ((buffer.endpoint_base ? 1 : 0) +\r\n                        (buffer.endpoint_tip ? 1 : 0));\r\n        }\r\n\r\n        // Start from previous frame contact points and get the closest points\r\n        // the latest segments to the previous frame contact points.\r\n        let to_assign = Math.min(contact_spheres.size, endpoints);\r\n        while (to_assign > 0) {\r\n          for (i of contact_spheres) {\r\n            const s = spheres[i];\r\n            if (s.segment != null)\r\n              continue;\r\n            // Get the closest current segment endpoint.\r\n            let nearest = Number.MAX_VALUE;\r\n            let nearest_k = -1;\r\n            let nearest_key = \"sp1\";\r\n            for (let k = 0; k < keys.length; k++) {\r\n              const buffer = getSegBuffer(k);\r\n              let squared_distance = buffer.endpoint_tip ?\r\n                                     vec3.squaredDistance(s.translate, buffer.world_tip) :\r\n                                     Number.MAX_VALUE;\r\n              if (squared_distance < nearest && squared_distance < buffer.sp1_square) {\r\n                nearest = squared_distance;\r\n                nearest_k = k;\r\n                nearest_key = \"sp1\";\r\n              }\r\n              squared_distance = buffer.endpoint_base ?\r\n                                 vec3.squaredDistance(s.translate, buffer.world_base) :\r\n                                 Number.MAX_VALUE;\r\n              if (squared_distance < nearest && squared_distance < buffer.sp2_square) {\r\n                nearest = squared_distance;\r\n                nearest_k = k;\r\n                nearest_key = \"sp2\";\r\n              }\r\n            }\r\n            if (nearest_k == -1)\r\n              continue; // This one doesn't get assigned.\r\n            const buffer = getSegBuffer(nearest_k);\r\n            if (buffer[nearest_key] != null) {\r\n              // There is another sphere claiming it is the closest to the\r\n              // segment endpoint. Invalidate it and do that sphere again.\r\n              to_assign++;\r\n              buffer[nearest_key].segment = null;\r\n              buffer[nearest_key + \"_square\"] = Number.MAX_VALUE; \r\n            }\r\n            buffer[nearest_key] = s;\r\n            buffer[nearest_key + \"_square\"] = nearest; \r\n            to_assign--;\r\n            s.segment = segment_data[keys[nearest_k]];\r\n          }\r\n        }\r\n\r\n\r\n        const TEN_CM_SQUARE = 0.01 * viewscale * viewscale;\r\n        // The final step in assigning previous joints - based on\r\n        // buffer.spX.s(phere), \r\n        function bothHoldsValidAssignment(key, buffer) {\r\n          // If both ends of one segment got assigned as contact points then\r\n          // we have an erroneous situation: contact points should be on\r\n          // different fingers, and previous frame fingertip is probably not\r\n          // visible in this frame so it got reassigned to the closest but\r\n          // wrong point. drop the box.\r\n          if (buffer.sp2 && buffer.sp1)\r\n            return false;\r\n          return buffer[key + \"_square\"] < TEN_CM_SQUARE;\r\n        }\r\n\r\n        for (let k = 0; k < keys.length; k++) {\r\n          const buffer = getSegBuffer(k);\r\n          // We need another sub-step here: check the distances and accept\r\n          // those that are the closest but not the ones that suddenly change\r\n          // the orientation. The idea is to avoid sudden jumps when finger is\r\n          // not visible. For now, drop the object as code bellow will not\r\n          // assign the sphere.\r\n          if (buffer.endpoint_tip && buffer.sp1 &&\r\n              bothHoldsValidAssignment(\"sp1\", buffer)) {\r\n            assignContactSphereToSegmentEndPoint(buffer, \"sp1\", buffer.sp1.segment, true);\r\n          }\r\n          if (buffer.endpoint_base && buffer.sp2 &&\r\n              bothHoldsValidAssignment(\"sp2\", buffer)) {\r\n            assignContactSphereToSegmentEndPoint(buffer, \"sp2\", buffer.sp2.segment, true);\r\n          }\r\n        }\r\n        \r\n        // Among other points, get the mapping to previous when they are nearby.\r\n        for (let k = 0; k < keys.length; k++) {\r\n          const segment = segment_data[keys[k]];\r\n          const buffer = getSegBuffer(k);\r\n          if (buffer.endpoint_tip && !buffer.sp1) {\r\n            buffer.sp1 = getMatchingPreviousFrameSphere(buffer.world_tip);\r\n            assignContactSphereToSegmentEndPoint(buffer, \"sp1\", segment);\r\n          }\r\n          if (buffer.endpoint_base && !buffer.sp2) {\r\n            buffer.sp2 = getMatchingPreviousFrameSphere(buffer.world_base);\r\n            assignContactSphereToSegmentEndPoint(buffer, \"sp2\", segment);\r\n          }\r\n        }\r\n\r\n        for (let k = 0; k < keys.length; k++) {\r\n          const segment = segment_data[keys[k]];\r\n          const buffer = getSegBuffer(k);\r\n          if (buffer.endpoint_tip && !buffer.sp1) {\r\n            // Get from the pool.\r\n            buffer.sp1 = getSphereFromPool();\r\n            assignContactSphereToSegmentEndPoint(buffer, \"sp1\", segment);\r\n          }\r\n          if (buffer.endpoint_base && !buffer.sp2) {\r\n            buffer.sp2 = getSphereFromPool();\r\n            assignContactSphereToSegmentEndPoint(buffer, \"sp2\", segment);\r\n          }\r\n        }\r\n\r\n        // If 2 fingers holding the object are not holding it anymore, drop the\r\n        // object.\r\n        for (let i = SPOOL_OFFSET, len = spheres.length; i < len; ++i) {\r\n          const sp = spheres[i];\r\n          const body = sp.physics_body;\r\n\r\n          if (sp.frameid == previous_frameid) {\r\n            body.setLinearVelocity(bt_zero_vec3);\r\n            body.setAngularVelocity(bt_zero_vec3);\r\n            // getBroadphaseProxy().masks and groups are not compiled in,\r\n            // DISABLE_SIMULATION is not honored so the way to avoid interaction\r\n            // of pool items is to add CF_NO_CONTACT_RESPONSE flag.\r\n            // As this means that the collision is still computed, we move the\r\n            // objects far away to get them processed out during broad phase.\r\n            body.setCollisionFlags(CF_NO_CONTACT_RESPONSE | CF_STATIC_OBJECT);\r\n            body.setActivationState(DISABLE_SIMULATION);\r\n            body.updateInertiaTensor();\r\n            // body.setWorldTransform(far_away);\r\n            // body.getMotionState().setWorldTransform(far_away);\r\n            // remove all the constraints this body has in the world.\r\n            dropObjectsHeldBySphere(sp, i);\r\n          }\r\n          sp.segment = null;\r\n          if (sp.frameid != frameid) {\r\n            sp.frameid = 0;\r\n            sp.visible = false; //sp.physics_body.isActive(); // false;\r\n            sp.buffer = null;\r\n          }\r\n        }\r\n\r\n        // Non contact areas get spheres assigned too.\r\n        for (let k = 0; k < keys.length; k++) {\r\n          const segment = segment_data[keys[k]];\r\n          const interpolated_count = depthseg.getSegmentInterpolatedCount(segment);\r\n          for (let i = 0; i < interpolated_count; i++) {\r\n            depthseg.getInterpolatedPoint(temp, segment, i);\r\n            const sp = getSphereFromPool();\r\n            assignSphereToPoint(sp, temp[0], temp[1], temp[2]);\r\n          }\r\n          if (segment.hasOwnProperty(\"joint\")) {\r\n            const sp = getSphereFromPool();\r\n            assignSphereToPoint(sp, segment.x, segment.y, segment.depth);            \r\n          }\r\n        }\r\n          \r\n        // World objects that are hold are getting the rotation from position\r\n        // of fingers holding them.\r\n        for (let i = 0; i < boxes.length; i++) {\r\n          if (boxes[i].constraints.length == 1)\r\n            console.error(\"shouldnt be 1\");\r\n          if (boxes[i].constraints.length > 0) {\r\n            const wb = boxes[i];\r\n            const sp0 = spheres[wb.constraints[0].finger_item];\r\n            const sp1 = spheres[wb.constraints[1].finger_item];\r\n            vec3.subtract(subtract, sp1.translate, sp0.translate);\r\n            \r\n            // If length between fingers is > threshold * initial holding length,\r\n            // drop it.\r\n            const hold_length = vec3.length(subtract);\r\n            if (hold_length > 1.5 * wb.holding_length) {\r\n              // drop the box.\r\n              dropObjectsHeldBySphere(sp0, wb.constraints[0].finger_item);\r\n              continue;\r\n            }\r\n\r\n            //  normalize subtract:\r\n            vec3.scale(subtract, subtract, 1 / hold_length);\r\n\r\n            // average holding vector to filter out spikes.\r\n            wb.holding_vector_recent = wb.holding_vector_recent || [];\r\n            filterOutNoise(subtract, wb.holding_vector_recent);\r\n\r\n            quat.rotationTo(quaternion, wb.holding_vector, subtract);\r\n            quat.multiply(quaternion, quaternion, wb.holding_quat);\r\n\r\n            const body = wb.physics_body;\r\n            transform.setIdentity();\r\n            vec3.lerp(subtract, sp0.translate, sp1.translate, 0.5);\r\n\r\n            vec3.add(temp, subtract, wb.center_offset);\r\n            btvec.setValue(temp[0], temp[1], temp[2]);\r\n            transform.setOrigin(btvec);\r\n            btquaternion.setValue(quaternion[0], quaternion[1], quaternion[2], quaternion[3]);\r\n            transform.setRotation(btquaternion);\r\n\r\n            body.setWorldTransform(transform);\r\n            body.getMotionState().setWorldTransform(transform);\r\n            // body.setLinearVelocity(bt_zero_vec3);\r\n            // body.setAngularVelocity(bt_zero_vec3);\r\n          }\r\n        }\r\n        updateNet();\r\n      }   \r\n    };\r\n    \r\n    function isAngleObtuse(a, b, c) {\r\n      vec3.subtract(temp, a, b);\r\n      vec3.subtract(temp1, c, b);\r\n      return (vec3.dot(temp, temp1) < 0);\r\n    }\r\n\r\n    // Can 2 manifolds hold the object? Both manifolds are on the same\r\n    // object, but different finger balls.\r\n    function canManifoldsHoldTheObject(con1, m2, ob, joint, finger) {\r\n      const m1 = con1.manifold;\r\n      const p1 = m1.getContactPoint(0);\r\n      const p2 = m2.getContactPoint(0);\r\n\r\n      // First, let's not allow picking objects from the lower side - to\r\n      // prevent this happening when carrying objects.\r\n      // It is box, so on.scale[0] is sufficient - otherwise, use the minimum.\r\n      const ymin = ob.pos[1] - ob.scale[0] * 0.5;\r\n      if (p1.get_m_positionWorldOnA().y() < ymin ||\r\n          p2.get_m_positionWorldOnA().y() < ymin) {\r\n        return false;\r\n      }\r\n      const pA1 = p1.get_m_localPointA();\r\n      const pB1 = p1.get_m_localPointB();\r\n      const pA2 = p2.get_m_localPointA();\r\n      const pB2 = p2.get_m_localPointB();\r\n\r\n      // As these are the boxes, holding if pBs are in the same.\r\n      // object to hold is a box, so simplify this so that we hold it on\r\n      // opposite sides of the box.\r\n      const xdiff = Math.abs(pA1.x() - pA2.x());\r\n      const ydiff = Math.abs(pA1.y() - pA2.y());\r\n      const zdiff = Math.abs(pA1.z() - pA2.z());\r\n      if (!(xdiff > 0.9 * ob.scale[0] || ydiff > 0.9 * ob.scale[1] ||\r\n          zdiff > 0.9 * ob.scale[2]))\r\n        return false;\r\n      // Some more math: the direction of the finger; towards or from within\r\n      // the box determines if fingers can hold the object.\r\n      const finger1 = spheres[con1.finger_item];\r\n      const joint1 = finger1.buffer.sp1 == finger1 ? finger1.buffer.world_base\r\n                                                   : finger1.buffer.world_tip;\r\n\r\n      // All together, we check 4 angles: joint - fingertip(contact) - center\r\n      // of object for both fingers and joint - fingertip(contact) - center of\r\n      // the grip between two points.\r\n      // If all angles are obtuse (> 90) then it can hold the box.\r\n      if (!isAngleObtuse(ob.pos, finger1.translate, joint1))\r\n        return false;\r\n\r\n      if (!isAngleObtuse(ob.pos, finger.translate, joint))\r\n        return false;\r\n\r\n      ob.center_offset = ob.center_offset || new glMatrix.ARRAY_TYPE(3);\r\n      vec3.lerp(ob.center_offset, finger.translate, finger1.translate, 0.5);\r\n\r\n      if (!isAngleObtuse(ob.center_offset, finger1.translate, joint1))\r\n        return false;\r\n\r\n      if (!isAngleObtuse(ob.center_offset, finger.translate, joint))\r\n        return false;\r\n\r\n      return true;\r\n    }\r\n\r\n    function processManifold(i0, i1, manifold) {\r\n      if (!manifold)\r\n          console.error(\"undefined manifold\");\r\n      i1 = i1 - SPHERES_OFFSET;\r\n      const ob = i0 < SPHERES_OFFSET ? boxes[i0] : spheres[i0 - SPHERES_OFFSET];\r\n      if (ob.constraints.length == 2 && ob.constraints[0].manifold == null)\r\n        return; // already two fingers holding the object, ignore other.\r\n      const finger = spheres[i1];\r\n      if (!finger.contact)\r\n        return;\r\n      const joint = finger.buffer.sp1 == finger ? finger.buffer.world_base\r\n                                                : finger.buffer.world_tip;\r\n      for (let i = 0; i < ob.constraints.length; i++) {\r\n        const con1 = ob.constraints[i];\r\n        if (canManifoldsHoldTheObject(con1, manifold, ob, joint, finger)) {\r\n          // We found the pair, so create real joints and clear the rest.\r\n          // Create constraint from the manifold.                     \r\n          const body = ob.physics_body;\r\n                        \r\n          const finger1 = spheres[con1.finger_item];\r\n          const pt = con1.manifold.getContactPoint(0);\r\n          finger1.constraints.push(con1);\r\n          con1.manifold = null;\r\n\r\n          contact_spheres.add(con1.finger_item);\r\n\r\n          // The second finger:\r\n          const pt2 = manifold.getContactPoint(0);\r\n          const con2 = {world_item: i0, finger_item: i1, manifold: null};\r\n          ob.constraints = [con1, con2]; // remove all other\r\n          finger.constraints.push(con2);\r\n      \r\n          contact_spheres.add(i1);\r\n\r\n          ob.holding_vector = ob.holding_vector || new glMatrix.ARRAY_TYPE(3);\r\n          vec3.subtract(ob.holding_vector, finger.translate, finger1.translate);\r\n          ob.holding_length = vec3.length(ob.holding_vector);\r\n          vec3.scale(ob.holding_vector, ob.holding_vector, 1 / ob.holding_length);\r\n          ob.holding_quat = quat.clone(ob.quat);\r\n\r\n          vec3.lerp(ob.center_offset, finger.translate, finger1.translate, 0.5);\r\n          vec3.subtract(ob.center_offset, ob.pos, ob.center_offset);\r\n\r\n          body.getCollisionShape().calculateLocalInertia(0, bt_inertia);   \r\n          body.setMassProps(0, bt_inertia);\r\n          body.setLinearVelocity(bt_zero_vec3);\r\n          body.setAngularVelocity(bt_zero_vec3);\r\n          // body.setCollisionFlags(body.getCollisionFlags() | (CF_KINEMATIC_OBJECT | ~CF_STATIC_OBJECT));\r\n          body.updateInertiaTensor();\r\n          return;\r\n        }\r\n      }\r\n\r\n      // Since it is not possible to hold an object, cache the manifold.\r\n      const con = {world_item: i0, finger_item: i1, manifold: manifold};\r\n      ob.constraints.push(con);\r\n    }\r\n\r\n    function createRigidBody(index) {\r\n      const box = boxes[index];\r\n      const scalestr = box.attributes.getNamedItem(\"scale\").value.slice(0);\r\n      const posstr = box.attributes.getNamedItem(\"position\").value.slice(0);\r\n      const mass = JSON.parse(box.attributes.getNamedItem(\"mass\").value);\r\n      const scale = JSON.parse(\"[\" + scalestr.replace(/ /g, ',') + \"]\");\r\n      box.scale = scale; // it is used in other demo, so keep it behaving the same until refactoring common code.\r\n      const position = JSON.parse(\"[\" + posstr.replace(/ /g, ',') + \"]\");\r\n      let shape = new Ammo.btBoxShape(new Ammo.btVector3(scale[0] * 0.5, scale[1] * 0.5, scale[2] * 0.5));\r\n      transform = transform || new Ammo.btTransform();\r\n      transform.setIdentity();\r\n      transform.setOrigin(new Ammo.btVector3(position[0], position[1], position[2]));\r\n      let motionState = new Ammo.btDefaultMotionState(transform);\r\n\r\n      shape.calculateLocalInertia(mass, bt_inertia);\r\n\r\n      let info = new Ammo.btRigidBodyConstructionInfo(mass, motionState, shape, bt_inertia);\r\n      let body = new Ammo.btRigidBody(info);\r\n      // if (box.hasOwnProperty(\"frameid\"))\r\n      //   body.setCollisionFlags(body.getCollisionFlags() | CF_KINEMATIC_OBJECT);\r\n      box.physics_body = body;\r\n      body.setUserPointer(box);\r\n      body.setUserIndex(index);\r\n      box.constraints = [];\r\n      box.holding_vector = null;\r\n      if (mass > 0) {\r\n        body.setActivationState(DISABLE_DEACTIVATION);\r\n      }\r\n      physics.addRigidBody(body);\r\n    }\r\n\r\n    // Internal algorithm assumes box having translate and quat arrays.\r\n    // This makes it.\r\n    function updateBoxesData() {\r\n      for (let i = 1; i < boxes.length; i++) {\r\n        const box = boxes[i];\r\n        box.pos = box.pos || new glMatrix.ARRAY_TYPE(3);\r\n        box.quat = box.quat || new glMatrix.ARRAY_TYPE(4);\r\n        let state = box.physics_body.getMotionState();\r\n        state.getWorldTransform(transform);\r\n        const t = transform.getOrigin();\r\n        let q = transform.getRotation();\r\n        const bt = box.pos;\r\n        const bq = box.quat;\r\n        bt[0] = t.x();\r\n        bt[1] = t.y();\r\n        bt[2] = t.z();\r\n        bq[0] = q.x();\r\n        bq[1] = q.y();\r\n        bq[2] = q.z();\r\n        bq[3] = q.w();\r\n      }\r\n      return true;\r\n    }\r\n\r\n    function addConnectionsForContacts() {\r\n      const disp = physics.getDispatcher();\r\n      let data_updated_from_physics_world = false;\r\n      for (let i = 0, num = disp.getNumManifolds(); i < num; i++) {\r\n        const manifold = disp.getManifoldByIndexInternal(i);\r\n        const num_contacts = manifold.getNumContacts();\r\n        if (!num_contacts)\r\n          continue;\r\n        const i0 = manifold.getBody0().getUserIndex();\r\n        const i1 = manifold.getBody1().getUserIndex();\r\n        if(i0 > i1)\r\n          throw \"first one should be less than the second\";\r\n        if (i0 >= SPHERES_OFFSET)\r\n          continue; // let's pick only boxes.\r\n        if (i1 < SPHERES_OFFSET + SPOOL_OFFSET)\r\n          continue;\r\n        if (i1 >= NETSPHERES_OFFSET)\r\n          continue;\r\n        if (!manifold.getBody1().isActive())\r\n          continue;\r\n        data_updated_from_physics_world =\r\n            data_updated_from_physics_world || updateBoxesData();\r\n        processManifold(i0, i1, manifold);\r\n      }\r\n      // reset back intermediate data.\r\n      for (let i = 1; i < boxes.length; i++) {\r\n        const cons = boxes[i].constraints;\r\n        if (cons.length != 0 && // don't reset if empty already\r\n            (cons.length != 2 || cons[0].manifold != null)) {\r\n          cons.length = 0;         \r\n        }\r\n      }\r\n    }\r\n\r\n    function btToScene(s) {\r\n      let state = s.physics_body.getMotionState();\r\n      if (!state)\r\n        return;\r\n      state.getWorldTransform(transform);\r\n      let t = transform.getOrigin();\r\n      let q = transform.getRotation();\r\n      s.object3D.position.set(t.x(), t.y(), t.z());\r\n      s.object3D.quaternion.set(q.x(), q.y(), q.z(), q.w());\r\n    }\r\n\r\n    function updatePhysics(time_delta) {\r\n      if ((boxes[1].constraints.length & 1) != 0 ||\r\n          (boxes[2].constraints.length & 1) != 0 ||\r\n          (boxes[3].constraints.length & 1) != 0)\r\n        console.error(\"expected even number of constraints\");\r\n      physics.stepSimulation(time_delta, 10);\r\n      addConnectionsForContacts();\r\n\r\n      for (let i = 1; i < boxes.length; i++)\r\n        btToScene(boxes[i]);\r\n      for (let i = 0; i < SPOOL_OFFSET; i++)\r\n        btToScene(spheres[i]);\r\n    }\r\n\r\n    const handsView = new THREE.Matrix4();\r\n    // TODO: check the scale\r\n    handsView.lookAt(new THREE.Vector3(0, 0, -5),   // eye\r\n                     new THREE.Vector3(0, 0, 0),   // target\r\n                     new THREE.Vector3(0, 1, 0));  // up\r\n\r\n    const hands = {\r\n      uniforms: THREE.UniformsUtils.merge( [\r\n        THREE.UniformsLib[ \"fog\" ],\r\n        THREE.UniformsLib[ \"lights\" ],\r\n        {\r\n          \"u_depth_texture\": {value: null},\r\n          \"u_depth_scale\": { value: 1.0 },\r\n          \"u_depth_offset\": { value: [0.0, 0.0] },\r\n          \"u_depth_focal_length_inv\" : { value: [0.0, 0.0] },\r\n          \"u_depth_texture_size\" : { value: [0.0, 0.0] },\r\n          \"diffuse\": { value: new THREE.Color( 0xeeeeee ) },\r\n          \"specular\": { value: new THREE.Color( 0x111111 ) },\r\n          \"shininess\": { value: 30 },\r\n          \"opacity\": { value: 1 },\r\n          \"modelViewMatrix1\": {value: handsView},\r\n        }\r\n\r\n      ] ),\r\n\r\n      fragmentShader:`#define PHONG\r\n      uniform vec3 diffuse;\r\n      uniform vec3 emissive;\r\n      uniform vec3 specular;\r\n      uniform float shininess;\r\n      uniform float opacity;\r\n\r\n      #include <common>\r\n      #include <packing>\r\n      #include <dithering_pars_fragment>\r\n      #include <color_pars_fragment>\r\n      #include <uv_pars_fragment>\r\n      #include <uv2_pars_fragment>\r\n      #include <map_pars_fragment>\r\n      #include <alphamap_pars_fragment>\r\n      #include <aomap_pars_fragment>\r\n      #include <lightmap_pars_fragment>\r\n      #include <emissivemap_pars_fragment>\r\n      #include <envmap_pars_fragment>\r\n      #include <gradientmap_pars_fragment>\r\n      #include <fog_pars_fragment>\r\n      #include <bsdfs>\r\n      #include <lights_pars>\r\n      #include <lights_phong_pars_fragment>\r\n      #include <shadowmap_pars_fragment>\r\n      #include <bumpmap_pars_fragment>\r\n      #include <normalmap_pars_fragment>\r\n      #include <specularmap_pars_fragment>\r\n      #include <logdepthbuf_pars_fragment>\r\n      #include <clipping_planes_pars_fragment>\r\n\r\n      varying vec4 v_depth_color;\r\n      varying float v_valid;\r\n\r\n      void main() {\r\n\r\n        #include <clipping_planes_fragment>\r\n\r\n        if (v_valid != 0.0)\r\n          discard;\r\n        vec4 diffuseColor = vec4( diffuse, opacity );\r\n        // diffuseColor = v_depth_color;\r\n        ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\r\n        vec3 totalEmissiveRadiance = emissive;\r\n\r\n        #include <logdepthbuf_fragment>\r\n        #include <map_fragment>\r\n        #include <color_fragment>\r\n        #include <alphamap_fragment>\r\n        #include <alphatest_fragment>\r\n        #include <specularmap_fragment>\r\n        #include <normal_fragment>\r\n        #include <emissivemap_fragment>\r\n\r\n        // accumulation\r\n        #include <lights_phong_fragment>\r\n        #include <lights_template>\r\n\r\n        // modulation\r\n        #include <aomap_fragment>\r\n\r\n        vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\r\n\r\n        #include <envmap_fragment>\r\n\r\n        gl_FragColor = vec4( outgoingLight, diffuseColor.a );\r\n\r\n        #include <tonemapping_fragment>\r\n        #include <encodings_fragment>\r\n        #include <fog_fragment>\r\n        #include <premultiplied_alpha_fragment>\r\n        #include <dithering_fragment>\r\n\r\n      }`,\r\n\r\n      vertexShader: `#define PHONG\r\n      varying vec3 vViewPosition;\r\n      varying vec4 v_depth_color;\r\n\r\n      #ifndef FLAT_SHADED\r\n\r\n        varying vec3 vNormal;\r\n\r\n      #endif\r\n\r\n      #include <common>\r\n      #include <uv_pars_vertex>\r\n      #include <uv2_pars_vertex>\r\n      #include <displacementmap_pars_vertex>\r\n      #include <envmap_pars_vertex>\r\n      #include <color_pars_vertex>\r\n      #include <fog_pars_vertex>\r\n      #include <morphtarget_pars_vertex>\r\n      #include <skinning_pars_vertex>\r\n      #include <shadowmap_pars_vertex>\r\n      #include <logdepthbuf_pars_vertex>\r\n      #include <clipping_planes_pars_vertex>\r\n\r\n      varying float v_valid;\r\n      uniform float u_depth_scale;\r\n      uniform vec2 u_depth_offset;\r\n      uniform vec2 u_depth_focal_length_inv;\r\n      uniform sampler2D u_depth_texture;\r\n      uniform vec2 u_depth_texture_size;\r\n      uniform mat4 modelViewMatrix1;\r\n      vec3 depth_deproject(vec2 index, float depth) {\r\n        vec2 position2d = (index - u_depth_offset) * u_depth_focal_length_inv;\r\n        return vec3(position2d * depth, -depth);\r\n      }\r\n\r\n      void main() {\r\n\r\n        #include <uv_vertex>\r\n        #include <uv2_vertex>\r\n        #include <color_vertex>\r\n\r\n        #include <beginnormal_vertex>\r\n        #include <morphnormal_vertex>\r\n        #include <skinbase_vertex>\r\n        #include <skinnormal_vertex>\r\n        #include <defaultnormal_vertex>\r\n\r\n      #ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED\r\n\r\n        vNormal = normalize( transformedNormal );\r\n\r\n      #endif\r\n\r\n        #include <begin_vertex> // vec3 transformed = vec3( position )\r\n        // position.xy are in range [-0.5, 0.5]\r\n        float depth = texture2D(u_depth_texture, vec2(position.x, position.y) + 0.5).r;\r\n        v_valid = depth > 0.0001 ? 0.0 : 1.0;\r\n        float depth_scaled = u_depth_scale * depth;\r\n        vec2 index = (vec2(position.x, position.y) + 0.5) * u_depth_texture_size;\r\n        transformed = depth_deproject(index, depth_scaled);\r\n        \r\n        v_depth_color = vec4(depth, depth, depth, 1.0) * 10.0; // TODO: remove as it is only for testing\r\n        // #include <project_vertex>\r\n        vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\r\n        gl_Position = projectionMatrix * mvPosition;\r\n        #include <logdepthbuf_vertex>\r\n        #include <clipping_planes_vertex>\r\n\r\n        vViewPosition = - mvPosition.xyz;\r\n\r\n        // #include <worldpos_vertex>\r\n        #if defined( USE_ENVMAP ) || defined( PHONG ) || defined( PHYSICAL ) || defined( LAMBERT ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\r\n          vec4 worldPosition = modelMatrix * vec4(transformed, 1.0);\r\n        #endif\r\n        #include <envmap_vertex>\r\n        #include <shadowmap_vertex>\r\n        #include <fog_vertex>\r\n      }`\r\n    };\r\n\r\n    const hands_shadow = {\r\n      uniforms: THREE.UniformsUtils.merge([\r\n        THREE.UniformsLib.common,\r\n        THREE.UniformsLib.displacementmap,\r\n        {\r\n          \"u_depth_texture\": {value: null},\r\n          \"u_depth_scale\": { value: 1.0 },\r\n          \"u_depth_offset\": { value: [0.0, 0.0] },\r\n          \"u_depth_focal_length_inv\" : { value: [0.0, 0.0] },\r\n          \"u_depth_texture_size\" : { value: [0.0, 0.0] },\r\n          \"modelViewMatrix1\": {value: handsView},\r\n        }\r\n      ]),\r\n\r\n      fragmentShader:`\r\n      #define DEPTH_PACKING 3201\r\n      #if DEPTH_PACKING == 3200\r\n        uniform float opacity;\r\n      #endif\r\n      #include <common>\r\n      #include <packing>\r\n      #include <uv_pars_fragment>\r\n      #include <map_pars_fragment>\r\n      #include <alphamap_pars_fragment>\r\n      #include <logdepthbuf_pars_fragment>\r\n      #include <clipping_planes_pars_fragment>\r\n      varying float v_valid;\r\n      void main() {\r\n        if (v_valid != 0.0)\r\n          discard;\r\n        #include <clipping_planes_fragment>\r\n        vec4 diffuseColor = vec4( 1.0 );\r\n        #if DEPTH_PACKING == 3200\r\n          diffuseColor.a = opacity;\r\n        #endif\r\n        #include <map_fragment>\r\n        #include <alphamap_fragment>\r\n        #include <alphatest_fragment>\r\n        #include <logdepthbuf_fragment>\r\n        #if DEPTH_PACKING == 3200\r\n          gl_FragColor = vec4( vec3( gl_FragCoord.z ), opacity );\r\n        #elif DEPTH_PACKING == 3201\r\n          gl_FragColor = packDepthToRGBA( gl_FragCoord.z );\r\n        #endif\r\n      }\r\n      `,\r\n\r\n      vertexShader: `#include <common>\r\n      #include <uv_pars_vertex>\r\n      #include <displacementmap_pars_vertex>\r\n      #include <morphtarget_pars_vertex>\r\n      #include <skinning_pars_vertex>\r\n      #include <logdepthbuf_pars_vertex>\r\n      #include <clipping_planes_pars_vertex>\r\n\r\n      varying float v_valid;\r\n      uniform float u_depth_scale;\r\n      uniform vec2 u_depth_offset;\r\n      uniform vec2 u_depth_focal_length_inv;\r\n      uniform sampler2D u_depth_texture;\r\n      uniform vec2 u_depth_texture_size;\r\n      uniform mat4 modelViewMatrix1;\r\n      vec3 depth_deproject(vec2 index, float depth) {\r\n        vec2 position2d = (index - u_depth_offset) * u_depth_focal_length_inv;\r\n        return vec3(position2d * depth, -depth);\r\n      }\r\n\r\n      void main() {\r\n        #include <uv_vertex>\r\n        #include <skinbase_vertex>\r\n        #ifdef USE_DISPLACEMENTMAP\r\n          #include <beginnormal_vertex>\r\n          #include <morphnormal_vertex>\r\n          #include <skinnormal_vertex>\r\n        #endif\r\n        #include <begin_vertex>\r\n\r\n        // position.xy are in range [-0.5, 0.5]\r\n        float depth = texture2D(u_depth_texture, vec2(position.x, position.y) + 0.5).r;\r\n        v_valid = depth > 0.0001 ? 0.0 : 1.0;\r\n        float depth_scaled = u_depth_scale * depth;\r\n        vec2 index = (vec2(position.x, position.y) + 0.5) * u_depth_texture_size;\r\n        transformed = depth_deproject(index, depth_scaled);\r\n\r\n        #include <morphtarget_vertex>\r\n        #include <skinning_vertex>\r\n        #include <displacementmap_vertex>\r\n//        #include <project_vertex>\r\n        vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\r\n        gl_Position = projectionMatrix * mvPosition;\r\n\r\n        #include <logdepthbuf_vertex>\r\n        #include <clipping_planes_vertex>\r\n      }`\r\n    };\r\n\r\n    let depthMesh;\r\n    function recreateDepthMesh() {\r\n      let uniformsHands = THREE.UniformsUtils.clone(hands.uniforms);\r\n      \r\n      if (!scene.renderer.context.three_depth_texture) {\r\n        const texture = new THREE.Texture();\r\n        const texProperties = scene.renderer.properties.get(texture);\r\n        texProperties.__webglTexture = scene.renderer.context.depth_texture;\r\n        texProperties.__webglInit = true;\r\n        scene.renderer.context.three_depth_texture = texture;\r\n      }\r\n\r\n      // Continue construction when depth video is loaded as then we have video frame size available.\r\n      function depthVideoLoaded() {\r\n        if (camera.object3D.children.length < 1)\r\n          return;\r\n        if (depthMesh)\r\n          camera.object3D.remove(depthMesh);\r\n\r\n        function setDepthUniforms(uniforms) {\r\n          uniforms['u_depth_scale'].value = depthseg.depth_scale * viewscale;\r\n          uniforms['u_depth_focal_length_inv'].value = depthseg.depth_focal_inv;\r\n          uniforms['u_depth_offset'].value = depthseg.depth_offset;\r\n          uniforms['u_depth_texture_size'].value = [depthseg.width, depthseg.height];\r\n          uniforms['u_depth_texture'].value = scene.renderer.context.three_depth_texture;\r\n        };\r\n        setDepthUniforms(uniformsHands);\r\n        let material = new THREE.ShaderMaterial({uniforms: uniformsHands,\r\n            vertexShader: hands.vertexShader, fragmentShader: hands.fragmentShader,\r\n            lights: true, fog: false, side: THREE.DoubleSide});\r\n\r\n        depthMesh = new THREE.Mesh(new THREE.PlaneBufferGeometry(1, 1, depthseg.width, depthseg.height), material);\r\n\r\n        let uniformsHandsShadow = THREE.UniformsUtils.clone(hands_shadow.uniforms);\r\n        setDepthUniforms(uniformsHandsShadow);\r\n        depthMesh.customDepthMaterial = new THREE.ShaderMaterial({\r\n          uniforms: uniformsHandsShadow,\r\n          vertexShader: hands_shadow.vertexShader,\r\n          fragmentShader: hands_shadow.fragmentShader,\r\n          fog: false, side: THREE.DoubleSide, depthPacking: THREE.RGBADepthPacking,\r\n        });\r\n        \r\n /*       const posstr = camera.attributes.getNamedItem(\"position\").value.slice(0);\r\n        const position = JSON.parse(\"[\" + posstr.replace(/ /g, ',') + \"]\");\r\n        depthMesh.position.y = position[1];\r\n        depthMesh.position.z = position[2];*/\r\n        // depthMesh.rotation.set(-0.52, 0, 0);\r\n        depthMesh.position.y = 0.15; // about 15 centimeters above the HMD.\r\n        depthMesh.rotation.set(-0.15, 0, 0); // rotate depth camera a bit down.\r\n        depthMesh.scale.x = 1.5; // TODO: calculate.        \r\n        depthMesh.scale.y = 1.5;        \r\n        depthMesh.castShadow = true;\r\n        depthMesh.receiveShadow = true;\r\n        depthMesh.width = depthseg.width;\r\n        camera.object3D.add(depthMesh);\r\n      }\r\n      depthseg.depthVideoLoadedCallback = depthVideoLoaded;\r\n      if (depthseg.depth_focal_inv)\r\n        depthVideoLoaded();\r\n    }\r\n\r\n    AFRAME.registerSystem('physics', {\r\n      init: function () {\r\n        scene = document.querySelector('a-scene');\r\n        camera = document.querySelector('a-camera');\r\n        Ammo().then(function(Ammo) {\r\n          // Physics setup\r\n          var collisionConfiguration = new Ammo.btDefaultCollisionConfiguration();\r\n          var dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration);\r\n          var pairCache = new Ammo.btDbvtBroadphase();\r\n          var solver = new Ammo.btSequentialImpulseConstraintSolver();\r\n          physics = new Ammo.btDiscreteDynamicsWorld(dispatcher, pairCache, solver,collisionConfiguration);\r\n          const gravity = new Ammo.btVector3(0, -9.81 / viewscale, 0);\r\n          physics.setGravity(gravity);\r\n          sceneLoaded();\r\n        });\r\n      },\r\n      tick: function (now, delta) {\r\n        if (physics) {\r\n          if (depthseg.process(scene.renderer.context))\r\n            updateFingerSegments();\r\n          if (!depthMesh || depthMesh.width != depthseg.width)\r\n            recreateDepthMesh();\r\n          updatePhysics(delta);\r\n        }\r\n      }\r\n    });  \r\n\r\n    AFRAME.registerComponent('mass', {\r\n      schema: { type: 'number',default: NaN, },\r\n      init: function() {\r\n        this.el.mass = this.data;\r\n      }\r\n    });\r\n  </script>\r\n  <a-scene physics>\r\n    <a-assets>\r\n      <img id=\"webgl\" src=\"webgl.png\">\r\n      <img id=\"grid\" src=\"grid.png\">\r\n      <img id=\"bone\" src=\"bone.png\">\r\n    </a-assets>\r\n    <a-box src=\"#grid\" repeat=\"20 20\" color=\"#7BC8A4\" transparent=\"true\" opacity=\"0.5\" position=\"0 0 0\" scale=\"30 0.5 30\" mass=\"0\" shadow></a-box>\r\n    <a-box src=\"#webgl\" color=\"#4CC3D9\" position=\"1 0.75 0\" scale=\"1 1 1\" mass=\"5\" shadow></a-box>\r\n    <a-box src=\"#webgl\" color=\"#4CC3D9\" position=\"3 0.75 0\" scale=\"1 1 1\" mass=\"5\" shadow></a-box>\r\n    <a-box src=\"#webgl\" color=\"#FFC65D\" position=\"-1 2.75 0\" scale=\"1 1 1\" mass=\"5\" shadow></a-box>\r\n    <a-sky color=\"#ECECEC\"></a-sky>\r\n    <a-entity position=\"0 5 3\" rotation=\"-45 0 0\">\r\n      <a-camera></a-camera>\r\n    </a-entity>\r\n    <a-entity light=\"type: ambient; color: #BBB\"></a-entity>\r\n    <a-entity light=\"color: #FFF; intensity: 0.6; castShadow: true; shadowBias: -0.0001; shadowCameraTop: 10; shadowCameraRight: 10; shadowCameraBottom: -10; shadowCameraLeft: -10; shadowMapHeight:1024; shadowMapWidth:1024\" position=\"10 10 3\"></a-entity>  </a-scene>\r\n  <div class=\"info\">\r\n    Hand physics - depth camera capture demo.\r\n    <div>\r\n      <a href=\"https://github.com/01org/depth-camera-web-demo\">Source code on GitHub</a>\r\n    </div>\r\n    <div id=\"console\" style=\"color: red; font-size: x-large;\"></div>\r\n\r\n  </div>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "index.html",
    "content": "<style>\n  body {\n    font-family: 'Roboto', 'Noto', sans-serif;\n    line-height: 1.5;\n    background-color: #fbfbfb;\n    margin: 20px;\n  }\n\n  #contents {\n    display: flex;\n    flex-direction: row;\n    flex-wrap: wrap;\n  }\n\n  #contents > div {\n    padding: 16px;\n    width: 25vw;\n    min-width: 400px;\n    height: auto;\n  }\n\n  img {\n    width: 100%;\n    height: auto;\n    object-fit: scale-down;\n  }\n</style>\n\n<h1>Web Depth Camera Capture demos</h1>\n\n<div id=\"contents\">\n  <div>\n    <img src=\"gesture/hands_interaction.gif\">\n    <br>\n    <p>\n      Moving boxes using hands demo shows live depth captured mesh interaction with scene objects; combining 3D world and depth captured hands (or other objects) rendering and Bullet Physics. <a href=\"https://01org.github.io/depth-camera-web-demo/gesture/index.html\">Run the live demo here.</a>\n    </p>\n  </div>  \n  <div>\n    <img src=\"backgroundremoval.gif\">\n    <br>\n    <p>\n      Simple background removal implemented as flood-fill of background color to similarly colored pixels.\n      Works only with simple backgrounds - e.g. room walls on the demo gif.\n      <a href=\"https://01org.github.io/depth-camera-web-demo/depthdemo.html\">Run the live demo here.</a>\n    </p>\n  </div>  \n  <div>\n    <img src=\"typing_in_the_air/typing_in_the_air.gif\">\n    <br>\n    <p>\n      Typing in the air tutorial shows how to use depth stream and WebGL transform feedback to do simple gesture recognition.\n      Check the <a href=\"typing_in_the_air/doc/tutorial.html\">tutorial text</a> and\n      <a href=\"https://01org.github.io/depth-camera-web-demo/typing_in_the_air/front_capture_typing.html\">run the live demo here.</a>\n    </p>\n  </div>\n  <div>\n    <img src=\"https://github.com/01org/depthcamera-pointcloud-web-demo/raw/master/recording.gif\">\n    <br>\n    <p>\n      3D point cloud rendering demo shows how to render and synchronize depth and color video on GPU.\n      <a href=\"https://01org.github.io/depthcamera-pointcloud-web-demo/\">Run the live demo here.</a>\n    </p>\n  </div>\n  <div>\n    <img src=\"how_the_demo_looks.gif\">\n    <br>\n    <p>\n      HTML5 Depth Capture tutorial shows how to access depth stream, check the\n      <a href=\"https://01.org/chromium/blogs/astojilj/2017/depth-camera-capture-html5\">tutorial text</a>\n      or <a href=\"https://01org.github.io/depth-camera-web-demo/depthdemo.html\">run the live demo here.</a>\n    </p>\n  </div>\n</div>"
  },
  {
    "path": "libs/aframe/LICENSE.txt",
    "content": "The MIT License\n\nCopyright © 2015-2017 A-Frame authors.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "libs/aframe/aframe-v0.7.1.js",
    "content": "(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.exports=f()}else if(typeof define===\"function\"&&define.amd){define([],f)}else{var g;if(typeof window!==\"undefined\"){g=window}else if(typeof global!==\"undefined\"){g=global}else if(typeof self!==\"undefined\"){g=self}else{g=this}g.AFRAME = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){\n(function (process){\n/**\n * Tween.js - Licensed under the MIT license\n * https://github.com/tweenjs/tween.js\n * ----------------------------------------------\n *\n * See https://github.com/tweenjs/tween.js/graphs/contributors for the full list of contributors.\n * Thank you all, you're awesome!\n */\n\n\nvar _Group = function () {\n\tthis._tweens = {};\n\tthis._tweensAddedDuringUpdate = {};\n};\n\n_Group.prototype = {\n\tgetAll: function () {\n\n\t\treturn Object.keys(this._tweens).map(function (tweenId) {\n\t\t\treturn this._tweens[tweenId];\n\t\t}.bind(this));\n\n\t},\n\n\tremoveAll: function () {\n\n\t\tthis._tweens = {};\n\n\t},\n\n\tadd: function (tween) {\n\n\t\tthis._tweens[tween.getId()] = tween;\n\t\tthis._tweensAddedDuringUpdate[tween.getId()] = tween;\n\n\t},\n\n\tremove: function (tween) {\n\n\t\tdelete this._tweens[tween.getId()];\n\t\tdelete this._tweensAddedDuringUpdate[tween.getId()];\n\n\t},\n\n\tupdate: function (time, preserve) {\n\n\t\tvar tweenIds = Object.keys(this._tweens);\n\n\t\tif (tweenIds.length === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\ttime = time !== undefined ? time : TWEEN.now();\n\n\t\t// Tweens are updated in \"batches\". If you add a new tween during an update, then the\n\t\t// new tween will be updated in the next batch.\n\t\t// If you remove a tween during an update, it will normally still be updated. However,\n\t\t// if the removed tween was added during the current batch, then it will not be updated.\n\t\twhile (tweenIds.length > 0) {\n\t\t\tthis._tweensAddedDuringUpdate = {};\n\n\t\t\tfor (var i = 0; i < tweenIds.length; i++) {\n\n\t\t\t\tif (this._tweens[tweenIds[i]].update(time) === false) {\n\t\t\t\t\tthis._tweens[tweenIds[i]]._isPlaying = false;\n\n\t\t\t\t\tif (!preserve) {\n\t\t\t\t\t\tdelete this._tweens[tweenIds[i]];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttweenIds = Object.keys(this._tweensAddedDuringUpdate);\n\t\t}\n\n\t\treturn true;\n\n\t}\n};\n\nvar TWEEN = new _Group();\n\nTWEEN.Group = _Group;\nTWEEN._nextId = 0;\nTWEEN.nextId = function () {\n\treturn TWEEN._nextId++;\n};\n\n\n// Include a performance.now polyfill.\n// In node.js, use process.hrtime.\nif (typeof (window) === 'undefined' && typeof (process) !== 'undefined') {\n\tTWEEN.now = function () {\n\t\tvar time = process.hrtime();\n\n\t\t// Convert [seconds, nanoseconds] to milliseconds.\n\t\treturn time[0] * 1000 + time[1] / 1000000;\n\t};\n}\n// In a browser, use window.performance.now if it is available.\nelse if (typeof (window) !== 'undefined' &&\n         window.performance !== undefined &&\n\t\t window.performance.now !== undefined) {\n\t// This must be bound, because directly assigning this function\n\t// leads to an invocation exception in Chrome.\n\tTWEEN.now = window.performance.now.bind(window.performance);\n}\n// Use Date.now if it is available.\nelse if (Date.now !== undefined) {\n\tTWEEN.now = Date.now;\n}\n// Otherwise, use 'new Date().getTime()'.\nelse {\n\tTWEEN.now = function () {\n\t\treturn new Date().getTime();\n\t};\n}\n\n\nTWEEN.Tween = function (object, group) {\n\tthis._object = object;\n\tthis._valuesStart = {};\n\tthis._valuesEnd = {};\n\tthis._valuesStartRepeat = {};\n\tthis._duration = 1000;\n\tthis._repeat = 0;\n\tthis._repeatDelayTime = undefined;\n\tthis._yoyo = false;\n\tthis._isPlaying = false;\n\tthis._reversed = false;\n\tthis._delayTime = 0;\n\tthis._startTime = null;\n\tthis._easingFunction = TWEEN.Easing.Linear.None;\n\tthis._interpolationFunction = TWEEN.Interpolation.Linear;\n\tthis._chainedTweens = [];\n\tthis._onStartCallback = null;\n\tthis._onStartCallbackFired = false;\n\tthis._onUpdateCallback = null;\n\tthis._onCompleteCallback = null;\n\tthis._onStopCallback = null;\n\tthis._group = group || TWEEN;\n\tthis._id = TWEEN.nextId();\n\n};\n\nTWEEN.Tween.prototype = {\n\tgetId: function getId() {\n\t\treturn this._id;\n\t},\n\n\tisPlaying: function isPlaying() {\n\t\treturn this._isPlaying;\n\t},\n\n\tto: function to(properties, duration) {\n\n\t\tthis._valuesEnd = properties;\n\n\t\tif (duration !== undefined) {\n\t\t\tthis._duration = duration;\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tstart: function start(time) {\n\n\t\tthis._group.add(this);\n\n\t\tthis._isPlaying = true;\n\n\t\tthis._onStartCallbackFired = false;\n\n\t\tthis._startTime = time !== undefined ? time : TWEEN.now();\n\t\tthis._startTime += this._delayTime;\n\n\t\tfor (var property in this._valuesEnd) {\n\n\t\t\t// Check if an Array was provided as property value\n\t\t\tif (this._valuesEnd[property] instanceof Array) {\n\n\t\t\t\tif (this._valuesEnd[property].length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Create a local copy of the Array with the start value at the front\n\t\t\t\tthis._valuesEnd[property] = [this._object[property]].concat(this._valuesEnd[property]);\n\n\t\t\t}\n\n\t\t\t// If `to()` specifies a property that doesn't exist in the source object,\n\t\t\t// we should not set that property in the object\n\t\t\tif (this._object[property] === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Save the starting value.\n\t\t\tthis._valuesStart[property] = this._object[property];\n\n\t\t\tif ((this._valuesStart[property] instanceof Array) === false) {\n\t\t\t\tthis._valuesStart[property] *= 1.0; // Ensures we're using numbers, not strings\n\t\t\t}\n\n\t\t\tthis._valuesStartRepeat[property] = this._valuesStart[property] || 0;\n\n\t\t}\n\n\t\treturn this;\n\n\t},\n\n\tstop: function stop() {\n\n\t\tif (!this._isPlaying) {\n\t\t\treturn this;\n\t\t}\n\n\t\tthis._group.remove(this);\n\t\tthis._isPlaying = false;\n\n\t\tif (this._onStopCallback !== null) {\n\t\t\tthis._onStopCallback.call(this._object, this._object);\n\t\t}\n\n\t\tthis.stopChainedTweens();\n\t\treturn this;\n\n\t},\n\n\tend: function end() {\n\n\t\tthis.update(this._startTime + this._duration);\n\t\treturn this;\n\n\t},\n\n\tstopChainedTweens: function stopChainedTweens() {\n\n\t\tfor (var i = 0, numChainedTweens = this._chainedTweens.length; i < numChainedTweens; i++) {\n\t\t\tthis._chainedTweens[i].stop();\n\t\t}\n\n\t},\n\n\tdelay: function delay(amount) {\n\n\t\tthis._delayTime = amount;\n\t\treturn this;\n\n\t},\n\n\trepeat: function repeat(times) {\n\n\t\tthis._repeat = times;\n\t\treturn this;\n\n\t},\n\n\trepeatDelay: function repeatDelay(amount) {\n\n\t\tthis._repeatDelayTime = amount;\n\t\treturn this;\n\n\t},\n\n\tyoyo: function yoyo(yoyo) {\n\n\t\tthis._yoyo = yoyo;\n\t\treturn this;\n\n\t},\n\n\teasing: function easing(easing) {\n\n\t\tthis._easingFunction = easing;\n\t\treturn this;\n\n\t},\n\n\tinterpolation: function interpolation(interpolation) {\n\n\t\tthis._interpolationFunction = interpolation;\n\t\treturn this;\n\n\t},\n\n\tchain: function chain() {\n\n\t\tthis._chainedTweens = arguments;\n\t\treturn this;\n\n\t},\n\n\tonStart: function onStart(callback) {\n\n\t\tthis._onStartCallback = callback;\n\t\treturn this;\n\n\t},\n\n\tonUpdate: function onUpdate(callback) {\n\n\t\tthis._onUpdateCallback = callback;\n\t\treturn this;\n\n\t},\n\n\tonComplete: function onComplete(callback) {\n\n\t\tthis._onCompleteCallback = callback;\n\t\treturn this;\n\n\t},\n\n\tonStop: function onStop(callback) {\n\n\t\tthis._onStopCallback = callback;\n\t\treturn this;\n\n\t},\n\n\tupdate: function update(time) {\n\n\t\tvar property;\n\t\tvar elapsed;\n\t\tvar value;\n\n\t\tif (time < this._startTime) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (this._onStartCallbackFired === false) {\n\n\t\t\tif (this._onStartCallback !== null) {\n\t\t\t\tthis._onStartCallback.call(this._object, this._object);\n\t\t\t}\n\n\t\t\tthis._onStartCallbackFired = true;\n\t\t}\n\n\t\telapsed = (time - this._startTime) / this._duration;\n\t\telapsed = elapsed > 1 ? 1 : elapsed;\n\n\t\tvalue = this._easingFunction(elapsed);\n\n\t\tfor (property in this._valuesEnd) {\n\n\t\t\t// Don't update properties that do not exist in the source object\n\t\t\tif (this._valuesStart[property] === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tvar start = this._valuesStart[property] || 0;\n\t\t\tvar end = this._valuesEnd[property];\n\n\t\t\tif (end instanceof Array) {\n\n\t\t\t\tthis._object[property] = this._interpolationFunction(end, value);\n\n\t\t\t} else {\n\n\t\t\t\t// Parses relative end values with start as base (e.g.: +10, -3)\n\t\t\t\tif (typeof (end) === 'string') {\n\n\t\t\t\t\tif (end.charAt(0) === '+' || end.charAt(0) === '-') {\n\t\t\t\t\t\tend = start + parseFloat(end);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tend = parseFloat(end);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Protect against non numeric properties.\n\t\t\t\tif (typeof (end) === 'number') {\n\t\t\t\t\tthis._object[property] = start + (end - start) * value;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tif (this._onUpdateCallback !== null) {\n\t\t\tthis._onUpdateCallback.call(this._object, value);\n\t\t}\n\n\t\tif (elapsed === 1) {\n\n\t\t\tif (this._repeat > 0) {\n\n\t\t\t\tif (isFinite(this._repeat)) {\n\t\t\t\t\tthis._repeat--;\n\t\t\t\t}\n\n\t\t\t\t// Reassign starting values, restart by making startTime = now\n\t\t\t\tfor (property in this._valuesStartRepeat) {\n\n\t\t\t\t\tif (typeof (this._valuesEnd[property]) === 'string') {\n\t\t\t\t\t\tthis._valuesStartRepeat[property] = this._valuesStartRepeat[property] + parseFloat(this._valuesEnd[property]);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this._yoyo) {\n\t\t\t\t\t\tvar tmp = this._valuesStartRepeat[property];\n\n\t\t\t\t\t\tthis._valuesStartRepeat[property] = this._valuesEnd[property];\n\t\t\t\t\t\tthis._valuesEnd[property] = tmp;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._valuesStart[property] = this._valuesStartRepeat[property];\n\n\t\t\t\t}\n\n\t\t\t\tif (this._yoyo) {\n\t\t\t\t\tthis._reversed = !this._reversed;\n\t\t\t\t}\n\n\t\t\t\tif (this._repeatDelayTime !== undefined) {\n\t\t\t\t\tthis._startTime = time + this._repeatDelayTime;\n\t\t\t\t} else {\n\t\t\t\t\tthis._startTime = time + this._delayTime;\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\n\t\t\t} else {\n\n\t\t\t\tif (this._onCompleteCallback !== null) {\n\n\t\t\t\t\tthis._onCompleteCallback.call(this._object, this._object);\n\t\t\t\t}\n\n\t\t\t\tfor (var i = 0, numChainedTweens = this._chainedTweens.length; i < numChainedTweens; i++) {\n\t\t\t\t\t// Make the chained tweens start exactly at the time they should,\n\t\t\t\t\t// even if the `update()` method was called way past the duration of the tween\n\t\t\t\t\tthis._chainedTweens[i].start(this._startTime + this._duration);\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n};\n\n\nTWEEN.Easing = {\n\n\tLinear: {\n\n\t\tNone: function (k) {\n\n\t\t\treturn k;\n\n\t\t}\n\n\t},\n\n\tQuadratic: {\n\n\t\tIn: function (k) {\n\n\t\t\treturn k * k;\n\n\t\t},\n\n\t\tOut: function (k) {\n\n\t\t\treturn k * (2 - k);\n\n\t\t},\n\n\t\tInOut: function (k) {\n\n\t\t\tif ((k *= 2) < 1) {\n\t\t\t\treturn 0.5 * k * k;\n\t\t\t}\n\n\t\t\treturn - 0.5 * (--k * (k - 2) - 1);\n\n\t\t}\n\n\t},\n\n\tCubic: {\n\n\t\tIn: function (k) {\n\n\t\t\treturn k * k * k;\n\n\t\t},\n\n\t\tOut: function (k) {\n\n\t\t\treturn --k * k * k + 1;\n\n\t\t},\n\n\t\tInOut: function (k) {\n\n\t\t\tif ((k *= 2) < 1) {\n\t\t\t\treturn 0.5 * k * k * k;\n\t\t\t}\n\n\t\t\treturn 0.5 * ((k -= 2) * k * k + 2);\n\n\t\t}\n\n\t},\n\n\tQuartic: {\n\n\t\tIn: function (k) {\n\n\t\t\treturn k * k * k * k;\n\n\t\t},\n\n\t\tOut: function (k) {\n\n\t\t\treturn 1 - (--k * k * k * k);\n\n\t\t},\n\n\t\tInOut: function (k) {\n\n\t\t\tif ((k *= 2) < 1) {\n\t\t\t\treturn 0.5 * k * k * k * k;\n\t\t\t}\n\n\t\t\treturn - 0.5 * ((k -= 2) * k * k * k - 2);\n\n\t\t}\n\n\t},\n\n\tQuintic: {\n\n\t\tIn: function (k) {\n\n\t\t\treturn k * k * k * k * k;\n\n\t\t},\n\n\t\tOut: function (k) {\n\n\t\t\treturn --k * k * k * k * k + 1;\n\n\t\t},\n\n\t\tInOut: function (k) {\n\n\t\t\tif ((k *= 2) < 1) {\n\t\t\t\treturn 0.5 * k * k * k * k * k;\n\t\t\t}\n\n\t\t\treturn 0.5 * ((k -= 2) * k * k * k * k + 2);\n\n\t\t}\n\n\t},\n\n\tSinusoidal: {\n\n\t\tIn: function (k) {\n\n\t\t\treturn 1 - Math.cos(k * Math.PI / 2);\n\n\t\t},\n\n\t\tOut: function (k) {\n\n\t\t\treturn Math.sin(k * Math.PI / 2);\n\n\t\t},\n\n\t\tInOut: function (k) {\n\n\t\t\treturn 0.5 * (1 - Math.cos(Math.PI * k));\n\n\t\t}\n\n\t},\n\n\tExponential: {\n\n\t\tIn: function (k) {\n\n\t\t\treturn k === 0 ? 0 : Math.pow(1024, k - 1);\n\n\t\t},\n\n\t\tOut: function (k) {\n\n\t\t\treturn k === 1 ? 1 : 1 - Math.pow(2, - 10 * k);\n\n\t\t},\n\n\t\tInOut: function (k) {\n\n\t\t\tif (k === 0) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif (k === 1) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tif ((k *= 2) < 1) {\n\t\t\t\treturn 0.5 * Math.pow(1024, k - 1);\n\t\t\t}\n\n\t\t\treturn 0.5 * (- Math.pow(2, - 10 * (k - 1)) + 2);\n\n\t\t}\n\n\t},\n\n\tCircular: {\n\n\t\tIn: function (k) {\n\n\t\t\treturn 1 - Math.sqrt(1 - k * k);\n\n\t\t},\n\n\t\tOut: function (k) {\n\n\t\t\treturn Math.sqrt(1 - (--k * k));\n\n\t\t},\n\n\t\tInOut: function (k) {\n\n\t\t\tif ((k *= 2) < 1) {\n\t\t\t\treturn - 0.5 * (Math.sqrt(1 - k * k) - 1);\n\t\t\t}\n\n\t\t\treturn 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1);\n\n\t\t}\n\n\t},\n\n\tElastic: {\n\n\t\tIn: function (k) {\n\n\t\t\tif (k === 0) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif (k === 1) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\treturn -Math.pow(2, 10 * (k - 1)) * Math.sin((k - 1.1) * 5 * Math.PI);\n\n\t\t},\n\n\t\tOut: function (k) {\n\n\t\t\tif (k === 0) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif (k === 1) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\treturn Math.pow(2, -10 * k) * Math.sin((k - 0.1) * 5 * Math.PI) + 1;\n\n\t\t},\n\n\t\tInOut: function (k) {\n\n\t\t\tif (k === 0) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif (k === 1) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tk *= 2;\n\n\t\t\tif (k < 1) {\n\t\t\t\treturn -0.5 * Math.pow(2, 10 * (k - 1)) * Math.sin((k - 1.1) * 5 * Math.PI);\n\t\t\t}\n\n\t\t\treturn 0.5 * Math.pow(2, -10 * (k - 1)) * Math.sin((k - 1.1) * 5 * Math.PI) + 1;\n\n\t\t}\n\n\t},\n\n\tBack: {\n\n\t\tIn: function (k) {\n\n\t\t\tvar s = 1.70158;\n\n\t\t\treturn k * k * ((s + 1) * k - s);\n\n\t\t},\n\n\t\tOut: function (k) {\n\n\t\t\tvar s = 1.70158;\n\n\t\t\treturn --k * k * ((s + 1) * k + s) + 1;\n\n\t\t},\n\n\t\tInOut: function (k) {\n\n\t\t\tvar s = 1.70158 * 1.525;\n\n\t\t\tif ((k *= 2) < 1) {\n\t\t\t\treturn 0.5 * (k * k * ((s + 1) * k - s));\n\t\t\t}\n\n\t\t\treturn 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2);\n\n\t\t}\n\n\t},\n\n\tBounce: {\n\n\t\tIn: function (k) {\n\n\t\t\treturn 1 - TWEEN.Easing.Bounce.Out(1 - k);\n\n\t\t},\n\n\t\tOut: function (k) {\n\n\t\t\tif (k < (1 / 2.75)) {\n\t\t\t\treturn 7.5625 * k * k;\n\t\t\t} else if (k < (2 / 2.75)) {\n\t\t\t\treturn 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75;\n\t\t\t} else if (k < (2.5 / 2.75)) {\n\t\t\t\treturn 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375;\n\t\t\t} else {\n\t\t\t\treturn 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375;\n\t\t\t}\n\n\t\t},\n\n\t\tInOut: function (k) {\n\n\t\t\tif (k < 0.5) {\n\t\t\t\treturn TWEEN.Easing.Bounce.In(k * 2) * 0.5;\n\t\t\t}\n\n\t\t\treturn TWEEN.Easing.Bounce.Out(k * 2 - 1) * 0.5 + 0.5;\n\n\t\t}\n\n\t}\n\n};\n\nTWEEN.Interpolation = {\n\n\tLinear: function (v, k) {\n\n\t\tvar m = v.length - 1;\n\t\tvar f = m * k;\n\t\tvar i = Math.floor(f);\n\t\tvar fn = TWEEN.Interpolation.Utils.Linear;\n\n\t\tif (k < 0) {\n\t\t\treturn fn(v[0], v[1], f);\n\t\t}\n\n\t\tif (k > 1) {\n\t\t\treturn fn(v[m], v[m - 1], m - f);\n\t\t}\n\n\t\treturn fn(v[i], v[i + 1 > m ? m : i + 1], f - i);\n\n\t},\n\n\tBezier: function (v, k) {\n\n\t\tvar b = 0;\n\t\tvar n = v.length - 1;\n\t\tvar pw = Math.pow;\n\t\tvar bn = TWEEN.Interpolation.Utils.Bernstein;\n\n\t\tfor (var i = 0; i <= n; i++) {\n\t\t\tb += pw(1 - k, n - i) * pw(k, i) * v[i] * bn(n, i);\n\t\t}\n\n\t\treturn b;\n\n\t},\n\n\tCatmullRom: function (v, k) {\n\n\t\tvar m = v.length - 1;\n\t\tvar f = m * k;\n\t\tvar i = Math.floor(f);\n\t\tvar fn = TWEEN.Interpolation.Utils.CatmullRom;\n\n\t\tif (v[0] === v[m]) {\n\n\t\t\tif (k < 0) {\n\t\t\t\ti = Math.floor(f = m * (1 + k));\n\t\t\t}\n\n\t\t\treturn fn(v[(i - 1 + m) % m], v[i], v[(i + 1) % m], v[(i + 2) % m], f - i);\n\n\t\t} else {\n\n\t\t\tif (k < 0) {\n\t\t\t\treturn v[0] - (fn(v[0], v[0], v[1], v[1], -f) - v[0]);\n\t\t\t}\n\n\t\t\tif (k > 1) {\n\t\t\t\treturn v[m] - (fn(v[m], v[m], v[m - 1], v[m - 1], f - m) - v[m]);\n\t\t\t}\n\n\t\t\treturn fn(v[i ? i - 1 : 0], v[i], v[m < i + 1 ? m : i + 1], v[m < i + 2 ? m : i + 2], f - i);\n\n\t\t}\n\n\t},\n\n\tUtils: {\n\n\t\tLinear: function (p0, p1, t) {\n\n\t\t\treturn (p1 - p0) * t + p0;\n\n\t\t},\n\n\t\tBernstein: function (n, i) {\n\n\t\t\tvar fc = TWEEN.Interpolation.Utils.Factorial;\n\n\t\t\treturn fc(n) / fc(i) / fc(n - i);\n\n\t\t},\n\n\t\tFactorial: (function () {\n\n\t\t\tvar a = [1];\n\n\t\t\treturn function (n) {\n\n\t\t\t\tvar s = 1;\n\n\t\t\t\tif (a[n]) {\n\t\t\t\t\treturn a[n];\n\t\t\t\t}\n\n\t\t\t\tfor (var i = n; i > 1; i--) {\n\t\t\t\t\ts *= i;\n\t\t\t\t}\n\n\t\t\t\ta[n] = s;\n\t\t\t\treturn s;\n\n\t\t\t};\n\n\t\t})(),\n\n\t\tCatmullRom: function (p0, p1, p2, p3, t) {\n\n\t\t\tvar v0 = (p2 - p0) * 0.5;\n\t\t\tvar v1 = (p3 - p1) * 0.5;\n\t\t\tvar t2 = t * t;\n\t\t\tvar t3 = t * t2;\n\n\t\t\treturn (2 * p1 - 2 * p2 + v0 + v1) * t3 + (- 3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1;\n\n\t\t}\n\n\t}\n\n};\n\n// UMD (Universal Module Definition)\n(function (root) {\n\n\tif (typeof define === 'function' && define.amd) {\n\n\t\t// AMD\n\t\tdefine([], function () {\n\t\t\treturn TWEEN;\n\t\t});\n\n\t} else if (typeof module !== 'undefined' && typeof exports === 'object') {\n\n\t\t// Node.js\n\t\tmodule.exports = TWEEN;\n\n\t} else if (root !== undefined) {\n\n\t\t// Global variable\n\t\troot.TWEEN = TWEEN;\n\n\t}\n\n})(this);\n\n}).call(this,_dereq_('_process'))\n\n},{\"_process\":6}],2:[function(_dereq_,module,exports){\nvar str = Object.prototype.toString\n\nmodule.exports = anArray\n\nfunction anArray(arr) {\n  return (\n       arr.BYTES_PER_ELEMENT\n    && str.call(arr.buffer) === '[object ArrayBuffer]'\n    || Array.isArray(arr)\n  )\n}\n\n},{}],3:[function(_dereq_,module,exports){\nmodule.exports = function numtype(num, def) {\n\treturn typeof num === 'number'\n\t\t? num \n\t\t: (typeof def === 'number' ? def : 0)\n}\n},{}],4:[function(_dereq_,module,exports){\n'use strict'\n\nexports.byteLength = byteLength\nexports.toByteArray = toByteArray\nexports.fromByteArray = fromByteArray\n\nvar lookup = []\nvar revLookup = []\nvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array\n\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\nrevLookup['-'.charCodeAt(0)] = 62\nrevLookup['_'.charCodeAt(0)] = 63\n\nfunction placeHoldersCount (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  // the number of equal signs (place holders)\n  // if there are two placeholders, than the two characters before it\n  // represent one byte\n  // if there is only one, then the three characters before it represent 2 bytes\n  // this is just a cheap hack to not do indexOf twice\n  return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0\n}\n\nfunction byteLength (b64) {\n  // base64 is 4/3 + up to two characters of the original data\n  return (b64.length * 3 / 4) - placeHoldersCount(b64)\n}\n\nfunction toByteArray (b64) {\n  var i, l, tmp, placeHolders, arr\n  var len = b64.length\n  placeHolders = placeHoldersCount(b64)\n\n  arr = new Arr((len * 3 / 4) - placeHolders)\n\n  // if there are placeholders, only get up to the last complete 4 chars\n  l = placeHolders > 0 ? len - 4 : len\n\n  var L = 0\n\n  for (i = 0; i < l; 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[L++] = (tmp >> 16) & 0xFF\n    arr[L++] = (tmp >> 8) & 0xFF\n    arr[L++] = tmp & 0xFF\n  }\n\n  if (placeHolders === 2) {\n    tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)\n    arr[L++] = tmp & 0xFF\n  } else if (placeHolders === 1) {\n    tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)\n    arr[L++] = (tmp >> 8) & 0xFF\n    arr[L++] = tmp & 0xFF\n  }\n\n  return arr\n}\n\nfunction tripletToBase64 (num) {\n  return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]\n}\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) + (uint8[i + 1] << 8) + (uint8[i + 2])\n    output.push(tripletToBase64(tmp))\n  }\n  return output.join('')\n}\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 output = ''\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    output += lookup[tmp >> 2]\n    output += lookup[(tmp << 4) & 0x3F]\n    output += '=='\n  } else if (extraBytes === 2) {\n    tmp = (uint8[len - 2] << 8) + (uint8[len - 1])\n    output += lookup[tmp >> 10]\n    output += lookup[(tmp >> 4) & 0x3F]\n    output += lookup[(tmp << 2) & 0x3F]\n    output += '='\n  }\n\n  parts.push(output)\n\n  return parts.join('')\n}\n\n},{}],5:[function(_dereq_,module,exports){\n'use strict';\n// For more information about browser field, check out the browser field at https://github.com/substack/browserify-handbook#browser-field.\n\nmodule.exports = {\n    // Create a <link> tag with optional data attributes\n    createLink: function(href, attributes) {\n        var head = document.head || document.getElementsByTagName('head')[0];\n        var link = document.createElement('link');\n\n        link.href = href;\n        link.rel = 'stylesheet';\n\n        for (var key in attributes) {\n            if ( ! attributes.hasOwnProperty(key)) {\n                continue;\n            }\n            var value = attributes[key];\n            link.setAttribute('data-' + key, value);\n        }\n\n        head.appendChild(link);\n    },\n    // Create a <style> tag with optional data attributes\n    createStyle: function(cssText, attributes) {\n        var head = document.head || document.getElementsByTagName('head')[0],\n            style = document.createElement('style');\n\n        style.type = 'text/css';\n\n        for (var key in attributes) {\n            if ( ! attributes.hasOwnProperty(key)) {\n                continue;\n            }\n            var value = attributes[key];\n            style.setAttribute('data-' + key, value);\n        }\n        \n        if (style.sheet) { // for jsdom and IE9+\n            style.innerHTML = cssText;\n            style.sheet.cssText = cssText;\n            head.appendChild(style);\n        } else if (style.styleSheet) { // for IE8 and below\n            head.appendChild(style);\n            style.styleSheet.cssText = cssText;\n        } else { // for Chrome, Firefox, and Safari\n            style.appendChild(document.createTextNode(cssText));\n            head.appendChild(style);\n        }\n    }\n};\n\n},{}],6:[function(_dereq_,module,exports){\n// shim for using process in browser\nvar process = module.exports = {};\n\n// cached from whatever global is present so that test runners that stub it\n// don't break things.  But we need to wrap it in a try catch in case it is\n// wrapped in strict mode code which doesn't define any globals.  It's inside a\n// function because try/catches deoptimize in certain engines.\n\nvar cachedSetTimeout;\nvar cachedClearTimeout;\n\nfunction defaultSetTimout() {\n    throw new Error('setTimeout has not been defined');\n}\nfunction defaultClearTimeout () {\n    throw new Error('clearTimeout has not been defined');\n}\n(function () {\n    try {\n        if (typeof setTimeout === 'function') {\n            cachedSetTimeout = setTimeout;\n        } else {\n            cachedSetTimeout = defaultSetTimout;\n        }\n    } catch (e) {\n        cachedSetTimeout = defaultSetTimout;\n    }\n    try {\n        if (typeof clearTimeout === 'function') {\n            cachedClearTimeout = clearTimeout;\n        } else {\n            cachedClearTimeout = defaultClearTimeout;\n        }\n    } catch (e) {\n        cachedClearTimeout = defaultClearTimeout;\n    }\n} ())\nfunction runTimeout(fun) {\n    if (cachedSetTimeout === setTimeout) {\n        //normal enviroments in sane situations\n        return setTimeout(fun, 0);\n    }\n    // if setTimeout wasn't available but was latter defined\n    if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {\n        cachedSetTimeout = setTimeout;\n        return setTimeout(fun, 0);\n    }\n    try {\n        // when when somebody has screwed with setTimeout but no I.E. maddness\n        return cachedSetTimeout(fun, 0);\n    } catch(e){\n        try {\n            // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n            return cachedSetTimeout.call(null, fun, 0);\n        } catch(e){\n            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error\n            return cachedSetTimeout.call(this, fun, 0);\n        }\n    }\n\n\n}\nfunction runClearTimeout(marker) {\n    if (cachedClearTimeout === clearTimeout) {\n        //normal enviroments in sane situations\n        return clearTimeout(marker);\n    }\n    // if clearTimeout wasn't available but was latter defined\n    if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {\n        cachedClearTimeout = clearTimeout;\n        return clearTimeout(marker);\n    }\n    try {\n        // when when somebody has screwed with setTimeout but no I.E. maddness\n        return cachedClearTimeout(marker);\n    } catch (e){\n        try {\n            // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally\n            return cachedClearTimeout.call(null, marker);\n        } catch (e){\n            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.\n            // Some versions of I.E. have different rules for clearTimeout vs setTimeout\n            return cachedClearTimeout.call(this, marker);\n        }\n    }\n\n\n\n}\nvar queue = [];\nvar draining = false;\nvar currentQueue;\nvar queueIndex = -1;\n\nfunction cleanUpNextTick() {\n    if (!draining || !currentQueue) {\n        return;\n    }\n    draining = false;\n    if (currentQueue.length) {\n        queue = currentQueue.concat(queue);\n    } else {\n        queueIndex = -1;\n    }\n    if (queue.length) {\n        drainQueue();\n    }\n}\n\nfunction drainQueue() {\n    if (draining) {\n        return;\n    }\n    var timeout = runTimeout(cleanUpNextTick);\n    draining = true;\n\n    var len = queue.length;\n    while(len) {\n        currentQueue = queue;\n        queue = [];\n        while (++queueIndex < len) {\n            if (currentQueue) {\n                currentQueue[queueIndex].run();\n            }\n        }\n        queueIndex = -1;\n        len = queue.length;\n    }\n    currentQueue = null;\n    draining = false;\n    runClearTimeout(timeout);\n}\n\nprocess.nextTick = function (fun) {\n    var args = new Array(arguments.length - 1);\n    if (arguments.length > 1) {\n        for (var i = 1; i < arguments.length; i++) {\n            args[i - 1] = arguments[i];\n        }\n    }\n    queue.push(new Item(fun, args));\n    if (queue.length === 1 && !draining) {\n        runTimeout(drainQueue);\n    }\n};\n\n// v8 likes predictible objects\nfunction Item(fun, array) {\n    this.fun = fun;\n    this.array = array;\n}\nItem.prototype.run = function () {\n    this.fun.apply(null, this.array);\n};\nprocess.title = 'browser';\nprocess.browser = true;\nprocess.env = {};\nprocess.argv = [];\nprocess.version = ''; // empty string to avoid regexp issues\nprocess.versions = {};\n\nfunction noop() {}\n\nprocess.on = noop;\nprocess.addListener = noop;\nprocess.once = noop;\nprocess.off = noop;\nprocess.removeListener = noop;\nprocess.removeAllListeners = noop;\nprocess.emit = noop;\nprocess.prependListener = noop;\nprocess.prependOnceListener = noop;\n\nprocess.listeners = function (name) { return [] }\n\nprocess.binding = function (name) {\n    throw new Error('process.binding is not supported');\n};\n\nprocess.cwd = function () { return '/' };\nprocess.chdir = function (dir) {\n    throw new Error('process.chdir is not supported');\n};\nprocess.umask = function() { return 0; };\n\n},{}],7:[function(_dereq_,module,exports){\nvar Buffer = _dereq_('buffer').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    \n    for (var i = 0; i < a.length; i++) {\n        if (a[i] !== b[i]) return false;\n    }\n    \n    return true;\n};\n\n},{\"buffer\":8}],8:[function(_dereq_,module,exports){\n(function (global){\n/*!\n * The buffer module from node.js, for the browser.\n *\n * @author   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>\n * @license  MIT\n */\n/* eslint-disable no-proto */\n\n'use strict'\n\nvar base64 = _dereq_('base64-js')\nvar ieee754 = _dereq_('ieee754')\nvar isArray = _dereq_('isarray')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n *   === true    Use Uint8Array implementation (fastest)\n *   === false   Use Object 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 * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n *   - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n *     See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n *   - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n *   - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n *     incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n  ? global.TYPED_ARRAY_SUPPORT\n  : typedArraySupport()\n\n/*\n * Export kMaxLength after typed array support is determined.\n */\nexports.kMaxLength = kMaxLength()\n\nfunction typedArraySupport () {\n  try {\n    var arr = new Uint8Array(1)\n    arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}\n    return arr.foo() === 42 && // typed array instances can be augmented\n        typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n        arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n  } catch (e) {\n    return false\n  }\n}\n\nfunction kMaxLength () {\n  return Buffer.TYPED_ARRAY_SUPPORT\n    ? 0x7fffffff\n    : 0x3fffffff\n}\n\nfunction createBuffer (that, length) {\n  if (kMaxLength() < length) {\n    throw new RangeError('Invalid typed array length')\n  }\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    // Return an augmented `Uint8Array` instance, for best performance\n    that = new Uint8Array(length)\n    that.__proto__ = Buffer.prototype\n  } else {\n    // Fallback: Return an object instance of the Buffer class\n    if (that === null) {\n      that = new Buffer(length)\n    }\n    that.length = length\n  }\n\n  return that\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  if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {\n    return new Buffer(arg, encodingOrOffset, length)\n  }\n\n  // Common case.\n  if (typeof arg === 'number') {\n    if (typeof encodingOrOffset === 'string') {\n      throw new Error(\n        'If encoding is specified then the first argument must be a string'\n      )\n    }\n    return allocUnsafe(this, arg)\n  }\n  return from(this, arg, encodingOrOffset, length)\n}\n\nBuffer.poolSize = 8192 // not used by this implementation\n\n// TODO: Legacy, not needed anymore. Remove in next major version.\nBuffer._augment = function (arr) {\n  arr.__proto__ = Buffer.prototype\n  return arr\n}\n\nfunction from (that, value, encodingOrOffset, length) {\n  if (typeof value === 'number') {\n    throw new TypeError('\"value\" argument must not be a number')\n  }\n\n  if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {\n    return fromArrayBuffer(that, value, encodingOrOffset, length)\n  }\n\n  if (typeof value === 'string') {\n    return fromString(that, value, encodingOrOffset)\n  }\n\n  return fromObject(that, 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(null, value, encodingOrOffset, length)\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n  Buffer.prototype.__proto__ = Uint8Array.prototype\n  Buffer.__proto__ = Uint8Array\n  if (typeof Symbol !== 'undefined' && Symbol.species &&\n      Buffer[Symbol.species] === Buffer) {\n    // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97\n    Object.defineProperty(Buffer, Symbol.species, {\n      value: null,\n      configurable: true\n    })\n  }\n}\n\nfunction assertSize (size) {\n  if (typeof size !== 'number') {\n    throw new TypeError('\"size\" argument must be a number')\n  } else if (size < 0) {\n    throw new RangeError('\"size\" argument must not be negative')\n  }\n}\n\nfunction alloc (that, size, fill, encoding) {\n  assertSize(size)\n  if (size <= 0) {\n    return createBuffer(that, 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 interpretted as a start offset.\n    return typeof encoding === 'string'\n      ? createBuffer(that, size).fill(fill, encoding)\n      : createBuffer(that, size).fill(fill)\n  }\n  return createBuffer(that, 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(null, size, fill, encoding)\n}\n\nfunction allocUnsafe (that, size) {\n  assertSize(size)\n  that = createBuffer(that, size < 0 ? 0 : checked(size) | 0)\n  if (!Buffer.TYPED_ARRAY_SUPPORT) {\n    for (var i = 0; i < size; ++i) {\n      that[i] = 0\n    }\n  }\n  return that\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(null, 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(null, size)\n}\n\nfunction fromString (that, string, encoding) {\n  if (typeof encoding !== 'string' || encoding === '') {\n    encoding = 'utf8'\n  }\n\n  if (!Buffer.isEncoding(encoding)) {\n    throw new TypeError('\"encoding\" must be a valid string encoding')\n  }\n\n  var length = byteLength(string, encoding) | 0\n  that = createBuffer(that, length)\n\n  var actual = that.write(string, encoding)\n\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    that = that.slice(0, actual)\n  }\n\n  return that\n}\n\nfunction fromArrayLike (that, array) {\n  var length = array.length < 0 ? 0 : checked(array.length) | 0\n  that = createBuffer(that, length)\n  for (var i = 0; i < length; i += 1) {\n    that[i] = array[i] & 255\n  }\n  return that\n}\n\nfunction fromArrayBuffer (that, array, byteOffset, length) {\n  array.byteLength // this throws if `array` is not a valid ArrayBuffer\n\n  if (byteOffset < 0 || array.byteLength < byteOffset) {\n    throw new RangeError('\\'offset\\' is out of bounds')\n  }\n\n  if (array.byteLength < byteOffset + (length || 0)) {\n    throw new RangeError('\\'length\\' is out of bounds')\n  }\n\n  if (byteOffset === undefined && length === undefined) {\n    array = new Uint8Array(array)\n  } else if (length === undefined) {\n    array = new Uint8Array(array, byteOffset)\n  } else {\n    array = new Uint8Array(array, byteOffset, length)\n  }\n\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    // Return an augmented `Uint8Array` instance, for best performance\n    that = array\n    that.__proto__ = Buffer.prototype\n  } else {\n    // Fallback: Return an object instance of the Buffer class\n    that = fromArrayLike(that, array)\n  }\n  return that\n}\n\nfunction fromObject (that, obj) {\n  if (Buffer.isBuffer(obj)) {\n    var len = checked(obj.length) | 0\n    that = createBuffer(that, len)\n\n    if (that.length === 0) {\n      return that\n    }\n\n    obj.copy(that, 0, 0, len)\n    return that\n  }\n\n  if (obj) {\n    if ((typeof ArrayBuffer !== 'undefined' &&\n        obj.buffer instanceof ArrayBuffer) || 'length' in obj) {\n      if (typeof obj.length !== 'number' || isnan(obj.length)) {\n        return createBuffer(that, 0)\n      }\n      return fromArrayLike(that, obj)\n    }\n\n    if (obj.type === 'Buffer' && isArray(obj.data)) {\n      return fromArrayLike(that, obj.data)\n    }\n  }\n\n  throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')\n}\n\nfunction checked (length) {\n  // Note: cannot use `length < kMaxLength()` here because that fails when\n  // length is NaN (which is otherwise coerced to zero.)\n  if (length >= kMaxLength()) {\n    throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n                         'size: 0x' + kMaxLength().toString(16) + ' bytes')\n  }\n  return length | 0\n}\n\nfunction SlowBuffer (length) {\n  if (+length != length) { // eslint-disable-line eqeqeq\n    length = 0\n  }\n  return Buffer.alloc(+length)\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n  return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n  if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n    throw new TypeError('Arguments must be Buffers')\n  }\n\n  if (a === b) return 0\n\n  var x = a.length\n  var y = b.length\n\n  for (var 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\n  if (x < y) return -1\n  if (y < x) return 1\n  return 0\n}\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}\n\nBuffer.concat = function concat (list, length) {\n  if (!isArray(list)) {\n    throw new TypeError('\"list\" argument must be an Array of Buffers')\n  }\n\n  if (list.length === 0) {\n    return Buffer.alloc(0)\n  }\n\n  var i\n  if (length === undefined) {\n    length = 0\n    for (i = 0; i < list.length; ++i) {\n      length += list[i].length\n    }\n  }\n\n  var buffer = Buffer.allocUnsafe(length)\n  var pos = 0\n  for (i = 0; i < list.length; ++i) {\n    var buf = list[i]\n    if (!Buffer.isBuffer(buf)) {\n      throw new TypeError('\"list\" argument must be an Array of Buffers')\n    }\n    buf.copy(buffer, pos)\n    pos += buf.length\n  }\n  return buffer\n}\n\nfunction byteLength (string, encoding) {\n  if (Buffer.isBuffer(string)) {\n    return string.length\n  }\n  if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&\n      (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {\n    return string.byteLength\n  }\n  if (typeof string !== 'string') {\n    string = '' + string\n  }\n\n  var len = string.length\n  if (len === 0) return 0\n\n  // Use a for loop to avoid recursion\n  var 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      case undefined:\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) return utf8ToBytes(string).length // assume utf8\n        encoding = ('' + encoding).toLowerCase()\n        loweredCase = true\n    }\n  }\n}\nBuffer.byteLength = byteLength\n\nfunction slowToString (encoding, start, end) {\n  var 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\n  if (end === undefined || end > this.length) {\n    end = this.length\n  }\n\n  if (end <= 0) {\n    return ''\n  }\n\n  // Force coersion to uint32. This will also coerce falsey/NaN values to 0.\n  end >>>= 0\n  start >>>= 0\n\n  if (end <= start) {\n    return ''\n  }\n\n  if (!encoding) encoding = 'utf8'\n\n  while (true) {\n    switch (encoding) {\n      case 'hex':\n        return hexSlice(this, start, end)\n\n      case 'utf8':\n      case 'utf-8':\n        return utf8Slice(this, start, end)\n\n      case 'ascii':\n        return asciiSlice(this, start, end)\n\n      case 'latin1':\n      case 'binary':\n        return latin1Slice(this, start, end)\n\n      case 'base64':\n        return base64Slice(this, start, end)\n\n      case 'ucs2':\n      case 'ucs-2':\n      case 'utf16le':\n      case 'utf-16le':\n        return utf16leSlice(this, start, end)\n\n      default:\n        if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n        encoding = (encoding + '').toLowerCase()\n        loweredCase = true\n    }\n  }\n}\n\n// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect\n// Buffer instances.\nBuffer.prototype._isBuffer = true\n\nfunction swap (b, n, m) {\n  var i = b[n]\n  b[n] = b[m]\n  b[m] = i\n}\n\nBuffer.prototype.swap16 = function swap16 () {\n  var len = this.length\n  if (len % 2 !== 0) {\n    throw new RangeError('Buffer size must be a multiple of 16-bits')\n  }\n  for (var i = 0; i < len; i += 2) {\n    swap(this, i, i + 1)\n  }\n  return this\n}\n\nBuffer.prototype.swap32 = function swap32 () {\n  var len = this.length\n  if (len % 4 !== 0) {\n    throw new RangeError('Buffer size must be a multiple of 32-bits')\n  }\n  for (var i = 0; i < len; i += 4) {\n    swap(this, i, i + 3)\n    swap(this, i + 1, i + 2)\n  }\n  return this\n}\n\nBuffer.prototype.swap64 = function swap64 () {\n  var len = this.length\n  if (len % 8 !== 0) {\n    throw new RangeError('Buffer size must be a multiple of 64-bits')\n  }\n  for (var 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}\n\nBuffer.prototype.toString = function toString () {\n  var length = this.length | 0\n  if (length === 0) return ''\n  if (arguments.length === 0) return utf8Slice(this, 0, length)\n  return slowToString.apply(this, arguments)\n}\n\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}\n\nBuffer.prototype.inspect = function inspect () {\n  var str = ''\n  var max = exports.INSPECT_MAX_BYTES\n  if (this.length > 0) {\n    str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n    if (this.length > max) str += ' ... '\n  }\n  return '<Buffer ' + str + '>'\n}\n\nBuffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {\n  if (!Buffer.isBuffer(target)) {\n    throw new TypeError('Argument must be a Buffer')\n  }\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\n  if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {\n    throw new RangeError('out of range index')\n  }\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\n  start >>>= 0\n  end >>>= 0\n  thisStart >>>= 0\n  thisEnd >>>= 0\n\n  if (this === target) return 0\n\n  var x = thisEnd - thisStart\n  var y = end - start\n  var len = Math.min(x, y)\n\n  var thisCopy = this.slice(thisStart, thisEnd)\n  var targetCopy = target.slice(start, end)\n\n  for (var i = 0; i < len; ++i) {\n    if (thisCopy[i] !== targetCopy[i]) {\n      x = thisCopy[i]\n      y = targetCopy[i]\n      break\n    }\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 (isNaN(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\n    else byteOffset = buffer.length - 1\n  } else if (byteOffset < 0) {\n    if (dir) byteOffset = 0\n    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 (Buffer.TYPED_ARRAY_SUPPORT &&\n        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\n  throw new TypeError('val must be string, number or Buffer')\n}\n\nfunction arrayIndexOf (arr, val, byteOffset, encoding, dir) {\n  var indexSize = 1\n  var arrLength = arr.length\n  var valLength = val.length\n\n  if (encoding !== undefined) {\n    encoding = String(encoding).toLowerCase()\n    if (encoding === 'ucs2' || encoding === 'ucs-2' ||\n        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\n  function read (buf, i) {\n    if (indexSize === 1) {\n      return buf[i]\n    } else {\n      return buf.readUInt16BE(i * indexSize)\n    }\n  }\n\n  var i\n  if (dir) {\n    var 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      var found = true\n      for (var 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\n  return -1\n}\n\nBuffer.prototype.includes = function includes (val, byteOffset, encoding) {\n  return this.indexOf(val, byteOffset, encoding) !== -1\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {\n  return bidirectionalIndexOf(this, val, byteOffset, encoding, true)\n}\n\nBuffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {\n  return bidirectionalIndexOf(this, val, byteOffset, encoding, false)\n}\n\nfunction hexWrite (buf, string, offset, length) {\n  offset = Number(offset) || 0\n  var 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\n  // must be an even number of digits\n  var strLen = string.length\n  if (strLen % 2 !== 0) throw new TypeError('Invalid hex string')\n\n  if (length > strLen / 2) {\n    length = strLen / 2\n  }\n  for (var i = 0; i < length; ++i) {\n    var parsed = parseInt(string.substr(i * 2, 2), 16)\n    if (isNaN(parsed)) return i\n    buf[offset + i] = parsed\n  }\n  return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n  return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n  return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction latin1Write (buf, string, offset, length) {\n  return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n  return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n  return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\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  // legacy write(string, encoding, offset, length) - remove in v0.13\n  } else {\n    throw new Error(\n      'Buffer.write(string, encoding, offset[, length]) is no longer supported'\n    )\n  }\n\n  var remaining = this.length - offset\n  if (length === undefined || length > remaining) length = remaining\n\n  if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n    throw new RangeError('Attempt to write outside buffer bounds')\n  }\n\n  if (!encoding) encoding = 'utf8'\n\n  var loweredCase = false\n  for (;;) {\n    switch (encoding) {\n      case 'hex':\n        return hexWrite(this, string, offset, length)\n\n      case 'utf8':\n      case 'utf-8':\n        return utf8Write(this, string, offset, length)\n\n      case 'ascii':\n        return asciiWrite(this, string, offset, length)\n\n      case 'latin1':\n      case 'binary':\n        return latin1Write(this, string, offset, length)\n\n      case 'base64':\n        // Warning: maxLength not taken into account in base64Write\n        return base64Write(this, string, offset, length)\n\n      case 'ucs2':\n      case 'ucs-2':\n      case 'utf16le':\n      case 'utf-16le':\n        return ucs2Write(this, string, offset, length)\n\n      default:\n        if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n        encoding = ('' + encoding).toLowerCase()\n        loweredCase = true\n    }\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}\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}\n\nfunction utf8Slice (buf, start, end) {\n  end = Math.min(buf.length, end)\n  var res = []\n\n  var i = start\n  while (i < end) {\n    var firstByte = buf[i]\n    var codePoint = null\n    var bytesPerSequence = (firstByte > 0xEF) ? 4\n      : (firstByte > 0xDF) ? 3\n      : (firstByte > 0xBF) ? 2\n      : 1\n\n    if (i + bytesPerSequence <= end) {\n      var secondByte, thirdByte, fourthByte, tempCodePoint\n\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\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\n    res.push(codePoint)\n    i += bytesPerSequence\n  }\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\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n  var 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  var res = ''\n  var i = 0\n  while (i < len) {\n    res += String.fromCharCode.apply(\n      String,\n      codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n    )\n  }\n  return res\n}\n\nfunction asciiSlice (buf, start, end) {\n  var ret = ''\n  end = Math.min(buf.length, end)\n\n  for (var i = start; i < end; ++i) {\n    ret += String.fromCharCode(buf[i] & 0x7F)\n  }\n  return ret\n}\n\nfunction latin1Slice (buf, start, end) {\n  var ret = ''\n  end = Math.min(buf.length, end)\n\n  for (var i = start; i < end; ++i) {\n    ret += String.fromCharCode(buf[i])\n  }\n  return ret\n}\n\nfunction hexSlice (buf, start, end) {\n  var len = buf.length\n\n  if (!start || start < 0) start = 0\n  if (!end || end < 0 || end > len) end = len\n\n  var out = ''\n  for (var i = start; i < end; ++i) {\n    out += toHex(buf[i])\n  }\n  return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n  var bytes = buf.slice(start, end)\n  var res = ''\n  for (var i = 0; i < bytes.length; i += 2) {\n    res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n  }\n  return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n  var len = this.length\n  start = ~~start\n  end = end === undefined ? len : ~~end\n\n  if (start < 0) {\n    start += len\n    if (start < 0) start = 0\n  } else if (start > len) {\n    start = len\n  }\n\n  if (end < 0) {\n    end += len\n    if (end < 0) end = 0\n  } else if (end > len) {\n    end = len\n  }\n\n  if (end < start) end = start\n\n  var newBuf\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    newBuf = this.subarray(start, end)\n    newBuf.__proto__ = Buffer.prototype\n  } else {\n    var sliceLen = end - start\n    newBuf = new Buffer(sliceLen, undefined)\n    for (var i = 0; i < sliceLen; ++i) {\n      newBuf[i] = this[i + start]\n    }\n  }\n\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}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n  var val = this[offset]\n  var mul = 1\n  var i = 0\n  while (++i < byteLength && (mul *= 0x100)) {\n    val += this[offset + i] * mul\n  }\n\n  return val\n}\n\nBuffer.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\n  var val = this[offset + --byteLength]\n  var mul = 1\n  while (byteLength > 0 && (mul *= 0x100)) {\n    val += this[offset + --byteLength] * mul\n  }\n\n  return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 1, this.length)\n  return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 2, this.length)\n  return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 2, this.length)\n  return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n\n  return ((this[offset]) |\n      (this[offset + 1] << 8) |\n      (this[offset + 2] << 16)) +\n      (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n\n  return (this[offset] * 0x1000000) +\n    ((this[offset + 1] << 16) |\n    (this[offset + 2] << 8) |\n    this[offset + 3])\n}\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\n  var val = this[offset]\n  var mul = 1\n  var i = 0\n  while (++i < byteLength && (mul *= 0x100)) {\n    val += this[offset + i] * mul\n  }\n  mul *= 0x80\n\n  if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n  return val\n}\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\n  var i = byteLength\n  var mul = 1\n  var val = this[offset + --i]\n  while (i > 0 && (mul *= 0x100)) {\n    val += this[offset + --i] * mul\n  }\n  mul *= 0x80\n\n  if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n  return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 1, this.length)\n  if (!(this[offset] & 0x80)) return (this[offset])\n  return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 2, this.length)\n  var val = this[offset] | (this[offset + 1] << 8)\n  return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 2, this.length)\n  var val = this[offset + 1] | (this[offset] << 8)\n  return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n\n  return (this[offset]) |\n    (this[offset + 1] << 8) |\n    (this[offset + 2] << 16) |\n    (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n\n  return (this[offset] << 24) |\n    (this[offset + 1] << 16) |\n    (this[offset + 2] << 8) |\n    (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n  return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n  return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 8, this.length)\n  return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 8, this.length)\n  return ieee754.read(this, offset, false, 52, 8)\n}\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}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n  value = +value\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) {\n    var maxBytes = Math.pow(2, 8 * byteLength) - 1\n    checkInt(this, value, offset, byteLength, maxBytes, 0)\n  }\n\n  var mul = 1\n  var i = 0\n  this[offset] = value & 0xFF\n  while (++i < byteLength && (mul *= 0x100)) {\n    this[offset + i] = (value / mul) & 0xFF\n  }\n\n  return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n  value = +value\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) {\n    var maxBytes = Math.pow(2, 8 * byteLength) - 1\n    checkInt(this, value, offset, byteLength, maxBytes, 0)\n  }\n\n  var i = byteLength - 1\n  var mul = 1\n  this[offset + i] = value & 0xFF\n  while (--i >= 0 && (mul *= 0x100)) {\n    this[offset + i] = (value / mul) & 0xFF\n  }\n\n  return offset + byteLength\n}\n\nBuffer.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  if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n  this[offset] = (value & 0xff)\n  return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n  if (value < 0) value = 0xffff + value + 1\n  for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {\n    buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n      (littleEndian ? i : 1 - i) * 8\n  }\n}\n\nBuffer.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  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value & 0xff)\n    this[offset + 1] = (value >>> 8)\n  } else {\n    objectWriteUInt16(this, value, offset, true)\n  }\n  return offset + 2\n}\n\nBuffer.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  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value >>> 8)\n    this[offset + 1] = (value & 0xff)\n  } else {\n    objectWriteUInt16(this, value, offset, false)\n  }\n  return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n  if (value < 0) value = 0xffffffff + value + 1\n  for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {\n    buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n  }\n}\n\nBuffer.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  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset + 3] = (value >>> 24)\n    this[offset + 2] = (value >>> 16)\n    this[offset + 1] = (value >>> 8)\n    this[offset] = (value & 0xff)\n  } else {\n    objectWriteUInt32(this, value, offset, true)\n  }\n  return offset + 4\n}\n\nBuffer.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  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value >>> 24)\n    this[offset + 1] = (value >>> 16)\n    this[offset + 2] = (value >>> 8)\n    this[offset + 3] = (value & 0xff)\n  } else {\n    objectWriteUInt32(this, value, offset, false)\n  }\n  return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) {\n    var limit = Math.pow(2, 8 * byteLength - 1)\n\n    checkInt(this, value, offset, byteLength, limit - 1, -limit)\n  }\n\n  var i = 0\n  var mul = 1\n  var 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\n  return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) {\n    var limit = Math.pow(2, 8 * byteLength - 1)\n\n    checkInt(this, value, offset, byteLength, limit - 1, -limit)\n  }\n\n  var i = byteLength - 1\n  var mul = 1\n  var 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\n  return offset + byteLength\n}\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 (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n  if (value < 0) value = 0xff + value + 1\n  this[offset] = (value & 0xff)\n  return offset + 1\n}\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  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value & 0xff)\n    this[offset + 1] = (value >>> 8)\n  } else {\n    objectWriteUInt16(this, value, offset, true)\n  }\n  return offset + 2\n}\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  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value >>> 8)\n    this[offset + 1] = (value & 0xff)\n  } else {\n    objectWriteUInt16(this, value, offset, false)\n  }\n  return offset + 2\n}\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  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value & 0xff)\n    this[offset + 1] = (value >>> 8)\n    this[offset + 2] = (value >>> 16)\n    this[offset + 3] = (value >>> 24)\n  } else {\n    objectWriteUInt32(this, value, offset, true)\n  }\n  return offset + 4\n}\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  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value >>> 24)\n    this[offset + 1] = (value >>> 16)\n    this[offset + 2] = (value >>> 8)\n    this[offset + 3] = (value & 0xff)\n  } else {\n    objectWriteUInt32(this, value, offset, false)\n  }\n  return offset + 4\n}\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}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\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}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n  return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n  return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\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}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n  return writeDouble(this, value, offset, true, noAssert)\n}\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 (!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('sourceStart out of bounds')\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\n  var len = end - start\n  var i\n\n  if (this === target && start < targetStart && targetStart < end) {\n    // descending copy from end\n    for (i = len - 1; i >= 0; --i) {\n      target[i + targetStart] = this[i + start]\n    }\n  } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n    // ascending copy from start\n    for (i = 0; i < len; ++i) {\n      target[i + targetStart] = this[i + start]\n    }\n  } else {\n    Uint8Array.prototype.set.call(\n      target,\n      this.subarray(start, start + len),\n      targetStart\n    )\n  }\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 (val.length === 1) {\n      var code = val.charCodeAt(0)\n      if (code < 256) {\n        val = code\n      }\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  } else if (typeof val === 'number') {\n    val = val & 255\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\n  if (end <= start) {\n    return this\n  }\n\n  start = start >>> 0\n  end = end === undefined ? this.length : end >>> 0\n\n  if (!val) val = 0\n\n  var i\n  if (typeof val === 'number') {\n    for (i = start; i < end; ++i) {\n      this[i] = val\n    }\n  } else {\n    var bytes = Buffer.isBuffer(val)\n      ? val\n      : utf8ToBytes(new Buffer(val, encoding).toString())\n    var len = bytes.length\n    for (i = 0; i < end - start; ++i) {\n      this[i + start] = bytes[i % len]\n    }\n  }\n\n  return this\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n  // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n  str = stringtrim(str).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}\n\nfunction stringtrim (str) {\n  if (str.trim) return str.trim()\n  return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n  if (n < 16) return '0' + n.toString(16)\n  return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n  units = units || Infinity\n  var codePoint\n  var length = string.length\n  var leadSurrogate = null\n  var bytes = []\n\n  for (var 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\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\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(\n        codePoint >> 0x6 | 0xC0,\n        codePoint & 0x3F | 0x80\n      )\n    } else if (codePoint < 0x10000) {\n      if ((units -= 3) < 0) break\n      bytes.push(\n        codePoint >> 0xC | 0xE0,\n        codePoint >> 0x6 & 0x3F | 0x80,\n        codePoint & 0x3F | 0x80\n      )\n    } else if (codePoint < 0x110000) {\n      if ((units -= 4) < 0) break\n      bytes.push(\n        codePoint >> 0x12 | 0xF0,\n        codePoint >> 0xC & 0x3F | 0x80,\n        codePoint >> 0x6 & 0x3F | 0x80,\n        codePoint & 0x3F | 0x80\n      )\n    } else {\n      throw new Error('Invalid code point')\n    }\n  }\n\n  return bytes\n}\n\nfunction asciiToBytes (str) {\n  var byteArray = []\n  for (var 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}\n\nfunction utf16leToBytes (str, units) {\n  var c, hi, lo\n  var byteArray = []\n  for (var i = 0; i < str.length; ++i) {\n    if ((units -= 2) < 0) break\n\n    c = str.charCodeAt(i)\n    hi = c >> 8\n    lo = c % 256\n    byteArray.push(lo)\n    byteArray.push(hi)\n  }\n\n  return byteArray\n}\n\nfunction base64ToBytes (str) {\n  return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n  for (var 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\nfunction isnan (val) {\n  return val !== val // eslint-disable-line no-self-compare\n}\n\n}).call(this,typeof global !== \"undefined\" ? global : typeof self !== \"undefined\" ? self : typeof window !== \"undefined\" ? window : {})\n\n},{\"base64-js\":4,\"ieee754\":18,\"isarray\":9}],9:[function(_dereq_,module,exports){\nvar toString = {}.toString;\n\nmodule.exports = Array.isArray || function (arr) {\n  return toString.call(arr) == '[object Array]';\n};\n\n},{}],10:[function(_dereq_,module,exports){\n\n/**\n * This is the web browser implementation of `debug()`.\n *\n * Expose `debug()` as the module.\n */\n\nexports = module.exports = _dereq_('./debug');\nexports.log = log;\nexports.formatArgs = formatArgs;\nexports.save = save;\nexports.load = load;\nexports.useColors = useColors;\nexports.storage = 'undefined' != typeof chrome\n               && 'undefined' != typeof chrome.storage\n                  ? chrome.storage.local\n                  : localstorage();\n\n/**\n * Colors.\n */\n\nexports.colors = [\n  'lightseagreen',\n  'forestgreen',\n  'goldenrod',\n  'dodgerblue',\n  'darkorchid',\n  'crimson'\n];\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\nfunction useColors() {\n  // is webkit? http://stackoverflow.com/a/16459606/376773\n  return ('WebkitAppearance' in document.documentElement.style) ||\n    // is firebug? http://stackoverflow.com/a/398120/376773\n    (window.console && (console.firebug || (console.exception && console.table))) ||\n    // is firefox >= v31?\n    // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages\n    (navigator.userAgent.toLowerCase().match(/firefox\\/(\\d+)/) && parseInt(RegExp.$1, 10) >= 31);\n}\n\n/**\n * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.\n */\n\nexports.formatters.j = function(v) {\n  return JSON.stringify(v);\n};\n\n\n/**\n * Colorize log arguments if enabled.\n *\n * @api public\n */\n\nfunction formatArgs() {\n  var args = arguments;\n  var useColors = this.useColors;\n\n  args[0] = (useColors ? '%c' : '')\n    + this.namespace\n    + (useColors ? ' %c' : ' ')\n    + args[0]\n    + (useColors ? '%c ' : ' ');\n\n  if (!useColors) return args;\n\n  var c = 'color: ' + this.color;\n  args = [args[0], c, 'color: inherit'].concat(Array.prototype.slice.call(args, 1));\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  var index = 0;\n  var lastC = 0;\n  args[0].replace(/%[a-z%]/g, function(match) {\n    if ('%%' === match) return;\n    index++;\n    if ('%c' === match) {\n      // we only are interested in the *last* %c\n      // (the user may have provided their own)\n      lastC = index;\n    }\n  });\n\n  args.splice(lastC, 0, c);\n  return args;\n}\n\n/**\n * Invokes `console.log()` when available.\n * No-op when `console.log` is not a \"function\".\n *\n * @api public\n */\n\nfunction log() {\n  // this hackery is required for IE8/9, where\n  // the `console.log` function doesn't have 'apply'\n  return 'object' === typeof console\n    && console.log\n    && Function.prototype.apply.call(console.log, console, arguments);\n}\n\n/**\n * Save `namespaces`.\n *\n * @param {String} namespaces\n * @api private\n */\n\nfunction save(namespaces) {\n  try {\n    if (null == namespaces) {\n      exports.storage.removeItem('debug');\n    } else {\n      exports.storage.debug = namespaces;\n    }\n  } catch(e) {}\n}\n\n/**\n * Load `namespaces`.\n *\n * @return {String} returns the previously persisted debug modes\n * @api private\n */\n\nfunction load() {\n  var r;\n  try {\n    r = exports.storage.debug;\n  } catch(e) {}\n  return r;\n}\n\n/**\n * Enable namespaces listed in `localStorage.debug` initially.\n */\n\nexports.enable(load());\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    return window.localStorage;\n  } catch (e) {}\n}\n\n},{\"./debug\":11}],11:[function(_dereq_,module,exports){\n\n/**\n * This is the common logic for both the Node.js and web browser\n * implementations of `debug()`.\n *\n * Expose `debug()` as the module.\n */\n\nexports = module.exports = debug;\nexports.coerce = coerce;\nexports.disable = disable;\nexports.enable = enable;\nexports.enabled = enabled;\n\n/**\n * The currently active debug mode names, and names to skip.\n */\n\nexports.names = [];\nexports.skips = [];\n\n/**\n * Map of special \"%n\" handling functions, for the debug \"format\" argument.\n *\n * Valid key names are a single, lowercased letter, i.e. \"n\".\n */\n\nexports.formatters = {};\n\n/**\n * Previously assigned color.\n */\n\nvar prevColor = 0;\n\n/**\n * Select a color.\n *\n * @return {Number}\n * @api private\n */\n\nfunction selectColor() {\n  return exports.colors[prevColor++ % exports.colors.length];\n}\n\n/**\n * Create a debugger with the given `namespace`.\n *\n * @param {String} namespace\n * @return {Function}\n * @api public\n */\n\nfunction debug(namespace) {\n\n  // define the `disabled` version\n  function disabled() {\n  }\n  disabled.enabled = false;\n\n  // define the `enabled` version\n  function enabled() {\n\n    var self = enabled;\n\n    // add the `color` if not set\n    if (null == self.useColors) self.useColors = exports.useColors();\n    if (null == self.color && self.useColors) self.color = selectColor();\n\n    var args = Array.prototype.slice.call(arguments);\n\n    args[0] = exports.coerce(args[0]);\n\n    if ('string' !== typeof args[0]) {\n      // anything else let's inspect with %o\n      args = ['%o'].concat(args);\n    }\n\n    // apply any `formatters` transformations\n    var index = 0;\n    args[0] = args[0].replace(/%([a-z%])/g, function(match, format) {\n      // if we encounter an escaped % then don't increase the array index\n      if (match === '%%') return match;\n      index++;\n      var formatter = exports.formatters[format];\n      if ('function' === typeof formatter) {\n        var 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    if ('function' === typeof exports.formatArgs) {\n      args = exports.formatArgs.apply(self, args);\n    }\n    var logFn = enabled.log || exports.log || console.log.bind(console);\n    logFn.apply(self, args);\n  }\n  enabled.enabled = true;\n\n  var fn = exports.enabled(namespace) ? enabled : disabled;\n\n  fn.namespace = namespace;\n\n  return fn;\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\nfunction enable(namespaces) {\n  exports.save(namespaces);\n\n  var split = (namespaces || '').split(/[\\s,]+/);\n  var len = split.length;\n\n  for (var i = 0; i < len; i++) {\n    if (!split[i]) continue; // ignore empty strings\n    namespaces = split[i].replace(/\\*/g, '.*?');\n    if (namespaces[0] === '-') {\n      exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));\n    } else {\n      exports.names.push(new RegExp('^' + namespaces + '$'));\n    }\n  }\n}\n\n/**\n * Disable debug output.\n *\n * @api public\n */\n\nfunction disable() {\n  exports.enable('');\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\nfunction enabled(name) {\n  var i, len;\n  for (i = 0, len = exports.skips.length; i < len; i++) {\n    if (exports.skips[i].test(name)) {\n      return false;\n    }\n  }\n  for (i = 0, len = exports.names.length; i < len; i++) {\n    if (exports.names[i].test(name)) {\n      return true;\n    }\n  }\n  return false;\n}\n\n/**\n * Coerce `val`.\n *\n * @param {Mixed} val\n * @return {Mixed}\n * @api private\n */\n\nfunction coerce(val) {\n  if (val instanceof Error) return val.stack || val.message;\n  return val;\n}\n\n},{}],12:[function(_dereq_,module,exports){\n'use strict';\nvar isObj = _dereq_('is-obj');\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\nvar propIsEnumerable = Object.prototype.propertyIsEnumerable;\n\nfunction toObject(val) {\n\tif (val === null || val === undefined) {\n\t\tthrow new TypeError('Sources cannot be null or undefined');\n\t}\n\n\treturn Object(val);\n}\n\nfunction assignKey(to, from, key) {\n\tvar val = from[key];\n\n\tif (val === undefined || val === null) {\n\t\treturn;\n\t}\n\n\tif (hasOwnProperty.call(to, key)) {\n\t\tif (to[key] === undefined || to[key] === null) {\n\t\t\tthrow new TypeError('Cannot convert undefined or null to object (' + key + ')');\n\t\t}\n\t}\n\n\tif (!hasOwnProperty.call(to, key) || !isObj(val)) {\n\t\tto[key] = val;\n\t} else {\n\t\tto[key] = assign(Object(to[key]), from[key]);\n\t}\n}\n\nfunction assign(to, from) {\n\tif (to === from) {\n\t\treturn to;\n\t}\n\n\tfrom = Object(from);\n\n\tfor (var key in from) {\n\t\tif (hasOwnProperty.call(from, key)) {\n\t\t\tassignKey(to, from, key);\n\t\t}\n\t}\n\n\tif (Object.getOwnPropertySymbols) {\n\t\tvar symbols = Object.getOwnPropertySymbols(from);\n\n\t\tfor (var i = 0; i < symbols.length; i++) {\n\t\t\tif (propIsEnumerable.call(from, symbols[i])) {\n\t\t\t\tassignKey(to, from, symbols[i]);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn to;\n}\n\nmodule.exports = function deepAssign(target) {\n\ttarget = toObject(target);\n\n\tfor (var s = 1; s < arguments.length; s++) {\n\t\tassign(target, arguments[s]);\n\t}\n\n\treturn target;\n};\n\n},{\"is-obj\":22}],13:[function(_dereq_,module,exports){\n/*! (C) WebReflection Mit Style License */\n(function(t,n,r,i){\"use strict\";function st(e,t){for(var n=0,r=e.length;n<r;n++)gt(e[n],t)}function ot(e){for(var t=0,n=e.length,r;t<n;t++)r=e[t],it(r,w[at(r)])}function ut(e){return function(t){F(t)&&(gt(t,e),st(t.querySelectorAll(E),e))}}function at(e){var t=R.call(e,\"is\"),n=e.nodeName.toUpperCase(),r=x.call(b,t?m+t.toUpperCase():v+n);return t&&-1<r&&!ft(n,t)?-1:r}function ft(e,t){return-1<E.indexOf(e+'[is=\"'+t+'\"]')}function lt(e){var t=e.currentTarget,n=e.attrChange,r=e.attrName,i=e.target;Y&&(!i||i===t)&&t.attributeChangedCallback&&r!==\"style\"&&e.prevValue!==e.newValue&&t.attributeChangedCallback(r,n===e[f]?null:e.prevValue,n===e[c]?null:e.newValue)}function ct(e){var t=ut(e);return function(e){$.push(t,e.target)}}function ht(e){G&&(G=!1,e.currentTarget.removeEventListener(p,ht)),st((e.target||n).querySelectorAll(E),e.detail===u?u:o),j&&vt()}function pt(e,t){var n=this;U.call(n,e,t),Z.call(n,{target:n})}function dt(e,t){P(e,t),nt?nt.observe(e,X):(Q&&(e.setAttribute=pt,e[s]=tt(e),e.addEventListener(d,Z)),e.addEventListener(h,lt)),e.createdCallback&&Y&&(e.created=!0,e.createdCallback(),e.created=!1)}function vt(){for(var e,t=0,n=I.length;t<n;t++)e=I[t],S.contains(e)||(n--,I.splice(t--,1),gt(e,u))}function mt(e){throw new Error(\"A \"+e+\" type is already registered\")}function gt(e,t){var n,r=at(e);-1<r&&(rt(e,w[r]),r=0,t===o&&!e[o]?(e[u]=!1,e[o]=!0,r=1,j&&x.call(I,e)<0&&I.push(e)):t===u&&!e[u]&&(e[o]=!1,e[u]=!0,r=1),r&&(n=e[t+\"Callback\"])&&n.call(e))}if(i in n)return;var s=\"__\"+i+(Math.random()*1e5>>0),o=\"attached\",u=\"detached\",a=\"extends\",f=\"ADDITION\",l=\"MODIFICATION\",c=\"REMOVAL\",h=\"DOMAttrModified\",p=\"DOMContentLoaded\",d=\"DOMSubtreeModified\",v=\"<\",m=\"=\",g=/^[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)+$/,y=[\"ANNOTATION-XML\",\"COLOR-PROFILE\",\"FONT-FACE\",\"FONT-FACE-SRC\",\"FONT-FACE-URI\",\"FONT-FACE-FORMAT\",\"FONT-FACE-NAME\",\"MISSING-GLYPH\"],b=[],w=[],E=\"\",S=n.documentElement,x=b.indexOf||function(e){for(var t=this.length;t--&&this[t]!==e;);return t},T=r.prototype,N=T.hasOwnProperty,C=T.isPrototypeOf,k=r.defineProperty,L=r.getOwnPropertyDescriptor,A=r.getOwnPropertyNames,O=r.getPrototypeOf,M=r.setPrototypeOf,_=!!r.__proto__,D=r.create||function yt(e){return e?(yt.prototype=e,new yt):this},P=M||(_?function(e,t){return e.__proto__=t,e}:A&&L?function(){function e(e,t){for(var n,r=A(t),i=0,s=r.length;i<s;i++)n=r[i],N.call(e,n)||k(e,n,L(t,n))}return function(t,n){do e(t,n);while((n=O(n))&&!C.call(n,t));return t}}():function(e,t){for(var n in t)e[n]=t[n];return e}),H=t.MutationObserver||t.WebKitMutationObserver,B=(t.HTMLElement||t.Element||t.Node).prototype,j=!C.call(B,S),F=j?function(e){return e.nodeType===1}:function(e){return C.call(B,e)},I=j&&[],q=B.cloneNode,R=B.getAttribute,U=B.setAttribute,z=B.removeAttribute,W=n.createElement,X=H&&{attributes:!0,characterData:!0,attributeOldValue:!0},V=H||function(e){Q=!1,S.removeEventListener(h,V)},$,J=t.requestAnimationFrame||t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||t.msRequestAnimationFrame||function(e){setTimeout(e,10)},K=!1,Q=!0,G=!0,Y=!0,Z,et,tt,nt,rt,it;M||_?(rt=function(e,t){C.call(t,e)||dt(e,t)},it=dt):(rt=function(e,t){e[s]||(e[s]=r(!0),dt(e,t))},it=rt),j?(Q=!1,function(){var t=L(B,\"addEventListener\"),n=t.value,r=function(e){var t=new CustomEvent(h,{bubbles:!0});t.attrName=e,t.prevValue=R.call(this,e),t.newValue=null,t[c]=t.attrChange=2,z.call(this,e),this.dispatchEvent(t)},i=function(t,n){var r=this.hasAttribute(t),i=r&&R.call(this,t);e=new CustomEvent(h,{bubbles:!0}),U.call(this,t,n),e.attrName=t,e.prevValue=r?i:null,e.newValue=n,r?e[l]=e.attrChange=1:e[f]=e.attrChange=0,this.dispatchEvent(e)},o=function(e){var t=e.currentTarget,n=t[s],r=e.propertyName,i;n.hasOwnProperty(r)&&(n=n[r],i=new CustomEvent(h,{bubbles:!0}),i.attrName=n.name,i.prevValue=n.value||null,i.newValue=n.value=t[r]||null,i.prevValue==null?i[f]=i.attrChange=0:i[l]=i.attrChange=1,t.dispatchEvent(i))};t.value=function(e,t,u){e===h&&this.attributeChangedCallback&&this.setAttribute!==i&&(this[s]={className:{name:\"class\",value:this.className}},this.setAttribute=i,this.removeAttribute=r,n.call(this,\"propertychange\",o)),n.call(this,e,t,u)},k(B,\"addEventListener\",t)}()):H||(S.addEventListener(h,V),S.setAttribute(s,1),S.removeAttribute(s),Q&&(Z=function(e){var t=this,n,r,i;if(t===e.target){n=t[s],t[s]=r=tt(t);for(i in r){if(!(i in n))return et(0,t,i,n[i],r[i],f);if(r[i]!==n[i])return et(1,t,i,n[i],r[i],l)}for(i in n)if(!(i in r))return et(2,t,i,n[i],r[i],c)}},et=function(e,t,n,r,i,s){var o={attrChange:e,currentTarget:t,attrName:n,prevValue:r,newValue:i};o[s]=e,lt(o)},tt=function(e){for(var t,n,r={},i=e.attributes,s=0,o=i.length;s<o;s++)t=i[s],n=t.name,n!==\"setAttribute\"&&(r[n]=t.value);return r})),n[i]=function(t,r){c=t.toUpperCase(),K||(K=!0,H?(nt=function(e,t){function n(e,t){for(var n=0,r=e.length;n<r;t(e[n++]));}return new H(function(r){for(var i,s,o,u=0,a=r.length;u<a;u++)i=r[u],i.type===\"childList\"?(n(i.addedNodes,e),n(i.removedNodes,t)):(s=i.target,Y&&s.attributeChangedCallback&&i.attributeName!==\"style\"&&(o=R.call(s,i.attributeName),o!==i.oldValue&&s.attributeChangedCallback(i.attributeName,i.oldValue,o)))})}(ut(o),ut(u)),nt.observe(n,{childList:!0,subtree:!0})):($=[],J(function d(){while($.length)$.shift().call(null,$.shift());J(d)}),n.addEventListener(\"DOMNodeInserted\",ct(o)),n.addEventListener(\"DOMNodeRemoved\",ct(u))),n.addEventListener(p,ht),n.addEventListener(\"readystatechange\",ht),n.createElement=function(e,t){var r=W.apply(n,arguments),i=\"\"+e,s=x.call(b,(t?m:v)+(t||i).toUpperCase()),o=-1<s;return t&&(r.setAttribute(\"is\",t=t.toLowerCase()),o&&(o=ft(i.toUpperCase(),t))),Y=!n.createElement.innerHTMLHelper,o&&it(r,w[s]),r},B.cloneNode=function(e){var t=q.call(this,!!e),n=at(t);return-1<n&&it(t,w[n]),e&&ot(t.querySelectorAll(E)),t}),-2<x.call(b,m+c)+x.call(b,v+c)&&mt(t);if(!g.test(c)||-1<x.call(y,c))throw new Error(\"The type \"+t+\" is invalid\");var i=function(){return f?n.createElement(l,c):n.createElement(l)},s=r||T,f=N.call(s,a),l=f?r[a].toUpperCase():c,c,h;return f&&-1<x.call(b,v+l)&&mt(l),h=b.push((f?m:v)+c)-1,E=E.concat(E.length?\",\":\"\",f?l+'[is=\"'+t.toLowerCase()+'\"]':l),i.prototype=w[h]=N.call(s,\"prototype\")?s.prototype:D(B),st(n.querySelectorAll(E),o),i}})(window,document,Object,\"registerElement\");\n},{}],14:[function(_dereq_,module,exports){\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},{}],15:[function(_dereq_,module,exports){\n/*eslint new-cap:0*/\nvar dtype = _dereq_('dtype')\nmodule.exports = flattenVertexData\nfunction flattenVertexData (data, output, offset) {\n  if (!data) throw new TypeError('must specify data as first parameter')\n  offset = +(offset || 0) | 0\n\n  if (Array.isArray(data) && Array.isArray(data[0])) {\n    var dim = data[0].length\n    var length = data.length * dim\n\n    // no output specified, create a new typed array\n    if (!output || typeof output === 'string') {\n      output = new (dtype(output || 'float32'))(length + offset)\n    }\n\n    var dstLength = output.length - offset\n    if (length !== dstLength) {\n      throw new Error('source length ' + length + ' (' + dim + 'x' + data.length + ')' +\n        ' does not match destination length ' + dstLength)\n    }\n\n    for (var i = 0, k = offset; i < data.length; i++) {\n      for (var j = 0; j < dim; j++) {\n        output[k++] = data[i][j]\n      }\n    }\n  } else {\n    if (!output || typeof output === 'string') {\n      // no output, create a new one\n      var Ctor = dtype(output || 'float32')\n      if (offset === 0) {\n        output = new Ctor(data)\n      } else {\n        output = new Ctor(data.length + offset)\n        output.set(data, offset)\n      }\n    } else {\n      // store output in existing array\n      output.set(data, offset)\n    }\n  }\n\n  return output\n}\n\n},{\"dtype\":14}],16:[function(_dereq_,module,exports){\nvar isFunction = _dereq_('is-function')\n\nmodule.exports = forEach\n\nvar toString = Object.prototype.toString\nvar hasOwnProperty = Object.prototype.hasOwnProperty\n\nfunction forEach(list, iterator, context) {\n    if (!isFunction(iterator)) {\n        throw new TypeError('iterator must be a function')\n    }\n\n    if (arguments.length < 3) {\n        context = this\n    }\n    \n    if (toString.call(list) === '[object Array]')\n        forEachArray(list, iterator, context)\n    else if (typeof list === 'string')\n        forEachString(list, iterator, context)\n    else\n        forEachObject(list, iterator, context)\n}\n\nfunction forEachArray(array, iterator, context) {\n    for (var i = 0, len = array.length; i < len; i++) {\n        if (hasOwnProperty.call(array, i)) {\n            iterator.call(context, array[i], i, array)\n        }\n    }\n}\n\nfunction forEachString(string, iterator, context) {\n    for (var i = 0, len = string.length; i < len; i++) {\n        // no such thing as a sparse string.\n        iterator.call(context, string.charAt(i), i, string)\n    }\n}\n\nfunction forEachObject(object, iterator, context) {\n    for (var k in object) {\n        if (hasOwnProperty.call(object, k)) {\n            iterator.call(context, object[k], k, object)\n        }\n    }\n}\n\n},{\"is-function\":21}],17:[function(_dereq_,module,exports){\n(function (global){\nvar win;\n\nif (typeof window !== \"undefined\") {\n    win = window;\n} else if (typeof global !== \"undefined\") {\n    win = global;\n} else if (typeof self !== \"undefined\"){\n    win = self;\n} else {\n    win = {};\n}\n\nmodule.exports = win;\n\n}).call(this,typeof global !== \"undefined\" ? global : typeof self !== \"undefined\" ? self : typeof window !== \"undefined\" ? window : {})\n\n},{}],18:[function(_dereq_,module,exports){\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\n  i += d\n\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\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\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}\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\n  value = Math.abs(value)\n\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\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\n  for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n  e = (e << mLen) | m\n  eLen += mLen\n  for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n  buffer[offset + i - d] |= s * 128\n}\n\n},{}],19:[function(_dereq_,module,exports){\nif (typeof Object.create === 'function') {\n  // implementation from standard node.js 'util' module\n  module.exports = function inherits(ctor, superCtor) {\n    ctor.super_ = superCtor\n    ctor.prototype = Object.create(superCtor.prototype, {\n      constructor: {\n        value: ctor,\n        enumerable: false,\n        writable: true,\n        configurable: true\n      }\n    });\n  };\n} else {\n  // old school shim for old browsers\n  module.exports = function inherits(ctor, superCtor) {\n    ctor.super_ = superCtor\n    var TempCtor = function () {}\n    TempCtor.prototype = superCtor.prototype\n    ctor.prototype = new TempCtor()\n    ctor.prototype.constructor = ctor\n  }\n}\n\n},{}],20:[function(_dereq_,module,exports){\n/*!\n * Determine if an object is a Buffer\n *\n * @author   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>\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}\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},{}],21:[function(_dereq_,module,exports){\nmodule.exports = isFunction\n\nvar toString = Object.prototype.toString\n\nfunction isFunction (fn) {\n  var string = toString.call(fn)\n  return string === '[object Function]' ||\n    (typeof fn === 'function' && string !== '[object RegExp]') ||\n    (typeof window !== 'undefined' &&\n     // IE8 and below\n     (fn === window.setTimeout ||\n      fn === window.alert ||\n      fn === window.confirm ||\n      fn === window.prompt))\n};\n\n},{}],22:[function(_dereq_,module,exports){\n'use strict';\nmodule.exports = function (x) {\n\tvar type = typeof x;\n\treturn x !== null && (type === 'object' || type === 'function');\n};\n\n},{}],23:[function(_dereq_,module,exports){\nvar wordWrap = _dereq_('word-wrapper')\nvar xtend = _dereq_('xtend')\nvar number = _dereq_('as-number')\n\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']\n\n\nvar TAB_ID = '\\t'.charCodeAt(0)\nvar SPACE_ID = ' '.charCodeAt(0)\nvar ALIGN_LEFT = 0, \n    ALIGN_CENTER = 1, \n    ALIGN_RIGHT = 2\n\nmodule.exports = function createLayout(opt) {\n  return new TextLayout(opt)\n}\n\nfunction TextLayout(opt) {\n  this.glyphs = []\n  this._measure = this.computeMetrics.bind(this)\n  this.update(opt)\n}\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\n  if (!opt.font)\n    throw new Error('must provide a valid bitmap font')\n\n  var glyphs = this.glyphs\n  var text = opt.text||'' \n  var font = opt.font\n  this._setupSpaceGlyphs(font)\n  \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) \n          x += getKerning(font, lastGlyph.id, glyph.id)\n\n        var tx = x\n        if (align === ALIGN_CENTER) \n          tx += (maxLineWidth-lineWidth)/2\n        else if (align === ALIGN_RIGHT)\n          tx += (maxLineWidth-lineWidth)\n\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}\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\n  if (!font.chars || font.chars.length === 0)\n    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) \n          || getMGlyph(font) \n          || 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, y: 0, xadvance: tabWidth, id: TAB_ID, \n    xoffset: 0, yoffset: 0, width: 0, height: 0\n  })\n}\n\nTextLayout.prototype.getGlyph = function(font, id) {\n  var glyph = getGlyphById(font, id)\n  if (glyph)\n    return glyph\n  else if (id === TAB_ID) \n    return this._fallbackTabGlyph\n  else if (id === SPACE_ID) \n    return this._fallbackSpaceGlyph\n  return null\n}\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\n  if (!font.chars || font.chars.length === 0) {\n    return {\n      start: start,\n      end: start,\n      width: 0\n    }\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\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\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)\n        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)\n    curWidth += lastGlyph.xoffset\n\n  return {\n    start: start,\n    end: start + count,\n    width: curWidth\n  }\n}\n\n//getters for the private vars\n;['width', 'height', \n  'descender', 'ascender',\n  'xHeight', 'baseline',\n  'capHeight',\n  'lineHeight' ].forEach(addGetter)\n\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([\n    'return function '+name+'() {',\n    '  return this._'+name,\n    '}'\n  ].join('\\n')))()\n}\n\nfunction getGlyphById(font, id) {\n  if (!font.chars || font.chars.length === 0)\n    return null\n\n  var glyphIdx = findChar(font.chars, id)\n  if (glyphIdx >= 0)\n    return font.chars[glyphIdx]\n  return null\n}\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) \n      return font.chars[idx].height\n  }\n  return 0\n}\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) \n      return font.chars[idx]\n  }\n  return 0\n}\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) \n      return font.chars[idx].height\n  }\n  return 0\n}\n\nfunction getKerning(font, left, right) {\n  if (!font.kernings || font.kernings.length === 0)\n    return 0\n\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)\n      return kern.amount\n  }\n  return 0\n}\n\nfunction getAlignType(align) {\n  if (align === 'center')\n    return ALIGN_CENTER\n  else if (align === 'right')\n    return ALIGN_RIGHT\n  return ALIGN_LEFT\n}\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},{\"as-number\":3,\"word-wrapper\":72,\"xtend\":75}],24:[function(_dereq_,module,exports){\n(function (Buffer){\nvar xhr = _dereq_('xhr')\nvar noop = function(){}\nvar parseASCII = _dereq_('parse-bmfont-ascii')\nvar parseXML = _dereq_('parse-bmfont-xml')\nvar readBinary = _dereq_('parse-bmfont-binary')\nvar isBinaryFormat = _dereq_('./lib/is-binary')\nvar xtend = _dereq_('xtend')\n\nvar xml2 = (function hasXML2() {\n  return self.XMLHttpRequest && \"withCredentials\" in new XMLHttpRequest\n})()\n\nmodule.exports = function(opt, cb) {\n  cb = typeof cb === 'function' ? cb : noop\n\n  if (typeof opt === 'string')\n    opt = { uri: opt }\n  else if (!opt)\n    opt = {}\n\n  var expectBinary = opt.binary\n  if (expectBinary)\n    opt = getBinaryOpts(opt)\n\n  xhr(opt, function(err, res, body) {\n    if (err)\n      return cb(err)\n    if (!/^2/.test(res.statusCode))\n      return cb(new Error('http status code: '+res.statusCode))\n    if (!body)\n      return cb(new Error('no body result'))\n\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 = new Buffer(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') \n        body = new Buffer(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))\n        body = body.toString(opt.encoding)\n      body = body.trim()\n    }\n\n    var result\n    try {\n      var type = res.headers['content-type']\n      if (binary)\n        result = readBinary(body)\n      else if (/json/.test(type) || body.charAt(0) === '{')\n        result = JSON.parse(body)\n      else if (/xml/.test(type)  || body.charAt(0) === '<')\n        result = parseXML(body)\n      else\n        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}\n\nfunction isArrayBuffer(arr) {\n  var str = Object.prototype.toString\n  return str.call(arr) === '[object ArrayBuffer]'\n}\n\nfunction getBinaryOpts(opt) {\n  //IE10+ and other modern browsers support array buffers\n  if (xml2)\n    return xtend(opt, { responseType: 'arraybuffer' })\n  \n  if (typeof self.XMLHttpRequest === 'undefined')\n    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}).call(this,_dereq_(\"buffer\").Buffer)\n\n},{\"./lib/is-binary\":25,\"buffer\":8,\"parse-bmfont-ascii\":27,\"parse-bmfont-binary\":28,\"parse-bmfont-xml\":29,\"xhr\":73,\"xtend\":75}],25:[function(_dereq_,module,exports){\n(function (Buffer){\nvar equal = _dereq_('buffer-equal')\nvar HEADER = new Buffer([66, 77, 70, 3])\n\nmodule.exports = function(buf) {\n  if (typeof buf === 'string')\n    return buf.substring(0, 3) === 'BMF'\n  return buf.length > 4 && equal(buf.slice(0, 4), HEADER)\n}\n}).call(this,_dereq_(\"buffer\").Buffer)\n\n},{\"buffer\":8,\"buffer-equal\":7}],26:[function(_dereq_,module,exports){\n/*\nobject-assign\n(c) Sindre Sorhus\n@license MIT\n*/\n\n'use strict';\n/* eslint-disable no-unused-vars */\nvar getOwnPropertySymbols = Object.getOwnPropertySymbols;\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\nvar propIsEnumerable = Object.prototype.propertyIsEnumerable;\n\nfunction toObject(val) {\n\tif (val === null || val === undefined) {\n\t\tthrow new TypeError('Object.assign cannot be called with null or undefined');\n\t}\n\n\treturn Object(val);\n}\n\nfunction shouldUseNative() {\n\ttry {\n\t\tif (!Object.assign) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Detect buggy property enumeration order in older V8 versions.\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=4118\n\t\tvar test1 = new String('abc');  // eslint-disable-line no-new-wrappers\n\t\ttest1[5] = 'de';\n\t\tif (Object.getOwnPropertyNames(test1)[0] === '5') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=3056\n\t\tvar test2 = {};\n\t\tfor (var i = 0; i < 10; i++) {\n\t\t\ttest2['_' + String.fromCharCode(i)] = i;\n\t\t}\n\t\tvar order2 = Object.getOwnPropertyNames(test2).map(function (n) {\n\t\t\treturn test2[n];\n\t\t});\n\t\tif (order2.join('') !== '0123456789') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=3056\n\t\tvar test3 = {};\n\t\t'abcdefghijklmnopqrst'.split('').forEach(function (letter) {\n\t\t\ttest3[letter] = letter;\n\t\t});\n\t\tif (Object.keys(Object.assign({}, test3)).join('') !==\n\t\t\t\t'abcdefghijklmnopqrst') {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t} catch (err) {\n\t\t// We don't expect any of the above to throw, but better to be safe.\n\t\treturn false;\n\t}\n}\n\nmodule.exports = shouldUseNative() ? Object.assign : function (target, source) {\n\tvar from;\n\tvar to = toObject(target);\n\tvar symbols;\n\n\tfor (var s = 1; s < arguments.length; s++) {\n\t\tfrom = Object(arguments[s]);\n\n\t\tfor (var key in from) {\n\t\t\tif (hasOwnProperty.call(from, key)) {\n\t\t\t\tto[key] = from[key];\n\t\t\t}\n\t\t}\n\n\t\tif (getOwnPropertySymbols) {\n\t\t\tsymbols = getOwnPropertySymbols(from);\n\t\t\tfor (var i = 0; i < symbols.length; i++) {\n\t\t\t\tif (propIsEnumerable.call(from, symbols[i])) {\n\t\t\t\t\tto[symbols[i]] = from[symbols[i]];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn to;\n};\n\n},{}],27:[function(_dereq_,module,exports){\nmodule.exports = function parseBMFontAscii(data) {\n  if (!data)\n    throw new Error('no data provided')\n  data = data.toString().trim()\n\n  var output = {\n    pages: [],\n    chars: [],\n    kernings: []\n  }\n\n  var lines = data.split(/\\r\\n?|\\n/g)\n\n  if (lines.length === 0)\n    throw new Error('no data in BMFont file')\n\n  for (var i = 0; i < lines.length; i++) {\n    var lineData = splitLine(lines[i], i)\n    if (!lineData) //skip empty lines\n      continue\n\n    if (lineData.key === 'page') {\n      if (typeof lineData.data.id !== 'number')\n        throw new Error('malformed file at line ' + i + ' -- needs page id=N')\n      if (typeof lineData.data.file !== 'string')\n        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\n  return output\n}\n\nfunction splitLine(line, idx) {\n  line = line.replace(/\\t+/g, ' ').trim()\n  if (!line)\n    return null\n\n  var space = line.indexOf(' ')\n  if (space === -1) \n    throw new Error(\"no named row at line \" + idx)\n\n  var key = line.substring(0, space)\n\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\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\n  var out = {\n    key: key,\n    data: {}\n  }\n\n  data.forEach(function(v) {\n    out.data[v.key] = v.data;\n  })\n\n  return out\n}\n\nfunction parseData(data) {\n  if (!data || data.length === 0)\n    return \"\"\n\n  if (data.indexOf('\"') === 0 || data.indexOf(\"'\") === 0)\n    return data.substring(1, data.length - 1)\n  if (data.indexOf(',') !== -1)\n    return parseIntList(data)\n  return parseInt(data, 10)\n}\n\nfunction parseIntList(data) {\n  return data.split(',').map(function(val) {\n    return parseInt(val, 10)\n  })\n}\n},{}],28:[function(_dereq_,module,exports){\nvar HEADER = [66, 77, 70]\n\nmodule.exports = function readBMFontBinary(buf) {\n  if (buf.length < 6)\n    throw new Error('invalid buffer length for BMFont')\n\n  var header = HEADER.every(function(byte, i) {\n    return buf.readUInt8(i) === byte\n  })\n\n  if (!header)\n    throw new Error('BMFont missing BMF byte header')\n\n  var i = 3\n  var vers = buf.readUInt8(i++)\n  if (vers > 3)\n    throw new Error('Only supports BMFont Binary v3 (BMFont App v1.10)')\n  \n  var target = { kernings: [], chars: [] }\n  for (var b=0; b<5; b++)\n    i += readBlock(target, buf, i)\n  return target\n}\n\nfunction readBlock(target, buf, i) {\n  if (i > buf.length-1)\n    return 0\n\n  var blockID = buf.readUInt8(i++)\n  var blockSize = buf.readInt32LE(i)\n  i += 4\n\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}\n\nfunction readInfo(buf, i) {\n  var info = {}\n  info.size = buf.readInt16LE(i)\n\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)\n    info.fixedHeight = 1\n  \n  info.charset = buf.readUInt8(i+3) || ''\n  info.stretchH = buf.readUInt16LE(i+4)\n  info.aa = buf.readUInt8(i+6)\n  info.padding = [\n    buf.readInt8(i+7),\n    buf.readInt8(i+8),\n    buf.readInt8(i+9),\n    buf.readInt8(i+10)\n  ]\n  info.spacing = [\n    buf.readInt8(i+11),\n    buf.readInt8(i+12)\n  ]\n  info.outline = buf.readUInt8(i+13)\n  info.face = readStringNT(buf, i+14)\n  return info\n}\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}\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}\n\nfunction readChars(buf, i, blockSize) {\n  var chars = []\n\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}\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}\n\nfunction readNameNT(buf, offset) {\n  var pos=offset\n  for (; pos<buf.length; pos++) {\n    if (buf[pos] === 0x00) \n      break\n  }\n  return buf.slice(offset, pos)\n}\n\nfunction readStringNT(buf, offset) {\n  return readNameNT(buf, offset).toString('utf8')\n}\n},{}],29:[function(_dereq_,module,exports){\nvar parseAttributes = _dereq_('./parse-attribs')\nvar parseFromString = _dereq_('xml-parse-from-string')\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}\n\nmodule.exports = function parse(data) {\n  data = data.toString()\n  \n  var xmlRoot = parseFromString(data)\n  var output = {\n    pages: [],\n    chars: [],\n    kernings: []\n  }\n\n  //get config settings\n  ;['info', 'common'].forEach(function(key) {\n    var element = xmlRoot.getElementsByTagName(key)[0]\n    if (element)\n      output[key] = parseAttributes(getAttribs(element))\n  })\n\n  //get page info\n  var pageRoot = xmlRoot.getElementsByTagName('pages')[0]\n  if (!pageRoot)\n    throw new Error('malformed file -- no <pages> 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))\n      throw new Error('malformed file -- page \"id\" attribute is NaN')\n    if (!file)\n      throw new Error('malformed file -- needs page \"file\" attribute')\n    output.pages[parseInt(id, 10)] = file\n  }\n\n  //get kernings / chars\n  ;['chars', 'kernings'].forEach(function(key) {\n    var element = xmlRoot.getElementsByTagName(key)[0]\n    if (!element)\n      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}\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}\n\nfunction getAttribList(element) {\n  //IE8+ and modern browsers\n  var attribs = []\n  for (var i=0; i<element.attributes.length; i++)\n    attribs.push(element.attributes[i])\n  return attribs\n}\n\nfunction mapName(nodeName) {\n  return NAME_MAP[nodeName.toLowerCase()] || nodeName\n}\n},{\"./parse-attribs\":30,\"xml-parse-from-string\":74}],30:[function(_dereq_,module,exports){\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'\n\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\n  for (var k in obj) {\n    if (k === 'face' || k === 'charset') \n      continue\n    else if (k === 'padding' || k === 'spacing')\n      obj[k] = parseIntList(obj[k])\n    else\n      obj[k] = parseInt(obj[k], 10) \n  }\n  return obj\n}\n\nfunction parseIntList(data) {\n  return data.split(',').map(function(val) {\n    return parseInt(val, 10)\n  })\n}\n},{}],31:[function(_dereq_,module,exports){\nvar trim = _dereq_('trim')\n  , forEach = _dereq_('for-each')\n  , isArray = function(arg) {\n      return Object.prototype.toString.call(arg) === '[object Array]';\n    }\n\nmodule.exports = function (headers) {\n  if (!headers)\n    return {}\n\n  var result = {}\n\n  forEach(\n      trim(headers).split('\\n')\n    , function (row) {\n        var index = row.indexOf(':')\n          , key = trim(row.slice(0, index)).toLowerCase()\n          , value = trim(row.slice(index + 1))\n\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  )\n\n  return result\n}\n},{\"for-each\":16,\"trim\":46}],32:[function(_dereq_,module,exports){\n(function (process){\n// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// resolves . and .. elements in a path array with directory names there\n// must be no slashes, empty elements, or device names (c:\\) in the array\n// (so also no leading and trailing slashes - it does not distinguish\n// relative and absolute paths)\nfunction normalizeArray(parts, allowAboveRoot) {\n  // if the path tries to go above the root, `up` ends up > 0\n  var up = 0;\n  for (var i = parts.length - 1; i >= 0; i--) {\n    var last = parts[i];\n    if (last === '.') {\n      parts.splice(i, 1);\n    } else if (last === '..') {\n      parts.splice(i, 1);\n      up++;\n    } else if (up) {\n      parts.splice(i, 1);\n      up--;\n    }\n  }\n\n  // if the path is allowed to go above the root, restore leading ..s\n  if (allowAboveRoot) {\n    for (; up--; up) {\n      parts.unshift('..');\n    }\n  }\n\n  return parts;\n}\n\n// Split a filename into [root, dir, basename, ext], unix version\n// 'root' is just a slash, or nothing.\nvar splitPathRe =\n    /^(\\/?|)([\\s\\S]*?)((?:\\.{1,2}|[^\\/]+?|)(\\.[^.\\/]*|))(?:[\\/]*)$/;\nvar splitPath = function(filename) {\n  return splitPathRe.exec(filename).slice(1);\n};\n\n// path.resolve([from ...], to)\n// posix version\nexports.resolve = function() {\n  var resolvedPath = '',\n      resolvedAbsolute = false;\n\n  for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {\n    var path = (i >= 0) ? arguments[i] : process.cwd();\n\n    // Skip empty and invalid entries\n    if (typeof path !== 'string') {\n      throw new TypeError('Arguments to path.resolve must be strings');\n    } else if (!path) {\n      continue;\n    }\n\n    resolvedPath = path + '/' + resolvedPath;\n    resolvedAbsolute = path.charAt(0) === '/';\n  }\n\n  // At this point the path should be resolved to a full absolute path, but\n  // handle relative paths to be safe (might happen when process.cwd() fails)\n\n  // Normalize the path\n  resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {\n    return !!p;\n  }), !resolvedAbsolute).join('/');\n\n  return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';\n};\n\n// path.normalize(path)\n// posix version\nexports.normalize = function(path) {\n  var isAbsolute = exports.isAbsolute(path),\n      trailingSlash = substr(path, -1) === '/';\n\n  // Normalize the path\n  path = normalizeArray(filter(path.split('/'), function(p) {\n    return !!p;\n  }), !isAbsolute).join('/');\n\n  if (!path && !isAbsolute) {\n    path = '.';\n  }\n  if (path && trailingSlash) {\n    path += '/';\n  }\n\n  return (isAbsolute ? '/' : '') + path;\n};\n\n// posix version\nexports.isAbsolute = function(path) {\n  return path.charAt(0) === '/';\n};\n\n// posix version\nexports.join = function() {\n  var paths = Array.prototype.slice.call(arguments, 0);\n  return exports.normalize(filter(paths, function(p, index) {\n    if (typeof p !== 'string') {\n      throw new TypeError('Arguments to path.join must be strings');\n    }\n    return p;\n  }).join('/'));\n};\n\n\n// path.relative(from, to)\n// posix version\nexports.relative = function(from, to) {\n  from = exports.resolve(from).substr(1);\n  to = exports.resolve(to).substr(1);\n\n  function trim(arr) {\n    var start = 0;\n    for (; start < arr.length; start++) {\n      if (arr[start] !== '') break;\n    }\n\n    var end = arr.length - 1;\n    for (; end >= 0; end--) {\n      if (arr[end] !== '') break;\n    }\n\n    if (start > end) return [];\n    return arr.slice(start, end - start + 1);\n  }\n\n  var fromParts = trim(from.split('/'));\n  var toParts = trim(to.split('/'));\n\n  var length = Math.min(fromParts.length, toParts.length);\n  var samePartsLength = length;\n  for (var i = 0; i < length; i++) {\n    if (fromParts[i] !== toParts[i]) {\n      samePartsLength = i;\n      break;\n    }\n  }\n\n  var outputParts = [];\n  for (var i = samePartsLength; i < fromParts.length; i++) {\n    outputParts.push('..');\n  }\n\n  outputParts = outputParts.concat(toParts.slice(samePartsLength));\n\n  return outputParts.join('/');\n};\n\nexports.sep = '/';\nexports.delimiter = ':';\n\nexports.dirname = function(path) {\n  var result = splitPath(path),\n      root = result[0],\n      dir = result[1];\n\n  if (!root && !dir) {\n    // No dirname whatsoever\n    return '.';\n  }\n\n  if (dir) {\n    // It has a dirname, strip trailing slash\n    dir = dir.substr(0, dir.length - 1);\n  }\n\n  return root + dir;\n};\n\n\nexports.basename = function(path, ext) {\n  var f = splitPath(path)[2];\n  // TODO: make this comparison case-insensitive on windows?\n  if (ext && f.substr(-1 * ext.length) === ext) {\n    f = f.substr(0, f.length - ext.length);\n  }\n  return f;\n};\n\n\nexports.extname = function(path) {\n  return splitPath(path)[3];\n};\n\nfunction filter (xs, f) {\n    if (xs.filter) return xs.filter(f);\n    var res = [];\n    for (var i = 0; i < xs.length; i++) {\n        if (f(xs[i], i, xs)) res.push(xs[i]);\n    }\n    return res;\n}\n\n// String.prototype.substr - negative index don't work in IE8\nvar substr = 'ab'.substr(-1) === 'b'\n    ? function (str, start, len) { return str.substr(start, len) }\n    : function (str, start, len) {\n        if (start < 0) start = str.length + start;\n        return str.substr(start, len);\n    }\n;\n\n}).call(this,_dereq_('_process'))\n\n},{\"_process\":6}],33:[function(_dereq_,module,exports){\n(function (global){\nvar performance = global.performance || {};\n\nvar present = (function () {\n  var names = ['now', 'webkitNow', 'msNow', 'mozNow', 'oNow'];\n  while (names.length) {\n    var name = names.shift();\n    if (name in performance) {\n      return performance[name].bind(performance);\n    }\n  }\n\n  var dateNow = Date.now || function () { return new Date().getTime(); };\n  var navigationStart = (performance.timing || {}).navigationStart || dateNow();\n  return function () {\n    return dateNow() - navigationStart;\n  };\n}());\n\npresent.performanceNow = performance.now;\npresent.noConflict = function () {\n  performance.now = present.performanceNow;\n};\npresent.conflict = function () {\n  performance.now = present;\n};\npresent.conflict();\n\nmodule.exports = present;\n\n}).call(this,typeof global !== \"undefined\" ? global : typeof self !== \"undefined\" ? self : typeof window !== \"undefined\" ? window : {})\n\n},{}],34:[function(_dereq_,module,exports){\n(function(root) {\n\n\t// Store setTimeout reference so promise-polyfill will be unaffected by\n\t// other code modifying setTimeout (like sinon.useFakeTimers())\n\tvar setTimeoutFunc = setTimeout;\n\n\t// Use polyfill for setImmediate for performance gains\n\tvar asap = (typeof setImmediate === 'function' && setImmediate) ||\n\t\tfunction(fn) { setTimeoutFunc(fn, 1); };\n\n\t// Polyfill for Function.prototype.bind\n\tfunction bind(fn, thisArg) {\n\t\treturn function() {\n\t\t\tfn.apply(thisArg, arguments);\n\t\t}\n\t}\n\n\tvar isArray = Array.isArray || function(value) { return Object.prototype.toString.call(value) === \"[object Array]\" };\n\n\tfunction Promise(fn) {\n\t\tif (typeof this !== 'object') throw new TypeError('Promises must be constructed via new');\n\t\tif (typeof fn !== 'function') throw new TypeError('not a function');\n\t\tthis._state = null;\n\t\tthis._value = null;\n\t\tthis._deferreds = []\n\n\t\tdoResolve(fn, bind(resolve, this), bind(reject, this))\n\t}\n\n\tfunction handle(deferred) {\n\t\tvar me = this;\n\t\tif (this._state === null) {\n\t\t\tthis._deferreds.push(deferred);\n\t\t\treturn\n\t\t}\n\t\tasap(function() {\n\t\t\tvar cb = me._state ? deferred.onFulfilled : deferred.onRejected\n\t\t\tif (cb === null) {\n\t\t\t\t(me._state ? deferred.resolve : deferred.reject)(me._value);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar ret;\n\t\t\ttry {\n\t\t\t\tret = cb(me._value);\n\t\t\t}\n\t\t\tcatch (e) {\n\t\t\t\tdeferred.reject(e);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdeferred.resolve(ret);\n\t\t})\n\t}\n\n\tfunction resolve(newValue) {\n\t\ttry { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure\n\t\t\tif (newValue === this) throw new TypeError('A promise cannot be resolved with itself.');\n\t\t\tif (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {\n\t\t\t\tvar then = newValue.then;\n\t\t\t\tif (typeof then === 'function') {\n\t\t\t\t\tdoResolve(bind(then, newValue), bind(resolve, this), bind(reject, this));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._state = true;\n\t\t\tthis._value = newValue;\n\t\t\tfinale.call(this);\n\t\t} catch (e) { reject.call(this, e); }\n\t}\n\n\tfunction reject(newValue) {\n\t\tthis._state = false;\n\t\tthis._value = newValue;\n\t\tfinale.call(this);\n\t}\n\n\tfunction finale() {\n\t\tfor (var i = 0, len = this._deferreds.length; i < len; i++) {\n\t\t\thandle.call(this, this._deferreds[i]);\n\t\t}\n\t\tthis._deferreds = null;\n\t}\n\n\tfunction Handler(onFulfilled, onRejected, resolve, reject){\n\t\tthis.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;\n\t\tthis.onRejected = typeof onRejected === 'function' ? onRejected : null;\n\t\tthis.resolve = resolve;\n\t\tthis.reject = reject;\n\t}\n\n\t/**\n\t * Take a potentially misbehaving resolver function and make sure\n\t * onFulfilled and onRejected are only called once.\n\t *\n\t * Makes no guarantees about asynchrony.\n\t */\n\tfunction doResolve(fn, onFulfilled, onRejected) {\n\t\tvar done = false;\n\t\ttry {\n\t\t\tfn(function (value) {\n\t\t\t\tif (done) return;\n\t\t\t\tdone = true;\n\t\t\t\tonFulfilled(value);\n\t\t\t}, function (reason) {\n\t\t\t\tif (done) return;\n\t\t\t\tdone = true;\n\t\t\t\tonRejected(reason);\n\t\t\t})\n\t\t} catch (ex) {\n\t\t\tif (done) return;\n\t\t\tdone = true;\n\t\t\tonRejected(ex);\n\t\t}\n\t}\n\n\tPromise.prototype['catch'] = function (onRejected) {\n\t\treturn this.then(null, onRejected);\n\t};\n\n\tPromise.prototype.then = function(onFulfilled, onRejected) {\n\t\tvar me = this;\n\t\treturn new Promise(function(resolve, reject) {\n\t\t\thandle.call(me, new Handler(onFulfilled, onRejected, resolve, reject));\n\t\t})\n\t};\n\n\tPromise.all = function () {\n\t\tvar args = Array.prototype.slice.call(arguments.length === 1 && isArray(arguments[0]) ? arguments[0] : arguments);\n\n\t\treturn new Promise(function (resolve, reject) {\n\t\t\tif (args.length === 0) return resolve([]);\n\t\t\tvar remaining = args.length;\n\t\t\tfunction res(i, val) {\n\t\t\t\ttry {\n\t\t\t\t\tif (val && (typeof val === 'object' || typeof val === 'function')) {\n\t\t\t\t\t\tvar then = val.then;\n\t\t\t\t\t\tif (typeof then === 'function') {\n\t\t\t\t\t\t\tthen.call(val, function (val) { res(i, val) }, reject);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\targs[i] = val;\n\t\t\t\t\tif (--remaining === 0) {\n\t\t\t\t\t\tresolve(args);\n\t\t\t\t\t}\n\t\t\t\t} catch (ex) {\n\t\t\t\t\treject(ex);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (var i = 0; i < args.length; i++) {\n\t\t\t\tres(i, args[i]);\n\t\t\t}\n\t\t});\n\t};\n\n\tPromise.resolve = function (value) {\n\t\tif (value && typeof value === 'object' && value.constructor === Promise) {\n\t\t\treturn value;\n\t\t}\n\n\t\treturn new Promise(function (resolve) {\n\t\t\tresolve(value);\n\t\t});\n\t};\n\n\tPromise.reject = function (value) {\n\t\treturn new Promise(function (resolve, reject) {\n\t\t\treject(value);\n\t\t});\n\t};\n\n\tPromise.race = function (values) {\n\t\treturn new Promise(function (resolve, reject) {\n\t\t\tfor(var i = 0, len = values.length; i < len; i++) {\n\t\t\t\tvalues[i].then(resolve, reject);\n\t\t\t}\n\t\t});\n\t};\n\n\t/**\n\t * Set the immediate function to execute callbacks\n\t * @param fn {function} Function to execute\n\t * @private\n\t */\n\tPromise._setImmediateFn = function _setImmediateFn(fn) {\n\t\tasap = fn;\n\t};\n\n\tif (typeof module !== 'undefined' && module.exports) {\n\t\tmodule.exports = Promise;\n\t} else if (!root.Promise) {\n\t\troot.Promise = Promise;\n\t}\n\n})(this);\n\n},{}],35:[function(_dereq_,module,exports){\nvar dtype = _dereq_('dtype')\nvar anArray = _dereq_('an-array')\nvar isBuffer = _dereq_('is-buffer')\n\nvar CW = [0, 2, 3]\nvar CCW = [2, 1, 3]\n\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\n    if (typeof opt === 'number') //backwards-compatible\n        opt = { count: opt }\n    else\n        opt = opt || {}\n\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\n    var dir = opt.clockwise !== false ? CW : CCW,\n        a = dir[0], \n        b = dir[1],\n        c = dir[2]\n\n    var numIndices = count * 6\n\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},{\"an-array\":2,\"dtype\":14,\"is-buffer\":20}],36:[function(_dereq_,module,exports){\n\n\n/*:: type Attr = { [key: string]: string | number } */\n/*:: type Opts = { preserveNumbers: ?boolean } */\n\n/*\n\nstyle-attr\n====\n\nVery simple parsing and stringifying of style attributes.\n\n`parse`\n----\n\nConvert a style attribute string to an object.\n\n*/\n\n/*:: declare function parse (raw: string, opts: ?Opts): Attr */\nfunction parse(raw, opts) {\n  opts = opts || {};\n\n  var preserveNumbers = opts.preserveNumbers;\n  var trim = function (s) {\n    return s.trim();\n  };\n  var obj = {};\n\n  getKeyValueChunks(raw).map(trim).filter(Boolean).forEach(function (item) {\n    // split with `.indexOf` rather than `.split` because the value may also contain colons.\n    var pos = item.indexOf(':');\n    var key = item.substr(0, pos).trim();\n    var val = item.substr(pos + 1).trim();\n    if (preserveNumbers && isNumeric(val)) {\n      val = Number(val);\n    }\n\n    obj[key] = val;\n  });\n\n  return obj;\n}\n\n/*\n\n`isNumeric`\n----\n\nCheck if a value is numeric.\nVia: https://stackoverflow.com/a/1830844/9324\n\n*/\n\n/*:: declare function isNumeric (n: any): boolean */\n\nfunction isNumeric(n) {\n  return !isNaN(parseFloat(n)) && isFinite(n);\n}\n\n/*\n\n`getKeyValueChunks`\n----\n\nSplit a string into chunks matching `<key>: <value>`\n\n*/\n/*:: declare function getKeyValueChunks (raw: string): Array<string> */\nfunction getKeyValueChunks(raw) {\n  var chunks = [];\n  var offset = 0;\n  var sep = ';';\n  var hasUnclosedUrl = /url\\([^\\)]+$/;\n  var chunk = '';\n  var nextSplit;\n  while (offset < raw.length) {\n    nextSplit = raw.indexOf(sep, offset);\n    if (nextSplit === -1) {\n      nextSplit = raw.length;\n    }\n\n    chunk += raw.substring(offset, nextSplit);\n\n    // data URIs can contain semicolons, so make sure we get the whole thing\n    if (hasUnclosedUrl.test(chunk)) {\n      chunk += ';';\n      offset = nextSplit + 1;\n      continue;\n    }\n\n    chunks.push(chunk);\n    chunk = '';\n    offset = nextSplit + 1;\n  }\n\n  return chunks;\n}\n\n/*\n\n`stringify`\n----\n\nConvert an object into an attribute string\n\n*/\n/*:: declare function stringify (obj: Attr): string */\nfunction stringify(obj) {\n  return Object.keys(obj).map(function (key) {\n    return key + ':' + obj[key];\n  }).join(';');\n}\n\n/*\n\n`normalize`\n----\n\nNormalize an attribute string (eg. collapse duplicates)\n\n*/\n/*:: declare function normalize (str: string, opts: ?Opts): string */\nfunction normalize(str, opts) {\n  return stringify(parse(str, opts));\n}\n\nmodule.exports.parse = parse;\nmodule.exports.stringify = stringify;\nmodule.exports.normalize = normalize;\n},{}],37:[function(_dereq_,module,exports){\nvar createLayout = _dereq_('layout-bmfont-text')\nvar inherits = _dereq_('inherits')\nvar createIndices = _dereq_('quad-indices')\nvar buffer = _dereq_('three-buffer-vertex-data')\nvar assign = _dereq_('object-assign')\n\nvar vertices = _dereq_('./lib/vertices')\nvar utils = _dereq_('./lib/utils')\n\nvar Base = THREE.BufferGeometry\n\nmodule.exports = function createTextGeometry (opt) {\n  return new TextGeometry(opt)\n}\n\nfunction TextGeometry (opt) {\n  Base.call(this)\n\n  if (typeof opt === 'string') {\n    opt = { text: opt }\n  }\n\n  // use these as default values for any subsequent\n  // calls to update()\n  this._opt = assign({}, opt)\n\n  // also do an initial setup...\n  if (opt) this.update(opt)\n}\n\ninherits(TextGeometry, Base)\n\nTextGeometry.prototype.update = function (opt) {\n  if (typeof opt === 'string') {\n    opt = { text: opt }\n  }\n\n  // use constructor defaults\n  opt = assign({}, this._opt, opt)\n\n  if (!opt.font) {\n    throw new TypeError('must specify a { font } in options')\n  }\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  buffer.index(this, indices, 1, 'uint16')\n  buffer.attr(this, 'position', positions, 2)\n  buffer.attr(this, 'uv', 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    var pages = vertices.pages(glyphs)\n    // enable multipage rendering\n    buffer.attr(this, 'page', pages, 1)\n  }\n}\n\nTextGeometry.prototype.computeBoundingSphere = function () {\n  if (this.boundingSphere === null) {\n    this.boundingSphere = new THREE.Sphere()\n  }\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(): ' +\n      'Computed radius is NaN. The ' +\n      '\"position\" attribute is likely to have NaN values.')\n  }\n}\n\nTextGeometry.prototype.computeBoundingBox = function () {\n  if (this.boundingBox === null) {\n    this.boundingBox = new THREE.Box3()\n  }\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},{\"./lib/utils\":38,\"./lib/vertices\":39,\"inherits\":19,\"layout-bmfont-text\":23,\"object-assign\":26,\"quad-indices\":35,\"three-buffer-vertex-data\":40}],38:[function(_dereq_,module,exports){\nvar itemSize = 2\nvar box = { min: [0, 0], 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\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}\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}\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},{}],39:[function(_dereq_,module,exports){\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}\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\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}\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},{}],40:[function(_dereq_,module,exports){\nvar flatten = _dereq_('flatten-vertex-data')\nvar warned = false;\n\nmodule.exports.attr = setAttribute\nmodule.exports.index = setIndex\n\nfunction setIndex (geometry, data, itemSize, dtype) {\n  if (typeof itemSize !== 'number') itemSize = 1\n  if (typeof dtype !== 'string') dtype = 'uint16'\n\n  var isR69 = !geometry.index && typeof geometry.setIndex !== 'function'\n  var attrib = isR69 ? geometry.getAttribute('index') : geometry.index\n  var newAttrib = updateAttribute(attrib, data, itemSize, dtype)\n  if (newAttrib) {\n    if (isR69) geometry.addAttribute('index', newAttrib)\n    else geometry.index = newAttrib\n  }\n}\n\nfunction setAttribute (geometry, key, data, itemSize, dtype) {\n  if (typeof itemSize !== 'number') itemSize = 3\n  if (typeof dtype !== 'string') dtype = 'float32'\n  if (Array.isArray(data) &&\n    Array.isArray(data[0]) &&\n    data[0].length !== itemSize) {\n    throw new Error('Nested vertex array has unexpected size; expected ' +\n      itemSize + ' but found ' + data[0].length)\n  }\n\n  var attrib = geometry.getAttribute(key)\n  var newAttrib = updateAttribute(attrib, data, itemSize, dtype)\n  if (newAttrib) {\n    geometry.addAttribute(key, newAttrib)\n  }\n}\n\nfunction updateAttribute (attrib, data, itemSize, dtype) {\n  data = data || []\n  if (!attrib || rebuildAttribute(attrib, data, itemSize)) {\n    // create a new array with desired type\n    data = flatten(data, dtype)\n\n    var needsNewBuffer = attrib && typeof attrib.setArray !== 'function'\n    if (!attrib || needsNewBuffer) {\n      // We are on an old version of ThreeJS which can't\n      // support growing / shrinking buffers, so we need\n      // to build a new buffer\n      if (needsNewBuffer && !warned) {\n        warned = true\n        console.warn([\n          'A WebGL buffer is being updated with a new size or itemSize, ',\n          'however this version of ThreeJS only supports fixed-size buffers.',\n          '\\nThe old buffer may still be kept in memory.\\n',\n          'To avoid memory leaks, it is recommended that you dispose ',\n          'your geometries and create new ones, or update to ThreeJS r82 or newer.\\n',\n          'See here for discussion:\\n',\n          'https://github.com/mrdoob/three.js/pull/9631'\n        ].join(''))\n      }\n\n      // Build a new attribute\n      attrib = new THREE.BufferAttribute(data, itemSize);\n    }\n\n    attrib.itemSize = itemSize\n    attrib.needsUpdate = true\n\n    // New versions of ThreeJS suggest using setArray\n    // to change the data. It will use bufferData internally,\n    // so you can change the array size without any issues\n    if (typeof attrib.setArray === 'function') {\n      attrib.setArray(data)\n    }\n\n    return attrib\n  } else {\n    // copy data into the existing array\n    flatten(data, attrib.array)\n    attrib.needsUpdate = true\n    return null\n  }\n}\n\n// Test whether the attribute needs to be re-created,\n// returns false if we can re-use it as-is.\nfunction rebuildAttribute (attrib, data, itemSize) {\n  if (attrib.itemSize !== itemSize) return true\n  if (!attrib.array) return true\n  var attribLength = attrib.array.length\n  if (Array.isArray(data) && Array.isArray(data[0])) {\n    // [ [ x, y, z ] ]\n    return attribLength !== data.length * itemSize\n  } else {\n    // [ x, y, z ]\n    return attribLength !== data.length\n  }\n  return false\n}\n\n},{\"flatten-vertex-data\":15}],41:[function(_dereq_,module,exports){\n(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :\n\ttypeof define === 'function' && define.amd ? define(['exports'], factory) :\n\t(factory((global.THREE = global.THREE || {})));\n}(this, (function (exports) { 'use strict';\n\n\t// Polyfills\n\n\tif ( Number.EPSILON === undefined ) {\n\n\t\tNumber.EPSILON = Math.pow( 2, - 52 );\n\n\t}\n\n\tif ( Number.isInteger === undefined ) {\n\n\t\t// Missing in IE\n\t\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger\n\n\t\tNumber.isInteger = function ( value ) {\n\n\t\t\treturn typeof value === 'number' && isFinite( value ) && Math.floor( value ) === value;\n\n\t\t};\n\n\t}\n\n\t//\n\n\tif ( Math.sign === undefined ) {\n\n\t\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign\n\n\t\tMath.sign = function ( x ) {\n\n\t\t\treturn ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : + x;\n\n\t\t};\n\n\t}\n\n\tif ( Function.prototype.name === undefined ) {\n\n\t\t// Missing in IE\n\t\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name\n\n\t\tObject.defineProperty( Function.prototype, 'name', {\n\n\t\t\tget: function () {\n\n\t\t\t\treturn this.toString().match( /^\\s*function\\s*([^\\(\\s]*)/ )[ 1 ];\n\n\t\t\t}\n\n\t\t} );\n\n\t}\n\n\tif ( Object.assign === undefined ) {\n\n\t\t// Missing in IE\n\t\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign\n\n\t\t( function () {\n\n\t\t\tObject.assign = function ( target ) {\n\n\t\t\t\t'use strict';\n\n\t\t\t\tif ( target === undefined || target === null ) {\n\n\t\t\t\t\tthrow new TypeError( 'Cannot convert undefined or null to object' );\n\n\t\t\t\t}\n\n\t\t\t\tvar output = Object( target );\n\n\t\t\t\tfor ( var index = 1; index < arguments.length; index ++ ) {\n\n\t\t\t\t\tvar source = arguments[ index ];\n\n\t\t\t\t\tif ( source !== undefined && source !== null ) {\n\n\t\t\t\t\t\tfor ( var nextKey in source ) {\n\n\t\t\t\t\t\t\tif ( Object.prototype.hasOwnProperty.call( source, nextKey ) ) {\n\n\t\t\t\t\t\t\t\toutput[ nextKey ] = source[ nextKey ];\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\treturn output;\n\n\t\t\t};\n\n\t\t} )();\n\n\t}\n\n\t/**\n\t * https://github.com/mrdoob/eventdispatcher.js/\n\t */\n\n\tfunction EventDispatcher() {}\n\n\tObject.assign( EventDispatcher.prototype, {\n\n\t\taddEventListener: function ( type, listener ) {\n\n\t\t\tif ( this._listeners === undefined ) this._listeners = {};\n\n\t\t\tvar listeners = this._listeners;\n\n\t\t\tif ( listeners[ type ] === undefined ) {\n\n\t\t\t\tlisteners[ type ] = [];\n\n\t\t\t}\n\n\t\t\tif ( listeners[ type ].indexOf( listener ) === - 1 ) {\n\n\t\t\t\tlisteners[ type ].push( listener );\n\n\t\t\t}\n\n\t\t},\n\n\t\thasEventListener: function ( type, listener ) {\n\n\t\t\tif ( this._listeners === undefined ) return false;\n\n\t\t\tvar listeners = this._listeners;\n\n\t\t\treturn listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1;\n\n\t\t},\n\n\t\tremoveEventListener: function ( type, listener ) {\n\n\t\t\tif ( this._listeners === undefined ) return;\n\n\t\t\tvar listeners = this._listeners;\n\t\t\tvar listenerArray = listeners[ type ];\n\n\t\t\tif ( listenerArray !== undefined ) {\n\n\t\t\t\tvar index = listenerArray.indexOf( listener );\n\n\t\t\t\tif ( index !== - 1 ) {\n\n\t\t\t\t\tlistenerArray.splice( index, 1 );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t},\n\n\t\tdispatchEvent: function ( event ) {\n\n\t\t\tif ( this._listeners === undefined ) return;\n\n\t\t\tvar listeners = this._listeners;\n\t\t\tvar listenerArray = listeners[ event.type ];\n\n\t\t\tif ( listenerArray !== undefined ) {\n\n\t\t\t\tevent.target = this;\n\n\t\t\t\tvar array = listenerArray.slice( 0 );\n\n\t\t\t\tfor ( var i = 0, l = array.length; i < l; i ++ ) {\n\n\t\t\t\t\tarray[ i ].call( this, event );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t} );\n\n\tvar REVISION = '87';\n\tvar MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };\n\tvar CullFaceNone = 0;\n\tvar CullFaceBack = 1;\n\tvar CullFaceFront = 2;\n\tvar CullFaceFrontBack = 3;\n\tvar FrontFaceDirectionCW = 0;\n\tvar FrontFaceDirectionCCW = 1;\n\tvar BasicShadowMap = 0;\n\tvar PCFShadowMap = 1;\n\tvar PCFSoftShadowMap = 2;\n\tvar FrontSide = 0;\n\tvar BackSide = 1;\n\tvar DoubleSide = 2;\n\tvar FlatShading = 1;\n\tvar SmoothShading = 2;\n\tvar NoColors = 0;\n\tvar FaceColors = 1;\n\tvar VertexColors = 2;\n\tvar NoBlending = 0;\n\tvar NormalBlending = 1;\n\tvar AdditiveBlending = 2;\n\tvar SubtractiveBlending = 3;\n\tvar MultiplyBlending = 4;\n\tvar CustomBlending = 5;\n\tvar AddEquation = 100;\n\tvar SubtractEquation = 101;\n\tvar ReverseSubtractEquation = 102;\n\tvar MinEquation = 103;\n\tvar MaxEquation = 104;\n\tvar ZeroFactor = 200;\n\tvar OneFactor = 201;\n\tvar SrcColorFactor = 202;\n\tvar OneMinusSrcColorFactor = 203;\n\tvar SrcAlphaFactor = 204;\n\tvar OneMinusSrcAlphaFactor = 205;\n\tvar DstAlphaFactor = 206;\n\tvar OneMinusDstAlphaFactor = 207;\n\tvar DstColorFactor = 208;\n\tvar OneMinusDstColorFactor = 209;\n\tvar SrcAlphaSaturateFactor = 210;\n\tvar NeverDepth = 0;\n\tvar AlwaysDepth = 1;\n\tvar LessDepth = 2;\n\tvar LessEqualDepth = 3;\n\tvar EqualDepth = 4;\n\tvar GreaterEqualDepth = 5;\n\tvar GreaterDepth = 6;\n\tvar NotEqualDepth = 7;\n\tvar MultiplyOperation = 0;\n\tvar MixOperation = 1;\n\tvar AddOperation = 2;\n\tvar NoToneMapping = 0;\n\tvar LinearToneMapping = 1;\n\tvar ReinhardToneMapping = 2;\n\tvar Uncharted2ToneMapping = 3;\n\tvar CineonToneMapping = 4;\n\tvar UVMapping = 300;\n\tvar CubeReflectionMapping = 301;\n\tvar CubeRefractionMapping = 302;\n\tvar EquirectangularReflectionMapping = 303;\n\tvar EquirectangularRefractionMapping = 304;\n\tvar SphericalReflectionMapping = 305;\n\tvar CubeUVReflectionMapping = 306;\n\tvar CubeUVRefractionMapping = 307;\n\tvar RepeatWrapping = 1000;\n\tvar ClampToEdgeWrapping = 1001;\n\tvar MirroredRepeatWrapping = 1002;\n\tvar NearestFilter = 1003;\n\tvar NearestMipMapNearestFilter = 1004;\n\tvar NearestMipMapLinearFilter = 1005;\n\tvar LinearFilter = 1006;\n\tvar LinearMipMapNearestFilter = 1007;\n\tvar LinearMipMapLinearFilter = 1008;\n\tvar UnsignedByteType = 1009;\n\tvar ByteType = 1010;\n\tvar ShortType = 1011;\n\tvar UnsignedShortType = 1012;\n\tvar IntType = 1013;\n\tvar UnsignedIntType = 1014;\n\tvar FloatType = 1015;\n\tvar HalfFloatType = 1016;\n\tvar UnsignedShort4444Type = 1017;\n\tvar UnsignedShort5551Type = 1018;\n\tvar UnsignedShort565Type = 1019;\n\tvar UnsignedInt248Type = 1020;\n\tvar AlphaFormat = 1021;\n\tvar RGBFormat = 1022;\n\tvar RGBAFormat = 1023;\n\tvar LuminanceFormat = 1024;\n\tvar LuminanceAlphaFormat = 1025;\n\tvar RGBEFormat = RGBAFormat;\n\tvar DepthFormat = 1026;\n\tvar DepthStencilFormat = 1027;\n\tvar RGB_S3TC_DXT1_Format = 2001;\n\tvar RGBA_S3TC_DXT1_Format = 2002;\n\tvar RGBA_S3TC_DXT3_Format = 2003;\n\tvar RGBA_S3TC_DXT5_Format = 2004;\n\tvar RGB_PVRTC_4BPPV1_Format = 2100;\n\tvar RGB_PVRTC_2BPPV1_Format = 2101;\n\tvar RGBA_PVRTC_4BPPV1_Format = 2102;\n\tvar RGBA_PVRTC_2BPPV1_Format = 2103;\n\tvar RGB_ETC1_Format = 2151;\n\tvar LoopOnce = 2200;\n\tvar LoopRepeat = 2201;\n\tvar LoopPingPong = 2202;\n\tvar InterpolateDiscrete = 2300;\n\tvar InterpolateLinear = 2301;\n\tvar InterpolateSmooth = 2302;\n\tvar ZeroCurvatureEnding = 2400;\n\tvar ZeroSlopeEnding = 2401;\n\tvar WrapAroundEnding = 2402;\n\tvar TrianglesDrawMode = 0;\n\tvar TriangleStripDrawMode = 1;\n\tvar TriangleFanDrawMode = 2;\n\tvar LinearEncoding = 3000;\n\tvar sRGBEncoding = 3001;\n\tvar GammaEncoding = 3007;\n\tvar RGBEEncoding = 3002;\n\tvar LogLuvEncoding = 3003;\n\tvar RGBM7Encoding = 3004;\n\tvar RGBM16Encoding = 3005;\n\tvar RGBDEncoding = 3006;\n\tvar BasicDepthPacking = 3200;\n\tvar RGBADepthPacking = 3201;\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tvar _Math = {\n\n\t\tDEG2RAD: Math.PI / 180,\n\t\tRAD2DEG: 180 / Math.PI,\n\n\t\tgenerateUUID: function () {\n\n\t\t\t// http://www.broofa.com/Tools/Math.uuid.htm\n\n\t\t\tvar chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split( '' );\n\t\t\tvar uuid = new Array( 36 );\n\t\t\tvar rnd = 0, r;\n\n\t\t\treturn function generateUUID() {\n\n\t\t\t\tfor ( var i = 0; i < 36; i ++ ) {\n\n\t\t\t\t\tif ( i === 8 || i === 13 || i === 18 || i === 23 ) {\n\n\t\t\t\t\t\tuuid[ i ] = '-';\n\n\t\t\t\t\t} else if ( i === 14 ) {\n\n\t\t\t\t\t\tuuid[ i ] = '4';\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0;\n\t\t\t\t\t\tr = rnd & 0xf;\n\t\t\t\t\t\trnd = rnd >> 4;\n\t\t\t\t\t\tuuid[ i ] = chars[ ( i === 19 ) ? ( r & 0x3 ) | 0x8 : r ];\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\treturn uuid.join( '' );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tclamp: function ( value, min, max ) {\n\n\t\t\treturn Math.max( min, Math.min( max, value ) );\n\n\t\t},\n\n\t\t// compute euclidian modulo of m % n\n\t\t// https://en.wikipedia.org/wiki/Modulo_operation\n\n\t\teuclideanModulo: function ( n, m ) {\n\n\t\t\treturn ( ( n % m ) + m ) % m;\n\n\t\t},\n\n\t\t// Linear mapping from range <a1, a2> to range <b1, b2>\n\n\t\tmapLinear: function ( x, a1, a2, b1, b2 ) {\n\n\t\t\treturn b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );\n\n\t\t},\n\n\t\t// https://en.wikipedia.org/wiki/Linear_interpolation\n\n\t\tlerp: function ( x, y, t ) {\n\n\t\t\treturn ( 1 - t ) * x + t * y;\n\n\t\t},\n\n\t\t// http://en.wikipedia.org/wiki/Smoothstep\n\n\t\tsmoothstep: function ( x, min, max ) {\n\n\t\t\tif ( x <= min ) return 0;\n\t\t\tif ( x >= max ) return 1;\n\n\t\t\tx = ( x - min ) / ( max - min );\n\n\t\t\treturn x * x * ( 3 - 2 * x );\n\n\t\t},\n\n\t\tsmootherstep: function ( x, min, max ) {\n\n\t\t\tif ( x <= min ) return 0;\n\t\t\tif ( x >= max ) return 1;\n\n\t\t\tx = ( x - min ) / ( max - min );\n\n\t\t\treturn x * x * x * ( x * ( x * 6 - 15 ) + 10 );\n\n\t\t},\n\n\t\t// Random integer from <low, high> interval\n\n\t\trandInt: function ( low, high ) {\n\n\t\t\treturn low + Math.floor( Math.random() * ( high - low + 1 ) );\n\n\t\t},\n\n\t\t// Random float from <low, high> interval\n\n\t\trandFloat: function ( low, high ) {\n\n\t\t\treturn low + Math.random() * ( high - low );\n\n\t\t},\n\n\t\t// Random float from <-range/2, range/2> interval\n\n\t\trandFloatSpread: function ( range ) {\n\n\t\t\treturn range * ( 0.5 - Math.random() );\n\n\t\t},\n\n\t\tdegToRad: function ( degrees ) {\n\n\t\t\treturn degrees * _Math.DEG2RAD;\n\n\t\t},\n\n\t\tradToDeg: function ( radians ) {\n\n\t\t\treturn radians * _Math.RAD2DEG;\n\n\t\t},\n\n\t\tisPowerOfTwo: function ( value ) {\n\n\t\t\treturn ( value & ( value - 1 ) ) === 0 && value !== 0;\n\n\t\t},\n\n\t\tnearestPowerOfTwo: function ( value ) {\n\n\t\t\treturn Math.pow( 2, Math.round( Math.log( value ) / Math.LN2 ) );\n\n\t\t},\n\n\t\tnextPowerOfTwo: function ( value ) {\n\n\t\t\tvalue --;\n\t\t\tvalue |= value >> 1;\n\t\t\tvalue |= value >> 2;\n\t\t\tvalue |= value >> 4;\n\t\t\tvalue |= value >> 8;\n\t\t\tvalue |= value >> 16;\n\t\t\tvalue ++;\n\n\t\t\treturn value;\n\n\t\t}\n\n\t};\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author philogb / http://blog.thejit.org/\n\t * @author egraether / http://egraether.com/\n\t * @author zz85 / http://www.lab4games.net/zz85/blog\n\t */\n\n\tfunction Vector2( x, y ) {\n\n\t\tthis.x = x || 0;\n\t\tthis.y = y || 0;\n\n\t}\n\n\tObject.defineProperties( Vector2.prototype, {\n\n\t\t\"width\" : {\n\n\t\t\tget: function () {\n\n\t\t\t\treturn this.x;\n\n\t\t\t},\n\n\t\t\tset: function ( value ) {\n\n\t\t\t\tthis.x = value;\n\n\t\t\t}\n\n\t\t},\n\n\t\t\"height\" : {\n\n\t\t\tget: function () {\n\n\t\t\t\treturn this.y;\n\n\t\t\t},\n\n\t\t\tset: function ( value ) {\n\n\t\t\t\tthis.y = value;\n\n\t\t\t}\n\n\t\t}\n\n\t} );\n\n\tObject.assign( Vector2.prototype, {\n\n\t\tisVector2: true,\n\n\t\tset: function ( x, y ) {\n\n\t\t\tthis.x = x;\n\t\t\tthis.y = y;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetScalar: function ( scalar ) {\n\n\t\t\tthis.x = scalar;\n\t\t\tthis.y = scalar;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetX: function ( x ) {\n\n\t\t\tthis.x = x;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetY: function ( y ) {\n\n\t\t\tthis.y = y;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetComponent: function ( index, value ) {\n\n\t\t\tswitch ( index ) {\n\n\t\t\t\tcase 0: this.x = value; break;\n\t\t\t\tcase 1: this.y = value; break;\n\t\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetComponent: function ( index ) {\n\n\t\t\tswitch ( index ) {\n\n\t\t\t\tcase 0: return this.x;\n\t\t\t\tcase 1: return this.y;\n\t\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t\t}\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor( this.x, this.y );\n\n\t\t},\n\n\t\tcopy: function ( v ) {\n\n\t\t\tthis.x = v.x;\n\t\t\tthis.y = v.y;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tadd: function ( v, w ) {\n\n\t\t\tif ( w !== undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );\n\t\t\t\treturn this.addVectors( v, w );\n\n\t\t\t}\n\n\t\t\tthis.x += v.x;\n\t\t\tthis.y += v.y;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\taddScalar: function ( s ) {\n\n\t\t\tthis.x += s;\n\t\t\tthis.y += s;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\taddVectors: function ( a, b ) {\n\n\t\t\tthis.x = a.x + b.x;\n\t\t\tthis.y = a.y + b.y;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\taddScaledVector: function ( v, s ) {\n\n\t\t\tthis.x += v.x * s;\n\t\t\tthis.y += v.y * s;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsub: function ( v, w ) {\n\n\t\t\tif ( w !== undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );\n\t\t\t\treturn this.subVectors( v, w );\n\n\t\t\t}\n\n\t\t\tthis.x -= v.x;\n\t\t\tthis.y -= v.y;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsubScalar: function ( s ) {\n\n\t\t\tthis.x -= s;\n\t\t\tthis.y -= s;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsubVectors: function ( a, b ) {\n\n\t\t\tthis.x = a.x - b.x;\n\t\t\tthis.y = a.y - b.y;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmultiply: function ( v ) {\n\n\t\t\tthis.x *= v.x;\n\t\t\tthis.y *= v.y;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmultiplyScalar: function ( scalar ) {\n\n\t\t\tthis.x *= scalar;\n\t\t\tthis.y *= scalar;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tdivide: function ( v ) {\n\n\t\t\tthis.x /= v.x;\n\t\t\tthis.y /= v.y;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tdivideScalar: function ( scalar ) {\n\n\t\t\treturn this.multiplyScalar( 1 / scalar );\n\n\t\t},\n\n\t\tmin: function ( v ) {\n\n\t\t\tthis.x = Math.min( this.x, v.x );\n\t\t\tthis.y = Math.min( this.y, v.y );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmax: function ( v ) {\n\n\t\t\tthis.x = Math.max( this.x, v.x );\n\t\t\tthis.y = Math.max( this.y, v.y );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclamp: function ( min, max ) {\n\n\t\t\t// assumes min < max, componentwise\n\n\t\t\tthis.x = Math.max( min.x, Math.min( max.x, this.x ) );\n\t\t\tthis.y = Math.max( min.y, Math.min( max.y, this.y ) );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclampScalar: function () {\n\n\t\t\tvar min = new Vector2();\n\t\t\tvar max = new Vector2();\n\n\t\t\treturn function clampScalar( minVal, maxVal ) {\n\n\t\t\t\tmin.set( minVal, minVal );\n\t\t\t\tmax.set( maxVal, maxVal );\n\n\t\t\t\treturn this.clamp( min, max );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tclampLength: function ( min, max ) {\n\n\t\t\tvar length = this.length();\n\n\t\t\treturn this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );\n\n\t\t},\n\n\t\tfloor: function () {\n\n\t\t\tthis.x = Math.floor( this.x );\n\t\t\tthis.y = Math.floor( this.y );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tceil: function () {\n\n\t\t\tthis.x = Math.ceil( this.x );\n\t\t\tthis.y = Math.ceil( this.y );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tround: function () {\n\n\t\t\tthis.x = Math.round( this.x );\n\t\t\tthis.y = Math.round( this.y );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\troundToZero: function () {\n\n\t\t\tthis.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );\n\t\t\tthis.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tnegate: function () {\n\n\t\t\tthis.x = - this.x;\n\t\t\tthis.y = - this.y;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tdot: function ( v ) {\n\n\t\t\treturn this.x * v.x + this.y * v.y;\n\n\t\t},\n\n\t\tlengthSq: function () {\n\n\t\t\treturn this.x * this.x + this.y * this.y;\n\n\t\t},\n\n\t\tlength: function () {\n\n\t\t\treturn Math.sqrt( this.x * this.x + this.y * this.y );\n\n\t\t},\n\n\t\tlengthManhattan: function() {\n\n\t\t\treturn Math.abs( this.x ) + Math.abs( this.y );\n\n\t\t},\n\n\t\tnormalize: function () {\n\n\t\t\treturn this.divideScalar( this.length() || 1 );\n\n\t\t},\n\n\t\tangle: function () {\n\n\t\t\t// computes the angle in radians with respect to the positive x-axis\n\n\t\t\tvar angle = Math.atan2( this.y, this.x );\n\n\t\t\tif ( angle < 0 ) angle += 2 * Math.PI;\n\n\t\t\treturn angle;\n\n\t\t},\n\n\t\tdistanceTo: function ( v ) {\n\n\t\t\treturn Math.sqrt( this.distanceToSquared( v ) );\n\n\t\t},\n\n\t\tdistanceToSquared: function ( v ) {\n\n\t\t\tvar dx = this.x - v.x, dy = this.y - v.y;\n\t\t\treturn dx * dx + dy * dy;\n\n\t\t},\n\n\t\tdistanceToManhattan: function ( v ) {\n\n\t\t\treturn Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );\n\n\t\t},\n\n\t\tsetLength: function ( length ) {\n\n\t\t\treturn this.normalize().multiplyScalar( length );\n\n\t\t},\n\n\t\tlerp: function ( v, alpha ) {\n\n\t\t\tthis.x += ( v.x - this.x ) * alpha;\n\t\t\tthis.y += ( v.y - this.y ) * alpha;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tlerpVectors: function ( v1, v2, alpha ) {\n\n\t\t\treturn this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );\n\n\t\t},\n\n\t\tequals: function ( v ) {\n\n\t\t\treturn ( ( v.x === this.x ) && ( v.y === this.y ) );\n\n\t\t},\n\n\t\tfromArray: function ( array, offset ) {\n\n\t\t\tif ( offset === undefined ) offset = 0;\n\n\t\t\tthis.x = array[ offset ];\n\t\t\tthis.y = array[ offset + 1 ];\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\ttoArray: function ( array, offset ) {\n\n\t\t\tif ( array === undefined ) array = [];\n\t\t\tif ( offset === undefined ) offset = 0;\n\n\t\t\tarray[ offset ] = this.x;\n\t\t\tarray[ offset + 1 ] = this.y;\n\n\t\t\treturn array;\n\n\t\t},\n\n\t\tfromBufferAttribute: function ( attribute, index, offset ) {\n\n\t\t\tif ( offset !== undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.Vector2: offset has been removed from .fromBufferAttribute().' );\n\n\t\t\t}\n\n\t\t\tthis.x = attribute.getX( index );\n\t\t\tthis.y = attribute.getY( index );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\trotateAround: function ( center, angle ) {\n\n\t\t\tvar c = Math.cos( angle ), s = Math.sin( angle );\n\n\t\t\tvar x = this.x - center.x;\n\t\t\tvar y = this.y - center.y;\n\n\t\t\tthis.x = x * c - y * s + center.x;\n\t\t\tthis.y = x * s + y * c + center.y;\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author szimek / https://github.com/szimek/\n\t */\n\n\tvar textureId = 0;\n\n\tfunction Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {\n\n\t\tObject.defineProperty( this, 'id', { value: textureId ++ } );\n\n\t\tthis.uuid = _Math.generateUUID();\n\n\t\tthis.name = '';\n\n\t\tthis.image = image !== undefined ? image : Texture.DEFAULT_IMAGE;\n\t\tthis.mipmaps = [];\n\n\t\tthis.mapping = mapping !== undefined ? mapping : Texture.DEFAULT_MAPPING;\n\n\t\tthis.wrapS = wrapS !== undefined ? wrapS : ClampToEdgeWrapping;\n\t\tthis.wrapT = wrapT !== undefined ? wrapT : ClampToEdgeWrapping;\n\n\t\tthis.magFilter = magFilter !== undefined ? magFilter : LinearFilter;\n\t\tthis.minFilter = minFilter !== undefined ? minFilter : LinearMipMapLinearFilter;\n\n\t\tthis.anisotropy = anisotropy !== undefined ? anisotropy : 1;\n\n\t\tthis.format = format !== undefined ? format : RGBAFormat;\n\t\tthis.type = type !== undefined ? type : UnsignedByteType;\n\n\t\tthis.offset = new Vector2( 0, 0 );\n\t\tthis.repeat = new Vector2( 1, 1 );\n\n\t\tthis.generateMipmaps = true;\n\t\tthis.premultiplyAlpha = false;\n\t\tthis.flipY = true;\n\t\tthis.unpackAlignment = 4;\t// valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)\n\n\t\t// Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap.\n\t\t//\n\t\t// Also changing the encoding after already used by a Material will not automatically make the Material\n\t\t// update.  You need to explicitly call Material.needsUpdate to trigger it to recompile.\n\t\tthis.encoding = encoding !== undefined ? encoding : LinearEncoding;\n\n\t\tthis.version = 0;\n\t\tthis.onUpdate = null;\n\n\t}\n\n\tTexture.DEFAULT_IMAGE = undefined;\n\tTexture.DEFAULT_MAPPING = UVMapping;\n\n\tObject.defineProperty( Texture.prototype, \"needsUpdate\", {\n\n\t\tset: function ( value ) {\n\n\t\t\tif ( value === true ) this.version ++;\n\n\t\t}\n\n\t} );\n\n\tObject.assign( Texture.prototype, EventDispatcher.prototype, {\n\n\t\tconstructor: Texture,\n\n\t\tisTexture: true,\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor().copy( this );\n\n\t\t},\n\n\t\tcopy: function ( source ) {\n\n\t\t\tthis.name = source.name;\n\n\t\t\tthis.image = source.image;\n\t\t\tthis.mipmaps = source.mipmaps.slice( 0 );\n\n\t\t\tthis.mapping = source.mapping;\n\n\t\t\tthis.wrapS = source.wrapS;\n\t\t\tthis.wrapT = source.wrapT;\n\n\t\t\tthis.magFilter = source.magFilter;\n\t\t\tthis.minFilter = source.minFilter;\n\n\t\t\tthis.anisotropy = source.anisotropy;\n\n\t\t\tthis.format = source.format;\n\t\t\tthis.type = source.type;\n\n\t\t\tthis.offset.copy( source.offset );\n\t\t\tthis.repeat.copy( source.repeat );\n\n\t\t\tthis.generateMipmaps = source.generateMipmaps;\n\t\t\tthis.premultiplyAlpha = source.premultiplyAlpha;\n\t\t\tthis.flipY = source.flipY;\n\t\t\tthis.unpackAlignment = source.unpackAlignment;\n\t\t\tthis.encoding = source.encoding;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\ttoJSON: function ( meta ) {\n\n\t\t\tif ( meta.textures[ this.uuid ] !== undefined ) {\n\n\t\t\t\treturn meta.textures[ this.uuid ];\n\n\t\t\t}\n\n\t\t\tfunction getDataURL( image ) {\n\n\t\t\t\tvar canvas;\n\n\t\t\t\tif ( image instanceof HTMLCanvasElement ) {\n\n\t\t\t\t\tcanvas = image;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tcanvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );\n\t\t\t\t\tcanvas.width = image.width;\n\t\t\t\t\tcanvas.height = image.height;\n\n\t\t\t\t\tvar context = canvas.getContext( '2d' );\n\n\t\t\t\t\tif ( image instanceof ImageData ) {\n\n\t\t\t\t\t\tcontext.putImageData( image, 0, 0 );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tcontext.drawImage( image, 0, 0, image.width, image.height );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( canvas.width > 2048 || canvas.height > 2048 ) {\n\n\t\t\t\t\treturn canvas.toDataURL( 'image/jpeg', 0.6 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn canvas.toDataURL( 'image/png' );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tvar output = {\n\t\t\t\tmetadata: {\n\t\t\t\t\tversion: 4.5,\n\t\t\t\t\ttype: 'Texture',\n\t\t\t\t\tgenerator: 'Texture.toJSON'\n\t\t\t\t},\n\n\t\t\t\tuuid: this.uuid,\n\t\t\t\tname: this.name,\n\n\t\t\t\tmapping: this.mapping,\n\n\t\t\t\trepeat: [ this.repeat.x, this.repeat.y ],\n\t\t\t\toffset: [ this.offset.x, this.offset.y ],\n\t\t\t\twrap: [ this.wrapS, this.wrapT ],\n\n\t\t\t\tminFilter: this.minFilter,\n\t\t\t\tmagFilter: this.magFilter,\n\t\t\t\tanisotropy: this.anisotropy,\n\n\t\t\t\tflipY: this.flipY\n\t\t\t};\n\n\t\t\tif ( this.image !== undefined ) {\n\n\t\t\t\t// TODO: Move to THREE.Image\n\n\t\t\t\tvar image = this.image;\n\n\t\t\t\tif ( image.uuid === undefined ) {\n\n\t\t\t\t\timage.uuid = _Math.generateUUID(); // UGH\n\n\t\t\t\t}\n\n\t\t\t\tif ( meta.images[ image.uuid ] === undefined ) {\n\n\t\t\t\t\tmeta.images[ image.uuid ] = {\n\t\t\t\t\t\tuuid: image.uuid,\n\t\t\t\t\t\turl: getDataURL( image )\n\t\t\t\t\t};\n\n\t\t\t\t}\n\n\t\t\t\toutput.image = image.uuid;\n\n\t\t\t}\n\n\t\t\tmeta.textures[ this.uuid ] = output;\n\n\t\t\treturn output;\n\n\t\t},\n\n\t\tdispose: function () {\n\n\t\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t\t},\n\n\t\ttransformUv: function ( uv ) {\n\n\t\t\tif ( this.mapping !== UVMapping ) return;\n\n\t\t\tuv.multiply( this.repeat );\n\t\t\tuv.add( this.offset );\n\n\t\t\tif ( uv.x < 0 || uv.x > 1 ) {\n\n\t\t\t\tswitch ( this.wrapS ) {\n\n\t\t\t\t\tcase RepeatWrapping:\n\n\t\t\t\t\t\tuv.x = uv.x - Math.floor( uv.x );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase ClampToEdgeWrapping:\n\n\t\t\t\t\t\tuv.x = uv.x < 0 ? 0 : 1;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase MirroredRepeatWrapping:\n\n\t\t\t\t\t\tif ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {\n\n\t\t\t\t\t\t\tuv.x = Math.ceil( uv.x ) - uv.x;\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tuv.x = uv.x - Math.floor( uv.x );\n\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( uv.y < 0 || uv.y > 1 ) {\n\n\t\t\t\tswitch ( this.wrapT ) {\n\n\t\t\t\t\tcase RepeatWrapping:\n\n\t\t\t\t\t\tuv.y = uv.y - Math.floor( uv.y );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase ClampToEdgeWrapping:\n\n\t\t\t\t\t\tuv.y = uv.y < 0 ? 0 : 1;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase MirroredRepeatWrapping:\n\n\t\t\t\t\t\tif ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {\n\n\t\t\t\t\t\t\tuv.y = Math.ceil( uv.y ) - uv.y;\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tuv.y = uv.y - Math.floor( uv.y );\n\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( this.flipY ) {\n\n\t\t\t\tuv.y = 1 - uv.y;\n\n\t\t\t}\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author supereggbert / http://www.paulbrunt.co.uk/\n\t * @author philogb / http://blog.thejit.org/\n\t * @author mikael emtinger / http://gomo.se/\n\t * @author egraether / http://egraether.com/\n\t * @author WestLangley / http://github.com/WestLangley\n\t */\n\n\tfunction Vector4( x, y, z, w ) {\n\n\t\tthis.x = x || 0;\n\t\tthis.y = y || 0;\n\t\tthis.z = z || 0;\n\t\tthis.w = ( w !== undefined ) ? w : 1;\n\n\t}\n\n\tObject.assign( Vector4.prototype, {\n\n\t\tisVector4: true,\n\n\t\tset: function ( x, y, z, w ) {\n\n\t\t\tthis.x = x;\n\t\t\tthis.y = y;\n\t\t\tthis.z = z;\n\t\t\tthis.w = w;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetScalar: function ( scalar ) {\n\n\t\t\tthis.x = scalar;\n\t\t\tthis.y = scalar;\n\t\t\tthis.z = scalar;\n\t\t\tthis.w = scalar;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetX: function ( x ) {\n\n\t\t\tthis.x = x;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetY: function ( y ) {\n\n\t\t\tthis.y = y;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetZ: function ( z ) {\n\n\t\t\tthis.z = z;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetW: function ( w ) {\n\n\t\t\tthis.w = w;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetComponent: function ( index, value ) {\n\n\t\t\tswitch ( index ) {\n\n\t\t\t\tcase 0: this.x = value; break;\n\t\t\t\tcase 1: this.y = value; break;\n\t\t\t\tcase 2: this.z = value; break;\n\t\t\t\tcase 3: this.w = value; break;\n\t\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetComponent: function ( index ) {\n\n\t\t\tswitch ( index ) {\n\n\t\t\t\tcase 0: return this.x;\n\t\t\t\tcase 1: return this.y;\n\t\t\t\tcase 2: return this.z;\n\t\t\t\tcase 3: return this.w;\n\t\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t\t}\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor( this.x, this.y, this.z, this.w );\n\n\t\t},\n\n\t\tcopy: function ( v ) {\n\n\t\t\tthis.x = v.x;\n\t\t\tthis.y = v.y;\n\t\t\tthis.z = v.z;\n\t\t\tthis.w = ( v.w !== undefined ) ? v.w : 1;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tadd: function ( v, w ) {\n\n\t\t\tif ( w !== undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );\n\t\t\t\treturn this.addVectors( v, w );\n\n\t\t\t}\n\n\t\t\tthis.x += v.x;\n\t\t\tthis.y += v.y;\n\t\t\tthis.z += v.z;\n\t\t\tthis.w += v.w;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\taddScalar: function ( s ) {\n\n\t\t\tthis.x += s;\n\t\t\tthis.y += s;\n\t\t\tthis.z += s;\n\t\t\tthis.w += s;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\taddVectors: function ( a, b ) {\n\n\t\t\tthis.x = a.x + b.x;\n\t\t\tthis.y = a.y + b.y;\n\t\t\tthis.z = a.z + b.z;\n\t\t\tthis.w = a.w + b.w;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\taddScaledVector: function ( v, s ) {\n\n\t\t\tthis.x += v.x * s;\n\t\t\tthis.y += v.y * s;\n\t\t\tthis.z += v.z * s;\n\t\t\tthis.w += v.w * s;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsub: function ( v, w ) {\n\n\t\t\tif ( w !== undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );\n\t\t\t\treturn this.subVectors( v, w );\n\n\t\t\t}\n\n\t\t\tthis.x -= v.x;\n\t\t\tthis.y -= v.y;\n\t\t\tthis.z -= v.z;\n\t\t\tthis.w -= v.w;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsubScalar: function ( s ) {\n\n\t\t\tthis.x -= s;\n\t\t\tthis.y -= s;\n\t\t\tthis.z -= s;\n\t\t\tthis.w -= s;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsubVectors: function ( a, b ) {\n\n\t\t\tthis.x = a.x - b.x;\n\t\t\tthis.y = a.y - b.y;\n\t\t\tthis.z = a.z - b.z;\n\t\t\tthis.w = a.w - b.w;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmultiplyScalar: function ( scalar ) {\n\n\t\t\tthis.x *= scalar;\n\t\t\tthis.y *= scalar;\n\t\t\tthis.z *= scalar;\n\t\t\tthis.w *= scalar;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tapplyMatrix4: function ( m ) {\n\n\t\t\tvar x = this.x, y = this.y, z = this.z, w = this.w;\n\t\t\tvar e = m.elements;\n\n\t\t\tthis.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;\n\t\t\tthis.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;\n\t\t\tthis.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;\n\t\t\tthis.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tdivideScalar: function ( scalar ) {\n\n\t\t\treturn this.multiplyScalar( 1 / scalar );\n\n\t\t},\n\n\t\tsetAxisAngleFromQuaternion: function ( q ) {\n\n\t\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm\n\n\t\t\t// q is assumed to be normalized\n\n\t\t\tthis.w = 2 * Math.acos( q.w );\n\n\t\t\tvar s = Math.sqrt( 1 - q.w * q.w );\n\n\t\t\tif ( s < 0.0001 ) {\n\n\t\t\t\t this.x = 1;\n\t\t\t\t this.y = 0;\n\t\t\t\t this.z = 0;\n\n\t\t\t} else {\n\n\t\t\t\t this.x = q.x / s;\n\t\t\t\t this.y = q.y / s;\n\t\t\t\t this.z = q.z / s;\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetAxisAngleFromRotationMatrix: function ( m ) {\n\n\t\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm\n\n\t\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\n\n\t\t\tvar angle, x, y, z,\t\t// variables for result\n\t\t\t\tepsilon = 0.01,\t\t// margin to allow for rounding errors\n\t\t\t\tepsilon2 = 0.1,\t\t// margin to distinguish between 0 and 180 degrees\n\n\t\t\t\tte = m.elements,\n\n\t\t\t\tm11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],\n\t\t\t\tm21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],\n\t\t\t\tm31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];\n\n\t\t\tif ( ( Math.abs( m12 - m21 ) < epsilon ) &&\n\t\t\t     ( Math.abs( m13 - m31 ) < epsilon ) &&\n\t\t\t     ( Math.abs( m23 - m32 ) < epsilon ) ) {\n\n\t\t\t\t// singularity found\n\t\t\t\t// first check for identity matrix which must have +1 for all terms\n\t\t\t\t// in leading diagonal and zero in other terms\n\n\t\t\t\tif ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&\n\t\t\t\t     ( Math.abs( m13 + m31 ) < epsilon2 ) &&\n\t\t\t\t     ( Math.abs( m23 + m32 ) < epsilon2 ) &&\n\t\t\t\t     ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {\n\n\t\t\t\t\t// this singularity is identity matrix so angle = 0\n\n\t\t\t\t\tthis.set( 1, 0, 0, 0 );\n\n\t\t\t\t\treturn this; // zero angle, arbitrary axis\n\n\t\t\t\t}\n\n\t\t\t\t// otherwise this singularity is angle = 180\n\n\t\t\t\tangle = Math.PI;\n\n\t\t\t\tvar xx = ( m11 + 1 ) / 2;\n\t\t\t\tvar yy = ( m22 + 1 ) / 2;\n\t\t\t\tvar zz = ( m33 + 1 ) / 2;\n\t\t\t\tvar xy = ( m12 + m21 ) / 4;\n\t\t\t\tvar xz = ( m13 + m31 ) / 4;\n\t\t\t\tvar yz = ( m23 + m32 ) / 4;\n\n\t\t\t\tif ( ( xx > yy ) && ( xx > zz ) ) {\n\n\t\t\t\t\t// m11 is the largest diagonal term\n\n\t\t\t\t\tif ( xx < epsilon ) {\n\n\t\t\t\t\t\tx = 0;\n\t\t\t\t\t\ty = 0.707106781;\n\t\t\t\t\t\tz = 0.707106781;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tx = Math.sqrt( xx );\n\t\t\t\t\t\ty = xy / x;\n\t\t\t\t\t\tz = xz / x;\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( yy > zz ) {\n\n\t\t\t\t\t// m22 is the largest diagonal term\n\n\t\t\t\t\tif ( yy < epsilon ) {\n\n\t\t\t\t\t\tx = 0.707106781;\n\t\t\t\t\t\ty = 0;\n\t\t\t\t\t\tz = 0.707106781;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\ty = Math.sqrt( yy );\n\t\t\t\t\t\tx = xy / y;\n\t\t\t\t\t\tz = yz / y;\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// m33 is the largest diagonal term so base result on this\n\n\t\t\t\t\tif ( zz < epsilon ) {\n\n\t\t\t\t\t\tx = 0.707106781;\n\t\t\t\t\t\ty = 0.707106781;\n\t\t\t\t\t\tz = 0;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tz = Math.sqrt( zz );\n\t\t\t\t\t\tx = xz / z;\n\t\t\t\t\t\ty = yz / z;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tthis.set( x, y, z, angle );\n\n\t\t\t\treturn this; // return 180 deg rotation\n\n\t\t\t}\n\n\t\t\t// as we have reached here there are no singularities so we can handle normally\n\n\t\t\tvar s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +\n\t\t\t                   ( m13 - m31 ) * ( m13 - m31 ) +\n\t\t\t                   ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize\n\n\t\t\tif ( Math.abs( s ) < 0.001 ) s = 1;\n\n\t\t\t// prevent divide by zero, should not happen if matrix is orthogonal and should be\n\t\t\t// caught by singularity test above, but I've left it in just in case\n\n\t\t\tthis.x = ( m32 - m23 ) / s;\n\t\t\tthis.y = ( m13 - m31 ) / s;\n\t\t\tthis.z = ( m21 - m12 ) / s;\n\t\t\tthis.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmin: function ( v ) {\n\n\t\t\tthis.x = Math.min( this.x, v.x );\n\t\t\tthis.y = Math.min( this.y, v.y );\n\t\t\tthis.z = Math.min( this.z, v.z );\n\t\t\tthis.w = Math.min( this.w, v.w );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmax: function ( v ) {\n\n\t\t\tthis.x = Math.max( this.x, v.x );\n\t\t\tthis.y = Math.max( this.y, v.y );\n\t\t\tthis.z = Math.max( this.z, v.z );\n\t\t\tthis.w = Math.max( this.w, v.w );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclamp: function ( min, max ) {\n\n\t\t\t// assumes min < max, componentwise\n\n\t\t\tthis.x = Math.max( min.x, Math.min( max.x, this.x ) );\n\t\t\tthis.y = Math.max( min.y, Math.min( max.y, this.y ) );\n\t\t\tthis.z = Math.max( min.z, Math.min( max.z, this.z ) );\n\t\t\tthis.w = Math.max( min.w, Math.min( max.w, this.w ) );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclampScalar: function () {\n\n\t\t\tvar min, max;\n\n\t\t\treturn function clampScalar( minVal, maxVal ) {\n\n\t\t\t\tif ( min === undefined ) {\n\n\t\t\t\t\tmin = new Vector4();\n\t\t\t\t\tmax = new Vector4();\n\n\t\t\t\t}\n\n\t\t\t\tmin.set( minVal, minVal, minVal, minVal );\n\t\t\t\tmax.set( maxVal, maxVal, maxVal, maxVal );\n\n\t\t\t\treturn this.clamp( min, max );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tclampLength: function ( min, max ) {\n\n\t\t\tvar length = this.length();\n\n\t\t\treturn this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );\n\n\t\t},\n\n\t\tfloor: function () {\n\n\t\t\tthis.x = Math.floor( this.x );\n\t\t\tthis.y = Math.floor( this.y );\n\t\t\tthis.z = Math.floor( this.z );\n\t\t\tthis.w = Math.floor( this.w );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tceil: function () {\n\n\t\t\tthis.x = Math.ceil( this.x );\n\t\t\tthis.y = Math.ceil( this.y );\n\t\t\tthis.z = Math.ceil( this.z );\n\t\t\tthis.w = Math.ceil( this.w );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tround: function () {\n\n\t\t\tthis.x = Math.round( this.x );\n\t\t\tthis.y = Math.round( this.y );\n\t\t\tthis.z = Math.round( this.z );\n\t\t\tthis.w = Math.round( this.w );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\troundToZero: function () {\n\n\t\t\tthis.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );\n\t\t\tthis.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );\n\t\t\tthis.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );\n\t\t\tthis.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tnegate: function () {\n\n\t\t\tthis.x = - this.x;\n\t\t\tthis.y = - this.y;\n\t\t\tthis.z = - this.z;\n\t\t\tthis.w = - this.w;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tdot: function ( v ) {\n\n\t\t\treturn this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;\n\n\t\t},\n\n\t\tlengthSq: function () {\n\n\t\t\treturn this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;\n\n\t\t},\n\n\t\tlength: function () {\n\n\t\t\treturn Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );\n\n\t\t},\n\n\t\tlengthManhattan: function () {\n\n\t\t\treturn Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );\n\n\t\t},\n\n\t\tnormalize: function () {\n\n\t\t\treturn this.divideScalar( this.length() || 1 );\n\n\t\t},\n\n\t\tsetLength: function ( length ) {\n\n\t\t\treturn this.normalize().multiplyScalar( length );\n\n\t\t},\n\n\t\tlerp: function ( v, alpha ) {\n\n\t\t\tthis.x += ( v.x - this.x ) * alpha;\n\t\t\tthis.y += ( v.y - this.y ) * alpha;\n\t\t\tthis.z += ( v.z - this.z ) * alpha;\n\t\t\tthis.w += ( v.w - this.w ) * alpha;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tlerpVectors: function ( v1, v2, alpha ) {\n\n\t\t\treturn this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );\n\n\t\t},\n\n\t\tequals: function ( v ) {\n\n\t\t\treturn ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );\n\n\t\t},\n\n\t\tfromArray: function ( array, offset ) {\n\n\t\t\tif ( offset === undefined ) offset = 0;\n\n\t\t\tthis.x = array[ offset ];\n\t\t\tthis.y = array[ offset + 1 ];\n\t\t\tthis.z = array[ offset + 2 ];\n\t\t\tthis.w = array[ offset + 3 ];\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\ttoArray: function ( array, offset ) {\n\n\t\t\tif ( array === undefined ) array = [];\n\t\t\tif ( offset === undefined ) offset = 0;\n\n\t\t\tarray[ offset ] = this.x;\n\t\t\tarray[ offset + 1 ] = this.y;\n\t\t\tarray[ offset + 2 ] = this.z;\n\t\t\tarray[ offset + 3 ] = this.w;\n\n\t\t\treturn array;\n\n\t\t},\n\n\t\tfromBufferAttribute: function ( attribute, index, offset ) {\n\n\t\t\tif ( offset !== undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' );\n\n\t\t\t}\n\n\t\t\tthis.x = attribute.getX( index );\n\t\t\tthis.y = attribute.getY( index );\n\t\t\tthis.z = attribute.getZ( index );\n\t\t\tthis.w = attribute.getW( index );\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author szimek / https://github.com/szimek/\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author Marius Kintel / https://github.com/kintel\n\t */\n\n\t/*\n\t In options, we can specify:\n\t * Texture parameters for an auto-generated target texture\n\t * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers\n\t*/\n\tfunction WebGLRenderTarget( width, height, options ) {\n\n\t\tthis.uuid = _Math.generateUUID();\n\n\t\tthis.width = width;\n\t\tthis.height = height;\n\n\t\tthis.scissor = new Vector4( 0, 0, width, height );\n\t\tthis.scissorTest = false;\n\n\t\tthis.viewport = new Vector4( 0, 0, width, height );\n\n\t\toptions = options || {};\n\n\t\tif ( options.minFilter === undefined ) options.minFilter = LinearFilter;\n\n\t\tthis.texture = new Texture( undefined, undefined, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding );\n\n\t\tthis.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;\n\t\tthis.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true;\n\t\tthis.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null;\n\n\t}\n\n\tObject.assign( WebGLRenderTarget.prototype, EventDispatcher.prototype, {\n\n\t\tisWebGLRenderTarget: true,\n\n\t\tsetSize: function ( width, height ) {\n\n\t\t\tif ( this.width !== width || this.height !== height ) {\n\n\t\t\t\tthis.width = width;\n\t\t\t\tthis.height = height;\n\n\t\t\t\tthis.dispose();\n\n\t\t\t}\n\n\t\t\tthis.viewport.set( 0, 0, width, height );\n\t\t\tthis.scissor.set( 0, 0, width, height );\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor().copy( this );\n\n\t\t},\n\n\t\tcopy: function ( source ) {\n\n\t\t\tthis.width = source.width;\n\t\t\tthis.height = source.height;\n\n\t\t\tthis.viewport.copy( source.viewport );\n\n\t\t\tthis.texture = source.texture.clone();\n\n\t\t\tthis.depthBuffer = source.depthBuffer;\n\t\t\tthis.stencilBuffer = source.stencilBuffer;\n\t\t\tthis.depthTexture = source.depthTexture;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tdispose: function () {\n\n\t\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com\n\t */\n\n\tfunction WebGLRenderTargetCube( width, height, options ) {\n\n\t\tWebGLRenderTarget.call( this, width, height, options );\n\n\t\tthis.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5\n\t\tthis.activeMipMapLevel = 0;\n\n\t}\n\n\tWebGLRenderTargetCube.prototype = Object.create( WebGLRenderTarget.prototype );\n\tWebGLRenderTargetCube.prototype.constructor = WebGLRenderTargetCube;\n\n\tWebGLRenderTargetCube.prototype.isWebGLRenderTargetCube = true;\n\n\t/**\n\t * @author mikael emtinger / http://gomo.se/\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author WestLangley / http://github.com/WestLangley\n\t * @author bhouston / http://clara.io\n\t */\n\n\tfunction Quaternion( x, y, z, w ) {\n\n\t\tthis._x = x || 0;\n\t\tthis._y = y || 0;\n\t\tthis._z = z || 0;\n\t\tthis._w = ( w !== undefined ) ? w : 1;\n\n\t}\n\n\tObject.assign( Quaternion, {\n\n\t\tslerp: function ( qa, qb, qm, t ) {\n\n\t\t\treturn qm.copy( qa ).slerp( qb, t );\n\n\t\t},\n\n\t\tslerpFlat: function ( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {\n\n\t\t\t// fuzz-free, array-based Quaternion SLERP operation\n\n\t\t\tvar x0 = src0[ srcOffset0 + 0 ],\n\t\t\t\ty0 = src0[ srcOffset0 + 1 ],\n\t\t\t\tz0 = src0[ srcOffset0 + 2 ],\n\t\t\t\tw0 = src0[ srcOffset0 + 3 ],\n\n\t\t\t\tx1 = src1[ srcOffset1 + 0 ],\n\t\t\t\ty1 = src1[ srcOffset1 + 1 ],\n\t\t\t\tz1 = src1[ srcOffset1 + 2 ],\n\t\t\t\tw1 = src1[ srcOffset1 + 3 ];\n\n\t\t\tif ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {\n\n\t\t\t\tvar s = 1 - t,\n\n\t\t\t\t\tcos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,\n\n\t\t\t\t\tdir = ( cos >= 0 ? 1 : - 1 ),\n\t\t\t\t\tsqrSin = 1 - cos * cos;\n\n\t\t\t\t// Skip the Slerp for tiny steps to avoid numeric problems:\n\t\t\t\tif ( sqrSin > Number.EPSILON ) {\n\n\t\t\t\t\tvar sin = Math.sqrt( sqrSin ),\n\t\t\t\t\t\tlen = Math.atan2( sin, cos * dir );\n\n\t\t\t\t\ts = Math.sin( s * len ) / sin;\n\t\t\t\t\tt = Math.sin( t * len ) / sin;\n\n\t\t\t\t}\n\n\t\t\t\tvar tDir = t * dir;\n\n\t\t\t\tx0 = x0 * s + x1 * tDir;\n\t\t\t\ty0 = y0 * s + y1 * tDir;\n\t\t\t\tz0 = z0 * s + z1 * tDir;\n\t\t\t\tw0 = w0 * s + w1 * tDir;\n\n\t\t\t\t// Normalize in case we just did a lerp:\n\t\t\t\tif ( s === 1 - t ) {\n\n\t\t\t\t\tvar f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );\n\n\t\t\t\t\tx0 *= f;\n\t\t\t\t\ty0 *= f;\n\t\t\t\t\tz0 *= f;\n\t\t\t\t\tw0 *= f;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tdst[ dstOffset ] = x0;\n\t\t\tdst[ dstOffset + 1 ] = y0;\n\t\t\tdst[ dstOffset + 2 ] = z0;\n\t\t\tdst[ dstOffset + 3 ] = w0;\n\n\t\t}\n\n\t} );\n\n\tObject.defineProperties( Quaternion.prototype, {\n\n\t\tx: {\n\n\t\t\tget: function () {\n\n\t\t\t\treturn this._x;\n\n\t\t\t},\n\n\t\t\tset: function ( value ) {\n\n\t\t\t\tthis._x = value;\n\t\t\t\tthis.onChangeCallback();\n\n\t\t\t}\n\n\t\t},\n\n\t\ty: {\n\n\t\t\tget: function () {\n\n\t\t\t\treturn this._y;\n\n\t\t\t},\n\n\t\t\tset: function ( value ) {\n\n\t\t\t\tthis._y = value;\n\t\t\t\tthis.onChangeCallback();\n\n\t\t\t}\n\n\t\t},\n\n\t\tz: {\n\n\t\t\tget: function () {\n\n\t\t\t\treturn this._z;\n\n\t\t\t},\n\n\t\t\tset: function ( value ) {\n\n\t\t\t\tthis._z = value;\n\t\t\t\tthis.onChangeCallback();\n\n\t\t\t}\n\n\t\t},\n\n\t\tw: {\n\n\t\t\tget: function () {\n\n\t\t\t\treturn this._w;\n\n\t\t\t},\n\n\t\t\tset: function ( value ) {\n\n\t\t\t\tthis._w = value;\n\t\t\t\tthis.onChangeCallback();\n\n\t\t\t}\n\n\t\t}\n\n\t} );\n\n\tObject.assign( Quaternion.prototype, {\n\n\t\tset: function ( x, y, z, w ) {\n\n\t\t\tthis._x = x;\n\t\t\tthis._y = y;\n\t\t\tthis._z = z;\n\t\t\tthis._w = w;\n\n\t\t\tthis.onChangeCallback();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor( this._x, this._y, this._z, this._w );\n\n\t\t},\n\n\t\tcopy: function ( quaternion ) {\n\n\t\t\tthis._x = quaternion.x;\n\t\t\tthis._y = quaternion.y;\n\t\t\tthis._z = quaternion.z;\n\t\t\tthis._w = quaternion.w;\n\n\t\t\tthis.onChangeCallback();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromEuler: function ( euler, update ) {\n\n\t\t\tif ( ! ( euler && euler.isEuler ) ) {\n\n\t\t\t\tthrow new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' );\n\n\t\t\t}\n\n\t\t\tvar x = euler._x, y = euler._y, z = euler._z, order = euler.order;\n\n\t\t\t// http://www.mathworks.com/matlabcentral/fileexchange/\n\t\t\t// \t20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/\n\t\t\t//\tcontent/SpinCalc.m\n\n\t\t\tvar cos = Math.cos;\n\t\t\tvar sin = Math.sin;\n\n\t\t\tvar c1 = cos( x / 2 );\n\t\t\tvar c2 = cos( y / 2 );\n\t\t\tvar c3 = cos( z / 2 );\n\n\t\t\tvar s1 = sin( x / 2 );\n\t\t\tvar s2 = sin( y / 2 );\n\t\t\tvar s3 = sin( z / 2 );\n\n\t\t\tif ( order === 'XYZ' ) {\n\n\t\t\t\tthis._x = s1 * c2 * c3 + c1 * s2 * s3;\n\t\t\t\tthis._y = c1 * s2 * c3 - s1 * c2 * s3;\n\t\t\t\tthis._z = c1 * c2 * s3 + s1 * s2 * c3;\n\t\t\t\tthis._w = c1 * c2 * c3 - s1 * s2 * s3;\n\n\t\t\t} else if ( order === 'YXZ' ) {\n\n\t\t\t\tthis._x = s1 * c2 * c3 + c1 * s2 * s3;\n\t\t\t\tthis._y = c1 * s2 * c3 - s1 * c2 * s3;\n\t\t\t\tthis._z = c1 * c2 * s3 - s1 * s2 * c3;\n\t\t\t\tthis._w = c1 * c2 * c3 + s1 * s2 * s3;\n\n\t\t\t} else if ( order === 'ZXY' ) {\n\n\t\t\t\tthis._x = s1 * c2 * c3 - c1 * s2 * s3;\n\t\t\t\tthis._y = c1 * s2 * c3 + s1 * c2 * s3;\n\t\t\t\tthis._z = c1 * c2 * s3 + s1 * s2 * c3;\n\t\t\t\tthis._w = c1 * c2 * c3 - s1 * s2 * s3;\n\n\t\t\t} else if ( order === 'ZYX' ) {\n\n\t\t\t\tthis._x = s1 * c2 * c3 - c1 * s2 * s3;\n\t\t\t\tthis._y = c1 * s2 * c3 + s1 * c2 * s3;\n\t\t\t\tthis._z = c1 * c2 * s3 - s1 * s2 * c3;\n\t\t\t\tthis._w = c1 * c2 * c3 + s1 * s2 * s3;\n\n\t\t\t} else if ( order === 'YZX' ) {\n\n\t\t\t\tthis._x = s1 * c2 * c3 + c1 * s2 * s3;\n\t\t\t\tthis._y = c1 * s2 * c3 + s1 * c2 * s3;\n\t\t\t\tthis._z = c1 * c2 * s3 - s1 * s2 * c3;\n\t\t\t\tthis._w = c1 * c2 * c3 - s1 * s2 * s3;\n\n\t\t\t} else if ( order === 'XZY' ) {\n\n\t\t\t\tthis._x = s1 * c2 * c3 - c1 * s2 * s3;\n\t\t\t\tthis._y = c1 * s2 * c3 - s1 * c2 * s3;\n\t\t\t\tthis._z = c1 * c2 * s3 + s1 * s2 * c3;\n\t\t\t\tthis._w = c1 * c2 * c3 + s1 * s2 * s3;\n\n\t\t\t}\n\n\t\t\tif ( update !== false ) this.onChangeCallback();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromAxisAngle: function ( axis, angle ) {\n\n\t\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm\n\n\t\t\t// assumes axis is normalized\n\n\t\t\tvar halfAngle = angle / 2, s = Math.sin( halfAngle );\n\n\t\t\tthis._x = axis.x * s;\n\t\t\tthis._y = axis.y * s;\n\t\t\tthis._z = axis.z * s;\n\t\t\tthis._w = Math.cos( halfAngle );\n\n\t\t\tthis.onChangeCallback();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromRotationMatrix: function ( m ) {\n\n\t\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm\n\n\t\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\n\n\t\t\tvar te = m.elements,\n\n\t\t\t\tm11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],\n\t\t\t\tm21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],\n\t\t\t\tm31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],\n\n\t\t\t\ttrace = m11 + m22 + m33,\n\t\t\t\ts;\n\n\t\t\tif ( trace > 0 ) {\n\n\t\t\t\ts = 0.5 / Math.sqrt( trace + 1.0 );\n\n\t\t\t\tthis._w = 0.25 / s;\n\t\t\t\tthis._x = ( m32 - m23 ) * s;\n\t\t\t\tthis._y = ( m13 - m31 ) * s;\n\t\t\t\tthis._z = ( m21 - m12 ) * s;\n\n\t\t\t} else if ( m11 > m22 && m11 > m33 ) {\n\n\t\t\t\ts = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );\n\n\t\t\t\tthis._w = ( m32 - m23 ) / s;\n\t\t\t\tthis._x = 0.25 * s;\n\t\t\t\tthis._y = ( m12 + m21 ) / s;\n\t\t\t\tthis._z = ( m13 + m31 ) / s;\n\n\t\t\t} else if ( m22 > m33 ) {\n\n\t\t\t\ts = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );\n\n\t\t\t\tthis._w = ( m13 - m31 ) / s;\n\t\t\t\tthis._x = ( m12 + m21 ) / s;\n\t\t\t\tthis._y = 0.25 * s;\n\t\t\t\tthis._z = ( m23 + m32 ) / s;\n\n\t\t\t} else {\n\n\t\t\t\ts = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );\n\n\t\t\t\tthis._w = ( m21 - m12 ) / s;\n\t\t\t\tthis._x = ( m13 + m31 ) / s;\n\t\t\t\tthis._y = ( m23 + m32 ) / s;\n\t\t\t\tthis._z = 0.25 * s;\n\n\t\t\t}\n\n\t\t\tthis.onChangeCallback();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromUnitVectors: function () {\n\n\t\t\t// assumes direction vectors vFrom and vTo are normalized\n\n\t\t\tvar v1 = new Vector3();\n\t\t\tvar r;\n\n\t\t\tvar EPS = 0.000001;\n\n\t\t\treturn function setFromUnitVectors( vFrom, vTo ) {\n\n\t\t\t\tif ( v1 === undefined ) v1 = new Vector3();\n\n\t\t\t\tr = vFrom.dot( vTo ) + 1;\n\n\t\t\t\tif ( r < EPS ) {\n\n\t\t\t\t\tr = 0;\n\n\t\t\t\t\tif ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {\n\n\t\t\t\t\t\tv1.set( - vFrom.y, vFrom.x, 0 );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tv1.set( 0, - vFrom.z, vFrom.y );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tv1.crossVectors( vFrom, vTo );\n\n\t\t\t\t}\n\n\t\t\t\tthis._x = v1.x;\n\t\t\t\tthis._y = v1.y;\n\t\t\t\tthis._z = v1.z;\n\t\t\t\tthis._w = r;\n\n\t\t\t\treturn this.normalize();\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tinverse: function () {\n\n\t\t\treturn this.conjugate().normalize();\n\n\t\t},\n\n\t\tconjugate: function () {\n\n\t\t\tthis._x *= - 1;\n\t\t\tthis._y *= - 1;\n\t\t\tthis._z *= - 1;\n\n\t\t\tthis.onChangeCallback();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tdot: function ( v ) {\n\n\t\t\treturn this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;\n\n\t\t},\n\n\t\tlengthSq: function () {\n\n\t\t\treturn this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;\n\n\t\t},\n\n\t\tlength: function () {\n\n\t\t\treturn Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );\n\n\t\t},\n\n\t\tnormalize: function () {\n\n\t\t\tvar l = this.length();\n\n\t\t\tif ( l === 0 ) {\n\n\t\t\t\tthis._x = 0;\n\t\t\t\tthis._y = 0;\n\t\t\t\tthis._z = 0;\n\t\t\t\tthis._w = 1;\n\n\t\t\t} else {\n\n\t\t\t\tl = 1 / l;\n\n\t\t\t\tthis._x = this._x * l;\n\t\t\t\tthis._y = this._y * l;\n\t\t\t\tthis._z = this._z * l;\n\t\t\t\tthis._w = this._w * l;\n\n\t\t\t}\n\n\t\t\tthis.onChangeCallback();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmultiply: function ( q, p ) {\n\n\t\t\tif ( p !== undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );\n\t\t\t\treturn this.multiplyQuaternions( q, p );\n\n\t\t\t}\n\n\t\t\treturn this.multiplyQuaternions( this, q );\n\n\t\t},\n\n\t\tpremultiply: function ( q ) {\n\n\t\t\treturn this.multiplyQuaternions( q, this );\n\n\t\t},\n\n\t\tmultiplyQuaternions: function ( a, b ) {\n\n\t\t\t// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm\n\n\t\t\tvar qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;\n\t\t\tvar qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;\n\n\t\t\tthis._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;\n\t\t\tthis._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;\n\t\t\tthis._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;\n\t\t\tthis._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;\n\n\t\t\tthis.onChangeCallback();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tslerp: function ( qb, t ) {\n\n\t\t\tif ( t === 0 ) return this;\n\t\t\tif ( t === 1 ) return this.copy( qb );\n\n\t\t\tvar x = this._x, y = this._y, z = this._z, w = this._w;\n\n\t\t\t// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/\n\n\t\t\tvar cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;\n\n\t\t\tif ( cosHalfTheta < 0 ) {\n\n\t\t\t\tthis._w = - qb._w;\n\t\t\t\tthis._x = - qb._x;\n\t\t\t\tthis._y = - qb._y;\n\t\t\t\tthis._z = - qb._z;\n\n\t\t\t\tcosHalfTheta = - cosHalfTheta;\n\n\t\t\t} else {\n\n\t\t\t\tthis.copy( qb );\n\n\t\t\t}\n\n\t\t\tif ( cosHalfTheta >= 1.0 ) {\n\n\t\t\t\tthis._w = w;\n\t\t\t\tthis._x = x;\n\t\t\t\tthis._y = y;\n\t\t\t\tthis._z = z;\n\n\t\t\t\treturn this;\n\n\t\t\t}\n\n\t\t\tvar sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );\n\n\t\t\tif ( Math.abs( sinHalfTheta ) < 0.001 ) {\n\n\t\t\t\tthis._w = 0.5 * ( w + this._w );\n\t\t\t\tthis._x = 0.5 * ( x + this._x );\n\t\t\t\tthis._y = 0.5 * ( y + this._y );\n\t\t\t\tthis._z = 0.5 * ( z + this._z );\n\n\t\t\t\treturn this;\n\n\t\t\t}\n\n\t\t\tvar halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );\n\t\t\tvar ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,\n\t\t\t\tratioB = Math.sin( t * halfTheta ) / sinHalfTheta;\n\n\t\t\tthis._w = ( w * ratioA + this._w * ratioB );\n\t\t\tthis._x = ( x * ratioA + this._x * ratioB );\n\t\t\tthis._y = ( y * ratioA + this._y * ratioB );\n\t\t\tthis._z = ( z * ratioA + this._z * ratioB );\n\n\t\t\tthis.onChangeCallback();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tequals: function ( quaternion ) {\n\n\t\t\treturn ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );\n\n\t\t},\n\n\t\tfromArray: function ( array, offset ) {\n\n\t\t\tif ( offset === undefined ) offset = 0;\n\n\t\t\tthis._x = array[ offset ];\n\t\t\tthis._y = array[ offset + 1 ];\n\t\t\tthis._z = array[ offset + 2 ];\n\t\t\tthis._w = array[ offset + 3 ];\n\n\t\t\tthis.onChangeCallback();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\ttoArray: function ( array, offset ) {\n\n\t\t\tif ( array === undefined ) array = [];\n\t\t\tif ( offset === undefined ) offset = 0;\n\n\t\t\tarray[ offset ] = this._x;\n\t\t\tarray[ offset + 1 ] = this._y;\n\t\t\tarray[ offset + 2 ] = this._z;\n\t\t\tarray[ offset + 3 ] = this._w;\n\n\t\t\treturn array;\n\n\t\t},\n\n\t\tonChange: function ( callback ) {\n\n\t\t\tthis.onChangeCallback = callback;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tonChangeCallback: function () {}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author kile / http://kile.stravaganza.org/\n\t * @author philogb / http://blog.thejit.org/\n\t * @author mikael emtinger / http://gomo.se/\n\t * @author egraether / http://egraether.com/\n\t * @author WestLangley / http://github.com/WestLangley\n\t */\n\n\tfunction Vector3( x, y, z ) {\n\n\t\tthis.x = x || 0;\n\t\tthis.y = y || 0;\n\t\tthis.z = z || 0;\n\n\t}\n\n\tObject.assign( Vector3.prototype, {\n\n\t\tisVector3: true,\n\n\t\tset: function ( x, y, z ) {\n\n\t\t\tthis.x = x;\n\t\t\tthis.y = y;\n\t\t\tthis.z = z;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetScalar: function ( scalar ) {\n\n\t\t\tthis.x = scalar;\n\t\t\tthis.y = scalar;\n\t\t\tthis.z = scalar;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetX: function ( x ) {\n\n\t\t\tthis.x = x;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetY: function ( y ) {\n\n\t\t\tthis.y = y;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetZ: function ( z ) {\n\n\t\t\tthis.z = z;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetComponent: function ( index, value ) {\n\n\t\t\tswitch ( index ) {\n\n\t\t\t\tcase 0: this.x = value; break;\n\t\t\t\tcase 1: this.y = value; break;\n\t\t\t\tcase 2: this.z = value; break;\n\t\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetComponent: function ( index ) {\n\n\t\t\tswitch ( index ) {\n\n\t\t\t\tcase 0: return this.x;\n\t\t\t\tcase 1: return this.y;\n\t\t\t\tcase 2: return this.z;\n\t\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t\t}\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor( this.x, this.y, this.z );\n\n\t\t},\n\n\t\tcopy: function ( v ) {\n\n\t\t\tthis.x = v.x;\n\t\t\tthis.y = v.y;\n\t\t\tthis.z = v.z;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tadd: function ( v, w ) {\n\n\t\t\tif ( w !== undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );\n\t\t\t\treturn this.addVectors( v, w );\n\n\t\t\t}\n\n\t\t\tthis.x += v.x;\n\t\t\tthis.y += v.y;\n\t\t\tthis.z += v.z;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\taddScalar: function ( s ) {\n\n\t\t\tthis.x += s;\n\t\t\tthis.y += s;\n\t\t\tthis.z += s;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\taddVectors: function ( a, b ) {\n\n\t\t\tthis.x = a.x + b.x;\n\t\t\tthis.y = a.y + b.y;\n\t\t\tthis.z = a.z + b.z;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\taddScaledVector: function ( v, s ) {\n\n\t\t\tthis.x += v.x * s;\n\t\t\tthis.y += v.y * s;\n\t\t\tthis.z += v.z * s;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsub: function ( v, w ) {\n\n\t\t\tif ( w !== undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );\n\t\t\t\treturn this.subVectors( v, w );\n\n\t\t\t}\n\n\t\t\tthis.x -= v.x;\n\t\t\tthis.y -= v.y;\n\t\t\tthis.z -= v.z;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsubScalar: function ( s ) {\n\n\t\t\tthis.x -= s;\n\t\t\tthis.y -= s;\n\t\t\tthis.z -= s;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsubVectors: function ( a, b ) {\n\n\t\t\tthis.x = a.x - b.x;\n\t\t\tthis.y = a.y - b.y;\n\t\t\tthis.z = a.z - b.z;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmultiply: function ( v, w ) {\n\n\t\t\tif ( w !== undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );\n\t\t\t\treturn this.multiplyVectors( v, w );\n\n\t\t\t}\n\n\t\t\tthis.x *= v.x;\n\t\t\tthis.y *= v.y;\n\t\t\tthis.z *= v.z;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmultiplyScalar: function ( scalar ) {\n\n\t\t\tthis.x *= scalar;\n\t\t\tthis.y *= scalar;\n\t\t\tthis.z *= scalar;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmultiplyVectors: function ( a, b ) {\n\n\t\t\tthis.x = a.x * b.x;\n\t\t\tthis.y = a.y * b.y;\n\t\t\tthis.z = a.z * b.z;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tapplyEuler: function () {\n\n\t\t\tvar quaternion = new Quaternion();\n\n\t\t\treturn function applyEuler( euler ) {\n\n\t\t\t\tif ( ! ( euler && euler.isEuler ) ) {\n\n\t\t\t\t\tconsole.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' );\n\n\t\t\t\t}\n\n\t\t\t\treturn this.applyQuaternion( quaternion.setFromEuler( euler ) );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tapplyAxisAngle: function () {\n\n\t\t\tvar quaternion = new Quaternion();\n\n\t\t\treturn function applyAxisAngle( axis, angle ) {\n\n\t\t\t\treturn this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tapplyMatrix3: function ( m ) {\n\n\t\t\tvar x = this.x, y = this.y, z = this.z;\n\t\t\tvar e = m.elements;\n\n\t\t\tthis.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;\n\t\t\tthis.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;\n\t\t\tthis.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tapplyMatrix4: function ( m ) {\n\n\t\t\tvar x = this.x, y = this.y, z = this.z;\n\t\t\tvar e = m.elements;\n\n\t\t\tvar w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] );\n\n\t\t\tthis.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ]  * z + e[ 12 ] ) * w;\n\t\t\tthis.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ]  * z + e[ 13 ] ) * w;\n\t\t\tthis.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tapplyQuaternion: function ( q ) {\n\n\t\t\tvar x = this.x, y = this.y, z = this.z;\n\t\t\tvar qx = q.x, qy = q.y, qz = q.z, qw = q.w;\n\n\t\t\t// calculate quat * vector\n\n\t\t\tvar ix =  qw * x + qy * z - qz * y;\n\t\t\tvar iy =  qw * y + qz * x - qx * z;\n\t\t\tvar iz =  qw * z + qx * y - qy * x;\n\t\t\tvar iw = - qx * x - qy * y - qz * z;\n\n\t\t\t// calculate result * inverse quat\n\n\t\t\tthis.x = ix * qw + iw * - qx + iy * - qz - iz * - qy;\n\t\t\tthis.y = iy * qw + iw * - qy + iz * - qx - ix * - qz;\n\t\t\tthis.z = iz * qw + iw * - qz + ix * - qy - iy * - qx;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tproject: function () {\n\n\t\t\tvar matrix = new Matrix4();\n\n\t\t\treturn function project( camera ) {\n\n\t\t\t\tmatrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) );\n\t\t\t\treturn this.applyMatrix4( matrix );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tunproject: function () {\n\n\t\t\tvar matrix = new Matrix4();\n\n\t\t\treturn function unproject( camera ) {\n\n\t\t\t\tmatrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) );\n\t\t\t\treturn this.applyMatrix4( matrix );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\ttransformDirection: function ( m ) {\n\n\t\t\t// input: THREE.Matrix4 affine matrix\n\t\t\t// vector interpreted as a direction\n\n\t\t\tvar x = this.x, y = this.y, z = this.z;\n\t\t\tvar e = m.elements;\n\n\t\t\tthis.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ]  * z;\n\t\t\tthis.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ]  * z;\n\t\t\tthis.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;\n\n\t\t\treturn this.normalize();\n\n\t\t},\n\n\t\tdivide: function ( v ) {\n\n\t\t\tthis.x /= v.x;\n\t\t\tthis.y /= v.y;\n\t\t\tthis.z /= v.z;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tdivideScalar: function ( scalar ) {\n\n\t\t\treturn this.multiplyScalar( 1 / scalar );\n\n\t\t},\n\n\t\tmin: function ( v ) {\n\n\t\t\tthis.x = Math.min( this.x, v.x );\n\t\t\tthis.y = Math.min( this.y, v.y );\n\t\t\tthis.z = Math.min( this.z, v.z );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmax: function ( v ) {\n\n\t\t\tthis.x = Math.max( this.x, v.x );\n\t\t\tthis.y = Math.max( this.y, v.y );\n\t\t\tthis.z = Math.max( this.z, v.z );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclamp: function ( min, max ) {\n\n\t\t\t// assumes min < max, componentwise\n\n\t\t\tthis.x = Math.max( min.x, Math.min( max.x, this.x ) );\n\t\t\tthis.y = Math.max( min.y, Math.min( max.y, this.y ) );\n\t\t\tthis.z = Math.max( min.z, Math.min( max.z, this.z ) );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclampScalar: function () {\n\n\t\t\tvar min = new Vector3();\n\t\t\tvar max = new Vector3();\n\n\t\t\treturn function clampScalar( minVal, maxVal ) {\n\n\t\t\t\tmin.set( minVal, minVal, minVal );\n\t\t\t\tmax.set( maxVal, maxVal, maxVal );\n\n\t\t\t\treturn this.clamp( min, max );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tclampLength: function ( min, max ) {\n\n\t\t\tvar length = this.length();\n\n\t\t\treturn this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );\n\n\t\t},\n\n\t\tfloor: function () {\n\n\t\t\tthis.x = Math.floor( this.x );\n\t\t\tthis.y = Math.floor( this.y );\n\t\t\tthis.z = Math.floor( this.z );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tceil: function () {\n\n\t\t\tthis.x = Math.ceil( this.x );\n\t\t\tthis.y = Math.ceil( this.y );\n\t\t\tthis.z = Math.ceil( this.z );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tround: function () {\n\n\t\t\tthis.x = Math.round( this.x );\n\t\t\tthis.y = Math.round( this.y );\n\t\t\tthis.z = Math.round( this.z );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\troundToZero: function () {\n\n\t\t\tthis.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );\n\t\t\tthis.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );\n\t\t\tthis.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tnegate: function () {\n\n\t\t\tthis.x = - this.x;\n\t\t\tthis.y = - this.y;\n\t\t\tthis.z = - this.z;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tdot: function ( v ) {\n\n\t\t\treturn this.x * v.x + this.y * v.y + this.z * v.z;\n\n\t\t},\n\n\t\t// TODO lengthSquared?\n\n\t\tlengthSq: function () {\n\n\t\t\treturn this.x * this.x + this.y * this.y + this.z * this.z;\n\n\t\t},\n\n\t\tlength: function () {\n\n\t\t\treturn Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );\n\n\t\t},\n\n\t\tlengthManhattan: function () {\n\n\t\t\treturn Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );\n\n\t\t},\n\n\t\tnormalize: function () {\n\n\t\t\treturn this.divideScalar( this.length() || 1 );\n\n\t\t},\n\n\t\tsetLength: function ( length ) {\n\n\t\t\treturn this.normalize().multiplyScalar( length );\n\n\t\t},\n\n\t\tlerp: function ( v, alpha ) {\n\n\t\t\tthis.x += ( v.x - this.x ) * alpha;\n\t\t\tthis.y += ( v.y - this.y ) * alpha;\n\t\t\tthis.z += ( v.z - this.z ) * alpha;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tlerpVectors: function ( v1, v2, alpha ) {\n\n\t\t\treturn this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );\n\n\t\t},\n\n\t\tcross: function ( v, w ) {\n\n\t\t\tif ( w !== undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );\n\t\t\t\treturn this.crossVectors( v, w );\n\n\t\t\t}\n\n\t\t\tvar x = this.x, y = this.y, z = this.z;\n\n\t\t\tthis.x = y * v.z - z * v.y;\n\t\t\tthis.y = z * v.x - x * v.z;\n\t\t\tthis.z = x * v.y - y * v.x;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcrossVectors: function ( a, b ) {\n\n\t\t\tvar ax = a.x, ay = a.y, az = a.z;\n\t\t\tvar bx = b.x, by = b.y, bz = b.z;\n\n\t\t\tthis.x = ay * bz - az * by;\n\t\t\tthis.y = az * bx - ax * bz;\n\t\t\tthis.z = ax * by - ay * bx;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tprojectOnVector: function ( vector ) {\n\n\t\t\tvar scalar = vector.dot( this ) / vector.lengthSq();\n\n\t\t\treturn this.copy( vector ).multiplyScalar( scalar );\n\n\t\t},\n\n\t\tprojectOnPlane: function () {\n\n\t\t\tvar v1 = new Vector3();\n\n\t\t\treturn function projectOnPlane( planeNormal ) {\n\n\t\t\t\tv1.copy( this ).projectOnVector( planeNormal );\n\n\t\t\t\treturn this.sub( v1 );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\treflect: function () {\n\n\t\t\t// reflect incident vector off plane orthogonal to normal\n\t\t\t// normal is assumed to have unit length\n\n\t\t\tvar v1 = new Vector3();\n\n\t\t\treturn function reflect( normal ) {\n\n\t\t\t\treturn this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tangleTo: function ( v ) {\n\n\t\t\tvar theta = this.dot( v ) / ( Math.sqrt( this.lengthSq() * v.lengthSq() ) );\n\n\t\t\t// clamp, to handle numerical problems\n\n\t\t\treturn Math.acos( _Math.clamp( theta, - 1, 1 ) );\n\n\t\t},\n\n\t\tdistanceTo: function ( v ) {\n\n\t\t\treturn Math.sqrt( this.distanceToSquared( v ) );\n\n\t\t},\n\n\t\tdistanceToSquared: function ( v ) {\n\n\t\t\tvar dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;\n\n\t\t\treturn dx * dx + dy * dy + dz * dz;\n\n\t\t},\n\n\t\tdistanceToManhattan: function ( v ) {\n\n\t\t\treturn Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );\n\n\t\t},\n\n\t\tsetFromSpherical: function ( s ) {\n\n\t\t\tvar sinPhiRadius = Math.sin( s.phi ) * s.radius;\n\n\t\t\tthis.x = sinPhiRadius * Math.sin( s.theta );\n\t\t\tthis.y = Math.cos( s.phi ) * s.radius;\n\t\t\tthis.z = sinPhiRadius * Math.cos( s.theta );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromCylindrical: function ( c ) {\n\n\t\t\tthis.x = c.radius * Math.sin( c.theta );\n\t\t\tthis.y = c.y;\n\t\t\tthis.z = c.radius * Math.cos( c.theta );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromMatrixPosition: function ( m ) {\n\n\t\t\tvar e = m.elements;\n\n\t\t\tthis.x = e[ 12 ];\n\t\t\tthis.y = e[ 13 ];\n\t\t\tthis.z = e[ 14 ];\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromMatrixScale: function ( m ) {\n\n\t\t\tvar sx = this.setFromMatrixColumn( m, 0 ).length();\n\t\t\tvar sy = this.setFromMatrixColumn( m, 1 ).length();\n\t\t\tvar sz = this.setFromMatrixColumn( m, 2 ).length();\n\n\t\t\tthis.x = sx;\n\t\t\tthis.y = sy;\n\t\t\tthis.z = sz;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromMatrixColumn: function ( m, index ) {\n\n\t\t\treturn this.fromArray( m.elements, index * 4 );\n\n\t\t},\n\n\t\tequals: function ( v ) {\n\n\t\t\treturn ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );\n\n\t\t},\n\n\t\tfromArray: function ( array, offset ) {\n\n\t\t\tif ( offset === undefined ) offset = 0;\n\n\t\t\tthis.x = array[ offset ];\n\t\t\tthis.y = array[ offset + 1 ];\n\t\t\tthis.z = array[ offset + 2 ];\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\ttoArray: function ( array, offset ) {\n\n\t\t\tif ( array === undefined ) array = [];\n\t\t\tif ( offset === undefined ) offset = 0;\n\n\t\t\tarray[ offset ] = this.x;\n\t\t\tarray[ offset + 1 ] = this.y;\n\t\t\tarray[ offset + 2 ] = this.z;\n\n\t\t\treturn array;\n\n\t\t},\n\n\t\tfromBufferAttribute: function ( attribute, index, offset ) {\n\n\t\t\tif ( offset !== undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' );\n\n\t\t\t}\n\n\t\t\tthis.x = attribute.getX( index );\n\t\t\tthis.y = attribute.getY( index );\n\t\t\tthis.z = attribute.getZ( index );\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author supereggbert / http://www.paulbrunt.co.uk/\n\t * @author philogb / http://blog.thejit.org/\n\t * @author jordi_ros / http://plattsoft.com\n\t * @author D1plo1d / http://github.com/D1plo1d\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author mikael emtinger / http://gomo.se/\n\t * @author timknip / http://www.floorplanner.com/\n\t * @author bhouston / http://clara.io\n\t * @author WestLangley / http://github.com/WestLangley\n\t */\n\n\tfunction Matrix4() {\n\n\t\tthis.elements = [\n\n\t\t\t1, 0, 0, 0,\n\t\t\t0, 1, 0, 0,\n\t\t\t0, 0, 1, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t];\n\n\t\tif ( arguments.length > 0 ) {\n\n\t\t\tconsole.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' );\n\n\t\t}\n\n\t}\n\n\tObject.assign( Matrix4.prototype, {\n\n\t\tisMatrix4: true,\n\n\t\tset: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {\n\n\t\t\tvar te = this.elements;\n\n\t\t\tte[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;\n\t\t\tte[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;\n\t\t\tte[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;\n\t\t\tte[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tidentity: function () {\n\n\t\t\tthis.set(\n\n\t\t\t\t1, 0, 0, 0,\n\t\t\t\t0, 1, 0, 0,\n\t\t\t\t0, 0, 1, 0,\n\t\t\t\t0, 0, 0, 1\n\n\t\t\t);\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new Matrix4().fromArray( this.elements );\n\n\t\t},\n\n\t\tcopy: function ( m ) {\n\n\t\t\tvar te = this.elements;\n\t\t\tvar me = m.elements;\n\n\t\t\tte[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ];\n\t\t\tte[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ];\n\t\t\tte[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ];\n\t\t\tte[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ];\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcopyPosition: function ( m ) {\n\n\t\t\tvar te = this.elements, me = m.elements;\n\n\t\t\tte[ 12 ] = me[ 12 ];\n\t\t\tte[ 13 ] = me[ 13 ];\n\t\t\tte[ 14 ] = me[ 14 ];\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\textractBasis: function ( xAxis, yAxis, zAxis ) {\n\n\t\t\txAxis.setFromMatrixColumn( this, 0 );\n\t\t\tyAxis.setFromMatrixColumn( this, 1 );\n\t\t\tzAxis.setFromMatrixColumn( this, 2 );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmakeBasis: function ( xAxis, yAxis, zAxis ) {\n\n\t\t\tthis.set(\n\t\t\t\txAxis.x, yAxis.x, zAxis.x, 0,\n\t\t\t\txAxis.y, yAxis.y, zAxis.y, 0,\n\t\t\t\txAxis.z, yAxis.z, zAxis.z, 0,\n\t\t\t\t0,       0,       0,       1\n\t\t\t);\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\textractRotation: function () {\n\n\t\t\tvar v1 = new Vector3();\n\n\t\t\treturn function extractRotation( m ) {\n\n\t\t\t\tvar te = this.elements;\n\t\t\t\tvar me = m.elements;\n\n\t\t\t\tvar scaleX = 1 / v1.setFromMatrixColumn( m, 0 ).length();\n\t\t\t\tvar scaleY = 1 / v1.setFromMatrixColumn( m, 1 ).length();\n\t\t\t\tvar scaleZ = 1 / v1.setFromMatrixColumn( m, 2 ).length();\n\n\t\t\t\tte[ 0 ] = me[ 0 ] * scaleX;\n\t\t\t\tte[ 1 ] = me[ 1 ] * scaleX;\n\t\t\t\tte[ 2 ] = me[ 2 ] * scaleX;\n\n\t\t\t\tte[ 4 ] = me[ 4 ] * scaleY;\n\t\t\t\tte[ 5 ] = me[ 5 ] * scaleY;\n\t\t\t\tte[ 6 ] = me[ 6 ] * scaleY;\n\n\t\t\t\tte[ 8 ] = me[ 8 ] * scaleZ;\n\t\t\t\tte[ 9 ] = me[ 9 ] * scaleZ;\n\t\t\t\tte[ 10 ] = me[ 10 ] * scaleZ;\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tmakeRotationFromEuler: function ( euler ) {\n\n\t\t\tif ( ! ( euler && euler.isEuler ) ) {\n\n\t\t\t\tconsole.error( 'THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );\n\n\t\t\t}\n\n\t\t\tvar te = this.elements;\n\n\t\t\tvar x = euler.x, y = euler.y, z = euler.z;\n\t\t\tvar a = Math.cos( x ), b = Math.sin( x );\n\t\t\tvar c = Math.cos( y ), d = Math.sin( y );\n\t\t\tvar e = Math.cos( z ), f = Math.sin( z );\n\n\t\t\tif ( euler.order === 'XYZ' ) {\n\n\t\t\t\tvar ae = a * e, af = a * f, be = b * e, bf = b * f;\n\n\t\t\t\tte[ 0 ] = c * e;\n\t\t\t\tte[ 4 ] = - c * f;\n\t\t\t\tte[ 8 ] = d;\n\n\t\t\t\tte[ 1 ] = af + be * d;\n\t\t\t\tte[ 5 ] = ae - bf * d;\n\t\t\t\tte[ 9 ] = - b * c;\n\n\t\t\t\tte[ 2 ] = bf - ae * d;\n\t\t\t\tte[ 6 ] = be + af * d;\n\t\t\t\tte[ 10 ] = a * c;\n\n\t\t\t} else if ( euler.order === 'YXZ' ) {\n\n\t\t\t\tvar ce = c * e, cf = c * f, de = d * e, df = d * f;\n\n\t\t\t\tte[ 0 ] = ce + df * b;\n\t\t\t\tte[ 4 ] = de * b - cf;\n\t\t\t\tte[ 8 ] = a * d;\n\n\t\t\t\tte[ 1 ] = a * f;\n\t\t\t\tte[ 5 ] = a * e;\n\t\t\t\tte[ 9 ] = - b;\n\n\t\t\t\tte[ 2 ] = cf * b - de;\n\t\t\t\tte[ 6 ] = df + ce * b;\n\t\t\t\tte[ 10 ] = a * c;\n\n\t\t\t} else if ( euler.order === 'ZXY' ) {\n\n\t\t\t\tvar ce = c * e, cf = c * f, de = d * e, df = d * f;\n\n\t\t\t\tte[ 0 ] = ce - df * b;\n\t\t\t\tte[ 4 ] = - a * f;\n\t\t\t\tte[ 8 ] = de + cf * b;\n\n\t\t\t\tte[ 1 ] = cf + de * b;\n\t\t\t\tte[ 5 ] = a * e;\n\t\t\t\tte[ 9 ] = df - ce * b;\n\n\t\t\t\tte[ 2 ] = - a * d;\n\t\t\t\tte[ 6 ] = b;\n\t\t\t\tte[ 10 ] = a * c;\n\n\t\t\t} else if ( euler.order === 'ZYX' ) {\n\n\t\t\t\tvar ae = a * e, af = a * f, be = b * e, bf = b * f;\n\n\t\t\t\tte[ 0 ] = c * e;\n\t\t\t\tte[ 4 ] = be * d - af;\n\t\t\t\tte[ 8 ] = ae * d + bf;\n\n\t\t\t\tte[ 1 ] = c * f;\n\t\t\t\tte[ 5 ] = bf * d + ae;\n\t\t\t\tte[ 9 ] = af * d - be;\n\n\t\t\t\tte[ 2 ] = - d;\n\t\t\t\tte[ 6 ] = b * c;\n\t\t\t\tte[ 10 ] = a * c;\n\n\t\t\t} else if ( euler.order === 'YZX' ) {\n\n\t\t\t\tvar ac = a * c, ad = a * d, bc = b * c, bd = b * d;\n\n\t\t\t\tte[ 0 ] = c * e;\n\t\t\t\tte[ 4 ] = bd - ac * f;\n\t\t\t\tte[ 8 ] = bc * f + ad;\n\n\t\t\t\tte[ 1 ] = f;\n\t\t\t\tte[ 5 ] = a * e;\n\t\t\t\tte[ 9 ] = - b * e;\n\n\t\t\t\tte[ 2 ] = - d * e;\n\t\t\t\tte[ 6 ] = ad * f + bc;\n\t\t\t\tte[ 10 ] = ac - bd * f;\n\n\t\t\t} else if ( euler.order === 'XZY' ) {\n\n\t\t\t\tvar ac = a * c, ad = a * d, bc = b * c, bd = b * d;\n\n\t\t\t\tte[ 0 ] = c * e;\n\t\t\t\tte[ 4 ] = - f;\n\t\t\t\tte[ 8 ] = d * e;\n\n\t\t\t\tte[ 1 ] = ac * f + bd;\n\t\t\t\tte[ 5 ] = a * e;\n\t\t\t\tte[ 9 ] = ad * f - bc;\n\n\t\t\t\tte[ 2 ] = bc * f - ad;\n\t\t\t\tte[ 6 ] = b * e;\n\t\t\t\tte[ 10 ] = bd * f + ac;\n\n\t\t\t}\n\n\t\t\t// last column\n\t\t\tte[ 3 ] = 0;\n\t\t\tte[ 7 ] = 0;\n\t\t\tte[ 11 ] = 0;\n\n\t\t\t// bottom row\n\t\t\tte[ 12 ] = 0;\n\t\t\tte[ 13 ] = 0;\n\t\t\tte[ 14 ] = 0;\n\t\t\tte[ 15 ] = 1;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmakeRotationFromQuaternion: function ( q ) {\n\n\t\t\tvar te = this.elements;\n\n\t\t\tvar x = q._x, y = q._y, z = q._z, w = q._w;\n\t\t\tvar x2 = x + x, y2 = y + y, z2 = z + z;\n\t\t\tvar xx = x * x2, xy = x * y2, xz = x * z2;\n\t\t\tvar yy = y * y2, yz = y * z2, zz = z * z2;\n\t\t\tvar wx = w * x2, wy = w * y2, wz = w * z2;\n\n\t\t\tte[ 0 ] = 1 - ( yy + zz );\n\t\t\tte[ 4 ] = xy - wz;\n\t\t\tte[ 8 ] = xz + wy;\n\n\t\t\tte[ 1 ] = xy + wz;\n\t\t\tte[ 5 ] = 1 - ( xx + zz );\n\t\t\tte[ 9 ] = yz - wx;\n\n\t\t\tte[ 2 ] = xz - wy;\n\t\t\tte[ 6 ] = yz + wx;\n\t\t\tte[ 10 ] = 1 - ( xx + yy );\n\n\t\t\t// last column\n\t\t\tte[ 3 ] = 0;\n\t\t\tte[ 7 ] = 0;\n\t\t\tte[ 11 ] = 0;\n\n\t\t\t// bottom row\n\t\t\tte[ 12 ] = 0;\n\t\t\tte[ 13 ] = 0;\n\t\t\tte[ 14 ] = 0;\n\t\t\tte[ 15 ] = 1;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tlookAt: function () {\n\n\t\t\tvar x = new Vector3();\n\t\t\tvar y = new Vector3();\n\t\t\tvar z = new Vector3();\n\n\t\t\treturn function lookAt( eye, target, up ) {\n\n\t\t\t\tvar te = this.elements;\n\n\t\t\t\tz.subVectors( eye, target );\n\n\t\t\t\tif ( z.lengthSq() === 0 ) {\n\n\t\t\t\t\t// eye and target are in the same position\n\n\t\t\t\t\tz.z = 1;\n\n\t\t\t\t}\n\n\t\t\t\tz.normalize();\n\t\t\t\tx.crossVectors( up, z );\n\n\t\t\t\tif ( x.lengthSq() === 0 ) {\n\n\t\t\t\t\t// up and z are parallel\n\n\t\t\t\t\tif ( Math.abs( up.z ) === 1 ) {\n\n\t\t\t\t\t\tz.x += 0.0001;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tz.z += 0.0001;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tz.normalize();\n\t\t\t\t\tx.crossVectors( up, z );\n\n\t\t\t\t}\n\n\t\t\t\tx.normalize();\n\t\t\t\ty.crossVectors( z, x );\n\n\t\t\t\tte[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x;\n\t\t\t\tte[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y;\n\t\t\t\tte[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z;\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tmultiply: function ( m, n ) {\n\n\t\t\tif ( n !== undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' );\n\t\t\t\treturn this.multiplyMatrices( m, n );\n\n\t\t\t}\n\n\t\t\treturn this.multiplyMatrices( this, m );\n\n\t\t},\n\n\t\tpremultiply: function ( m ) {\n\n\t\t\treturn this.multiplyMatrices( m, this );\n\n\t\t},\n\n\t\tmultiplyMatrices: function ( a, b ) {\n\n\t\t\tvar ae = a.elements;\n\t\t\tvar be = b.elements;\n\t\t\tvar te = this.elements;\n\n\t\t\tvar a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];\n\t\t\tvar a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];\n\t\t\tvar a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];\n\t\t\tvar a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];\n\n\t\t\tvar b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];\n\t\t\tvar b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];\n\t\t\tvar b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];\n\t\t\tvar b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];\n\n\t\t\tte[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;\n\t\t\tte[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;\n\t\t\tte[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;\n\t\t\tte[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;\n\n\t\t\tte[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;\n\t\t\tte[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;\n\t\t\tte[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;\n\t\t\tte[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;\n\n\t\t\tte[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;\n\t\t\tte[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;\n\t\t\tte[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;\n\t\t\tte[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;\n\n\t\t\tte[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;\n\t\t\tte[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;\n\t\t\tte[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;\n\t\t\tte[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmultiplyScalar: function ( s ) {\n\n\t\t\tvar te = this.elements;\n\n\t\t\tte[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;\n\t\t\tte[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;\n\t\t\tte[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;\n\t\t\tte[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tapplyToBufferAttribute: function () {\n\n\t\t\tvar v1 = new Vector3();\n\n\t\t\treturn function applyToBufferAttribute( attribute ) {\n\n\t\t\t\tfor ( var i = 0, l = attribute.count; i < l; i ++ ) {\n\n\t\t\t\t\tv1.x = attribute.getX( i );\n\t\t\t\t\tv1.y = attribute.getY( i );\n\t\t\t\t\tv1.z = attribute.getZ( i );\n\n\t\t\t\t\tv1.applyMatrix4( this );\n\n\t\t\t\t\tattribute.setXYZ( i, v1.x, v1.y, v1.z );\n\n\t\t\t\t}\n\n\t\t\t\treturn attribute;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tdeterminant: function () {\n\n\t\t\tvar te = this.elements;\n\n\t\t\tvar n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];\n\t\t\tvar n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];\n\t\t\tvar n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];\n\t\t\tvar n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];\n\n\t\t\t//TODO: make this more efficient\n\t\t\t//( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )\n\n\t\t\treturn (\n\t\t\t\tn41 * (\n\t\t\t\t\t+ n14 * n23 * n32\n\t\t\t\t\t - n13 * n24 * n32\n\t\t\t\t\t - n14 * n22 * n33\n\t\t\t\t\t + n12 * n24 * n33\n\t\t\t\t\t + n13 * n22 * n34\n\t\t\t\t\t - n12 * n23 * n34\n\t\t\t\t) +\n\t\t\t\tn42 * (\n\t\t\t\t\t+ n11 * n23 * n34\n\t\t\t\t\t - n11 * n24 * n33\n\t\t\t\t\t + n14 * n21 * n33\n\t\t\t\t\t - n13 * n21 * n34\n\t\t\t\t\t + n13 * n24 * n31\n\t\t\t\t\t - n14 * n23 * n31\n\t\t\t\t) +\n\t\t\t\tn43 * (\n\t\t\t\t\t+ n11 * n24 * n32\n\t\t\t\t\t - n11 * n22 * n34\n\t\t\t\t\t - n14 * n21 * n32\n\t\t\t\t\t + n12 * n21 * n34\n\t\t\t\t\t + n14 * n22 * n31\n\t\t\t\t\t - n12 * n24 * n31\n\t\t\t\t) +\n\t\t\t\tn44 * (\n\t\t\t\t\t- n13 * n22 * n31\n\t\t\t\t\t - n11 * n23 * n32\n\t\t\t\t\t + n11 * n22 * n33\n\t\t\t\t\t + n13 * n21 * n32\n\t\t\t\t\t - n12 * n21 * n33\n\t\t\t\t\t + n12 * n23 * n31\n\t\t\t\t)\n\n\t\t\t);\n\n\t\t},\n\n\t\ttranspose: function () {\n\n\t\t\tvar te = this.elements;\n\t\t\tvar tmp;\n\n\t\t\ttmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;\n\t\t\ttmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;\n\t\t\ttmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;\n\n\t\t\ttmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;\n\t\t\ttmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;\n\t\t\ttmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetPosition: function ( v ) {\n\n\t\t\tvar te = this.elements;\n\n\t\t\tte[ 12 ] = v.x;\n\t\t\tte[ 13 ] = v.y;\n\t\t\tte[ 14 ] = v.z;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetInverse: function ( m, throwOnDegenerate ) {\n\n\t\t\t// based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm\n\t\t\tvar te = this.elements,\n\t\t\t\tme = m.elements,\n\n\t\t\t\tn11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], n41 = me[ 3 ],\n\t\t\t\tn12 = me[ 4 ], n22 = me[ 5 ], n32 = me[ 6 ], n42 = me[ 7 ],\n\t\t\t\tn13 = me[ 8 ], n23 = me[ 9 ], n33 = me[ 10 ], n43 = me[ 11 ],\n\t\t\t\tn14 = me[ 12 ], n24 = me[ 13 ], n34 = me[ 14 ], n44 = me[ 15 ],\n\n\t\t\t\tt11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,\n\t\t\t\tt12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,\n\t\t\t\tt13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,\n\t\t\t\tt14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;\n\n\t\t\tvar det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;\n\n\t\t\tif ( det === 0 ) {\n\n\t\t\t\tvar msg = \"THREE.Matrix4: .getInverse() can't invert matrix, determinant is 0\";\n\n\t\t\t\tif ( throwOnDegenerate === true ) {\n\n\t\t\t\t\tthrow new Error( msg );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.warn( msg );\n\n\t\t\t\t}\n\n\t\t\t\treturn this.identity();\n\n\t\t\t}\n\n\t\t\tvar detInv = 1 / det;\n\n\t\t\tte[ 0 ] = t11 * detInv;\n\t\t\tte[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;\n\t\t\tte[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;\n\t\t\tte[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;\n\n\t\t\tte[ 4 ] = t12 * detInv;\n\t\t\tte[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;\n\t\t\tte[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;\n\t\t\tte[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;\n\n\t\t\tte[ 8 ] = t13 * detInv;\n\t\t\tte[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;\n\t\t\tte[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;\n\t\t\tte[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;\n\n\t\t\tte[ 12 ] = t14 * detInv;\n\t\t\tte[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;\n\t\t\tte[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;\n\t\t\tte[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tscale: function ( v ) {\n\n\t\t\tvar te = this.elements;\n\t\t\tvar x = v.x, y = v.y, z = v.z;\n\n\t\t\tte[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;\n\t\t\tte[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;\n\t\t\tte[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;\n\t\t\tte[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetMaxScaleOnAxis: function () {\n\n\t\t\tvar te = this.elements;\n\n\t\t\tvar scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];\n\t\t\tvar scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];\n\t\t\tvar scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];\n\n\t\t\treturn Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );\n\n\t\t},\n\n\t\tmakeTranslation: function ( x, y, z ) {\n\n\t\t\tthis.set(\n\n\t\t\t\t1, 0, 0, x,\n\t\t\t\t0, 1, 0, y,\n\t\t\t\t0, 0, 1, z,\n\t\t\t\t0, 0, 0, 1\n\n\t\t\t);\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmakeRotationX: function ( theta ) {\n\n\t\t\tvar c = Math.cos( theta ), s = Math.sin( theta );\n\n\t\t\tthis.set(\n\n\t\t\t\t1, 0,  0, 0,\n\t\t\t\t0, c, - s, 0,\n\t\t\t\t0, s,  c, 0,\n\t\t\t\t0, 0,  0, 1\n\n\t\t\t);\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmakeRotationY: function ( theta ) {\n\n\t\t\tvar c = Math.cos( theta ), s = Math.sin( theta );\n\n\t\t\tthis.set(\n\n\t\t\t\t c, 0, s, 0,\n\t\t\t\t 0, 1, 0, 0,\n\t\t\t\t- s, 0, c, 0,\n\t\t\t\t 0, 0, 0, 1\n\n\t\t\t);\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmakeRotationZ: function ( theta ) {\n\n\t\t\tvar c = Math.cos( theta ), s = Math.sin( theta );\n\n\t\t\tthis.set(\n\n\t\t\t\tc, - s, 0, 0,\n\t\t\t\ts,  c, 0, 0,\n\t\t\t\t0,  0, 1, 0,\n\t\t\t\t0,  0, 0, 1\n\n\t\t\t);\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmakeRotationAxis: function ( axis, angle ) {\n\n\t\t\t// Based on http://www.gamedev.net/reference/articles/article1199.asp\n\n\t\t\tvar c = Math.cos( angle );\n\t\t\tvar s = Math.sin( angle );\n\t\t\tvar t = 1 - c;\n\t\t\tvar x = axis.x, y = axis.y, z = axis.z;\n\t\t\tvar tx = t * x, ty = t * y;\n\n\t\t\tthis.set(\n\n\t\t\t\ttx * x + c, tx * y - s * z, tx * z + s * y, 0,\n\t\t\t\ttx * y + s * z, ty * y + c, ty * z - s * x, 0,\n\t\t\t\ttx * z - s * y, ty * z + s * x, t * z * z + c, 0,\n\t\t\t\t0, 0, 0, 1\n\n\t\t\t);\n\n\t\t\t return this;\n\n\t\t},\n\n\t\tmakeScale: function ( x, y, z ) {\n\n\t\t\tthis.set(\n\n\t\t\t\tx, 0, 0, 0,\n\t\t\t\t0, y, 0, 0,\n\t\t\t\t0, 0, z, 0,\n\t\t\t\t0, 0, 0, 1\n\n\t\t\t);\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmakeShear: function ( x, y, z ) {\n\n\t\t\tthis.set(\n\n\t\t\t\t1, y, z, 0,\n\t\t\t\tx, 1, z, 0,\n\t\t\t\tx, y, 1, 0,\n\t\t\t\t0, 0, 0, 1\n\n\t\t\t);\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcompose: function ( position, quaternion, scale ) {\n\n\t\t\tthis.makeRotationFromQuaternion( quaternion );\n\t\t\tthis.scale( scale );\n\t\t\tthis.setPosition( position );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tdecompose: function () {\n\n\t\t\tvar vector = new Vector3();\n\t\t\tvar matrix = new Matrix4();\n\n\t\t\treturn function decompose( position, quaternion, scale ) {\n\n\t\t\t\tvar te = this.elements;\n\n\t\t\t\tvar sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();\n\t\t\t\tvar sy = vector.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();\n\t\t\t\tvar sz = vector.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();\n\n\t\t\t\t// if determine is negative, we need to invert one scale\n\t\t\t\tvar det = this.determinant();\n\t\t\t\tif ( det < 0 ) sx = - sx;\n\n\t\t\t\tposition.x = te[ 12 ];\n\t\t\t\tposition.y = te[ 13 ];\n\t\t\t\tposition.z = te[ 14 ];\n\n\t\t\t\t// scale the rotation part\n\t\t\t\tmatrix.copy( this );\n\n\t\t\t\tvar invSX = 1 / sx;\n\t\t\t\tvar invSY = 1 / sy;\n\t\t\t\tvar invSZ = 1 / sz;\n\n\t\t\t\tmatrix.elements[ 0 ] *= invSX;\n\t\t\t\tmatrix.elements[ 1 ] *= invSX;\n\t\t\t\tmatrix.elements[ 2 ] *= invSX;\n\n\t\t\t\tmatrix.elements[ 4 ] *= invSY;\n\t\t\t\tmatrix.elements[ 5 ] *= invSY;\n\t\t\t\tmatrix.elements[ 6 ] *= invSY;\n\n\t\t\t\tmatrix.elements[ 8 ] *= invSZ;\n\t\t\t\tmatrix.elements[ 9 ] *= invSZ;\n\t\t\t\tmatrix.elements[ 10 ] *= invSZ;\n\n\t\t\t\tquaternion.setFromRotationMatrix( matrix );\n\n\t\t\t\tscale.x = sx;\n\t\t\t\tscale.y = sy;\n\t\t\t\tscale.z = sz;\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tmakePerspective: function ( left, right, top, bottom, near, far ) {\n\n\t\t\tif ( far === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' );\n\n\t\t\t}\n\n\t\t\tvar te = this.elements;\n\t\t\tvar x = 2 * near / ( right - left );\n\t\t\tvar y = 2 * near / ( top - bottom );\n\n\t\t\tvar a = ( right + left ) / ( right - left );\n\t\t\tvar b = ( top + bottom ) / ( top - bottom );\n\t\t\tvar c = - ( far + near ) / ( far - near );\n\t\t\tvar d = - 2 * far * near / ( far - near );\n\n\t\t\tte[ 0 ] = x;\tte[ 4 ] = 0;\tte[ 8 ] = a;\tte[ 12 ] = 0;\n\t\t\tte[ 1 ] = 0;\tte[ 5 ] = y;\tte[ 9 ] = b;\tte[ 13 ] = 0;\n\t\t\tte[ 2 ] = 0;\tte[ 6 ] = 0;\tte[ 10 ] = c;\tte[ 14 ] = d;\n\t\t\tte[ 3 ] = 0;\tte[ 7 ] = 0;\tte[ 11 ] = - 1;\tte[ 15 ] = 0;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmakeOrthographic: function ( left, right, top, bottom, near, far ) {\n\n\t\t\tvar te = this.elements;\n\t\t\tvar w = 1.0 / ( right - left );\n\t\t\tvar h = 1.0 / ( top - bottom );\n\t\t\tvar p = 1.0 / ( far - near );\n\n\t\t\tvar x = ( right + left ) * w;\n\t\t\tvar y = ( top + bottom ) * h;\n\t\t\tvar z = ( far + near ) * p;\n\n\t\t\tte[ 0 ] = 2 * w;\tte[ 4 ] = 0;\tte[ 8 ] = 0;\tte[ 12 ] = - x;\n\t\t\tte[ 1 ] = 0;\tte[ 5 ] = 2 * h;\tte[ 9 ] = 0;\tte[ 13 ] = - y;\n\t\t\tte[ 2 ] = 0;\tte[ 6 ] = 0;\tte[ 10 ] = - 2 * p;\tte[ 14 ] = - z;\n\t\t\tte[ 3 ] = 0;\tte[ 7 ] = 0;\tte[ 11 ] = 0;\tte[ 15 ] = 1;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tequals: function ( matrix ) {\n\n\t\t\tvar te = this.elements;\n\t\t\tvar me = matrix.elements;\n\n\t\t\tfor ( var i = 0; i < 16; i ++ ) {\n\n\t\t\t\tif ( te[ i ] !== me[ i ] ) return false;\n\n\t\t\t}\n\n\t\t\treturn true;\n\n\t\t},\n\n\t\tfromArray: function ( array, offset ) {\n\n\t\t\tif ( offset === undefined ) offset = 0;\n\n\t\t\tfor ( var i = 0; i < 16; i ++ ) {\n\n\t\t\t\tthis.elements[ i ] = array[ i + offset ];\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\ttoArray: function ( array, offset ) {\n\n\t\t\tif ( array === undefined ) array = [];\n\t\t\tif ( offset === undefined ) offset = 0;\n\n\t\t\tvar te = this.elements;\n\n\t\t\tarray[ offset ] = te[ 0 ];\n\t\t\tarray[ offset + 1 ] = te[ 1 ];\n\t\t\tarray[ offset + 2 ] = te[ 2 ];\n\t\t\tarray[ offset + 3 ] = te[ 3 ];\n\n\t\t\tarray[ offset + 4 ] = te[ 4 ];\n\t\t\tarray[ offset + 5 ] = te[ 5 ];\n\t\t\tarray[ offset + 6 ] = te[ 6 ];\n\t\t\tarray[ offset + 7 ] = te[ 7 ];\n\n\t\t\tarray[ offset + 8 ] = te[ 8 ];\n\t\t\tarray[ offset + 9 ] = te[ 9 ];\n\t\t\tarray[ offset + 10 ] = te[ 10 ];\n\t\t\tarray[ offset + 11 ] = te[ 11 ];\n\n\t\t\tarray[ offset + 12 ] = te[ 12 ];\n\t\t\tarray[ offset + 13 ] = te[ 13 ];\n\t\t\tarray[ offset + 14 ] = te[ 14 ];\n\t\t\tarray[ offset + 15 ] = te[ 15 ];\n\n\t\t\treturn array;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tfunction DataTexture( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {\n\n\t\tTexture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );\n\n\t\tthis.image = { data: data, width: width, height: height };\n\n\t\tthis.magFilter = magFilter !== undefined ? magFilter : NearestFilter;\n\t\tthis.minFilter = minFilter !== undefined ? minFilter : NearestFilter;\n\n\t\tthis.generateMipmaps = false;\n\t\tthis.flipY = false;\n\t\tthis.unpackAlignment = 1;\n\n\t}\n\n\tDataTexture.prototype = Object.create( Texture.prototype );\n\tDataTexture.prototype.constructor = DataTexture;\n\n\tDataTexture.prototype.isDataTexture = true;\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {\n\n\t\timages = images !== undefined ? images : [];\n\t\tmapping = mapping !== undefined ? mapping : CubeReflectionMapping;\n\n\t\tTexture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );\n\n\t\tthis.flipY = false;\n\n\t}\n\n\tCubeTexture.prototype = Object.create( Texture.prototype );\n\tCubeTexture.prototype.constructor = CubeTexture;\n\n\tCubeTexture.prototype.isCubeTexture = true;\n\n\tObject.defineProperty( CubeTexture.prototype, 'images', {\n\n\t\tget: function () {\n\n\t\t\treturn this.image;\n\n\t\t},\n\n\t\tset: function ( value ) {\n\n\t\t\tthis.image = value;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author tschw\n\t *\n\t * Uniforms of a program.\n\t * Those form a tree structure with a special top-level container for the root,\n\t * which you get by calling 'new WebGLUniforms( gl, program, renderer )'.\n\t *\n\t *\n\t * Properties of inner nodes including the top-level container:\n\t *\n\t * .seq - array of nested uniforms\n\t * .map - nested uniforms by name\n\t *\n\t *\n\t * Methods of all nodes except the top-level container:\n\t *\n\t * .setValue( gl, value, [renderer] )\n\t *\n\t * \t\tuploads a uniform value(s)\n\t *  \tthe 'renderer' parameter is needed for sampler uniforms\n\t *\n\t *\n\t * Static methods of the top-level container (renderer factorizations):\n\t *\n\t * .upload( gl, seq, values, renderer )\n\t *\n\t * \t\tsets uniforms in 'seq' to 'values[id].value'\n\t *\n\t * .seqWithValue( seq, values ) : filteredSeq\n\t *\n\t * \t\tfilters 'seq' entries with corresponding entry in values\n\t *\n\t *\n\t * Methods of the top-level container (renderer factorizations):\n\t *\n\t * .setValue( gl, name, value )\n\t *\n\t * \t\tsets uniform with  name 'name' to 'value'\n\t *\n\t * .set( gl, obj, prop )\n\t *\n\t * \t\tsets uniform from object and property with same name than uniform\n\t *\n\t * .setOptional( gl, obj, prop )\n\t *\n\t * \t\tlike .set for an optional property of the object\n\t *\n\t */\n\n\tvar emptyTexture = new Texture();\n\tvar emptyCubeTexture = new CubeTexture();\n\n\t// --- Base for inner nodes (including the root) ---\n\n\tfunction UniformContainer() {\n\n\t\tthis.seq = [];\n\t\tthis.map = {};\n\n\t}\n\n\t// --- Utilities ---\n\n\t// Array Caches (provide typed arrays for temporary by size)\n\n\tvar arrayCacheF32 = [];\n\tvar arrayCacheI32 = [];\n\n\t// Float32Array caches used for uploading Matrix uniforms\n\n\tvar mat4array = new Float32Array( 16 );\n\tvar mat3array = new Float32Array( 9 );\n\n\t// Flattening for arrays of vectors and matrices\n\n\tfunction flatten( array, nBlocks, blockSize ) {\n\n\t\tvar firstElem = array[ 0 ];\n\n\t\tif ( firstElem <= 0 || firstElem > 0 ) return array;\n\t\t// unoptimized: ! isNaN( firstElem )\n\t\t// see http://jacksondunstan.com/articles/983\n\n\t\tvar n = nBlocks * blockSize,\n\t\t\tr = arrayCacheF32[ n ];\n\n\t\tif ( r === undefined ) {\n\n\t\t\tr = new Float32Array( n );\n\t\t\tarrayCacheF32[ n ] = r;\n\n\t\t}\n\n\t\tif ( nBlocks !== 0 ) {\n\n\t\t\tfirstElem.toArray( r, 0 );\n\n\t\t\tfor ( var i = 1, offset = 0; i !== nBlocks; ++ i ) {\n\n\t\t\t\toffset += blockSize;\n\t\t\t\tarray[ i ].toArray( r, offset );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn r;\n\n\t}\n\n\t// Texture unit allocation\n\n\tfunction allocTexUnits( renderer, n ) {\n\n\t\tvar r = arrayCacheI32[ n ];\n\n\t\tif ( r === undefined ) {\n\n\t\t\tr = new Int32Array( n );\n\t\t\tarrayCacheI32[ n ] = r;\n\n\t\t}\n\n\t\tfor ( var i = 0; i !== n; ++ i )\n\t\t\tr[ i ] = renderer.allocTextureUnit();\n\n\t\treturn r;\n\n\t}\n\n\t// --- Setters ---\n\n\t// Note: Defining these methods externally, because they come in a bunch\n\t// and this way their names minify.\n\n\t// Single scalar\n\n\tfunction setValue1f( gl, v ) { gl.uniform1f( this.addr, v ); }\n\tfunction setValue1i( gl, v ) { gl.uniform1i( this.addr, v ); }\n\n\t// Single float vector (from flat array or THREE.VectorN)\n\n\tfunction setValue2fv( gl, v ) {\n\n\t\tif ( v.x === undefined ) gl.uniform2fv( this.addr, v );\n\t\telse gl.uniform2f( this.addr, v.x, v.y );\n\n\t}\n\n\tfunction setValue3fv( gl, v ) {\n\n\t\tif ( v.x !== undefined )\n\t\t\tgl.uniform3f( this.addr, v.x, v.y, v.z );\n\t\telse if ( v.r !== undefined )\n\t\t\tgl.uniform3f( this.addr, v.r, v.g, v.b );\n\t\telse\n\t\t\tgl.uniform3fv( this.addr, v );\n\n\t}\n\n\tfunction setValue4fv( gl, v ) {\n\n\t\tif ( v.x === undefined ) gl.uniform4fv( this.addr, v );\n\t\telse gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );\n\n\t}\n\n\t// Single matrix (from flat array or MatrixN)\n\n\tfunction setValue2fm( gl, v ) {\n\n\t\tgl.uniformMatrix2fv( this.addr, false, v.elements || v );\n\n\t}\n\n\tfunction setValue3fm( gl, v ) {\n\n\t\tif ( v.elements === undefined ) {\n\n\t\t\tgl.uniformMatrix3fv( this.addr, false, v );\n\n\t\t} else {\n\n\t\t\tmat3array.set( v.elements );\n\t\t\tgl.uniformMatrix3fv( this.addr, false, mat3array );\n\n\t\t}\n\n\t}\n\n\tfunction setValue4fm( gl, v ) {\n\n\t\tif ( v.elements === undefined ) {\n\n\t\t\tgl.uniformMatrix4fv( this.addr, false, v );\n\n\t\t} else {\n\n\t\t\tmat4array.set( v.elements );\n\t\t\tgl.uniformMatrix4fv( this.addr, false, mat4array );\n\n\t\t}\n\n\t}\n\n\t// Single texture (2D / Cube)\n\n\tfunction setValueT1( gl, v, renderer ) {\n\n\t\tvar unit = renderer.allocTextureUnit();\n\t\tgl.uniform1i( this.addr, unit );\n\t\trenderer.setTexture2D( v || emptyTexture, unit );\n\n\t}\n\n\tfunction setValueT6( gl, v, renderer ) {\n\n\t\tvar unit = renderer.allocTextureUnit();\n\t\tgl.uniform1i( this.addr, unit );\n\t\trenderer.setTextureCube( v || emptyCubeTexture, unit );\n\n\t}\n\n\t// Integer / Boolean vectors or arrays thereof (always flat arrays)\n\n\tfunction setValue2iv( gl, v ) { gl.uniform2iv( this.addr, v ); }\n\tfunction setValue3iv( gl, v ) { gl.uniform3iv( this.addr, v ); }\n\tfunction setValue4iv( gl, v ) { gl.uniform4iv( this.addr, v ); }\n\n\t// Helper to pick the right setter for the singular case\n\n\tfunction getSingularSetter( type ) {\n\n\t\tswitch ( type ) {\n\n\t\t\tcase 0x1406: return setValue1f; // FLOAT\n\t\t\tcase 0x8b50: return setValue2fv; // _VEC2\n\t\t\tcase 0x8b51: return setValue3fv; // _VEC3\n\t\t\tcase 0x8b52: return setValue4fv; // _VEC4\n\n\t\t\tcase 0x8b5a: return setValue2fm; // _MAT2\n\t\t\tcase 0x8b5b: return setValue3fm; // _MAT3\n\t\t\tcase 0x8b5c: return setValue4fm; // _MAT4\n\n\t\t\tcase 0x8b5e: case 0x8d66: return setValueT1; // SAMPLER_2D, SAMPLER_EXTERNAL_OES\n\t\t\tcase 0x8b60: return setValueT6; // SAMPLER_CUBE\n\n\t\t\tcase 0x1404: case 0x8b56: return setValue1i; // INT, BOOL\n\t\t\tcase 0x8b53: case 0x8b57: return setValue2iv; // _VEC2\n\t\t\tcase 0x8b54: case 0x8b58: return setValue3iv; // _VEC3\n\t\t\tcase 0x8b55: case 0x8b59: return setValue4iv; // _VEC4\n\n\t\t}\n\n\t}\n\n\t// Array of scalars\n\n\tfunction setValue1fv( gl, v ) { gl.uniform1fv( this.addr, v ); }\n\tfunction setValue1iv( gl, v ) { gl.uniform1iv( this.addr, v ); }\n\n\t// Array of vectors (flat or from THREE classes)\n\n\tfunction setValueV2a( gl, v ) {\n\n\t\tgl.uniform2fv( this.addr, flatten( v, this.size, 2 ) );\n\n\t}\n\n\tfunction setValueV3a( gl, v ) {\n\n\t\tgl.uniform3fv( this.addr, flatten( v, this.size, 3 ) );\n\n\t}\n\n\tfunction setValueV4a( gl, v ) {\n\n\t\tgl.uniform4fv( this.addr, flatten( v, this.size, 4 ) );\n\n\t}\n\n\t// Array of matrices (flat or from THREE clases)\n\n\tfunction setValueM2a( gl, v ) {\n\n\t\tgl.uniformMatrix2fv( this.addr, false, flatten( v, this.size, 4 ) );\n\n\t}\n\n\tfunction setValueM3a( gl, v ) {\n\n\t\tgl.uniformMatrix3fv( this.addr, false, flatten( v, this.size, 9 ) );\n\n\t}\n\n\tfunction setValueM4a( gl, v ) {\n\n\t\tgl.uniformMatrix4fv( this.addr, false, flatten( v, this.size, 16 ) );\n\n\t}\n\n\t// Array of textures (2D / Cube)\n\n\tfunction setValueT1a( gl, v, renderer ) {\n\n\t\tvar n = v.length,\n\t\t\tunits = allocTexUnits( renderer, n );\n\n\t\tgl.uniform1iv( this.addr, units );\n\n\t\tfor ( var i = 0; i !== n; ++ i ) {\n\n\t\t\trenderer.setTexture2D( v[ i ] || emptyTexture, units[ i ] );\n\n\t\t}\n\n\t}\n\n\tfunction setValueT6a( gl, v, renderer ) {\n\n\t\tvar n = v.length,\n\t\t\tunits = allocTexUnits( renderer, n );\n\n\t\tgl.uniform1iv( this.addr, units );\n\n\t\tfor ( var i = 0; i !== n; ++ i ) {\n\n\t\t\trenderer.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );\n\n\t\t}\n\n\t}\n\n\t// Helper to pick the right setter for a pure (bottom-level) array\n\n\tfunction getPureArraySetter( type ) {\n\n\t\tswitch ( type ) {\n\n\t\t\tcase 0x1406: return setValue1fv; // FLOAT\n\t\t\tcase 0x8b50: return setValueV2a; // _VEC2\n\t\t\tcase 0x8b51: return setValueV3a; // _VEC3\n\t\t\tcase 0x8b52: return setValueV4a; // _VEC4\n\n\t\t\tcase 0x8b5a: return setValueM2a; // _MAT2\n\t\t\tcase 0x8b5b: return setValueM3a; // _MAT3\n\t\t\tcase 0x8b5c: return setValueM4a; // _MAT4\n\n\t\t\tcase 0x8b5e: return setValueT1a; // SAMPLER_2D\n\t\t\tcase 0x8b60: return setValueT6a; // SAMPLER_CUBE\n\n\t\t\tcase 0x1404: case 0x8b56: return setValue1iv; // INT, BOOL\n\t\t\tcase 0x8b53: case 0x8b57: return setValue2iv; // _VEC2\n\t\t\tcase 0x8b54: case 0x8b58: return setValue3iv; // _VEC3\n\t\t\tcase 0x8b55: case 0x8b59: return setValue4iv; // _VEC4\n\n\t\t}\n\n\t}\n\n\t// --- Uniform Classes ---\n\n\tfunction SingleUniform( id, activeInfo, addr ) {\n\n\t\tthis.id = id;\n\t\tthis.addr = addr;\n\t\tthis.setValue = getSingularSetter( activeInfo.type );\n\n\t\t// this.path = activeInfo.name; // DEBUG\n\n\t}\n\n\tfunction PureArrayUniform( id, activeInfo, addr ) {\n\n\t\tthis.id = id;\n\t\tthis.addr = addr;\n\t\tthis.size = activeInfo.size;\n\t\tthis.setValue = getPureArraySetter( activeInfo.type );\n\n\t\t// this.path = activeInfo.name; // DEBUG\n\n\t}\n\n\tfunction StructuredUniform( id ) {\n\n\t\tthis.id = id;\n\n\t\tUniformContainer.call( this ); // mix-in\n\n\t}\n\n\tStructuredUniform.prototype.setValue = function ( gl, value ) {\n\n\t\t// Note: Don't need an extra 'renderer' parameter, since samplers\n\t\t// are not allowed in structured uniforms.\n\n\t\tvar seq = this.seq;\n\n\t\tfor ( var i = 0, n = seq.length; i !== n; ++ i ) {\n\n\t\t\tvar u = seq[ i ];\n\t\t\tu.setValue( gl, value[ u.id ] );\n\n\t\t}\n\n\t};\n\n\t// --- Top-level ---\n\n\t// Parser - builds up the property tree from the path strings\n\n\tvar RePathPart = /([\\w\\d_]+)(\\])?(\\[|\\.)?/g;\n\n\t// extracts\n\t// \t- the identifier (member name or array index)\n\t//  - followed by an optional right bracket (found when array index)\n\t//  - followed by an optional left bracket or dot (type of subscript)\n\t//\n\t// Note: These portions can be read in a non-overlapping fashion and\n\t// allow straightforward parsing of the hierarchy that WebGL encodes\n\t// in the uniform names.\n\n\tfunction addUniform( container, uniformObject ) {\n\n\t\tcontainer.seq.push( uniformObject );\n\t\tcontainer.map[ uniformObject.id ] = uniformObject;\n\n\t}\n\n\tfunction parseUniform( activeInfo, addr, container ) {\n\n\t\tvar path = activeInfo.name,\n\t\t\tpathLength = path.length;\n\n\t\t// reset RegExp object, because of the early exit of a previous run\n\t\tRePathPart.lastIndex = 0;\n\n\t\tfor ( ; ; ) {\n\n\t\t\tvar match = RePathPart.exec( path ),\n\t\t\t\tmatchEnd = RePathPart.lastIndex,\n\n\t\t\t\tid = match[ 1 ],\n\t\t\t\tidIsIndex = match[ 2 ] === ']',\n\t\t\t\tsubscript = match[ 3 ];\n\n\t\t\tif ( idIsIndex ) id = id | 0; // convert to integer\n\n\t\t\tif ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {\n\n\t\t\t\t// bare name or \"pure\" bottom-level array \"[0]\" suffix\n\n\t\t\t\taddUniform( container, subscript === undefined ?\n\t\t\t\t\t\tnew SingleUniform( id, activeInfo, addr ) :\n\t\t\t\t\t\tnew PureArrayUniform( id, activeInfo, addr ) );\n\n\t\t\t\tbreak;\n\n\t\t\t} else {\n\n\t\t\t\t// step into inner node / create it in case it doesn't exist\n\n\t\t\t\tvar map = container.map, next = map[ id ];\n\n\t\t\t\tif ( next === undefined ) {\n\n\t\t\t\t\tnext = new StructuredUniform( id );\n\t\t\t\t\taddUniform( container, next );\n\n\t\t\t\t}\n\n\t\t\t\tcontainer = next;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t// Root Container\n\n\tfunction WebGLUniforms( gl, program, renderer ) {\n\n\t\tUniformContainer.call( this );\n\n\t\tthis.renderer = renderer;\n\n\t\tvar n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );\n\n\t\tfor ( var i = 0; i < n; ++ i ) {\n\n\t\t\tvar info = gl.getActiveUniform( program, i ),\n\t\t\t\tpath = info.name,\n\t\t\t\taddr = gl.getUniformLocation( program, path );\n\n\t\t\tparseUniform( info, addr, this );\n\n\t\t}\n\n\t}\n\n\tWebGLUniforms.prototype.setValue = function ( gl, name, value ) {\n\n\t\tvar u = this.map[ name ];\n\n\t\tif ( u !== undefined ) u.setValue( gl, value, this.renderer );\n\n\t};\n\n\tWebGLUniforms.prototype.setOptional = function ( gl, object, name ) {\n\n\t\tvar v = object[ name ];\n\n\t\tif ( v !== undefined ) this.setValue( gl, name, v );\n\n\t};\n\n\n\t// Static interface\n\n\tWebGLUniforms.upload = function ( gl, seq, values, renderer ) {\n\n\t\tfor ( var i = 0, n = seq.length; i !== n; ++ i ) {\n\n\t\t\tvar u = seq[ i ],\n\t\t\t\tv = values[ u.id ];\n\n\t\t\tif ( v.needsUpdate !== false ) {\n\n\t\t\t\t// note: always updating when .needsUpdate is undefined\n\t\t\t\tu.setValue( gl, v.value, renderer );\n\n\t\t\t}\n\n\t\t}\n\n\t};\n\n\tWebGLUniforms.seqWithValue = function ( seq, values ) {\n\n\t\tvar r = [];\n\n\t\tfor ( var i = 0, n = seq.length; i !== n; ++ i ) {\n\n\t\t\tvar u = seq[ i ];\n\t\t\tif ( u.id in values ) r.push( u );\n\n\t\t}\n\n\t\treturn r;\n\n\t};\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tvar ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,\n\t\t'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,\n\t\t'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,\n\t\t'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,\n\t\t'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,\n\t\t'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,\n\t\t'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,\n\t\t'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,\n\t\t'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,\n\t\t'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,\n\t\t'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,\n\t\t'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,\n\t\t'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,\n\t\t'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,\n\t\t'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,\n\t\t'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,\n\t\t'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,\n\t\t'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,\n\t\t'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,\n\t\t'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,\n\t\t'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,\n\t\t'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,\n\t\t'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,\n\t\t'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };\n\n\tfunction Color( r, g, b ) {\n\n\t\tif ( g === undefined && b === undefined ) {\n\n\t\t\t// r is THREE.Color, hex or string\n\t\t\treturn this.set( r );\n\n\t\t}\n\n\t\treturn this.setRGB( r, g, b );\n\n\t}\n\n\tObject.assign( Color.prototype, {\n\n\t\tisColor: true,\n\n\t\tr: 1, g: 1, b: 1,\n\n\t\tset: function ( value ) {\n\n\t\t\tif ( value && value.isColor ) {\n\n\t\t\t\tthis.copy( value );\n\n\t\t\t} else if ( typeof value === 'number' ) {\n\n\t\t\t\tthis.setHex( value );\n\n\t\t\t} else if ( typeof value === 'string' ) {\n\n\t\t\t\tthis.setStyle( value );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetScalar: function ( scalar ) {\n\n\t\t\tthis.r = scalar;\n\t\t\tthis.g = scalar;\n\t\t\tthis.b = scalar;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetHex: function ( hex ) {\n\n\t\t\thex = Math.floor( hex );\n\n\t\t\tthis.r = ( hex >> 16 & 255 ) / 255;\n\t\t\tthis.g = ( hex >> 8 & 255 ) / 255;\n\t\t\tthis.b = ( hex & 255 ) / 255;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetRGB: function ( r, g, b ) {\n\n\t\t\tthis.r = r;\n\t\t\tthis.g = g;\n\t\t\tthis.b = b;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetHSL: function () {\n\n\t\t\tfunction hue2rgb( p, q, t ) {\n\n\t\t\t\tif ( t < 0 ) t += 1;\n\t\t\t\tif ( t > 1 ) t -= 1;\n\t\t\t\tif ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;\n\t\t\t\tif ( t < 1 / 2 ) return q;\n\t\t\t\tif ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );\n\t\t\t\treturn p;\n\n\t\t\t}\n\n\t\t\treturn function setHSL( h, s, l ) {\n\n\t\t\t\t// h,s,l ranges are in 0.0 - 1.0\n\t\t\t\th = _Math.euclideanModulo( h, 1 );\n\t\t\t\ts = _Math.clamp( s, 0, 1 );\n\t\t\t\tl = _Math.clamp( l, 0, 1 );\n\n\t\t\t\tif ( s === 0 ) {\n\n\t\t\t\t\tthis.r = this.g = this.b = l;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tvar p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );\n\t\t\t\t\tvar q = ( 2 * l ) - p;\n\n\t\t\t\t\tthis.r = hue2rgb( q, p, h + 1 / 3 );\n\t\t\t\t\tthis.g = hue2rgb( q, p, h );\n\t\t\t\t\tthis.b = hue2rgb( q, p, h - 1 / 3 );\n\n\t\t\t\t}\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tsetStyle: function ( style ) {\n\n\t\t\tfunction handleAlpha( string ) {\n\n\t\t\t\tif ( string === undefined ) return;\n\n\t\t\t\tif ( parseFloat( string ) < 1 ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\n\t\t\tvar m;\n\n\t\t\tif ( m = /^((?:rgb|hsl)a?)\\(\\s*([^\\)]*)\\)/.exec( style ) ) {\n\n\t\t\t\t// rgb / hsl\n\n\t\t\t\tvar color;\n\t\t\t\tvar name = m[ 1 ];\n\t\t\t\tvar components = m[ 2 ];\n\n\t\t\t\tswitch ( name ) {\n\n\t\t\t\t\tcase 'rgb':\n\t\t\t\t\tcase 'rgba':\n\n\t\t\t\t\t\tif ( color = /^(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*(,\\s*([0-9]*\\.?[0-9]+)\\s*)?$/.exec( components ) ) {\n\n\t\t\t\t\t\t\t// rgb(255,0,0) rgba(255,0,0,0.5)\n\t\t\t\t\t\t\tthis.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255;\n\t\t\t\t\t\t\tthis.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;\n\t\t\t\t\t\t\tthis.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;\n\n\t\t\t\t\t\t\thandleAlpha( color[ 5 ] );\n\n\t\t\t\t\t\t\treturn this;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( color = /^(\\d+)\\%\\s*,\\s*(\\d+)\\%\\s*,\\s*(\\d+)\\%\\s*(,\\s*([0-9]*\\.?[0-9]+)\\s*)?$/.exec( components ) ) {\n\n\t\t\t\t\t\t\t// rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)\n\t\t\t\t\t\t\tthis.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100;\n\t\t\t\t\t\t\tthis.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;\n\t\t\t\t\t\t\tthis.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;\n\n\t\t\t\t\t\t\thandleAlpha( color[ 5 ] );\n\n\t\t\t\t\t\t\treturn this;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'hsl':\n\t\t\t\t\tcase 'hsla':\n\n\t\t\t\t\t\tif ( color = /^([0-9]*\\.?[0-9]+)\\s*,\\s*(\\d+)\\%\\s*,\\s*(\\d+)\\%\\s*(,\\s*([0-9]*\\.?[0-9]+)\\s*)?$/.exec( components ) ) {\n\n\t\t\t\t\t\t\t// hsl(120,50%,50%) hsla(120,50%,50%,0.5)\n\t\t\t\t\t\t\tvar h = parseFloat( color[ 1 ] ) / 360;\n\t\t\t\t\t\t\tvar s = parseInt( color[ 2 ], 10 ) / 100;\n\t\t\t\t\t\t\tvar l = parseInt( color[ 3 ], 10 ) / 100;\n\n\t\t\t\t\t\t\thandleAlpha( color[ 5 ] );\n\n\t\t\t\t\t\t\treturn this.setHSL( h, s, l );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t} else if ( m = /^\\#([A-Fa-f0-9]+)$/.exec( style ) ) {\n\n\t\t\t\t// hex color\n\n\t\t\t\tvar hex = m[ 1 ];\n\t\t\t\tvar size = hex.length;\n\n\t\t\t\tif ( size === 3 ) {\n\n\t\t\t\t\t// #ff0\n\t\t\t\t\tthis.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255;\n\t\t\t\t\tthis.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;\n\t\t\t\t\tthis.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;\n\n\t\t\t\t\treturn this;\n\n\t\t\t\t} else if ( size === 6 ) {\n\n\t\t\t\t\t// #ff0000\n\t\t\t\t\tthis.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255;\n\t\t\t\t\tthis.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;\n\t\t\t\t\tthis.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;\n\n\t\t\t\t\treturn this;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( style && style.length > 0 ) {\n\n\t\t\t\t// color keywords\n\t\t\t\tvar hex = ColorKeywords[ style ];\n\n\t\t\t\tif ( hex !== undefined ) {\n\n\t\t\t\t\t// red\n\t\t\t\t\tthis.setHex( hex );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// unknown color\n\t\t\t\t\tconsole.warn( 'THREE.Color: Unknown color ' + style );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor( this.r, this.g, this.b );\n\n\t\t},\n\n\t\tcopy: function ( color ) {\n\n\t\t\tthis.r = color.r;\n\t\t\tthis.g = color.g;\n\t\t\tthis.b = color.b;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcopyGammaToLinear: function ( color, gammaFactor ) {\n\n\t\t\tif ( gammaFactor === undefined ) gammaFactor = 2.0;\n\n\t\t\tthis.r = Math.pow( color.r, gammaFactor );\n\t\t\tthis.g = Math.pow( color.g, gammaFactor );\n\t\t\tthis.b = Math.pow( color.b, gammaFactor );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcopyLinearToGamma: function ( color, gammaFactor ) {\n\n\t\t\tif ( gammaFactor === undefined ) gammaFactor = 2.0;\n\n\t\t\tvar safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0;\n\n\t\t\tthis.r = Math.pow( color.r, safeInverse );\n\t\t\tthis.g = Math.pow( color.g, safeInverse );\n\t\t\tthis.b = Math.pow( color.b, safeInverse );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tconvertGammaToLinear: function () {\n\n\t\t\tvar r = this.r, g = this.g, b = this.b;\n\n\t\t\tthis.r = r * r;\n\t\t\tthis.g = g * g;\n\t\t\tthis.b = b * b;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tconvertLinearToGamma: function () {\n\n\t\t\tthis.r = Math.sqrt( this.r );\n\t\t\tthis.g = Math.sqrt( this.g );\n\t\t\tthis.b = Math.sqrt( this.b );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetHex: function () {\n\n\t\t\treturn ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0;\n\n\t\t},\n\n\t\tgetHexString: function () {\n\n\t\t\treturn ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );\n\n\t\t},\n\n\t\tgetHSL: function ( optionalTarget ) {\n\n\t\t\t// h,s,l ranges are in 0.0 - 1.0\n\n\t\t\tvar hsl = optionalTarget || { h: 0, s: 0, l: 0 };\n\n\t\t\tvar r = this.r, g = this.g, b = this.b;\n\n\t\t\tvar max = Math.max( r, g, b );\n\t\t\tvar min = Math.min( r, g, b );\n\n\t\t\tvar hue, saturation;\n\t\t\tvar lightness = ( min + max ) / 2.0;\n\n\t\t\tif ( min === max ) {\n\n\t\t\t\thue = 0;\n\t\t\t\tsaturation = 0;\n\n\t\t\t} else {\n\n\t\t\t\tvar delta = max - min;\n\n\t\t\t\tsaturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );\n\n\t\t\t\tswitch ( max ) {\n\n\t\t\t\t\tcase r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;\n\t\t\t\t\tcase g: hue = ( b - r ) / delta + 2; break;\n\t\t\t\t\tcase b: hue = ( r - g ) / delta + 4; break;\n\n\t\t\t\t}\n\n\t\t\t\thue /= 6;\n\n\t\t\t}\n\n\t\t\thsl.h = hue;\n\t\t\thsl.s = saturation;\n\t\t\thsl.l = lightness;\n\n\t\t\treturn hsl;\n\n\t\t},\n\n\t\tgetStyle: function () {\n\n\t\t\treturn 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';\n\n\t\t},\n\n\t\toffsetHSL: function ( h, s, l ) {\n\n\t\t\tvar hsl = this.getHSL();\n\n\t\t\thsl.h += h; hsl.s += s; hsl.l += l;\n\n\t\t\tthis.setHSL( hsl.h, hsl.s, hsl.l );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tadd: function ( color ) {\n\n\t\t\tthis.r += color.r;\n\t\t\tthis.g += color.g;\n\t\t\tthis.b += color.b;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\taddColors: function ( color1, color2 ) {\n\n\t\t\tthis.r = color1.r + color2.r;\n\t\t\tthis.g = color1.g + color2.g;\n\t\t\tthis.b = color1.b + color2.b;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\taddScalar: function ( s ) {\n\n\t\t\tthis.r += s;\n\t\t\tthis.g += s;\n\t\t\tthis.b += s;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsub: function( color ) {\n\n\t\t\tthis.r = Math.max( 0, this.r - color.r );\n\t\t\tthis.g = Math.max( 0, this.g - color.g );\n\t\t\tthis.b = Math.max( 0, this.b - color.b );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmultiply: function ( color ) {\n\n\t\t\tthis.r *= color.r;\n\t\t\tthis.g *= color.g;\n\t\t\tthis.b *= color.b;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmultiplyScalar: function ( s ) {\n\n\t\t\tthis.r *= s;\n\t\t\tthis.g *= s;\n\t\t\tthis.b *= s;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tlerp: function ( color, alpha ) {\n\n\t\t\tthis.r += ( color.r - this.r ) * alpha;\n\t\t\tthis.g += ( color.g - this.g ) * alpha;\n\t\t\tthis.b += ( color.b - this.b ) * alpha;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tequals: function ( c ) {\n\n\t\t\treturn ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );\n\n\t\t},\n\n\t\tfromArray: function ( array, offset ) {\n\n\t\t\tif ( offset === undefined ) offset = 0;\n\n\t\t\tthis.r = array[ offset ];\n\t\t\tthis.g = array[ offset + 1 ];\n\t\t\tthis.b = array[ offset + 2 ];\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\ttoArray: function ( array, offset ) {\n\n\t\t\tif ( array === undefined ) array = [];\n\t\t\tif ( offset === undefined ) offset = 0;\n\n\t\t\tarray[ offset ] = this.r;\n\t\t\tarray[ offset + 1 ] = this.g;\n\t\t\tarray[ offset + 2 ] = this.b;\n\n\t\t\treturn array;\n\n\t\t},\n\n\t\ttoJSON: function () {\n\n\t\t\treturn this.getHex();\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * Uniforms library for shared webgl shaders\n\t */\n\n\tvar UniformsLib = {\n\n\t\tcommon: {\n\n\t\t\tdiffuse: { value: new Color( 0xeeeeee ) },\n\t\t\topacity: { value: 1.0 },\n\n\t\t\tmap: { value: null },\n\t\t\toffsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) },\n\n\t\t\talphaMap: { value: null },\n\n\t\t},\n\n\t\tspecularmap: {\n\n\t\t\tspecularMap: { value: null },\n\n\t\t},\n\n\t\tenvmap: {\n\n\t\t\tenvMap: { value: null },\n\t\t\tflipEnvMap: { value: - 1 },\n\t\t\treflectivity: { value: 1.0 },\n\t\t\trefractionRatio: { value: 0.98 }\n\n\t\t},\n\n\t\taomap: {\n\n\t\t\taoMap: { value: null },\n\t\t\taoMapIntensity: { value: 1 }\n\n\t\t},\n\n\t\tlightmap: {\n\n\t\t\tlightMap: { value: null },\n\t\t\tlightMapIntensity: { value: 1 }\n\n\t\t},\n\n\t\temissivemap: {\n\n\t\t\temissiveMap: { value: null }\n\n\t\t},\n\n\t\tbumpmap: {\n\n\t\t\tbumpMap: { value: null },\n\t\t\tbumpScale: { value: 1 }\n\n\t\t},\n\n\t\tnormalmap: {\n\n\t\t\tnormalMap: { value: null },\n\t\t\tnormalScale: { value: new Vector2( 1, 1 ) }\n\n\t\t},\n\n\t\tdisplacementmap: {\n\n\t\t\tdisplacementMap: { value: null },\n\t\t\tdisplacementScale: { value: 1 },\n\t\t\tdisplacementBias: { value: 0 }\n\n\t\t},\n\n\t\troughnessmap: {\n\n\t\t\troughnessMap: { value: null }\n\n\t\t},\n\n\t\tmetalnessmap: {\n\n\t\t\tmetalnessMap: { value: null }\n\n\t\t},\n\n\t\tgradientmap: {\n\n\t\t\tgradientMap: { value: null }\n\n\t\t},\n\n\t\tfog: {\n\n\t\t\tfogDensity: { value: 0.00025 },\n\t\t\tfogNear: { value: 1 },\n\t\t\tfogFar: { value: 2000 },\n\t\t\tfogColor: { value: new Color( 0xffffff ) }\n\n\t\t},\n\n\t\tlights: {\n\n\t\t\tambientLightColor: { value: [] },\n\n\t\t\tdirectionalLights: { value: [], properties: {\n\t\t\t\tdirection: {},\n\t\t\t\tcolor: {},\n\n\t\t\t\tshadow: {},\n\t\t\t\tshadowBias: {},\n\t\t\t\tshadowRadius: {},\n\t\t\t\tshadowMapSize: {}\n\t\t\t} },\n\n\t\t\tdirectionalShadowMap: { value: [] },\n\t\t\tdirectionalShadowMatrix: { value: [] },\n\n\t\t\tspotLights: { value: [], properties: {\n\t\t\t\tcolor: {},\n\t\t\t\tposition: {},\n\t\t\t\tdirection: {},\n\t\t\t\tdistance: {},\n\t\t\t\tconeCos: {},\n\t\t\t\tpenumbraCos: {},\n\t\t\t\tdecay: {},\n\n\t\t\t\tshadow: {},\n\t\t\t\tshadowBias: {},\n\t\t\t\tshadowRadius: {},\n\t\t\t\tshadowMapSize: {}\n\t\t\t} },\n\n\t\t\tspotShadowMap: { value: [] },\n\t\t\tspotShadowMatrix: { value: [] },\n\n\t\t\tpointLights: { value: [], properties: {\n\t\t\t\tcolor: {},\n\t\t\t\tposition: {},\n\t\t\t\tdecay: {},\n\t\t\t\tdistance: {},\n\n\t\t\t\tshadow: {},\n\t\t\t\tshadowBias: {},\n\t\t\t\tshadowRadius: {},\n\t\t\t\tshadowMapSize: {},\n\t\t\t\tshadowCameraNear: {},\n\t\t\t\tshadowCameraFar: {}\n\t\t\t} },\n\n\t\t\tpointShadowMap: { value: [] },\n\t\t\tpointShadowMatrix: { value: [] },\n\n\t\t\themisphereLights: { value: [], properties: {\n\t\t\t\tdirection: {},\n\t\t\t\tskyColor: {},\n\t\t\t\tgroundColor: {}\n\t\t\t} },\n\n\t\t\t// TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src\n\t\t\trectAreaLights: { value: [], properties: {\n\t\t\t\tcolor: {},\n\t\t\t\tposition: {},\n\t\t\t\twidth: {},\n\t\t\t\theight: {}\n\t\t\t} }\n\n\t\t},\n\n\t\tpoints: {\n\n\t\t\tdiffuse: { value: new Color( 0xeeeeee ) },\n\t\t\topacity: { value: 1.0 },\n\t\t\tsize: { value: 1.0 },\n\t\t\tscale: { value: 1.0 },\n\t\t\tmap: { value: null },\n\t\t\toffsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) }\n\n\t\t}\n\n\t};\n\n\t/**\n\t * Uniform Utilities\n\t */\n\n\tvar UniformsUtils = {\n\n\t\tmerge: function ( uniforms ) {\n\n\t\t\tvar merged = {};\n\n\t\t\tfor ( var u = 0; u < uniforms.length; u ++ ) {\n\n\t\t\t\tvar tmp = this.clone( uniforms[ u ] );\n\n\t\t\t\tfor ( var p in tmp ) {\n\n\t\t\t\t\tmerged[ p ] = tmp[ p ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn merged;\n\n\t\t},\n\n\t\tclone: function ( uniforms_src ) {\n\n\t\t\tvar uniforms_dst = {};\n\n\t\t\tfor ( var u in uniforms_src ) {\n\n\t\t\t\tuniforms_dst[ u ] = {};\n\n\t\t\t\tfor ( var p in uniforms_src[ u ] ) {\n\n\t\t\t\t\tvar parameter_src = uniforms_src[ u ][ p ];\n\n\t\t\t\t\tif ( parameter_src && ( parameter_src.isColor ||\n\t\t\t\t\t\tparameter_src.isMatrix3 || parameter_src.isMatrix4 ||\n\t\t\t\t\t\tparameter_src.isVector2 || parameter_src.isVector3 || parameter_src.isVector4 ||\n\t\t\t\t\t\tparameter_src.isTexture ) ) {\n\n\t\t\t\t\t\tuniforms_dst[ u ][ p ] = parameter_src.clone();\n\n\t\t\t\t\t} else if ( Array.isArray( parameter_src ) ) {\n\n\t\t\t\t\t\tuniforms_dst[ u ][ p ] = parameter_src.slice();\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tuniforms_dst[ u ][ p ] = parameter_src;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn uniforms_dst;\n\n\t\t}\n\n\t};\n\n\tvar alphamap_fragment = \"#ifdef USE_ALPHAMAP\\n\\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\\n#endif\\n\";\n\n\tvar alphamap_pars_fragment = \"#ifdef USE_ALPHAMAP\\n\\tuniform sampler2D alphaMap;\\n#endif\\n\";\n\n\tvar alphatest_fragment = \"#ifdef ALPHATEST\\n\\tif ( diffuseColor.a < ALPHATEST ) discard;\\n#endif\\n\";\n\n\tvar aomap_fragment = \"#ifdef USE_AOMAP\\n\\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\\n\\treflectedLight.indirectDiffuse *= ambientOcclusion;\\n\\t#if defined( USE_ENVMAP ) && defined( PHYSICAL )\\n\\t\\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\\n\\t\\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\\n\\t#endif\\n#endif\\n\";\n\n\tvar aomap_pars_fragment = \"#ifdef USE_AOMAP\\n\\tuniform sampler2D aoMap;\\n\\tuniform float aoMapIntensity;\\n#endif\";\n\n\tvar begin_vertex = \"\\nvec3 transformed = vec3( position );\\n\";\n\n\tvar beginnormal_vertex = \"\\nvec3 objectNormal = vec3( normal );\\n\";\n\n\tvar bsdfs = \"float punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\\n\\tif( decayExponent > 0.0 ) {\\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\\n\\t\\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\\n\\t\\tfloat maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\\n\\t\\treturn distanceFalloff * maxDistanceCutoffFactor;\\n#else\\n\\t\\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\\n#endif\\n\\t}\\n\\treturn 1.0;\\n}\\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\\n\\treturn RECIPROCAL_PI * diffuseColor;\\n}\\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\\n\\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\\n\\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\\n}\\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\\n\\tfloat a2 = pow2( alpha );\\n\\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\\n\\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\\n\\treturn 1.0 / ( gl * gv );\\n}\\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\\n\\tfloat a2 = pow2( alpha );\\n\\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\\n\\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\\n\\treturn 0.5 / max( gv + gl, EPSILON );\\n}\\nfloat D_GGX( const in float alpha, const in float dotNH ) {\\n\\tfloat a2 = pow2( alpha );\\n\\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\\n\\treturn RECIPROCAL_PI * a2 / pow2( denom );\\n}\\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\\n\\tfloat alpha = pow2( roughness );\\n\\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\\n\\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\\n\\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\\n\\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\\n\\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\\n\\tvec3 F = F_Schlick( specularColor, dotLH );\\n\\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\\n\\tfloat D = D_GGX( alpha, dotNH );\\n\\treturn F * ( G * D );\\n}\\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\\n\\tconst float LUT_SIZE  = 64.0;\\n\\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\\n\\tconst float LUT_BIAS  = 0.5 / LUT_SIZE;\\n\\tfloat theta = acos( dot( N, V ) );\\n\\tvec2 uv = vec2(\\n\\t\\tsqrt( saturate( roughness ) ),\\n\\t\\tsaturate( theta / ( 0.5 * PI ) ) );\\n\\tuv = uv * LUT_SCALE + LUT_BIAS;\\n\\treturn uv;\\n}\\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\\n\\tfloat l = length( f );\\n\\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\\n}\\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\\n\\tfloat x = dot( v1, v2 );\\n\\tfloat y = abs( x );\\n\\tfloat a = 0.86267 + (0.49788 + 0.01436 * y ) * y;\\n\\tfloat b = 3.45068 + (4.18814 + y) * y;\\n\\tfloat v = a / b;\\n\\tfloat theta_sintheta = (x > 0.0) ? v : 0.5 * inversesqrt( 1.0 - x * x ) - v;\\n\\treturn cross( v1, v2 ) * theta_sintheta;\\n}\\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\\n\\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\\n\\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\\n\\tvec3 lightNormal = cross( v1, v2 );\\n\\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\\n\\tvec3 T1, T2;\\n\\tT1 = normalize( V - N * dot( V, N ) );\\n\\tT2 = - cross( N, T1 );\\n\\tmat3 mat = mInv * transpose( mat3( T1, T2, N ) );\\n\\tvec3 coords[ 4 ];\\n\\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\\n\\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\\n\\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\\n\\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\\n\\tcoords[ 0 ] = normalize( coords[ 0 ] );\\n\\tcoords[ 1 ] = normalize( coords[ 1 ] );\\n\\tcoords[ 2 ] = normalize( coords[ 2 ] );\\n\\tcoords[ 3 ] = normalize( coords[ 3 ] );\\n\\tvec3 vectorFormFactor = vec3( 0.0 );\\n\\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\\n\\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\\n\\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\\n\\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\\n\\tvec3 result = vec3( LTC_ClippedSphereFormFactor( vectorFormFactor ) );\\n\\treturn result;\\n}\\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\\n\\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\\n\\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\\n\\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\\n\\tvec4 r = roughness * c0 + c1;\\n\\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\\n\\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\\n\\treturn specularColor * AB.x + AB.y;\\n}\\nfloat G_BlinnPhong_Implicit( ) {\\n\\treturn 0.25;\\n}\\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\\n\\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\\n}\\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\\n\\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\\n\\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\\n\\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\\n\\tvec3 F = F_Schlick( specularColor, dotLH );\\n\\tfloat G = G_BlinnPhong_Implicit( );\\n\\tfloat D = D_BlinnPhong( shininess, dotNH );\\n\\treturn F * ( G * D );\\n}\\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\\n\\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\\n}\\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\\n\\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\\n}\\n\";\n\n\tvar bumpmap_pars_fragment = \"#ifdef USE_BUMPMAP\\n\\tuniform sampler2D bumpMap;\\n\\tuniform float bumpScale;\\n\\tvec2 dHdxy_fwd() {\\n\\t\\tvec2 dSTdx = dFdx( vUv );\\n\\t\\tvec2 dSTdy = dFdy( vUv );\\n\\t\\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\\n\\t\\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\\n\\t\\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\\n\\t\\treturn vec2( dBx, dBy );\\n\\t}\\n\\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\\n\\t\\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\\n\\t\\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\\n\\t\\tvec3 vN = surf_norm;\\n\\t\\tvec3 R1 = cross( vSigmaY, vN );\\n\\t\\tvec3 R2 = cross( vN, vSigmaX );\\n\\t\\tfloat fDet = dot( vSigmaX, R1 );\\n\\t\\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\\n\\t\\treturn normalize( abs( fDet ) * surf_norm - vGrad );\\n\\t}\\n#endif\\n\";\n\n\tvar clipping_planes_fragment = \"#if NUM_CLIPPING_PLANES > 0\\n\\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; ++ i ) {\\n\\t\\tvec4 plane = clippingPlanes[ i ];\\n\\t\\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\\n\\t}\\n\\t\\t\\n\\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\\n\\t\\tbool clipped = true;\\n\\t\\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; ++ i ) {\\n\\t\\t\\tvec4 plane = clippingPlanes[ i ];\\n\\t\\t\\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\\n\\t\\t}\\n\\t\\tif ( clipped ) discard;\\n\\t\\n\\t#endif\\n#endif\\n\";\n\n\tvar clipping_planes_pars_fragment = \"#if NUM_CLIPPING_PLANES > 0\\n\\t#if ! defined( PHYSICAL ) && ! defined( PHONG )\\n\\t\\tvarying vec3 vViewPosition;\\n\\t#endif\\n\\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\\n#endif\\n\";\n\n\tvar clipping_planes_pars_vertex = \"#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\\n\\tvarying vec3 vViewPosition;\\n#endif\\n\";\n\n\tvar clipping_planes_vertex = \"#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\\n\\tvViewPosition = - mvPosition.xyz;\\n#endif\\n\";\n\n\tvar color_fragment = \"#ifdef USE_COLOR\\n\\tdiffuseColor.rgb *= vColor;\\n#endif\";\n\n\tvar color_pars_fragment = \"#ifdef USE_COLOR\\n\\tvarying vec3 vColor;\\n#endif\\n\";\n\n\tvar color_pars_vertex = \"#ifdef USE_COLOR\\n\\tvarying vec3 vColor;\\n#endif\";\n\n\tvar color_vertex = \"#ifdef USE_COLOR\\n\\tvColor.xyz = color.xyz;\\n#endif\";\n\n\tvar common = \"#define PI 3.14159265359\\n#define PI2 6.28318530718\\n#define PI_HALF 1.5707963267949\\n#define RECIPROCAL_PI 0.31830988618\\n#define RECIPROCAL_PI2 0.15915494\\n#define LOG2 1.442695\\n#define EPSILON 1e-6\\n#define saturate(a) clamp( a, 0.0, 1.0 )\\n#define whiteCompliment(a) ( 1.0 - saturate( a ) )\\nfloat pow2( const in float x ) { return x*x; }\\nfloat pow3( const in float x ) { return x*x*x; }\\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\\nhighp float rand( const in vec2 uv ) {\\n\\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\\n\\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\\n\\treturn fract(sin(sn) * c);\\n}\\nstruct IncidentLight {\\n\\tvec3 color;\\n\\tvec3 direction;\\n\\tbool visible;\\n};\\nstruct ReflectedLight {\\n\\tvec3 directDiffuse;\\n\\tvec3 directSpecular;\\n\\tvec3 indirectDiffuse;\\n\\tvec3 indirectSpecular;\\n};\\nstruct GeometricContext {\\n\\tvec3 position;\\n\\tvec3 normal;\\n\\tvec3 viewDir;\\n};\\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\\n\\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\\n}\\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\\n\\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\\n}\\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\\n\\tfloat distance = dot( planeNormal, point - pointOnPlane );\\n\\treturn - distance * planeNormal + point;\\n}\\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\\n\\treturn sign( dot( point - pointOnPlane, planeNormal ) );\\n}\\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\\n\\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\\n}\\nmat3 transpose( const in mat3 v ) {\\n\\tmat3 tmp;\\n\\ttmp[0] = vec3(v[0].x, v[1].x, v[2].x);\\n\\ttmp[1] = vec3(v[0].y, v[1].y, v[2].y);\\n\\ttmp[2] = vec3(v[0].z, v[1].z, v[2].z);\\n\\treturn tmp;\\n}\\n\";\n\n\tvar cube_uv_reflection_fragment = \"#ifdef ENVMAP_TYPE_CUBE_UV\\n#define cubeUV_textureSize (1024.0)\\nint getFaceFromDirection(vec3 direction) {\\n\\tvec3 absDirection = abs(direction);\\n\\tint face = -1;\\n\\tif( absDirection.x > absDirection.z ) {\\n\\t\\tif(absDirection.x > absDirection.y )\\n\\t\\t\\tface = direction.x > 0.0 ? 0 : 3;\\n\\t\\telse\\n\\t\\t\\tface = direction.y > 0.0 ? 1 : 4;\\n\\t}\\n\\telse {\\n\\t\\tif(absDirection.z > absDirection.y )\\n\\t\\t\\tface = direction.z > 0.0 ? 2 : 5;\\n\\t\\telse\\n\\t\\t\\tface = direction.y > 0.0 ? 1 : 4;\\n\\t}\\n\\treturn face;\\n}\\n#define cubeUV_maxLods1  (log2(cubeUV_textureSize*0.25) - 1.0)\\n#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0))\\nvec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) {\\n\\tfloat scale = exp2(cubeUV_maxLods1 - roughnessLevel);\\n\\tfloat dxRoughness = dFdx(roughness);\\n\\tfloat dyRoughness = dFdy(roughness);\\n\\tvec3 dx = dFdx( vec * scale * dxRoughness );\\n\\tvec3 dy = dFdy( vec * scale * dyRoughness );\\n\\tfloat d = max( dot( dx, dx ), dot( dy, dy ) );\\n\\td = clamp(d, 1.0, cubeUV_rangeClamp);\\n\\tfloat mipLevel = 0.5 * log2(d);\\n\\treturn vec2(floor(mipLevel), fract(mipLevel));\\n}\\n#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0)\\n#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize)\\nvec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) {\\n\\tmipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;\\n\\tfloat a = 16.0 * cubeUV_rcpTextureSize;\\n\\tvec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );\\n\\tvec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;\\n\\tfloat powScale = exp2_packed.x * exp2_packed.y;\\n\\tfloat scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;\\n\\tfloat mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;\\n\\tbool bRes = mipLevel == 0.0;\\n\\tscale =  bRes && (scale < a) ? a : scale;\\n\\tvec3 r;\\n\\tvec2 offset;\\n\\tint face = getFaceFromDirection(direction);\\n\\tfloat rcpPowScale = 1.0 / powScale;\\n\\tif( face == 0) {\\n\\t\\tr = vec3(direction.x, -direction.z, direction.y);\\n\\t\\toffset = vec2(0.0+mipOffset,0.75 * rcpPowScale);\\n\\t\\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\\n\\t}\\n\\telse if( face == 1) {\\n\\t\\tr = vec3(direction.y, direction.x, direction.z);\\n\\t\\toffset = vec2(scale+mipOffset, 0.75 * rcpPowScale);\\n\\t\\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\\n\\t}\\n\\telse if( face == 2) {\\n\\t\\tr = vec3(direction.z, direction.x, direction.y);\\n\\t\\toffset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);\\n\\t\\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\\n\\t}\\n\\telse if( face == 3) {\\n\\t\\tr = vec3(direction.x, direction.z, direction.y);\\n\\t\\toffset = vec2(0.0+mipOffset,0.5 * rcpPowScale);\\n\\t\\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\\n\\t}\\n\\telse if( face == 4) {\\n\\t\\tr = vec3(direction.y, direction.x, -direction.z);\\n\\t\\toffset = vec2(scale+mipOffset, 0.5 * rcpPowScale);\\n\\t\\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\\n\\t}\\n\\telse {\\n\\t\\tr = vec3(direction.z, -direction.x, direction.y);\\n\\t\\toffset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);\\n\\t\\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\\n\\t}\\n\\tr = normalize(r);\\n\\tfloat texelOffset = 0.5 * cubeUV_rcpTextureSize;\\n\\tvec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;\\n\\tvec2 base = offset + vec2( texelOffset );\\n\\treturn base + s * ( scale - 2.0 * texelOffset );\\n}\\n#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0)\\nvec4 textureCubeUV(vec3 reflectedDirection, float roughness ) {\\n\\tfloat roughnessVal = roughness* cubeUV_maxLods3;\\n\\tfloat r1 = floor(roughnessVal);\\n\\tfloat r2 = r1 + 1.0;\\n\\tfloat t = fract(roughnessVal);\\n\\tvec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness);\\n\\tfloat s = mipInfo.y;\\n\\tfloat level0 = mipInfo.x;\\n\\tfloat level1 = level0 + 1.0;\\n\\tlevel1 = level1 > 5.0 ? 5.0 : level1;\\n\\tlevel0 += min( floor( s + 0.5 ), 5.0 );\\n\\tvec2 uv_10 = getCubeUV(reflectedDirection, r1, level0);\\n\\tvec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));\\n\\tvec2 uv_20 = getCubeUV(reflectedDirection, r2, level0);\\n\\tvec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));\\n\\tvec4 result = mix(color10, color20, t);\\n\\treturn vec4(result.rgb, 1.0);\\n}\\n#endif\\n\";\n\n\tvar defaultnormal_vertex = \"vec3 transformedNormal = normalMatrix * objectNormal;\\n#ifdef FLIP_SIDED\\n\\ttransformedNormal = - transformedNormal;\\n#endif\\n\";\n\n\tvar displacementmap_pars_vertex = \"#ifdef USE_DISPLACEMENTMAP\\n\\tuniform sampler2D displacementMap;\\n\\tuniform float displacementScale;\\n\\tuniform float displacementBias;\\n#endif\\n\";\n\n\tvar displacementmap_vertex = \"#ifdef USE_DISPLACEMENTMAP\\n\\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\\n#endif\\n\";\n\n\tvar emissivemap_fragment = \"#ifdef USE_EMISSIVEMAP\\n\\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\\n\\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\\n\\ttotalEmissiveRadiance *= emissiveColor.rgb;\\n#endif\\n\";\n\n\tvar emissivemap_pars_fragment = \"#ifdef USE_EMISSIVEMAP\\n\\tuniform sampler2D emissiveMap;\\n#endif\\n\";\n\n\tvar encodings_fragment = \"  gl_FragColor = linearToOutputTexel( gl_FragColor );\\n\";\n\n\tvar encodings_pars_fragment = \"\\nvec4 LinearToLinear( in vec4 value ) {\\n\\treturn value;\\n}\\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\\n\\treturn vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );\\n}\\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\\n\\treturn vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );\\n}\\nvec4 sRGBToLinear( in vec4 value ) {\\n\\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );\\n}\\nvec4 LinearTosRGB( in vec4 value ) {\\n\\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.w );\\n}\\nvec4 RGBEToLinear( in vec4 value ) {\\n\\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\\n}\\nvec4 LinearToRGBE( in vec4 value ) {\\n\\tfloat maxComponent = max( max( value.r, value.g ), value.b );\\n\\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\\n\\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\\n}\\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\\n\\treturn vec4( value.xyz * value.w * maxRange, 1.0 );\\n}\\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\\n\\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\\n\\tfloat M      = clamp( maxRGB / maxRange, 0.0, 1.0 );\\n\\tM            = ceil( M * 255.0 ) / 255.0;\\n\\treturn vec4( value.rgb / ( M * maxRange ), M );\\n}\\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\\n\\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\\n}\\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\\n\\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\\n\\tfloat D      = max( maxRange / maxRGB, 1.0 );\\n\\tD            = min( floor( D ) / 255.0, 1.0 );\\n\\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\\n}\\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\\nvec4 LinearToLogLuv( in vec4 value )  {\\n\\tvec3 Xp_Y_XYZp = value.rgb * cLogLuvM;\\n\\tXp_Y_XYZp = max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));\\n\\tvec4 vResult;\\n\\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\\n\\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\\n\\tvResult.w = fract(Le);\\n\\tvResult.z = (Le - (floor(vResult.w*255.0))/255.0)/255.0;\\n\\treturn vResult;\\n}\\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\\nvec4 LogLuvToLinear( in vec4 value ) {\\n\\tfloat Le = value.z * 255.0 + value.w;\\n\\tvec3 Xp_Y_XYZp;\\n\\tXp_Y_XYZp.y = exp2((Le - 127.0) / 2.0);\\n\\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\\n\\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\\n\\tvec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;\\n\\treturn vec4( max(vRGB, 0.0), 1.0 );\\n}\\n\";\n\n\tvar envmap_fragment = \"#ifdef USE_ENVMAP\\n\\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\\n\\t\\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\\n\\t\\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\\n\\t\\t#ifdef ENVMAP_MODE_REFLECTION\\n\\t\\t\\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\\n\\t\\t#else\\n\\t\\t\\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\\n\\t\\t#endif\\n\\t#else\\n\\t\\tvec3 reflectVec = vReflect;\\n\\t#endif\\n\\t#ifdef ENVMAP_TYPE_CUBE\\n\\t\\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\\n\\t#elif defined( ENVMAP_TYPE_EQUIREC )\\n\\t\\tvec2 sampleUV;\\n\\t\\treflectVec = normalize( reflectVec );\\n\\t\\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\\n\\t\\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\\n\\t\\tvec4 envColor = texture2D( envMap, sampleUV );\\n\\t#elif defined( ENVMAP_TYPE_SPHERE )\\n\\t\\treflectVec = normalize( reflectVec );\\n\\t\\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\\n\\t\\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\\n\\t#else\\n\\t\\tvec4 envColor = vec4( 0.0 );\\n\\t#endif\\n\\tenvColor = envMapTexelToLinear( envColor );\\n\\t#ifdef ENVMAP_BLENDING_MULTIPLY\\n\\t\\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\\n\\t#elif defined( ENVMAP_BLENDING_MIX )\\n\\t\\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\\n\\t#elif defined( ENVMAP_BLENDING_ADD )\\n\\t\\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\\n\\t#endif\\n#endif\\n\";\n\n\tvar envmap_pars_fragment = \"#if defined( USE_ENVMAP ) || defined( PHYSICAL )\\n\\tuniform float reflectivity;\\n\\tuniform float envMapIntensity;\\n#endif\\n#ifdef USE_ENVMAP\\n\\t#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )\\n\\t\\tvarying vec3 vWorldPosition;\\n\\t#endif\\n\\t#ifdef ENVMAP_TYPE_CUBE\\n\\t\\tuniform samplerCube envMap;\\n\\t#else\\n\\t\\tuniform sampler2D envMap;\\n\\t#endif\\n\\tuniform float flipEnvMap;\\n\\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )\\n\\t\\tuniform float refractionRatio;\\n\\t#else\\n\\t\\tvarying vec3 vReflect;\\n\\t#endif\\n#endif\\n\";\n\n\tvar envmap_pars_vertex = \"#ifdef USE_ENVMAP\\n\\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\\n\\t\\tvarying vec3 vWorldPosition;\\n\\t#else\\n\\t\\tvarying vec3 vReflect;\\n\\t\\tuniform float refractionRatio;\\n\\t#endif\\n#endif\\n\";\n\n\tvar envmap_vertex = \"#ifdef USE_ENVMAP\\n\\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\\n\\t\\tvWorldPosition = worldPosition.xyz;\\n\\t#else\\n\\t\\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\\n\\t\\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\\n\\t\\t#ifdef ENVMAP_MODE_REFLECTION\\n\\t\\t\\tvReflect = reflect( cameraToVertex, worldNormal );\\n\\t\\t#else\\n\\t\\t\\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\\n\\t\\t#endif\\n\\t#endif\\n#endif\\n\";\n\n\tvar fog_vertex = \"\\n#ifdef USE_FOG\\nfogDepth = -mvPosition.z;\\n#endif\";\n\n\tvar fog_pars_vertex = \"#ifdef USE_FOG\\n  varying float fogDepth;\\n#endif\\n\";\n\n\tvar fog_fragment = \"#ifdef USE_FOG\\n\\t#ifdef FOG_EXP2\\n\\t\\tfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) );\\n\\t#else\\n\\t\\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\\n\\t#endif\\n\\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\\n#endif\\n\";\n\n\tvar fog_pars_fragment = \"#ifdef USE_FOG\\n\\tuniform vec3 fogColor;\\n\\tvarying float fogDepth;\\n\\t#ifdef FOG_EXP2\\n\\t\\tuniform float fogDensity;\\n\\t#else\\n\\t\\tuniform float fogNear;\\n\\t\\tuniform float fogFar;\\n\\t#endif\\n#endif\\n\";\n\n\tvar gradientmap_pars_fragment = \"#ifdef TOON\\n\\tuniform sampler2D gradientMap;\\n\\tvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\\n\\t\\tfloat dotNL = dot( normal, lightDirection );\\n\\t\\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\\n\\t\\t#ifdef USE_GRADIENTMAP\\n\\t\\t\\treturn texture2D( gradientMap, coord ).rgb;\\n\\t\\t#else\\n\\t\\t\\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\\n\\t\\t#endif\\n\\t}\\n#endif\\n\";\n\n\tvar lightmap_fragment = \"#ifdef USE_LIGHTMAP\\n\\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\\n#endif\\n\";\n\n\tvar lightmap_pars_fragment = \"#ifdef USE_LIGHTMAP\\n\\tuniform sampler2D lightMap;\\n\\tuniform float lightMapIntensity;\\n#endif\";\n\n\tvar lights_lambert_vertex = \"vec3 diffuse = vec3( 1.0 );\\nGeometricContext geometry;\\ngeometry.position = mvPosition.xyz;\\ngeometry.normal = normalize( transformedNormal );\\ngeometry.viewDir = normalize( -mvPosition.xyz );\\nGeometricContext backGeometry;\\nbackGeometry.position = geometry.position;\\nbackGeometry.normal = -geometry.normal;\\nbackGeometry.viewDir = geometry.viewDir;\\nvLightFront = vec3( 0.0 );\\n#ifdef DOUBLE_SIDED\\n\\tvLightBack = vec3( 0.0 );\\n#endif\\nIncidentLight directLight;\\nfloat dotNL;\\nvec3 directLightColor_Diffuse;\\n#if NUM_POINT_LIGHTS > 0\\n\\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\\n\\t\\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\\n\\t\\tdotNL = dot( geometry.normal, directLight.direction );\\n\\t\\tdirectLightColor_Diffuse = PI * directLight.color;\\n\\t\\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\\n\\t\\t#ifdef DOUBLE_SIDED\\n\\t\\t\\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\\n\\t\\t#endif\\n\\t}\\n#endif\\n#if NUM_SPOT_LIGHTS > 0\\n\\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\\n\\t\\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\\n\\t\\tdotNL = dot( geometry.normal, directLight.direction );\\n\\t\\tdirectLightColor_Diffuse = PI * directLight.color;\\n\\t\\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\\n\\t\\t#ifdef DOUBLE_SIDED\\n\\t\\t\\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\\n\\t\\t#endif\\n\\t}\\n#endif\\n#if NUM_DIR_LIGHTS > 0\\n\\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\\n\\t\\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\\n\\t\\tdotNL = dot( geometry.normal, directLight.direction );\\n\\t\\tdirectLightColor_Diffuse = PI * directLight.color;\\n\\t\\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\\n\\t\\t#ifdef DOUBLE_SIDED\\n\\t\\t\\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\\n\\t\\t#endif\\n\\t}\\n#endif\\n#if NUM_HEMI_LIGHTS > 0\\n\\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\\n\\t\\tvLightFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\\n\\t\\t#ifdef DOUBLE_SIDED\\n\\t\\t\\tvLightBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\\n\\t\\t#endif\\n\\t}\\n#endif\\n\";\n\n\tvar lights_pars = \"uniform vec3 ambientLightColor;\\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\\n\\tvec3 irradiance = ambientLightColor;\\n\\t#ifndef PHYSICALLY_CORRECT_LIGHTS\\n\\t\\tirradiance *= PI;\\n\\t#endif\\n\\treturn irradiance;\\n}\\n#if NUM_DIR_LIGHTS > 0\\n\\tstruct DirectionalLight {\\n\\t\\tvec3 direction;\\n\\t\\tvec3 color;\\n\\t\\tint shadow;\\n\\t\\tfloat shadowBias;\\n\\t\\tfloat shadowRadius;\\n\\t\\tvec2 shadowMapSize;\\n\\t};\\n\\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\\n\\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\\n\\t\\tdirectLight.color = directionalLight.color;\\n\\t\\tdirectLight.direction = directionalLight.direction;\\n\\t\\tdirectLight.visible = true;\\n\\t}\\n#endif\\n#if NUM_POINT_LIGHTS > 0\\n\\tstruct PointLight {\\n\\t\\tvec3 position;\\n\\t\\tvec3 color;\\n\\t\\tfloat distance;\\n\\t\\tfloat decay;\\n\\t\\tint shadow;\\n\\t\\tfloat shadowBias;\\n\\t\\tfloat shadowRadius;\\n\\t\\tvec2 shadowMapSize;\\n\\t\\tfloat shadowCameraNear;\\n\\t\\tfloat shadowCameraFar;\\n\\t};\\n\\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\\n\\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\\n\\t\\tvec3 lVector = pointLight.position - geometry.position;\\n\\t\\tdirectLight.direction = normalize( lVector );\\n\\t\\tfloat lightDistance = length( lVector );\\n\\t\\tdirectLight.color = pointLight.color;\\n\\t\\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\\n\\t\\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\\n\\t}\\n#endif\\n#if NUM_SPOT_LIGHTS > 0\\n\\tstruct SpotLight {\\n\\t\\tvec3 position;\\n\\t\\tvec3 direction;\\n\\t\\tvec3 color;\\n\\t\\tfloat distance;\\n\\t\\tfloat decay;\\n\\t\\tfloat coneCos;\\n\\t\\tfloat penumbraCos;\\n\\t\\tint shadow;\\n\\t\\tfloat shadowBias;\\n\\t\\tfloat shadowRadius;\\n\\t\\tvec2 shadowMapSize;\\n\\t};\\n\\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\\n\\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight  ) {\\n\\t\\tvec3 lVector = spotLight.position - geometry.position;\\n\\t\\tdirectLight.direction = normalize( lVector );\\n\\t\\tfloat lightDistance = length( lVector );\\n\\t\\tfloat angleCos = dot( directLight.direction, spotLight.direction );\\n\\t\\tif ( angleCos > spotLight.coneCos ) {\\n\\t\\t\\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\\n\\t\\t\\tdirectLight.color = spotLight.color;\\n\\t\\t\\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\\n\\t\\t\\tdirectLight.visible = true;\\n\\t\\t} else {\\n\\t\\t\\tdirectLight.color = vec3( 0.0 );\\n\\t\\t\\tdirectLight.visible = false;\\n\\t\\t}\\n\\t}\\n#endif\\n#if NUM_RECT_AREA_LIGHTS > 0\\n\\tstruct RectAreaLight {\\n\\t\\tvec3 color;\\n\\t\\tvec3 position;\\n\\t\\tvec3 halfWidth;\\n\\t\\tvec3 halfHeight;\\n\\t};\\n\\tuniform sampler2D ltcMat;\\tuniform sampler2D ltcMag;\\n\\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\\n#endif\\n#if NUM_HEMI_LIGHTS > 0\\n\\tstruct HemisphereLight {\\n\\t\\tvec3 direction;\\n\\t\\tvec3 skyColor;\\n\\t\\tvec3 groundColor;\\n\\t};\\n\\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\\n\\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\\n\\t\\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\\n\\t\\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\\n\\t\\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\\n\\t\\t#ifndef PHYSICALLY_CORRECT_LIGHTS\\n\\t\\t\\tirradiance *= PI;\\n\\t\\t#endif\\n\\t\\treturn irradiance;\\n\\t}\\n#endif\\n#if defined( USE_ENVMAP ) && defined( PHYSICAL )\\n\\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\\n\\t\\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\\n\\t\\t#ifdef ENVMAP_TYPE_CUBE\\n\\t\\t\\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\\n\\t\\t\\t#ifdef TEXTURE_LOD_EXT\\n\\t\\t\\t\\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\\n\\t\\t\\t#else\\n\\t\\t\\t\\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\\n\\t\\t\\t#endif\\n\\t\\t\\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\\n\\t\\t#elif defined( ENVMAP_TYPE_CUBE_UV )\\n\\t\\t\\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\\n\\t\\t\\tvec4 envMapColor = textureCubeUV( queryVec, 1.0 );\\n\\t\\t#else\\n\\t\\t\\tvec4 envMapColor = vec4( 0.0 );\\n\\t\\t#endif\\n\\t\\treturn PI * envMapColor.rgb * envMapIntensity;\\n\\t}\\n\\tfloat getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {\\n\\t\\tfloat maxMIPLevelScalar = float( maxMIPLevel );\\n\\t\\tfloat desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\\n\\t\\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\\n\\t}\\n\\tvec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {\\n\\t\\t#ifdef ENVMAP_MODE_REFLECTION\\n\\t\\t\\tvec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );\\n\\t\\t#else\\n\\t\\t\\tvec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );\\n\\t\\t#endif\\n\\t\\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\\n\\t\\tfloat specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, maxMIPLevel );\\n\\t\\t#ifdef ENVMAP_TYPE_CUBE\\n\\t\\t\\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\\n\\t\\t\\t#ifdef TEXTURE_LOD_EXT\\n\\t\\t\\t\\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\\n\\t\\t\\t#else\\n\\t\\t\\t\\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\\n\\t\\t\\t#endif\\n\\t\\t\\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\\n\\t\\t#elif defined( ENVMAP_TYPE_CUBE_UV )\\n\\t\\t\\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\\n\\t\\t\\tvec4 envMapColor = textureCubeUV(queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent));\\n\\t\\t#elif defined( ENVMAP_TYPE_EQUIREC )\\n\\t\\t\\tvec2 sampleUV;\\n\\t\\t\\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\\n\\t\\t\\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\\n\\t\\t\\t#ifdef TEXTURE_LOD_EXT\\n\\t\\t\\t\\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\\n\\t\\t\\t#else\\n\\t\\t\\t\\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\\n\\t\\t\\t#endif\\n\\t\\t\\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\\n\\t\\t#elif defined( ENVMAP_TYPE_SPHERE )\\n\\t\\t\\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\\n\\t\\t\\t#ifdef TEXTURE_LOD_EXT\\n\\t\\t\\t\\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\\n\\t\\t\\t#else\\n\\t\\t\\t\\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\\n\\t\\t\\t#endif\\n\\t\\t\\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\\n\\t\\t#endif\\n\\t\\treturn envMapColor.rgb * envMapIntensity;\\n\\t}\\n#endif\\n\";\n\n\tvar lights_phong_fragment = \"BlinnPhongMaterial material;\\nmaterial.diffuseColor = diffuseColor.rgb;\\nmaterial.specularColor = specular;\\nmaterial.specularShininess = shininess;\\nmaterial.specularStrength = specularStrength;\\n\";\n\n\tvar lights_phong_pars_fragment = \"varying vec3 vViewPosition;\\n#ifndef FLAT_SHADED\\n\\tvarying vec3 vNormal;\\n#endif\\nstruct BlinnPhongMaterial {\\n\\tvec3\\tdiffuseColor;\\n\\tvec3\\tspecularColor;\\n\\tfloat\\tspecularShininess;\\n\\tfloat\\tspecularStrength;\\n};\\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\\n\\t#ifdef TOON\\n\\t\\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\\n\\t#else\\n\\t\\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\\n\\t\\tvec3 irradiance = dotNL * directLight.color;\\n\\t#endif\\n\\t#ifndef PHYSICALLY_CORRECT_LIGHTS\\n\\t\\tirradiance *= PI;\\n\\t#endif\\n\\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\\n\\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\\n}\\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\\n\\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\\n}\\n#define RE_Direct\\t\\t\\t\\tRE_Direct_BlinnPhong\\n#define RE_IndirectDiffuse\\t\\tRE_IndirectDiffuse_BlinnPhong\\n#define Material_LightProbeLOD( material )\\t(0)\\n\";\n\n\tvar lights_physical_fragment = \"PhysicalMaterial material;\\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\\nmaterial.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );\\n#ifdef STANDARD\\n\\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\\n#else\\n\\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\\n\\tmaterial.clearCoat = saturate( clearCoat );\\tmaterial.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );\\n#endif\\n\";\n\n\tvar lights_physical_pars_fragment = \"struct PhysicalMaterial {\\n\\tvec3\\tdiffuseColor;\\n\\tfloat\\tspecularRoughness;\\n\\tvec3\\tspecularColor;\\n\\t#ifndef STANDARD\\n\\t\\tfloat clearCoat;\\n\\t\\tfloat clearCoatRoughness;\\n\\t#endif\\n};\\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\\nfloat clearCoatDHRApprox( const in float roughness, const in float dotNL ) {\\n\\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\\n}\\n#if NUM_RECT_AREA_LIGHTS > 0\\n\\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\\n\\t\\tvec3 normal = geometry.normal;\\n\\t\\tvec3 viewDir = geometry.viewDir;\\n\\t\\tvec3 position = geometry.position;\\n\\t\\tvec3 lightPos = rectAreaLight.position;\\n\\t\\tvec3 halfWidth = rectAreaLight.halfWidth;\\n\\t\\tvec3 halfHeight = rectAreaLight.halfHeight;\\n\\t\\tvec3 lightColor = rectAreaLight.color;\\n\\t\\tfloat roughness = material.specularRoughness;\\n\\t\\tvec3 rectCoords[ 4 ];\\n\\t\\trectCoords[ 0 ] = lightPos - halfWidth - halfHeight;\\t\\trectCoords[ 1 ] = lightPos + halfWidth - halfHeight;\\n\\t\\trectCoords[ 2 ] = lightPos + halfWidth + halfHeight;\\n\\t\\trectCoords[ 3 ] = lightPos - halfWidth + halfHeight;\\n\\t\\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\\n\\t\\tfloat norm = texture2D( ltcMag, uv ).a;\\n\\t\\tvec4 t = texture2D( ltcMat, uv );\\n\\t\\tmat3 mInv = mat3(\\n\\t\\t\\tvec3(   1,   0, t.y ),\\n\\t\\t\\tvec3(   0, t.z,   0 ),\\n\\t\\t\\tvec3( t.w,   0, t.x )\\n\\t\\t);\\n\\t\\treflectedLight.directSpecular += lightColor * material.specularColor * norm * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\\n\\t\\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1 ), rectCoords );\\n\\t}\\n#endif\\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\\n\\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\\n\\tvec3 irradiance = dotNL * directLight.color;\\n\\t#ifndef PHYSICALLY_CORRECT_LIGHTS\\n\\t\\tirradiance *= PI;\\n\\t#endif\\n\\t#ifndef STANDARD\\n\\t\\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\\n\\t#else\\n\\t\\tfloat clearCoatDHR = 0.0;\\n\\t#endif\\n\\treflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness );\\n\\treflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\\n\\t#ifndef STANDARD\\n\\t\\treflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\\n\\t#endif\\n}\\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\\n\\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\\n}\\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\\n\\t#ifndef STANDARD\\n\\t\\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\\n\\t\\tfloat dotNL = dotNV;\\n\\t\\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\\n\\t#else\\n\\t\\tfloat clearCoatDHR = 0.0;\\n\\t#endif\\n\\treflectedLight.indirectSpecular += ( 1.0 - clearCoatDHR ) * radiance * BRDF_Specular_GGX_Environment( geometry, material.specularColor, material.specularRoughness );\\n\\t#ifndef STANDARD\\n\\t\\treflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\\n\\t#endif\\n}\\n#define RE_Direct\\t\\t\\t\\tRE_Direct_Physical\\n#define RE_Direct_RectArea\\t\\tRE_Direct_RectArea_Physical\\n#define RE_IndirectDiffuse\\t\\tRE_IndirectDiffuse_Physical\\n#define RE_IndirectSpecular\\t\\tRE_IndirectSpecular_Physical\\n#define Material_BlinnShininessExponent( material )   GGXRoughnessToBlinnExponent( material.specularRoughness )\\n#define Material_ClearCoat_BlinnShininessExponent( material )   GGXRoughnessToBlinnExponent( material.clearCoatRoughness )\\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\\n\\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\\n}\\n\";\n\n\tvar lights_template = \"\\nGeometricContext geometry;\\ngeometry.position = - vViewPosition;\\ngeometry.normal = normal;\\ngeometry.viewDir = normalize( vViewPosition );\\nIncidentLight directLight;\\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\\n\\tPointLight pointLight;\\n\\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\\n\\t\\tpointLight = pointLights[ i ];\\n\\t\\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\\n\\t\\t#ifdef USE_SHADOWMAP\\n\\t\\tdirectLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\\n\\t\\t#endif\\n\\t\\tRE_Direct( directLight, geometry, material, reflectedLight );\\n\\t}\\n#endif\\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\\n\\tSpotLight spotLight;\\n\\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\\n\\t\\tspotLight = spotLights[ i ];\\n\\t\\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\\n\\t\\t#ifdef USE_SHADOWMAP\\n\\t\\tdirectLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\\n\\t\\t#endif\\n\\t\\tRE_Direct( directLight, geometry, material, reflectedLight );\\n\\t}\\n#endif\\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\\n\\tDirectionalLight directionalLight;\\n\\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\\n\\t\\tdirectionalLight = directionalLights[ i ];\\n\\t\\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\\n\\t\\t#ifdef USE_SHADOWMAP\\n\\t\\tdirectLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\\n\\t\\t#endif\\n\\t\\tRE_Direct( directLight, geometry, material, reflectedLight );\\n\\t}\\n#endif\\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\\n\\tRectAreaLight rectAreaLight;\\n\\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\\n\\t\\trectAreaLight = rectAreaLights[ i ];\\n\\t\\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\\n\\t}\\n#endif\\n#if defined( RE_IndirectDiffuse )\\n\\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\\n\\t#ifdef USE_LIGHTMAP\\n\\t\\tvec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\\n\\t\\t#ifndef PHYSICALLY_CORRECT_LIGHTS\\n\\t\\t\\tlightMapIrradiance *= PI;\\n\\t\\t#endif\\n\\t\\tirradiance += lightMapIrradiance;\\n\\t#endif\\n\\t#if ( NUM_HEMI_LIGHTS > 0 )\\n\\t\\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\\n\\t\\t\\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\\n\\t\\t}\\n\\t#endif\\n\\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\\n\\t\\tirradiance += getLightProbeIndirectIrradiance( geometry, 8 );\\n\\t#endif\\n\\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\\n#endif\\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\\n\\tvec3 radiance = getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), 8 );\\n\\t#ifndef STANDARD\\n\\t\\tvec3 clearCoatRadiance = getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), 8 );\\n\\t#else\\n\\t\\tvec3 clearCoatRadiance = vec3( 0.0 );\\n\\t#endif\\n\\tRE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight );\\n#endif\\n\";\n\n\tvar logdepthbuf_fragment = \"#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\\n\\tgl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\\n#endif\";\n\n\tvar logdepthbuf_pars_fragment = \"#ifdef USE_LOGDEPTHBUF\\n\\tuniform float logDepthBufFC;\\n\\t#ifdef USE_LOGDEPTHBUF_EXT\\n\\t\\tvarying float vFragDepth;\\n\\t#endif\\n#endif\\n\";\n\n\tvar logdepthbuf_pars_vertex = \"#ifdef USE_LOGDEPTHBUF\\n\\t#ifdef USE_LOGDEPTHBUF_EXT\\n\\t\\tvarying float vFragDepth;\\n\\t#endif\\n\\tuniform float logDepthBufFC;\\n#endif\";\n\n\tvar logdepthbuf_vertex = \"#ifdef USE_LOGDEPTHBUF\\n\\tgl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\\n\\t#ifdef USE_LOGDEPTHBUF_EXT\\n\\t\\tvFragDepth = 1.0 + gl_Position.w;\\n\\t#else\\n\\t\\tgl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\\n\\t#endif\\n#endif\\n\";\n\n\tvar map_fragment = \"#ifdef USE_MAP\\n\\tvec4 texelColor = texture2D( map, vUv );\\n\\ttexelColor = mapTexelToLinear( texelColor );\\n\\tdiffuseColor *= texelColor;\\n#endif\\n\";\n\n\tvar map_pars_fragment = \"#ifdef USE_MAP\\n\\tuniform sampler2D map;\\n#endif\\n\";\n\n\tvar map_particle_fragment = \"#ifdef USE_MAP\\n\\tvec4 mapTexel = texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\\n\\tdiffuseColor *= mapTexelToLinear( mapTexel );\\n#endif\\n\";\n\n\tvar map_particle_pars_fragment = \"#ifdef USE_MAP\\n\\tuniform vec4 offsetRepeat;\\n\\tuniform sampler2D map;\\n#endif\\n\";\n\n\tvar metalnessmap_fragment = \"float metalnessFactor = metalness;\\n#ifdef USE_METALNESSMAP\\n\\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\\n\\tmetalnessFactor *= texelMetalness.b;\\n#endif\\n\";\n\n\tvar metalnessmap_pars_fragment = \"#ifdef USE_METALNESSMAP\\n\\tuniform sampler2D metalnessMap;\\n#endif\";\n\n\tvar morphnormal_vertex = \"#ifdef USE_MORPHNORMALS\\n\\tobjectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\\n\\tobjectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\\n\\tobjectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\\n\\tobjectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\\n#endif\\n\";\n\n\tvar morphtarget_pars_vertex = \"#ifdef USE_MORPHTARGETS\\n\\t#ifndef USE_MORPHNORMALS\\n\\tuniform float morphTargetInfluences[ 8 ];\\n\\t#else\\n\\tuniform float morphTargetInfluences[ 4 ];\\n\\t#endif\\n#endif\";\n\n\tvar morphtarget_vertex = \"#ifdef USE_MORPHTARGETS\\n\\ttransformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\\n\\ttransformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\\n\\ttransformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\\n\\ttransformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\\n\\t#ifndef USE_MORPHNORMALS\\n\\ttransformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\\n\\ttransformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\\n\\ttransformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\\n\\ttransformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\\n\\t#endif\\n#endif\\n\";\n\n\tvar normal_fragment = \"#ifdef FLAT_SHADED\\n\\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\\n\\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\\n\\tvec3 normal = normalize( cross( fdx, fdy ) );\\n#else\\n\\tvec3 normal = normalize( vNormal );\\n\\t#ifdef DOUBLE_SIDED\\n\\t\\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\\n\\t#endif\\n#endif\\n#ifdef USE_NORMALMAP\\n\\tnormal = perturbNormal2Arb( -vViewPosition, normal );\\n#elif defined( USE_BUMPMAP )\\n\\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\\n#endif\\n\";\n\n\tvar normalmap_pars_fragment = \"#ifdef USE_NORMALMAP\\n\\tuniform sampler2D normalMap;\\n\\tuniform vec2 normalScale;\\n\\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\\n\\t\\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\\n\\t\\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\\n\\t\\tvec2 st0 = dFdx( vUv.st );\\n\\t\\tvec2 st1 = dFdy( vUv.st );\\n\\t\\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\\n\\t\\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\\n\\t\\tvec3 N = normalize( surf_norm );\\n\\t\\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\\n\\t\\tmapN.xy = normalScale * mapN.xy;\\n\\t\\tmat3 tsn = mat3( S, T, N );\\n\\t\\treturn normalize( tsn * mapN );\\n\\t}\\n#endif\\n\";\n\n\tvar packing = \"vec3 packNormalToRGB( const in vec3 normal ) {\\n\\treturn normalize( normal ) * 0.5 + 0.5;\\n}\\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\\n\\treturn 1.0 - 2.0 * rgb.xyz;\\n}\\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256.,  256. );\\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\\nconst float ShiftRight8 = 1. / 256.;\\nvec4 packDepthToRGBA( const in float v ) {\\n\\tvec4 r = vec4( fract( v * PackFactors ), v );\\n\\tr.yzw -= r.xyz * ShiftRight8;\\treturn r * PackUpscale;\\n}\\nfloat unpackRGBAToDepth( const in vec4 v ) {\\n\\treturn dot( v, UnpackFactors );\\n}\\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\\n\\treturn ( viewZ + near ) / ( near - far );\\n}\\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\\n\\treturn linearClipZ * ( near - far ) - near;\\n}\\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\\n\\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\\n}\\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\\n\\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\\n}\\n\";\n\n\tvar premultiplied_alpha_fragment = \"#ifdef PREMULTIPLIED_ALPHA\\n\\tgl_FragColor.rgb *= gl_FragColor.a;\\n#endif\\n\";\n\n\tvar project_vertex = \"vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\\ngl_Position = projectionMatrix * mvPosition;\\n\";\n\n\tvar dithering_fragment = \"#if defined( DITHERING )\\n  gl_FragColor.rgb = dithering( gl_FragColor.rgb );\\n#endif\\n\";\n\n\tvar dithering_pars_fragment = \"#if defined( DITHERING )\\n\\tvec3 dithering( vec3 color ) {\\n\\t\\tfloat grid_position = rand( gl_FragCoord.xy );\\n\\t\\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\\n\\t\\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\\n\\t\\treturn color + dither_shift_RGB;\\n\\t}\\n#endif\\n\";\n\n\tvar roughnessmap_fragment = \"float roughnessFactor = roughness;\\n#ifdef USE_ROUGHNESSMAP\\n\\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\\n\\troughnessFactor *= texelRoughness.g;\\n#endif\\n\";\n\n\tvar roughnessmap_pars_fragment = \"#ifdef USE_ROUGHNESSMAP\\n\\tuniform sampler2D roughnessMap;\\n#endif\";\n\n\tvar shadowmap_pars_fragment = \"#ifdef USE_SHADOWMAP\\n\\t#if NUM_DIR_LIGHTS > 0\\n\\t\\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];\\n\\t\\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\\n\\t#endif\\n\\t#if NUM_SPOT_LIGHTS > 0\\n\\t\\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];\\n\\t\\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\\n\\t#endif\\n\\t#if NUM_POINT_LIGHTS > 0\\n\\t\\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];\\n\\t\\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\\n\\t#endif\\n\\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\\n\\t\\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\\n\\t}\\n\\tfloat texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {\\n\\t\\tconst vec2 offset = vec2( 0.0, 1.0 );\\n\\t\\tvec2 texelSize = vec2( 1.0 ) / size;\\n\\t\\tvec2 centroidUV = floor( uv * size + 0.5 ) / size;\\n\\t\\tfloat lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );\\n\\t\\tfloat lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );\\n\\t\\tfloat rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );\\n\\t\\tfloat rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );\\n\\t\\tvec2 f = fract( uv * size + 0.5 );\\n\\t\\tfloat a = mix( lb, lt, f.y );\\n\\t\\tfloat b = mix( rb, rt, f.y );\\n\\t\\tfloat c = mix( a, b, f.x );\\n\\t\\treturn c;\\n\\t}\\n\\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\\n\\t\\tfloat shadow = 1.0;\\n\\t\\tshadowCoord.xyz /= shadowCoord.w;\\n\\t\\tshadowCoord.z += shadowBias;\\n\\t\\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\\n\\t\\tbool inFrustum = all( inFrustumVec );\\n\\t\\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\\n\\t\\tbool frustumTest = all( frustumTestVec );\\n\\t\\tif ( frustumTest ) {\\n\\t\\t#if defined( SHADOWMAP_TYPE_PCF )\\n\\t\\t\\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\\n\\t\\t\\tfloat dx0 = - texelSize.x * shadowRadius;\\n\\t\\t\\tfloat dy0 = - texelSize.y * shadowRadius;\\n\\t\\t\\tfloat dx1 = + texelSize.x * shadowRadius;\\n\\t\\t\\tfloat dy1 = + texelSize.y * shadowRadius;\\n\\t\\t\\tshadow = (\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\\n\\t\\t\\t) * ( 1.0 / 9.0 );\\n\\t\\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\\n\\t\\t\\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\\n\\t\\t\\tfloat dx0 = - texelSize.x * shadowRadius;\\n\\t\\t\\tfloat dy0 = - texelSize.y * shadowRadius;\\n\\t\\t\\tfloat dx1 = + texelSize.x * shadowRadius;\\n\\t\\t\\tfloat dy1 = + texelSize.y * shadowRadius;\\n\\t\\t\\tshadow = (\\n\\t\\t\\t\\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\\n\\t\\t\\t\\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\\n\\t\\t\\t) * ( 1.0 / 9.0 );\\n\\t\\t#else\\n\\t\\t\\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\\n\\t\\t#endif\\n\\t\\t}\\n\\t\\treturn shadow;\\n\\t}\\n\\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\\n\\t\\tvec3 absV = abs( v );\\n\\t\\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\\n\\t\\tabsV *= scaleToCube;\\n\\t\\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\\n\\t\\tvec2 planar = v.xy;\\n\\t\\tfloat almostATexel = 1.5 * texelSizeY;\\n\\t\\tfloat almostOne = 1.0 - almostATexel;\\n\\t\\tif ( absV.z >= almostOne ) {\\n\\t\\t\\tif ( v.z > 0.0 )\\n\\t\\t\\t\\tplanar.x = 4.0 - v.x;\\n\\t\\t} else if ( absV.x >= almostOne ) {\\n\\t\\t\\tfloat signX = sign( v.x );\\n\\t\\t\\tplanar.x = v.z * signX + 2.0 * signX;\\n\\t\\t} else if ( absV.y >= almostOne ) {\\n\\t\\t\\tfloat signY = sign( v.y );\\n\\t\\t\\tplanar.x = v.x + 2.0 * signY + 2.0;\\n\\t\\t\\tplanar.y = v.z * signY - 2.0;\\n\\t\\t}\\n\\t\\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\\n\\t}\\n\\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\\n\\t\\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\\n\\t\\tvec3 lightToPosition = shadowCoord.xyz;\\n\\t\\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\\t\\tdp += shadowBias;\\n\\t\\tvec3 bd3D = normalize( lightToPosition );\\n\\t\\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )\\n\\t\\t\\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\\n\\t\\t\\treturn (\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\\n\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\\n\\t\\t\\t) * ( 1.0 / 9.0 );\\n\\t\\t#else\\n\\t\\t\\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\\n\\t\\t#endif\\n\\t}\\n#endif\\n\";\n\n\tvar shadowmap_pars_vertex = \"#ifdef USE_SHADOWMAP\\n\\t#if NUM_DIR_LIGHTS > 0\\n\\t\\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];\\n\\t\\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\\n\\t#endif\\n\\t#if NUM_SPOT_LIGHTS > 0\\n\\t\\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];\\n\\t\\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\\n\\t#endif\\n\\t#if NUM_POINT_LIGHTS > 0\\n\\t\\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];\\n\\t\\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\\n\\t#endif\\n#endif\\n\";\n\n\tvar shadowmap_vertex = \"#ifdef USE_SHADOWMAP\\n\\t#if NUM_DIR_LIGHTS > 0\\n\\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\\n\\t\\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\\n\\t}\\n\\t#endif\\n\\t#if NUM_SPOT_LIGHTS > 0\\n\\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\\n\\t\\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\\n\\t}\\n\\t#endif\\n\\t#if NUM_POINT_LIGHTS > 0\\n\\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\\n\\t\\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\\n\\t}\\n\\t#endif\\n#endif\\n\";\n\n\tvar shadowmask_pars_fragment = \"float getShadowMask() {\\n\\tfloat shadow = 1.0;\\n\\t#ifdef USE_SHADOWMAP\\n\\t#if NUM_DIR_LIGHTS > 0\\n\\tDirectionalLight directionalLight;\\n\\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\\n\\t\\tdirectionalLight = directionalLights[ i ];\\n\\t\\tshadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\\n\\t}\\n\\t#endif\\n\\t#if NUM_SPOT_LIGHTS > 0\\n\\tSpotLight spotLight;\\n\\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\\n\\t\\tspotLight = spotLights[ i ];\\n\\t\\tshadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\\n\\t}\\n\\t#endif\\n\\t#if NUM_POINT_LIGHTS > 0\\n\\tPointLight pointLight;\\n\\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\\n\\t\\tpointLight = pointLights[ i ];\\n\\t\\tshadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\\n\\t}\\n\\t#endif\\n\\t#endif\\n\\treturn shadow;\\n}\\n\";\n\n\tvar skinbase_vertex = \"#ifdef USE_SKINNING\\n\\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\\n\\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\\n\\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\\n\\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\\n#endif\";\n\n\tvar skinning_pars_vertex = \"#ifdef USE_SKINNING\\n\\tuniform mat4 bindMatrix;\\n\\tuniform mat4 bindMatrixInverse;\\n\\t#ifdef BONE_TEXTURE\\n\\t\\tuniform sampler2D boneTexture;\\n\\t\\tuniform int boneTextureSize;\\n\\t\\tmat4 getBoneMatrix( const in float i ) {\\n\\t\\t\\tfloat j = i * 4.0;\\n\\t\\t\\tfloat x = mod( j, float( boneTextureSize ) );\\n\\t\\t\\tfloat y = floor( j / float( boneTextureSize ) );\\n\\t\\t\\tfloat dx = 1.0 / float( boneTextureSize );\\n\\t\\t\\tfloat dy = 1.0 / float( boneTextureSize );\\n\\t\\t\\ty = dy * ( y + 0.5 );\\n\\t\\t\\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\\n\\t\\t\\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\\n\\t\\t\\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\\n\\t\\t\\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\\n\\t\\t\\tmat4 bone = mat4( v1, v2, v3, v4 );\\n\\t\\t\\treturn bone;\\n\\t\\t}\\n\\t#else\\n\\t\\tuniform mat4 boneMatrices[ MAX_BONES ];\\n\\t\\tmat4 getBoneMatrix( const in float i ) {\\n\\t\\t\\tmat4 bone = boneMatrices[ int(i) ];\\n\\t\\t\\treturn bone;\\n\\t\\t}\\n\\t#endif\\n#endif\\n\";\n\n\tvar skinning_vertex = \"#ifdef USE_SKINNING\\n\\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\\n\\tvec4 skinned = vec4( 0.0 );\\n\\tskinned += boneMatX * skinVertex * skinWeight.x;\\n\\tskinned += boneMatY * skinVertex * skinWeight.y;\\n\\tskinned += boneMatZ * skinVertex * skinWeight.z;\\n\\tskinned += boneMatW * skinVertex * skinWeight.w;\\n\\ttransformed = ( bindMatrixInverse * skinned ).xyz;\\n#endif\\n\";\n\n\tvar skinnormal_vertex = \"#ifdef USE_SKINNING\\n\\tmat4 skinMatrix = mat4( 0.0 );\\n\\tskinMatrix += skinWeight.x * boneMatX;\\n\\tskinMatrix += skinWeight.y * boneMatY;\\n\\tskinMatrix += skinWeight.z * boneMatZ;\\n\\tskinMatrix += skinWeight.w * boneMatW;\\n\\tskinMatrix  = bindMatrixInverse * skinMatrix * bindMatrix;\\n\\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\\n#endif\\n\";\n\n\tvar specularmap_fragment = \"float specularStrength;\\n#ifdef USE_SPECULARMAP\\n\\tvec4 texelSpecular = texture2D( specularMap, vUv );\\n\\tspecularStrength = texelSpecular.r;\\n#else\\n\\tspecularStrength = 1.0;\\n#endif\";\n\n\tvar specularmap_pars_fragment = \"#ifdef USE_SPECULARMAP\\n\\tuniform sampler2D specularMap;\\n#endif\";\n\n\tvar tonemapping_fragment = \"#if defined( TONE_MAPPING )\\n  gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\\n#endif\\n\";\n\n\tvar tonemapping_pars_fragment = \"#define saturate(a) clamp( a, 0.0, 1.0 )\\nuniform float toneMappingExposure;\\nuniform float toneMappingWhitePoint;\\nvec3 LinearToneMapping( vec3 color ) {\\n\\treturn toneMappingExposure * color;\\n}\\nvec3 ReinhardToneMapping( vec3 color ) {\\n\\tcolor *= toneMappingExposure;\\n\\treturn saturate( color / ( vec3( 1.0 ) + color ) );\\n}\\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\\nvec3 Uncharted2ToneMapping( vec3 color ) {\\n\\tcolor *= toneMappingExposure;\\n\\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\\n}\\nvec3 OptimizedCineonToneMapping( vec3 color ) {\\n\\tcolor *= toneMappingExposure;\\n\\tcolor = max( vec3( 0.0 ), color - 0.004 );\\n\\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\\n}\\n\";\n\n\tvar uv_pars_fragment = \"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\\n\\tvarying vec2 vUv;\\n#endif\";\n\n\tvar uv_pars_vertex = \"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\\n\\tvarying vec2 vUv;\\n\\tuniform vec4 offsetRepeat;\\n#endif\\n\";\n\n\tvar uv_vertex = \"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\\n\\tvUv = uv * offsetRepeat.zw + offsetRepeat.xy;\\n#endif\";\n\n\tvar uv2_pars_fragment = \"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\\n\\tvarying vec2 vUv2;\\n#endif\";\n\n\tvar uv2_pars_vertex = \"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\\n\\tattribute vec2 uv2;\\n\\tvarying vec2 vUv2;\\n#endif\";\n\n\tvar uv2_vertex = \"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\\n\\tvUv2 = uv2;\\n#endif\";\n\n\tvar worldpos_vertex = \"#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( PHYSICAL ) || defined( LAMBERT ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\\n\\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\\n#endif\\n\";\n\n\tvar cube_frag = \"uniform samplerCube tCube;\\nuniform float tFlip;\\nuniform float opacity;\\nvarying vec3 vWorldPosition;\\nvoid main() {\\n\\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\\n\\tgl_FragColor.a *= opacity;\\n}\\n\";\n\n\tvar cube_vert = \"varying vec3 vWorldPosition;\\n#include <common>\\nvoid main() {\\n\\tvWorldPosition = transformDirection( position, modelMatrix );\\n\\t#include <begin_vertex>\\n\\t#include <project_vertex>\\n}\\n\";\n\n\tvar depth_frag = \"#if DEPTH_PACKING == 3200\\n\\tuniform float opacity;\\n#endif\\n#include <common>\\n#include <packing>\\n#include <uv_pars_fragment>\\n#include <map_pars_fragment>\\n#include <alphamap_pars_fragment>\\n#include <logdepthbuf_pars_fragment>\\n#include <clipping_planes_pars_fragment>\\nvoid main() {\\n\\t#include <clipping_planes_fragment>\\n\\tvec4 diffuseColor = vec4( 1.0 );\\n\\t#if DEPTH_PACKING == 3200\\n\\t\\tdiffuseColor.a = opacity;\\n\\t#endif\\n\\t#include <map_fragment>\\n\\t#include <alphamap_fragment>\\n\\t#include <alphatest_fragment>\\n\\t#include <logdepthbuf_fragment>\\n\\t#if DEPTH_PACKING == 3200\\n\\t\\tgl_FragColor = vec4( vec3( gl_FragCoord.z ), opacity );\\n\\t#elif DEPTH_PACKING == 3201\\n\\t\\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\\n\\t#endif\\n}\\n\";\n\n\tvar depth_vert = \"#include <common>\\n#include <uv_pars_vertex>\\n#include <displacementmap_pars_vertex>\\n#include <morphtarget_pars_vertex>\\n#include <skinning_pars_vertex>\\n#include <logdepthbuf_pars_vertex>\\n#include <clipping_planes_pars_vertex>\\nvoid main() {\\n\\t#include <uv_vertex>\\n\\t#include <skinbase_vertex>\\n\\t#ifdef USE_DISPLACEMENTMAP\\n\\t\\t#include <beginnormal_vertex>\\n\\t\\t#include <morphnormal_vertex>\\n\\t\\t#include <skinnormal_vertex>\\n\\t#endif\\n\\t#include <begin_vertex>\\n\\t#include <morphtarget_vertex>\\n\\t#include <skinning_vertex>\\n\\t#include <displacementmap_vertex>\\n\\t#include <project_vertex>\\n\\t#include <logdepthbuf_vertex>\\n\\t#include <clipping_planes_vertex>\\n}\\n\";\n\n\tvar distanceRGBA_frag = \"#define DISTANCE\\nuniform vec3 referencePosition;\\nuniform float nearDistance;\\nuniform float farDistance;\\nvarying vec3 vWorldPosition;\\n#include <common>\\n#include <packing>\\n#include <uv_pars_fragment>\\n#include <map_pars_fragment>\\n#include <alphamap_pars_fragment>\\n#include <clipping_planes_pars_fragment>\\nvoid main () {\\n\\t#include <clipping_planes_fragment>\\n\\tvec4 diffuseColor = vec4( 1.0 );\\n\\t#include <map_fragment>\\n\\t#include <alphamap_fragment>\\n\\t#include <alphatest_fragment>\\n\\tfloat dist = length( vWorldPosition - referencePosition );\\n\\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\\n\\tdist = saturate( dist );\\n\\tgl_FragColor = packDepthToRGBA( dist );\\n}\\n\";\n\n\tvar distanceRGBA_vert = \"#define DISTANCE\\nvarying vec3 vWorldPosition;\\n#include <common>\\n#include <uv_pars_vertex>\\n#include <displacementmap_pars_vertex>\\n#include <morphtarget_pars_vertex>\\n#include <skinning_pars_vertex>\\n#include <clipping_planes_pars_vertex>\\nvoid main() {\\n\\t#include <uv_vertex>\\n\\t#include <skinbase_vertex>\\n\\t#ifdef USE_DISPLACEMENTMAP\\n\\t\\t#include <beginnormal_vertex>\\n\\t\\t#include <morphnormal_vertex>\\n\\t\\t#include <skinnormal_vertex>\\n\\t#endif\\n\\t#include <begin_vertex>\\n\\t#include <morphtarget_vertex>\\n\\t#include <skinning_vertex>\\n\\t#include <displacementmap_vertex>\\n\\t#include <project_vertex>\\n\\t#include <worldpos_vertex>\\n\\t#include <clipping_planes_vertex>\\n\\tvWorldPosition = worldPosition.xyz;\\n}\\n\";\n\n\tvar equirect_frag = \"uniform sampler2D tEquirect;\\nvarying vec3 vWorldPosition;\\n#include <common>\\nvoid main() {\\n\\tvec3 direction = normalize( vWorldPosition );\\n\\tvec2 sampleUV;\\n\\tsampleUV.y = asin( clamp( direction.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\\n\\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\\n\\tgl_FragColor = texture2D( tEquirect, sampleUV );\\n}\\n\";\n\n\tvar equirect_vert = \"varying vec3 vWorldPosition;\\n#include <common>\\nvoid main() {\\n\\tvWorldPosition = transformDirection( position, modelMatrix );\\n\\t#include <begin_vertex>\\n\\t#include <project_vertex>\\n}\\n\";\n\n\tvar linedashed_frag = \"uniform vec3 diffuse;\\nuniform float opacity;\\nuniform float dashSize;\\nuniform float totalSize;\\nvarying float vLineDistance;\\n#include <common>\\n#include <color_pars_fragment>\\n#include <fog_pars_fragment>\\n#include <logdepthbuf_pars_fragment>\\n#include <clipping_planes_pars_fragment>\\nvoid main() {\\n\\t#include <clipping_planes_fragment>\\n\\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\\n\\t\\tdiscard;\\n\\t}\\n\\tvec3 outgoingLight = vec3( 0.0 );\\n\\tvec4 diffuseColor = vec4( diffuse, opacity );\\n\\t#include <logdepthbuf_fragment>\\n\\t#include <color_fragment>\\n\\toutgoingLight = diffuseColor.rgb;\\n\\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\\n\\t#include <premultiplied_alpha_fragment>\\n\\t#include <tonemapping_fragment>\\n\\t#include <encodings_fragment>\\n\\t#include <fog_fragment>\\n}\\n\";\n\n\tvar linedashed_vert = \"uniform float scale;\\nattribute float lineDistance;\\nvarying float vLineDistance;\\n#include <common>\\n#include <color_pars_vertex>\\n#include <fog_pars_vertex>\\n#include <logdepthbuf_pars_vertex>\\n#include <clipping_planes_pars_vertex>\\nvoid main() {\\n\\t#include <color_vertex>\\n\\tvLineDistance = scale * lineDistance;\\n\\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\\n\\tgl_Position = projectionMatrix * mvPosition;\\n\\t#include <logdepthbuf_vertex>\\n\\t#include <clipping_planes_vertex>\\n\\t#include <fog_vertex>\\n}\\n\";\n\n\tvar meshbasic_frag = \"uniform vec3 diffuse;\\nuniform float opacity;\\n#ifndef FLAT_SHADED\\n\\tvarying vec3 vNormal;\\n#endif\\n#include <common>\\n#include <color_pars_fragment>\\n#include <uv_pars_fragment>\\n#include <uv2_pars_fragment>\\n#include <map_pars_fragment>\\n#include <alphamap_pars_fragment>\\n#include <aomap_pars_fragment>\\n#include <lightmap_pars_fragment>\\n#include <envmap_pars_fragment>\\n#include <fog_pars_fragment>\\n#include <specularmap_pars_fragment>\\n#include <logdepthbuf_pars_fragment>\\n#include <clipping_planes_pars_fragment>\\nvoid main() {\\n\\t#include <clipping_planes_fragment>\\n\\tvec4 diffuseColor = vec4( diffuse, opacity );\\n\\t#include <logdepthbuf_fragment>\\n\\t#include <map_fragment>\\n\\t#include <color_fragment>\\n\\t#include <alphamap_fragment>\\n\\t#include <alphatest_fragment>\\n\\t#include <specularmap_fragment>\\n\\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\\n\\t#ifdef USE_LIGHTMAP\\n\\t\\treflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\\n\\t#else\\n\\t\\treflectedLight.indirectDiffuse += vec3( 1.0 );\\n\\t#endif\\n\\t#include <aomap_fragment>\\n\\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\\n\\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\\n\\t#include <envmap_fragment>\\n\\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\\n\\t#include <premultiplied_alpha_fragment>\\n\\t#include <tonemapping_fragment>\\n\\t#include <encodings_fragment>\\n\\t#include <fog_fragment>\\n}\\n\";\n\n\tvar meshbasic_vert = \"#include <common>\\n#include <uv_pars_vertex>\\n#include <uv2_pars_vertex>\\n#include <envmap_pars_vertex>\\n#include <color_pars_vertex>\\n#include <fog_pars_vertex>\\n#include <morphtarget_pars_vertex>\\n#include <skinning_pars_vertex>\\n#include <logdepthbuf_pars_vertex>\\n#include <clipping_planes_pars_vertex>\\nvoid main() {\\n\\t#include <uv_vertex>\\n\\t#include <uv2_vertex>\\n\\t#include <color_vertex>\\n\\t#include <skinbase_vertex>\\n\\t#ifdef USE_ENVMAP\\n\\t#include <beginnormal_vertex>\\n\\t#include <morphnormal_vertex>\\n\\t#include <skinnormal_vertex>\\n\\t#include <defaultnormal_vertex>\\n\\t#endif\\n\\t#include <begin_vertex>\\n\\t#include <morphtarget_vertex>\\n\\t#include <skinning_vertex>\\n\\t#include <project_vertex>\\n\\t#include <logdepthbuf_vertex>\\n\\t#include <worldpos_vertex>\\n\\t#include <clipping_planes_vertex>\\n\\t#include <envmap_vertex>\\n\\t#include <fog_vertex>\\n}\\n\";\n\n\tvar meshlambert_frag = \"uniform vec3 diffuse;\\nuniform vec3 emissive;\\nuniform float opacity;\\nvarying vec3 vLightFront;\\n#ifdef DOUBLE_SIDED\\n\\tvarying vec3 vLightBack;\\n#endif\\n#include <common>\\n#include <packing>\\n#include <dithering_pars_fragment>\\n#include <color_pars_fragment>\\n#include <uv_pars_fragment>\\n#include <uv2_pars_fragment>\\n#include <map_pars_fragment>\\n#include <alphamap_pars_fragment>\\n#include <aomap_pars_fragment>\\n#include <lightmap_pars_fragment>\\n#include <emissivemap_pars_fragment>\\n#include <envmap_pars_fragment>\\n#include <bsdfs>\\n#include <lights_pars>\\n#include <fog_pars_fragment>\\n#include <shadowmap_pars_fragment>\\n#include <shadowmask_pars_fragment>\\n#include <specularmap_pars_fragment>\\n#include <logdepthbuf_pars_fragment>\\n#include <clipping_planes_pars_fragment>\\nvoid main() {\\n\\t#include <clipping_planes_fragment>\\n\\tvec4 diffuseColor = vec4( diffuse, opacity );\\n\\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\\n\\tvec3 totalEmissiveRadiance = emissive;\\n\\t#include <logdepthbuf_fragment>\\n\\t#include <map_fragment>\\n\\t#include <color_fragment>\\n\\t#include <alphamap_fragment>\\n\\t#include <alphatest_fragment>\\n\\t#include <specularmap_fragment>\\n\\t#include <emissivemap_fragment>\\n\\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\\n\\t#include <lightmap_fragment>\\n\\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\\n\\t#ifdef DOUBLE_SIDED\\n\\t\\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\\n\\t#else\\n\\t\\treflectedLight.directDiffuse = vLightFront;\\n\\t#endif\\n\\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\\n\\t#include <aomap_fragment>\\n\\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\\n\\t#include <envmap_fragment>\\n\\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\\n\\t#include <tonemapping_fragment>\\n\\t#include <encodings_fragment>\\n\\t#include <fog_fragment>\\n\\t#include <premultiplied_alpha_fragment>\\n\\t#include <dithering_fragment>\\n}\\n\";\n\n\tvar meshlambert_vert = \"#define LAMBERT\\nvarying vec3 vLightFront;\\n#ifdef DOUBLE_SIDED\\n\\tvarying vec3 vLightBack;\\n#endif\\n#include <common>\\n#include <uv_pars_vertex>\\n#include <uv2_pars_vertex>\\n#include <envmap_pars_vertex>\\n#include <bsdfs>\\n#include <lights_pars>\\n#include <color_pars_vertex>\\n#include <fog_pars_vertex>\\n#include <morphtarget_pars_vertex>\\n#include <skinning_pars_vertex>\\n#include <shadowmap_pars_vertex>\\n#include <logdepthbuf_pars_vertex>\\n#include <clipping_planes_pars_vertex>\\nvoid main() {\\n\\t#include <uv_vertex>\\n\\t#include <uv2_vertex>\\n\\t#include <color_vertex>\\n\\t#include <beginnormal_vertex>\\n\\t#include <morphnormal_vertex>\\n\\t#include <skinbase_vertex>\\n\\t#include <skinnormal_vertex>\\n\\t#include <defaultnormal_vertex>\\n\\t#include <begin_vertex>\\n\\t#include <morphtarget_vertex>\\n\\t#include <skinning_vertex>\\n\\t#include <project_vertex>\\n\\t#include <logdepthbuf_vertex>\\n\\t#include <clipping_planes_vertex>\\n\\t#include <worldpos_vertex>\\n\\t#include <envmap_vertex>\\n\\t#include <lights_lambert_vertex>\\n\\t#include <shadowmap_vertex>\\n\\t#include <fog_vertex>\\n}\\n\";\n\n\tvar meshphong_frag = \"#define PHONG\\nuniform vec3 diffuse;\\nuniform vec3 emissive;\\nuniform vec3 specular;\\nuniform float shininess;\\nuniform float opacity;\\n#include <common>\\n#include <packing>\\n#include <dithering_pars_fragment>\\n#include <color_pars_fragment>\\n#include <uv_pars_fragment>\\n#include <uv2_pars_fragment>\\n#include <map_pars_fragment>\\n#include <alphamap_pars_fragment>\\n#include <aomap_pars_fragment>\\n#include <lightmap_pars_fragment>\\n#include <emissivemap_pars_fragment>\\n#include <envmap_pars_fragment>\\n#include <gradientmap_pars_fragment>\\n#include <fog_pars_fragment>\\n#include <bsdfs>\\n#include <lights_pars>\\n#include <lights_phong_pars_fragment>\\n#include <shadowmap_pars_fragment>\\n#include <bumpmap_pars_fragment>\\n#include <normalmap_pars_fragment>\\n#include <specularmap_pars_fragment>\\n#include <logdepthbuf_pars_fragment>\\n#include <clipping_planes_pars_fragment>\\nvoid main() {\\n\\t#include <clipping_planes_fragment>\\n\\tvec4 diffuseColor = vec4( diffuse, opacity );\\n\\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\\n\\tvec3 totalEmissiveRadiance = emissive;\\n\\t#include <logdepthbuf_fragment>\\n\\t#include <map_fragment>\\n\\t#include <color_fragment>\\n\\t#include <alphamap_fragment>\\n\\t#include <alphatest_fragment>\\n\\t#include <specularmap_fragment>\\n\\t#include <normal_fragment>\\n\\t#include <emissivemap_fragment>\\n\\t#include <lights_phong_fragment>\\n\\t#include <lights_template>\\n\\t#include <aomap_fragment>\\n\\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\\n\\t#include <envmap_fragment>\\n\\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\\n\\t#include <tonemapping_fragment>\\n\\t#include <encodings_fragment>\\n\\t#include <fog_fragment>\\n\\t#include <premultiplied_alpha_fragment>\\n\\t#include <dithering_fragment>\\n}\\n\";\n\n\tvar meshphong_vert = \"#define PHONG\\nvarying vec3 vViewPosition;\\n#ifndef FLAT_SHADED\\n\\tvarying vec3 vNormal;\\n#endif\\n#include <common>\\n#include <uv_pars_vertex>\\n#include <uv2_pars_vertex>\\n#include <displacementmap_pars_vertex>\\n#include <envmap_pars_vertex>\\n#include <color_pars_vertex>\\n#include <fog_pars_vertex>\\n#include <morphtarget_pars_vertex>\\n#include <skinning_pars_vertex>\\n#include <shadowmap_pars_vertex>\\n#include <logdepthbuf_pars_vertex>\\n#include <clipping_planes_pars_vertex>\\nvoid main() {\\n\\t#include <uv_vertex>\\n\\t#include <uv2_vertex>\\n\\t#include <color_vertex>\\n\\t#include <beginnormal_vertex>\\n\\t#include <morphnormal_vertex>\\n\\t#include <skinbase_vertex>\\n\\t#include <skinnormal_vertex>\\n\\t#include <defaultnormal_vertex>\\n#ifndef FLAT_SHADED\\n\\tvNormal = normalize( transformedNormal );\\n#endif\\n\\t#include <begin_vertex>\\n\\t#include <morphtarget_vertex>\\n\\t#include <skinning_vertex>\\n\\t#include <displacementmap_vertex>\\n\\t#include <project_vertex>\\n\\t#include <logdepthbuf_vertex>\\n\\t#include <clipping_planes_vertex>\\n\\tvViewPosition = - mvPosition.xyz;\\n\\t#include <worldpos_vertex>\\n\\t#include <envmap_vertex>\\n\\t#include <shadowmap_vertex>\\n\\t#include <fog_vertex>\\n}\\n\";\n\n\tvar meshphysical_frag = \"#define PHYSICAL\\nuniform vec3 diffuse;\\nuniform vec3 emissive;\\nuniform float roughness;\\nuniform float metalness;\\nuniform float opacity;\\n#ifndef STANDARD\\n\\tuniform float clearCoat;\\n\\tuniform float clearCoatRoughness;\\n#endif\\nvarying vec3 vViewPosition;\\n#ifndef FLAT_SHADED\\n\\tvarying vec3 vNormal;\\n#endif\\n#include <common>\\n#include <packing>\\n#include <dithering_pars_fragment>\\n#include <color_pars_fragment>\\n#include <uv_pars_fragment>\\n#include <uv2_pars_fragment>\\n#include <map_pars_fragment>\\n#include <alphamap_pars_fragment>\\n#include <aomap_pars_fragment>\\n#include <lightmap_pars_fragment>\\n#include <emissivemap_pars_fragment>\\n#include <envmap_pars_fragment>\\n#include <fog_pars_fragment>\\n#include <bsdfs>\\n#include <cube_uv_reflection_fragment>\\n#include <lights_pars>\\n#include <lights_physical_pars_fragment>\\n#include <shadowmap_pars_fragment>\\n#include <bumpmap_pars_fragment>\\n#include <normalmap_pars_fragment>\\n#include <roughnessmap_pars_fragment>\\n#include <metalnessmap_pars_fragment>\\n#include <logdepthbuf_pars_fragment>\\n#include <clipping_planes_pars_fragment>\\nvoid main() {\\n\\t#include <clipping_planes_fragment>\\n\\tvec4 diffuseColor = vec4( diffuse, opacity );\\n\\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\\n\\tvec3 totalEmissiveRadiance = emissive;\\n\\t#include <logdepthbuf_fragment>\\n\\t#include <map_fragment>\\n\\t#include <color_fragment>\\n\\t#include <alphamap_fragment>\\n\\t#include <alphatest_fragment>\\n\\t#include <roughnessmap_fragment>\\n\\t#include <metalnessmap_fragment>\\n\\t#include <normal_fragment>\\n\\t#include <emissivemap_fragment>\\n\\t#include <lights_physical_fragment>\\n\\t#include <lights_template>\\n\\t#include <aomap_fragment>\\n\\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\\n\\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\\n\\t#include <tonemapping_fragment>\\n\\t#include <encodings_fragment>\\n\\t#include <fog_fragment>\\n\\t#include <premultiplied_alpha_fragment>\\n\\t#include <dithering_fragment>\\n}\\n\";\n\n\tvar meshphysical_vert = \"#define PHYSICAL\\nvarying vec3 vViewPosition;\\n#ifndef FLAT_SHADED\\n\\tvarying vec3 vNormal;\\n#endif\\n#include <common>\\n#include <uv_pars_vertex>\\n#include <uv2_pars_vertex>\\n#include <displacementmap_pars_vertex>\\n#include <color_pars_vertex>\\n#include <fog_pars_vertex>\\n#include <morphtarget_pars_vertex>\\n#include <skinning_pars_vertex>\\n#include <shadowmap_pars_vertex>\\n#include <logdepthbuf_pars_vertex>\\n#include <clipping_planes_pars_vertex>\\nvoid main() {\\n\\t#include <uv_vertex>\\n\\t#include <uv2_vertex>\\n\\t#include <color_vertex>\\n\\t#include <beginnormal_vertex>\\n\\t#include <morphnormal_vertex>\\n\\t#include <skinbase_vertex>\\n\\t#include <skinnormal_vertex>\\n\\t#include <defaultnormal_vertex>\\n#ifndef FLAT_SHADED\\n\\tvNormal = normalize( transformedNormal );\\n#endif\\n\\t#include <begin_vertex>\\n\\t#include <morphtarget_vertex>\\n\\t#include <skinning_vertex>\\n\\t#include <displacementmap_vertex>\\n\\t#include <project_vertex>\\n\\t#include <logdepthbuf_vertex>\\n\\t#include <clipping_planes_vertex>\\n\\tvViewPosition = - mvPosition.xyz;\\n\\t#include <worldpos_vertex>\\n\\t#include <shadowmap_vertex>\\n\\t#include <fog_vertex>\\n}\\n\";\n\n\tvar normal_frag = \"#define NORMAL\\nuniform float opacity;\\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\\n\\tvarying vec3 vViewPosition;\\n#endif\\n#ifndef FLAT_SHADED\\n\\tvarying vec3 vNormal;\\n#endif\\n#include <packing>\\n#include <uv_pars_fragment>\\n#include <bumpmap_pars_fragment>\\n#include <normalmap_pars_fragment>\\n#include <logdepthbuf_pars_fragment>\\nvoid main() {\\n\\t#include <logdepthbuf_fragment>\\n\\t#include <normal_fragment>\\n\\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\\n}\\n\";\n\n\tvar normal_vert = \"#define NORMAL\\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\\n\\tvarying vec3 vViewPosition;\\n#endif\\n#ifndef FLAT_SHADED\\n\\tvarying vec3 vNormal;\\n#endif\\n#include <uv_pars_vertex>\\n#include <displacementmap_pars_vertex>\\n#include <morphtarget_pars_vertex>\\n#include <skinning_pars_vertex>\\n#include <logdepthbuf_pars_vertex>\\nvoid main() {\\n\\t#include <uv_vertex>\\n\\t#include <beginnormal_vertex>\\n\\t#include <morphnormal_vertex>\\n\\t#include <skinbase_vertex>\\n\\t#include <skinnormal_vertex>\\n\\t#include <defaultnormal_vertex>\\n#ifndef FLAT_SHADED\\n\\tvNormal = normalize( transformedNormal );\\n#endif\\n\\t#include <begin_vertex>\\n\\t#include <morphtarget_vertex>\\n\\t#include <skinning_vertex>\\n\\t#include <displacementmap_vertex>\\n\\t#include <project_vertex>\\n\\t#include <logdepthbuf_vertex>\\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\\n\\tvViewPosition = - mvPosition.xyz;\\n#endif\\n}\\n\";\n\n\tvar points_frag = \"uniform vec3 diffuse;\\nuniform float opacity;\\n#include <common>\\n#include <packing>\\n#include <color_pars_fragment>\\n#include <map_particle_pars_fragment>\\n#include <fog_pars_fragment>\\n#include <shadowmap_pars_fragment>\\n#include <logdepthbuf_pars_fragment>\\n#include <clipping_planes_pars_fragment>\\nvoid main() {\\n\\t#include <clipping_planes_fragment>\\n\\tvec3 outgoingLight = vec3( 0.0 );\\n\\tvec4 diffuseColor = vec4( diffuse, opacity );\\n\\t#include <logdepthbuf_fragment>\\n\\t#include <map_particle_fragment>\\n\\t#include <color_fragment>\\n\\t#include <alphatest_fragment>\\n\\toutgoingLight = diffuseColor.rgb;\\n\\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\\n\\t#include <premultiplied_alpha_fragment>\\n\\t#include <tonemapping_fragment>\\n\\t#include <encodings_fragment>\\n\\t#include <fog_fragment>\\n}\\n\";\n\n\tvar points_vert = \"uniform float size;\\nuniform float scale;\\n#include <common>\\n#include <color_pars_vertex>\\n#include <fog_pars_vertex>\\n#include <shadowmap_pars_vertex>\\n#include <logdepthbuf_pars_vertex>\\n#include <clipping_planes_pars_vertex>\\nvoid main() {\\n\\t#include <color_vertex>\\n\\t#include <begin_vertex>\\n\\t#include <project_vertex>\\n\\t#ifdef USE_SIZEATTENUATION\\n\\t\\tgl_PointSize = size * ( scale / - mvPosition.z );\\n\\t#else\\n\\t\\tgl_PointSize = size;\\n\\t#endif\\n\\t#include <logdepthbuf_vertex>\\n\\t#include <clipping_planes_vertex>\\n\\t#include <worldpos_vertex>\\n\\t#include <shadowmap_vertex>\\n\\t#include <fog_vertex>\\n}\\n\";\n\n\tvar shadow_frag = \"uniform vec3 color;\\nuniform float opacity;\\n#include <common>\\n#include <packing>\\n#include <bsdfs>\\n#include <lights_pars>\\n#include <shadowmap_pars_fragment>\\n#include <shadowmask_pars_fragment>\\nvoid main() {\\n\\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\\n}\\n\";\n\n\tvar shadow_vert = \"#include <shadowmap_pars_vertex>\\nvoid main() {\\n\\t#include <begin_vertex>\\n\\t#include <project_vertex>\\n\\t#include <worldpos_vertex>\\n\\t#include <shadowmap_vertex>\\n}\\n\";\n\n\tvar ShaderChunk = {\n\t\talphamap_fragment: alphamap_fragment,\n\t\talphamap_pars_fragment: alphamap_pars_fragment,\n\t\talphatest_fragment: alphatest_fragment,\n\t\taomap_fragment: aomap_fragment,\n\t\taomap_pars_fragment: aomap_pars_fragment,\n\t\tbegin_vertex: begin_vertex,\n\t\tbeginnormal_vertex: beginnormal_vertex,\n\t\tbsdfs: bsdfs,\n\t\tbumpmap_pars_fragment: bumpmap_pars_fragment,\n\t\tclipping_planes_fragment: clipping_planes_fragment,\n\t\tclipping_planes_pars_fragment: clipping_planes_pars_fragment,\n\t\tclipping_planes_pars_vertex: clipping_planes_pars_vertex,\n\t\tclipping_planes_vertex: clipping_planes_vertex,\n\t\tcolor_fragment: color_fragment,\n\t\tcolor_pars_fragment: color_pars_fragment,\n\t\tcolor_pars_vertex: color_pars_vertex,\n\t\tcolor_vertex: color_vertex,\n\t\tcommon: common,\n\t\tcube_uv_reflection_fragment: cube_uv_reflection_fragment,\n\t\tdefaultnormal_vertex: defaultnormal_vertex,\n\t\tdisplacementmap_pars_vertex: displacementmap_pars_vertex,\n\t\tdisplacementmap_vertex: displacementmap_vertex,\n\t\temissivemap_fragment: emissivemap_fragment,\n\t\temissivemap_pars_fragment: emissivemap_pars_fragment,\n\t\tencodings_fragment: encodings_fragment,\n\t\tencodings_pars_fragment: encodings_pars_fragment,\n\t\tenvmap_fragment: envmap_fragment,\n\t\tenvmap_pars_fragment: envmap_pars_fragment,\n\t\tenvmap_pars_vertex: envmap_pars_vertex,\n\t\tenvmap_vertex: envmap_vertex,\n\t\tfog_vertex: fog_vertex,\n\t\tfog_pars_vertex: fog_pars_vertex,\n\t\tfog_fragment: fog_fragment,\n\t\tfog_pars_fragment: fog_pars_fragment,\n\t\tgradientmap_pars_fragment: gradientmap_pars_fragment,\n\t\tlightmap_fragment: lightmap_fragment,\n\t\tlightmap_pars_fragment: lightmap_pars_fragment,\n\t\tlights_lambert_vertex: lights_lambert_vertex,\n\t\tlights_pars: lights_pars,\n\t\tlights_phong_fragment: lights_phong_fragment,\n\t\tlights_phong_pars_fragment: lights_phong_pars_fragment,\n\t\tlights_physical_fragment: lights_physical_fragment,\n\t\tlights_physical_pars_fragment: lights_physical_pars_fragment,\n\t\tlights_template: lights_template,\n\t\tlogdepthbuf_fragment: logdepthbuf_fragment,\n\t\tlogdepthbuf_pars_fragment: logdepthbuf_pars_fragment,\n\t\tlogdepthbuf_pars_vertex: logdepthbuf_pars_vertex,\n\t\tlogdepthbuf_vertex: logdepthbuf_vertex,\n\t\tmap_fragment: map_fragment,\n\t\tmap_pars_fragment: map_pars_fragment,\n\t\tmap_particle_fragment: map_particle_fragment,\n\t\tmap_particle_pars_fragment: map_particle_pars_fragment,\n\t\tmetalnessmap_fragment: metalnessmap_fragment,\n\t\tmetalnessmap_pars_fragment: metalnessmap_pars_fragment,\n\t\tmorphnormal_vertex: morphnormal_vertex,\n\t\tmorphtarget_pars_vertex: morphtarget_pars_vertex,\n\t\tmorphtarget_vertex: morphtarget_vertex,\n\t\tnormal_fragment: normal_fragment,\n\t\tnormalmap_pars_fragment: normalmap_pars_fragment,\n\t\tpacking: packing,\n\t\tpremultiplied_alpha_fragment: premultiplied_alpha_fragment,\n\t\tproject_vertex: project_vertex,\n\t\tdithering_fragment: dithering_fragment,\n\t\tdithering_pars_fragment: dithering_pars_fragment,\n\t\troughnessmap_fragment: roughnessmap_fragment,\n\t\troughnessmap_pars_fragment: roughnessmap_pars_fragment,\n\t\tshadowmap_pars_fragment: shadowmap_pars_fragment,\n\t\tshadowmap_pars_vertex: shadowmap_pars_vertex,\n\t\tshadowmap_vertex: shadowmap_vertex,\n\t\tshadowmask_pars_fragment: shadowmask_pars_fragment,\n\t\tskinbase_vertex: skinbase_vertex,\n\t\tskinning_pars_vertex: skinning_pars_vertex,\n\t\tskinning_vertex: skinning_vertex,\n\t\tskinnormal_vertex: skinnormal_vertex,\n\t\tspecularmap_fragment: specularmap_fragment,\n\t\tspecularmap_pars_fragment: specularmap_pars_fragment,\n\t\ttonemapping_fragment: tonemapping_fragment,\n\t\ttonemapping_pars_fragment: tonemapping_pars_fragment,\n\t\tuv_pars_fragment: uv_pars_fragment,\n\t\tuv_pars_vertex: uv_pars_vertex,\n\t\tuv_vertex: uv_vertex,\n\t\tuv2_pars_fragment: uv2_pars_fragment,\n\t\tuv2_pars_vertex: uv2_pars_vertex,\n\t\tuv2_vertex: uv2_vertex,\n\t\tworldpos_vertex: worldpos_vertex,\n\n\t\tcube_frag: cube_frag,\n\t\tcube_vert: cube_vert,\n\t\tdepth_frag: depth_frag,\n\t\tdepth_vert: depth_vert,\n\t\tdistanceRGBA_frag: distanceRGBA_frag,\n\t\tdistanceRGBA_vert: distanceRGBA_vert,\n\t\tequirect_frag: equirect_frag,\n\t\tequirect_vert: equirect_vert,\n\t\tlinedashed_frag: linedashed_frag,\n\t\tlinedashed_vert: linedashed_vert,\n\t\tmeshbasic_frag: meshbasic_frag,\n\t\tmeshbasic_vert: meshbasic_vert,\n\t\tmeshlambert_frag: meshlambert_frag,\n\t\tmeshlambert_vert: meshlambert_vert,\n\t\tmeshphong_frag: meshphong_frag,\n\t\tmeshphong_vert: meshphong_vert,\n\t\tmeshphysical_frag: meshphysical_frag,\n\t\tmeshphysical_vert: meshphysical_vert,\n\t\tnormal_frag: normal_frag,\n\t\tnormal_vert: normal_vert,\n\t\tpoints_frag: points_frag,\n\t\tpoints_vert: points_vert,\n\t\tshadow_frag: shadow_frag,\n\t\tshadow_vert: shadow_vert\n\t};\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author mikael emtinger / http://gomo.se/\n\t */\n\n\tvar ShaderLib = {\n\n\t\tbasic: {\n\n\t\t\tuniforms: UniformsUtils.merge( [\n\t\t\t\tUniformsLib.common,\n\t\t\t\tUniformsLib.specularmap,\n\t\t\t\tUniformsLib.envmap,\n\t\t\t\tUniformsLib.aomap,\n\t\t\t\tUniformsLib.lightmap,\n\t\t\t\tUniformsLib.fog\n\t\t\t] ),\n\n\t\t\tvertexShader: ShaderChunk.meshbasic_vert,\n\t\t\tfragmentShader: ShaderChunk.meshbasic_frag\n\n\t\t},\n\n\t\tlambert: {\n\n\t\t\tuniforms: UniformsUtils.merge( [\n\t\t\t\tUniformsLib.common,\n\t\t\t\tUniformsLib.specularmap,\n\t\t\t\tUniformsLib.envmap,\n\t\t\t\tUniformsLib.aomap,\n\t\t\t\tUniformsLib.lightmap,\n\t\t\t\tUniformsLib.emissivemap,\n\t\t\t\tUniformsLib.fog,\n\t\t\t\tUniformsLib.lights,\n\t\t\t\t{\n\t\t\t\t\temissive: { value: new Color( 0x000000 ) }\n\t\t\t\t}\n\t\t\t] ),\n\n\t\t\tvertexShader: ShaderChunk.meshlambert_vert,\n\t\t\tfragmentShader: ShaderChunk.meshlambert_frag\n\n\t\t},\n\n\t\tphong: {\n\n\t\t\tuniforms: UniformsUtils.merge( [\n\t\t\t\tUniformsLib.common,\n\t\t\t\tUniformsLib.specularmap,\n\t\t\t\tUniformsLib.envmap,\n\t\t\t\tUniformsLib.aomap,\n\t\t\t\tUniformsLib.lightmap,\n\t\t\t\tUniformsLib.emissivemap,\n\t\t\t\tUniformsLib.bumpmap,\n\t\t\t\tUniformsLib.normalmap,\n\t\t\t\tUniformsLib.displacementmap,\n\t\t\t\tUniformsLib.gradientmap,\n\t\t\t\tUniformsLib.fog,\n\t\t\t\tUniformsLib.lights,\n\t\t\t\t{\n\t\t\t\t\temissive: { value: new Color( 0x000000 ) },\n\t\t\t\t\tspecular: { value: new Color( 0x111111 ) },\n\t\t\t\t\tshininess: { value: 30 }\n\t\t\t\t}\n\t\t\t] ),\n\n\t\t\tvertexShader: ShaderChunk.meshphong_vert,\n\t\t\tfragmentShader: ShaderChunk.meshphong_frag\n\n\t\t},\n\n\t\tstandard: {\n\n\t\t\tuniforms: UniformsUtils.merge( [\n\t\t\t\tUniformsLib.common,\n\t\t\t\tUniformsLib.envmap,\n\t\t\t\tUniformsLib.aomap,\n\t\t\t\tUniformsLib.lightmap,\n\t\t\t\tUniformsLib.emissivemap,\n\t\t\t\tUniformsLib.bumpmap,\n\t\t\t\tUniformsLib.normalmap,\n\t\t\t\tUniformsLib.displacementmap,\n\t\t\t\tUniformsLib.roughnessmap,\n\t\t\t\tUniformsLib.metalnessmap,\n\t\t\t\tUniformsLib.fog,\n\t\t\t\tUniformsLib.lights,\n\t\t\t\t{\n\t\t\t\t\temissive: { value: new Color( 0x000000 ) },\n\t\t\t\t\troughness: { value: 0.5 },\n\t\t\t\t\tmetalness: { value: 0.5 },\n\t\t\t\t\tenvMapIntensity: { value: 1 } // temporary\n\t\t\t\t}\n\t\t\t] ),\n\n\t\t\tvertexShader: ShaderChunk.meshphysical_vert,\n\t\t\tfragmentShader: ShaderChunk.meshphysical_frag\n\n\t\t},\n\n\t\tpoints: {\n\n\t\t\tuniforms: UniformsUtils.merge( [\n\t\t\t\tUniformsLib.points,\n\t\t\t\tUniformsLib.fog\n\t\t\t] ),\n\n\t\t\tvertexShader: ShaderChunk.points_vert,\n\t\t\tfragmentShader: ShaderChunk.points_frag\n\n\t\t},\n\n\t\tdashed: {\n\n\t\t\tuniforms: UniformsUtils.merge( [\n\t\t\t\tUniformsLib.common,\n\t\t\t\tUniformsLib.fog,\n\t\t\t\t{\n\t\t\t\t\tscale: { value: 1 },\n\t\t\t\t\tdashSize: { value: 1 },\n\t\t\t\t\ttotalSize: { value: 2 }\n\t\t\t\t}\n\t\t\t] ),\n\n\t\t\tvertexShader: ShaderChunk.linedashed_vert,\n\t\t\tfragmentShader: ShaderChunk.linedashed_frag\n\n\t\t},\n\n\t\tdepth: {\n\n\t\t\tuniforms: UniformsUtils.merge( [\n\t\t\t\tUniformsLib.common,\n\t\t\t\tUniformsLib.displacementmap\n\t\t\t] ),\n\n\t\t\tvertexShader: ShaderChunk.depth_vert,\n\t\t\tfragmentShader: ShaderChunk.depth_frag\n\n\t\t},\n\n\t\tnormal: {\n\n\t\t\tuniforms: UniformsUtils.merge( [\n\t\t\t\tUniformsLib.common,\n\t\t\t\tUniformsLib.bumpmap,\n\t\t\t\tUniformsLib.normalmap,\n\t\t\t\tUniformsLib.displacementmap,\n\t\t\t\t{\n\t\t\t\t\topacity: { value: 1.0 }\n\t\t\t\t}\n\t\t\t] ),\n\n\t\t\tvertexShader: ShaderChunk.normal_vert,\n\t\t\tfragmentShader: ShaderChunk.normal_frag\n\n\t\t},\n\n\t\t/* -------------------------------------------------------------------------\n\t\t//\tCube map shader\n\t\t ------------------------------------------------------------------------- */\n\n\t\tcube: {\n\n\t\t\tuniforms: {\n\t\t\t\ttCube: { value: null },\n\t\t\t\ttFlip: { value: - 1 },\n\t\t\t\topacity: { value: 1.0 }\n\t\t\t},\n\n\t\t\tvertexShader: ShaderChunk.cube_vert,\n\t\t\tfragmentShader: ShaderChunk.cube_frag\n\n\t\t},\n\n\t\tequirect: {\n\n\t\t\tuniforms: {\n\t\t\t\ttEquirect: { value: null },\n\t\t\t},\n\n\t\t\tvertexShader: ShaderChunk.equirect_vert,\n\t\t\tfragmentShader: ShaderChunk.equirect_frag\n\n\t\t},\n\n\t\tdistanceRGBA: {\n\n\t\t\tuniforms: UniformsUtils.merge( [\n\t\t\t\tUniformsLib.common,\n\t\t\t\tUniformsLib.displacementmap,\n\t\t\t\t{\n\t\t\t\t\treferencePosition: { value: new Vector3() },\n\t\t\t\t\tnearDistance: { value: 1 },\n\t\t\t\t\tfarDistance: { value: 1000 }\n\t\t\t\t}\n\t\t\t] ),\n\n\t\t\tvertexShader: ShaderChunk.distanceRGBA_vert,\n\t\t\tfragmentShader: ShaderChunk.distanceRGBA_frag\n\n\t\t},\n\n\t\tshadow: {\n\n\t\t\tuniforms: UniformsUtils.merge( [\n\t\t\t\tUniformsLib.lights,\n\t\t\t\t{\n\t\t\t\t\tcolor: { value: new Color( 0x00000 ) },\n\t\t\t\t\topacity: { value: 1.0 }\n\t\t\t\t},\n\t\t\t] ),\n\n\t\t\tvertexShader: ShaderChunk.shadow_vert,\n\t\t\tfragmentShader: ShaderChunk.shadow_frag\n\n\t\t}\n\n\t};\n\n\tShaderLib.physical = {\n\n\t\tuniforms: UniformsUtils.merge( [\n\t\t\tShaderLib.standard.uniforms,\n\t\t\t{\n\t\t\t\tclearCoat: { value: 0 },\n\t\t\t\tclearCoatRoughness: { value: 0 }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.meshphysical_vert,\n\t\tfragmentShader: ShaderChunk.meshphysical_frag\n\n\t};\n\n\t/**\n\t * @author bhouston / http://clara.io\n\t */\n\n\tfunction Box2( min, max ) {\n\n\t\tthis.min = ( min !== undefined ) ? min : new Vector2( + Infinity, + Infinity );\n\t\tthis.max = ( max !== undefined ) ? max : new Vector2( - Infinity, - Infinity );\n\n\t}\n\n\tObject.assign( Box2.prototype, {\n\n\t\tset: function ( min, max ) {\n\n\t\t\tthis.min.copy( min );\n\t\t\tthis.max.copy( max );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromPoints: function ( points ) {\n\n\t\t\tthis.makeEmpty();\n\n\t\t\tfor ( var i = 0, il = points.length; i < il; i ++ ) {\n\n\t\t\t\tthis.expandByPoint( points[ i ] );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromCenterAndSize: function () {\n\n\t\t\tvar v1 = new Vector2();\n\n\t\t\treturn function setFromCenterAndSize( center, size ) {\n\n\t\t\t\tvar halfSize = v1.copy( size ).multiplyScalar( 0.5 );\n\t\t\t\tthis.min.copy( center ).sub( halfSize );\n\t\t\t\tthis.max.copy( center ).add( halfSize );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor().copy( this );\n\n\t\t},\n\n\t\tcopy: function ( box ) {\n\n\t\t\tthis.min.copy( box.min );\n\t\t\tthis.max.copy( box.max );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmakeEmpty: function () {\n\n\t\t\tthis.min.x = this.min.y = + Infinity;\n\t\t\tthis.max.x = this.max.y = - Infinity;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tisEmpty: function () {\n\n\t\t\t// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes\n\n\t\t\treturn ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );\n\n\t\t},\n\n\t\tgetCenter: function ( optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Vector2();\n\t\t\treturn this.isEmpty() ? result.set( 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );\n\n\t\t},\n\n\t\tgetSize: function ( optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Vector2();\n\t\t\treturn this.isEmpty() ? result.set( 0, 0 ) : result.subVectors( this.max, this.min );\n\n\t\t},\n\n\t\texpandByPoint: function ( point ) {\n\n\t\t\tthis.min.min( point );\n\t\t\tthis.max.max( point );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\texpandByVector: function ( vector ) {\n\n\t\t\tthis.min.sub( vector );\n\t\t\tthis.max.add( vector );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\texpandByScalar: function ( scalar ) {\n\n\t\t\tthis.min.addScalar( - scalar );\n\t\t\tthis.max.addScalar( scalar );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcontainsPoint: function ( point ) {\n\n\t\t\treturn point.x < this.min.x || point.x > this.max.x ||\n\t\t\t\tpoint.y < this.min.y || point.y > this.max.y ? false : true;\n\n\t\t},\n\n\t\tcontainsBox: function ( box ) {\n\n\t\t\treturn this.min.x <= box.min.x && box.max.x <= this.max.x &&\n\t\t\t\tthis.min.y <= box.min.y && box.max.y <= this.max.y;\n\n\t\t},\n\n\t\tgetParameter: function ( point, optionalTarget ) {\n\n\t\t\t// This can potentially have a divide by zero if the box\n\t\t\t// has a size dimension of 0.\n\n\t\t\tvar result = optionalTarget || new Vector2();\n\n\t\t\treturn result.set(\n\t\t\t\t( point.x - this.min.x ) / ( this.max.x - this.min.x ),\n\t\t\t\t( point.y - this.min.y ) / ( this.max.y - this.min.y )\n\t\t\t);\n\n\t\t},\n\n\t\tintersectsBox: function ( box ) {\n\n\t\t\t// using 4 splitting planes to rule out intersections\n\n\t\t\treturn box.max.x < this.min.x || box.min.x > this.max.x ||\n\t\t\t\tbox.max.y < this.min.y || box.min.y > this.max.y ? false : true;\n\n\t\t},\n\n\t\tclampPoint: function ( point, optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Vector2();\n\t\t\treturn result.copy( point ).clamp( this.min, this.max );\n\n\t\t},\n\n\t\tdistanceToPoint: function () {\n\n\t\t\tvar v1 = new Vector2();\n\n\t\t\treturn function distanceToPoint( point ) {\n\n\t\t\t\tvar clampedPoint = v1.copy( point ).clamp( this.min, this.max );\n\t\t\t\treturn clampedPoint.sub( point ).length();\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tintersect: function ( box ) {\n\n\t\t\tthis.min.max( box.min );\n\t\t\tthis.max.min( box.max );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tunion: function ( box ) {\n\n\t\t\tthis.min.min( box.min );\n\t\t\tthis.max.max( box.max );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\ttranslate: function ( offset ) {\n\n\t\t\tthis.min.add( offset );\n\t\t\tthis.max.add( offset );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tequals: function ( box ) {\n\n\t\t\treturn box.min.equals( this.min ) && box.max.equals( this.max );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mikael emtinger / http://gomo.se/\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tfunction WebGLFlareRenderer( renderer, gl, state, textures, capabilities ) {\n\n\t\tvar vertexBuffer, elementBuffer;\n\t\tvar shader, program, attributes, uniforms;\n\n\t\tvar tempTexture, occlusionTexture;\n\n\t\tfunction init() {\n\n\t\t\tvar vertices = new Float32Array( [\n\t\t\t\t- 1, - 1,  0, 0,\n\t\t\t\t 1, - 1,  1, 0,\n\t\t\t\t 1,  1,  1, 1,\n\t\t\t\t- 1,  1,  0, 1\n\t\t\t] );\n\n\t\t\tvar faces = new Uint16Array( [\n\t\t\t\t0, 1, 2,\n\t\t\t\t0, 2, 3\n\t\t\t] );\n\n\t\t\t// buffers\n\n\t\t\tvertexBuffer     = gl.createBuffer();\n\t\t\telementBuffer    = gl.createBuffer();\n\n\t\t\tgl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );\n\t\t\tgl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW );\n\n\t\t\tgl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );\n\t\t\tgl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW );\n\n\t\t\t// textures\n\n\t\t\ttempTexture      = gl.createTexture();\n\t\t\tocclusionTexture = gl.createTexture();\n\n\t\t\tstate.bindTexture( gl.TEXTURE_2D, tempTexture );\n\t\t\tgl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, 16, 16, 0, gl.RGB, gl.UNSIGNED_BYTE, null );\n\t\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );\n\t\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );\n\t\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );\n\t\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );\n\n\t\t\tstate.bindTexture( gl.TEXTURE_2D, occlusionTexture );\n\t\t\tgl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null );\n\t\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );\n\t\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );\n\t\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );\n\t\t\tgl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );\n\n\t\t\tshader = {\n\n\t\t\t\tvertexShader: [\n\n\t\t\t\t\t\"uniform lowp int renderType;\",\n\n\t\t\t\t\t\"uniform vec3 screenPosition;\",\n\t\t\t\t\t\"uniform vec2 scale;\",\n\t\t\t\t\t\"uniform float rotation;\",\n\n\t\t\t\t\t\"uniform sampler2D occlusionMap;\",\n\n\t\t\t\t\t\"attribute vec2 position;\",\n\t\t\t\t\t\"attribute vec2 uv;\",\n\n\t\t\t\t\t\"varying vec2 vUV;\",\n\t\t\t\t\t\"varying float vVisibility;\",\n\n\t\t\t\t\t\"void main() {\",\n\n\t\t\t\t\t\t\"vUV = uv;\",\n\n\t\t\t\t\t\t\"vec2 pos = position;\",\n\n\t\t\t\t\t\t\"if ( renderType == 2 ) {\",\n\n\t\t\t\t\t\t\t\"vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );\",\n\t\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );\",\n\t\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );\",\n\t\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );\",\n\t\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );\",\n\t\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );\",\n\t\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );\",\n\t\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );\",\n\t\t\t\t\t\t\t\"visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );\",\n\n\t\t\t\t\t\t\t\"vVisibility =        visibility.r / 9.0;\",\n\t\t\t\t\t\t\t\"vVisibility *= 1.0 - visibility.g / 9.0;\",\n\t\t\t\t\t\t\t\"vVisibility *=       visibility.b / 9.0;\",\n\t\t\t\t\t\t\t\"vVisibility *= 1.0 - visibility.a / 9.0;\",\n\n\t\t\t\t\t\t\t\"pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;\",\n\t\t\t\t\t\t\t\"pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;\",\n\n\t\t\t\t\t\t\"}\",\n\n\t\t\t\t\t\t\"gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );\",\n\n\t\t\t\t\t\"}\"\n\n\t\t\t\t].join( \"\\n\" ),\n\n\t\t\t\tfragmentShader: [\n\n\t\t\t\t\t\"uniform lowp int renderType;\",\n\n\t\t\t\t\t\"uniform sampler2D map;\",\n\t\t\t\t\t\"uniform float opacity;\",\n\t\t\t\t\t\"uniform vec3 color;\",\n\n\t\t\t\t\t\"varying vec2 vUV;\",\n\t\t\t\t\t\"varying float vVisibility;\",\n\n\t\t\t\t\t\"void main() {\",\n\n\t\t\t\t\t\t// pink square\n\n\t\t\t\t\t\t\"if ( renderType == 0 ) {\",\n\n\t\t\t\t\t\t\t\"gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );\",\n\n\t\t\t\t\t\t// restore\n\n\t\t\t\t\t\t\"} else if ( renderType == 1 ) {\",\n\n\t\t\t\t\t\t\t\"gl_FragColor = texture2D( map, vUV );\",\n\n\t\t\t\t\t\t// flare\n\n\t\t\t\t\t\t\"} else {\",\n\n\t\t\t\t\t\t\t\"vec4 texture = texture2D( map, vUV );\",\n\t\t\t\t\t\t\t\"texture.a *= opacity * vVisibility;\",\n\t\t\t\t\t\t\t\"gl_FragColor = texture;\",\n\t\t\t\t\t\t\t\"gl_FragColor.rgb *= color;\",\n\n\t\t\t\t\t\t\"}\",\n\n\t\t\t\t\t\"}\"\n\n\t\t\t\t].join( \"\\n\" )\n\n\t\t\t};\n\n\t\t\tprogram = createProgram( shader );\n\n\t\t\tattributes = {\n\t\t\t\tvertex: gl.getAttribLocation ( program, \"position\" ),\n\t\t\t\tuv:     gl.getAttribLocation ( program, \"uv\" )\n\t\t\t};\n\n\t\t\tuniforms = {\n\t\t\t\trenderType:     gl.getUniformLocation( program, \"renderType\" ),\n\t\t\t\tmap:            gl.getUniformLocation( program, \"map\" ),\n\t\t\t\tocclusionMap:   gl.getUniformLocation( program, \"occlusionMap\" ),\n\t\t\t\topacity:        gl.getUniformLocation( program, \"opacity\" ),\n\t\t\t\tcolor:          gl.getUniformLocation( program, \"color\" ),\n\t\t\t\tscale:          gl.getUniformLocation( program, \"scale\" ),\n\t\t\t\trotation:       gl.getUniformLocation( program, \"rotation\" ),\n\t\t\t\tscreenPosition: gl.getUniformLocation( program, \"screenPosition\" )\n\t\t\t};\n\n\t\t}\n\n\t\t/*\n\t\t * Render lens flares\n\t\t * Method: renders 16x16 0xff00ff-colored points scattered over the light source area,\n\t\t *         reads these back and calculates occlusion.\n\t\t */\n\n\t\tthis.render = function ( flares, scene, camera, viewport ) {\n\n\t\t\tif ( flares.length === 0 ) return;\n\n\t\t\tvar tempPosition = new Vector3();\n\n\t\t\tvar invAspect = viewport.w / viewport.z,\n\t\t\t\thalfViewportWidth = viewport.z * 0.5,\n\t\t\t\thalfViewportHeight = viewport.w * 0.5;\n\n\t\t\tvar size = 16 / viewport.w,\n\t\t\t\tscale = new Vector2( size * invAspect, size );\n\n\t\t\tvar screenPosition = new Vector3( 1, 1, 0 ),\n\t\t\t\tscreenPositionPixels = new Vector2( 1, 1 );\n\n\t\t\tvar validArea = new Box2();\n\n\t\t\tvalidArea.min.set( viewport.x, viewport.y );\n\t\t\tvalidArea.max.set( viewport.x + ( viewport.z - 16 ), viewport.y + ( viewport.w - 16 ) );\n\n\t\t\tif ( program === undefined ) {\n\n\t\t\t\tinit();\n\n\t\t\t}\n\n\t\t\tstate.useProgram( program );\n\n\t\t\tstate.initAttributes();\n\t\t\tstate.enableAttribute( attributes.vertex );\n\t\t\tstate.enableAttribute( attributes.uv );\n\t\t\tstate.disableUnusedAttributes();\n\n\t\t\t// loop through all lens flares to update their occlusion and positions\n\t\t\t// setup gl and common used attribs/uniforms\n\n\t\t\tgl.uniform1i( uniforms.occlusionMap, 0 );\n\t\t\tgl.uniform1i( uniforms.map, 1 );\n\n\t\t\tgl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );\n\t\t\tgl.vertexAttribPointer( attributes.vertex, 2, gl.FLOAT, false, 2 * 8, 0 );\n\t\t\tgl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 );\n\n\t\t\tgl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );\n\n\t\t\tstate.disable( gl.CULL_FACE );\n\t\t\tstate.buffers.depth.setMask( false );\n\n\t\t\tfor ( var i = 0, l = flares.length; i < l; i ++ ) {\n\n\t\t\t\tsize = 16 / viewport.w;\n\t\t\t\tscale.set( size * invAspect, size );\n\n\t\t\t\t// calc object screen position\n\n\t\t\t\tvar flare = flares[ i ];\n\n\t\t\t\ttempPosition.set( flare.matrixWorld.elements[ 12 ], flare.matrixWorld.elements[ 13 ], flare.matrixWorld.elements[ 14 ] );\n\n\t\t\t\ttempPosition.applyMatrix4( camera.matrixWorldInverse );\n\t\t\t\ttempPosition.applyMatrix4( camera.projectionMatrix );\n\n\t\t\t\t// setup arrays for gl programs\n\n\t\t\t\tscreenPosition.copy( tempPosition );\n\n\t\t\t\t// horizontal and vertical coordinate of the lower left corner of the pixels to copy\n\n\t\t\t\tscreenPositionPixels.x = viewport.x + ( screenPosition.x * halfViewportWidth ) + halfViewportWidth - 8;\n\t\t\t\tscreenPositionPixels.y = viewport.y + ( screenPosition.y * halfViewportHeight ) + halfViewportHeight - 8;\n\n\t\t\t\t// screen cull\n\n\t\t\t\tif ( validArea.containsPoint( screenPositionPixels ) === true ) {\n\n\t\t\t\t\t// save current RGB to temp texture\n\n\t\t\t\t\tstate.activeTexture( gl.TEXTURE0 );\n\t\t\t\t\tstate.bindTexture( gl.TEXTURE_2D, null );\n\t\t\t\t\tstate.activeTexture( gl.TEXTURE1 );\n\t\t\t\t\tstate.bindTexture( gl.TEXTURE_2D, tempTexture );\n\t\t\t\t\tgl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGB, screenPositionPixels.x, screenPositionPixels.y, 16, 16, 0 );\n\n\n\t\t\t\t\t// render pink quad\n\n\t\t\t\t\tgl.uniform1i( uniforms.renderType, 0 );\n\t\t\t\t\tgl.uniform2f( uniforms.scale, scale.x, scale.y );\n\t\t\t\t\tgl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );\n\n\t\t\t\t\tstate.disable( gl.BLEND );\n\t\t\t\t\tstate.enable( gl.DEPTH_TEST );\n\n\t\t\t\t\tgl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );\n\n\n\t\t\t\t\t// copy result to occlusionMap\n\n\t\t\t\t\tstate.activeTexture( gl.TEXTURE0 );\n\t\t\t\t\tstate.bindTexture( gl.TEXTURE_2D, occlusionTexture );\n\t\t\t\t\tgl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGBA, screenPositionPixels.x, screenPositionPixels.y, 16, 16, 0 );\n\n\n\t\t\t\t\t// restore graphics\n\n\t\t\t\t\tgl.uniform1i( uniforms.renderType, 1 );\n\t\t\t\t\tstate.disable( gl.DEPTH_TEST );\n\n\t\t\t\t\tstate.activeTexture( gl.TEXTURE1 );\n\t\t\t\t\tstate.bindTexture( gl.TEXTURE_2D, tempTexture );\n\t\t\t\t\tgl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );\n\n\n\t\t\t\t\t// update object positions\n\n\t\t\t\t\tflare.positionScreen.copy( screenPosition );\n\n\t\t\t\t\tif ( flare.customUpdateCallback ) {\n\n\t\t\t\t\t\tflare.customUpdateCallback( flare );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tflare.updateLensFlares();\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// render flares\n\n\t\t\t\t\tgl.uniform1i( uniforms.renderType, 2 );\n\t\t\t\t\tstate.enable( gl.BLEND );\n\n\t\t\t\t\tfor ( var j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) {\n\n\t\t\t\t\t\tvar sprite = flare.lensFlares[ j ];\n\n\t\t\t\t\t\tif ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) {\n\n\t\t\t\t\t\t\tscreenPosition.x = sprite.x;\n\t\t\t\t\t\t\tscreenPosition.y = sprite.y;\n\t\t\t\t\t\t\tscreenPosition.z = sprite.z;\n\n\t\t\t\t\t\t\tsize = sprite.size * sprite.scale / viewport.w;\n\n\t\t\t\t\t\t\tscale.x = size * invAspect;\n\t\t\t\t\t\t\tscale.y = size;\n\n\t\t\t\t\t\t\tgl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );\n\t\t\t\t\t\t\tgl.uniform2f( uniforms.scale, scale.x, scale.y );\n\t\t\t\t\t\t\tgl.uniform1f( uniforms.rotation, sprite.rotation );\n\n\t\t\t\t\t\t\tgl.uniform1f( uniforms.opacity, sprite.opacity );\n\t\t\t\t\t\t\tgl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b );\n\n\t\t\t\t\t\t\tstate.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst );\n\n\t\t\t\t\t\t\ttextures.setTexture2D( sprite.texture, 1 );\n\n\t\t\t\t\t\t\tgl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// restore gl\n\n\t\t\tstate.enable( gl.CULL_FACE );\n\t\t\tstate.enable( gl.DEPTH_TEST );\n\t\t\tstate.buffers.depth.setMask( true );\n\n\t\t\tstate.reset();\n\n\t\t};\n\n\t\tfunction createProgram( shader ) {\n\n\t\t\tvar program = gl.createProgram();\n\n\t\t\tvar fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );\n\t\t\tvar vertexShader = gl.createShader( gl.VERTEX_SHADER );\n\n\t\t\tvar prefix = \"precision \" + capabilities.precision + \" float;\\n\";\n\n\t\t\tgl.shaderSource( fragmentShader, prefix + shader.fragmentShader );\n\t\t\tgl.shaderSource( vertexShader, prefix + shader.vertexShader );\n\n\t\t\tgl.compileShader( fragmentShader );\n\t\t\tgl.compileShader( vertexShader );\n\n\t\t\tgl.attachShader( program, fragmentShader );\n\t\t\tgl.attachShader( program, vertexShader );\n\n\t\t\tgl.linkProgram( program );\n\n\t\t\treturn program;\n\n\t\t}\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction CanvasTexture( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {\n\n\t\tTexture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );\n\n\t\tthis.needsUpdate = true;\n\n\t}\n\n\tCanvasTexture.prototype = Object.create( Texture.prototype );\n\tCanvasTexture.prototype.constructor = CanvasTexture;\n\n\t/**\n\t * @author mikael emtinger / http://gomo.se/\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tfunction WebGLSpriteRenderer( renderer, gl, state, textures, capabilities ) {\n\n\t\tvar vertexBuffer, elementBuffer;\n\t\tvar program, attributes, uniforms;\n\n\t\tvar texture;\n\n\t\t// decompose matrixWorld\n\n\t\tvar spritePosition = new Vector3();\n\t\tvar spriteRotation = new Quaternion();\n\t\tvar spriteScale = new Vector3();\n\n\t\tfunction init() {\n\n\t\t\tvar vertices = new Float32Array( [\n\t\t\t\t- 0.5, - 0.5,  0, 0,\n\t\t\t\t  0.5, - 0.5,  1, 0,\n\t\t\t\t  0.5,   0.5,  1, 1,\n\t\t\t\t- 0.5,   0.5,  0, 1\n\t\t\t] );\n\n\t\t\tvar faces = new Uint16Array( [\n\t\t\t\t0, 1, 2,\n\t\t\t\t0, 2, 3\n\t\t\t] );\n\n\t\t\tvertexBuffer  = gl.createBuffer();\n\t\t\telementBuffer = gl.createBuffer();\n\n\t\t\tgl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );\n\t\t\tgl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW );\n\n\t\t\tgl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );\n\t\t\tgl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW );\n\n\t\t\tprogram = createProgram();\n\n\t\t\tattributes = {\n\t\t\t\tposition:\t\t\tgl.getAttribLocation ( program, 'position' ),\n\t\t\t\tuv:\t\t\t\t\tgl.getAttribLocation ( program, 'uv' )\n\t\t\t};\n\n\t\t\tuniforms = {\n\t\t\t\tuvOffset:\t\t\tgl.getUniformLocation( program, 'uvOffset' ),\n\t\t\t\tuvScale:\t\t\tgl.getUniformLocation( program, 'uvScale' ),\n\n\t\t\t\trotation:\t\t\tgl.getUniformLocation( program, 'rotation' ),\n\t\t\t\tscale:\t\t\t\tgl.getUniformLocation( program, 'scale' ),\n\n\t\t\t\tcolor:\t\t\t\tgl.getUniformLocation( program, 'color' ),\n\t\t\t\tmap:\t\t\t\tgl.getUniformLocation( program, 'map' ),\n\t\t\t\topacity:\t\t\tgl.getUniformLocation( program, 'opacity' ),\n\n\t\t\t\tmodelViewMatrix: \tgl.getUniformLocation( program, 'modelViewMatrix' ),\n\t\t\t\tprojectionMatrix:\tgl.getUniformLocation( program, 'projectionMatrix' ),\n\n\t\t\t\tfogType:\t\t\tgl.getUniformLocation( program, 'fogType' ),\n\t\t\t\tfogDensity:\t\t\tgl.getUniformLocation( program, 'fogDensity' ),\n\t\t\t\tfogNear:\t\t\tgl.getUniformLocation( program, 'fogNear' ),\n\t\t\t\tfogFar:\t\t\t\tgl.getUniformLocation( program, 'fogFar' ),\n\t\t\t\tfogColor:\t\t\tgl.getUniformLocation( program, 'fogColor' ),\n\n\t\t\t\talphaTest:\t\t\tgl.getUniformLocation( program, 'alphaTest' )\n\t\t\t};\n\n\t\t\tvar canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );\n\t\t\tcanvas.width = 8;\n\t\t\tcanvas.height = 8;\n\n\t\t\tvar context = canvas.getContext( '2d' );\n\t\t\tcontext.fillStyle = 'white';\n\t\t\tcontext.fillRect( 0, 0, 8, 8 );\n\n\t\t\ttexture = new CanvasTexture( canvas );\n\n\t\t}\n\n\t\tthis.render = function ( sprites, scene, camera ) {\n\n\t\t\tif ( sprites.length === 0 ) return;\n\n\t\t\t// setup gl\n\n\t\t\tif ( program === undefined ) {\n\n\t\t\t\tinit();\n\n\t\t\t}\n\n\t\t\tstate.useProgram( program );\n\n\t\t\tstate.initAttributes();\n\t\t\tstate.enableAttribute( attributes.position );\n\t\t\tstate.enableAttribute( attributes.uv );\n\t\t\tstate.disableUnusedAttributes();\n\n\t\t\tstate.disable( gl.CULL_FACE );\n\t\t\tstate.enable( gl.BLEND );\n\n\t\t\tgl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );\n\t\t\tgl.vertexAttribPointer( attributes.position, 2, gl.FLOAT, false, 2 * 8, 0 );\n\t\t\tgl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 );\n\n\t\t\tgl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );\n\n\t\t\tgl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements );\n\n\t\t\tstate.activeTexture( gl.TEXTURE0 );\n\t\t\tgl.uniform1i( uniforms.map, 0 );\n\n\t\t\tvar oldFogType = 0;\n\t\t\tvar sceneFogType = 0;\n\t\t\tvar fog = scene.fog;\n\n\t\t\tif ( fog ) {\n\n\t\t\t\tgl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b );\n\n\t\t\t\tif ( fog.isFog ) {\n\n\t\t\t\t\tgl.uniform1f( uniforms.fogNear, fog.near );\n\t\t\t\t\tgl.uniform1f( uniforms.fogFar, fog.far );\n\n\t\t\t\t\tgl.uniform1i( uniforms.fogType, 1 );\n\t\t\t\t\toldFogType = 1;\n\t\t\t\t\tsceneFogType = 1;\n\n\t\t\t\t} else if ( fog.isFogExp2 ) {\n\n\t\t\t\t\tgl.uniform1f( uniforms.fogDensity, fog.density );\n\n\t\t\t\t\tgl.uniform1i( uniforms.fogType, 2 );\n\t\t\t\t\toldFogType = 2;\n\t\t\t\t\tsceneFogType = 2;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tgl.uniform1i( uniforms.fogType, 0 );\n\t\t\t\toldFogType = 0;\n\t\t\t\tsceneFogType = 0;\n\n\t\t\t}\n\n\n\t\t\t// update positions and sort\n\n\t\t\tfor ( var i = 0, l = sprites.length; i < l; i ++ ) {\n\n\t\t\t\tvar sprite = sprites[ i ];\n\n\t\t\t\tsprite.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld );\n\t\t\t\tsprite.z = - sprite.modelViewMatrix.elements[ 14 ];\n\n\t\t\t}\n\n\t\t\tsprites.sort( painterSortStable );\n\n\t\t\t// render all sprites\n\n\t\t\tvar scale = [];\n\n\t\t\tfor ( var i = 0, l = sprites.length; i < l; i ++ ) {\n\n\t\t\t\tvar sprite = sprites[ i ];\n\t\t\t\tvar material = sprite.material;\n\n\t\t\t\tif ( material.visible === false ) continue;\n\n\t\t\t\tsprite.onBeforeRender( renderer, scene, camera, undefined, material, undefined );\n\n\t\t\t\tgl.uniform1f( uniforms.alphaTest, material.alphaTest );\n\t\t\t\tgl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite.modelViewMatrix.elements );\n\n\t\t\t\tsprite.matrixWorld.decompose( spritePosition, spriteRotation, spriteScale );\n\n\t\t\t\tscale[ 0 ] = spriteScale.x;\n\t\t\t\tscale[ 1 ] = spriteScale.y;\n\n\t\t\t\tvar fogType = 0;\n\n\t\t\t\tif ( scene.fog && material.fog ) {\n\n\t\t\t\t\tfogType = sceneFogType;\n\n\t\t\t\t}\n\n\t\t\t\tif ( oldFogType !== fogType ) {\n\n\t\t\t\t\tgl.uniform1i( uniforms.fogType, fogType );\n\t\t\t\t\toldFogType = fogType;\n\n\t\t\t\t}\n\n\t\t\t\tif ( material.map !== null ) {\n\n\t\t\t\t\tgl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y );\n\t\t\t\t\tgl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tgl.uniform2f( uniforms.uvOffset, 0, 0 );\n\t\t\t\t\tgl.uniform2f( uniforms.uvScale, 1, 1 );\n\n\t\t\t\t}\n\n\t\t\t\tgl.uniform1f( uniforms.opacity, material.opacity );\n\t\t\t\tgl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b );\n\n\t\t\t\tgl.uniform1f( uniforms.rotation, material.rotation );\n\t\t\t\tgl.uniform2fv( uniforms.scale, scale );\n\n\t\t\t\tstate.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha );\n\t\t\t\tstate.buffers.depth.setTest( material.depthTest );\n\t\t\t\tstate.buffers.depth.setMask( material.depthWrite );\n\n\t\t\t\ttextures.setTexture2D( material.map || texture, 0 );\n\n\t\t\t\tgl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );\n\n\t\t\t\tsprite.onAfterRender( renderer, scene, camera, undefined, material, undefined );\n\n\t\t\t}\n\n\t\t\t// restore gl\n\n\t\t\tstate.enable( gl.CULL_FACE );\n\n\t\t\tstate.reset();\n\n\t\t};\n\n\t\tfunction createProgram() {\n\n\t\t\tvar program = gl.createProgram();\n\n\t\t\tvar vertexShader = gl.createShader( gl.VERTEX_SHADER );\n\t\t\tvar fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );\n\n\t\t\tgl.shaderSource( vertexShader, [\n\n\t\t\t\t'precision ' + capabilities.precision + ' float;',\n\n\t\t\t\t'#define SHADER_NAME ' + 'SpriteMaterial',\n\n\t\t\t\t'uniform mat4 modelViewMatrix;',\n\t\t\t\t'uniform mat4 projectionMatrix;',\n\t\t\t\t'uniform float rotation;',\n\t\t\t\t'uniform vec2 scale;',\n\t\t\t\t'uniform vec2 uvOffset;',\n\t\t\t\t'uniform vec2 uvScale;',\n\n\t\t\t\t'attribute vec2 position;',\n\t\t\t\t'attribute vec2 uv;',\n\n\t\t\t\t'varying vec2 vUV;',\n\n\t\t\t\t'void main() {',\n\n\t\t\t\t\t'vUV = uvOffset + uv * uvScale;',\n\n\t\t\t\t\t'vec2 alignedPosition = position * scale;',\n\n\t\t\t\t\t'vec2 rotatedPosition;',\n\t\t\t\t\t'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;',\n\t\t\t\t\t'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;',\n\n\t\t\t\t\t'vec4 finalPosition;',\n\n\t\t\t\t\t'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );',\n\t\t\t\t\t'finalPosition.xy += rotatedPosition;',\n\t\t\t\t\t'finalPosition = projectionMatrix * finalPosition;',\n\n\t\t\t\t\t'gl_Position = finalPosition;',\n\n\t\t\t\t'}'\n\n\t\t\t].join( '\\n' ) );\n\n\t\t\tgl.shaderSource( fragmentShader, [\n\n\t\t\t\t'precision ' + capabilities.precision + ' float;',\n\n\t\t\t\t'#define SHADER_NAME ' + 'SpriteMaterial',\n\n\t\t\t\t'uniform vec3 color;',\n\t\t\t\t'uniform sampler2D map;',\n\t\t\t\t'uniform float opacity;',\n\n\t\t\t\t'uniform int fogType;',\n\t\t\t\t'uniform vec3 fogColor;',\n\t\t\t\t'uniform float fogDensity;',\n\t\t\t\t'uniform float fogNear;',\n\t\t\t\t'uniform float fogFar;',\n\t\t\t\t'uniform float alphaTest;',\n\n\t\t\t\t'varying vec2 vUV;',\n\n\t\t\t\t'void main() {',\n\n\t\t\t\t\t'vec4 texture = texture2D( map, vUV );',\n\n\t\t\t\t\t'if ( texture.a < alphaTest ) discard;',\n\n\t\t\t\t\t'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );',\n\n\t\t\t\t\t'if ( fogType > 0 ) {',\n\n\t\t\t\t\t\t'float depth = gl_FragCoord.z / gl_FragCoord.w;',\n\t\t\t\t\t\t'float fogFactor = 0.0;',\n\n\t\t\t\t\t\t'if ( fogType == 1 ) {',\n\n\t\t\t\t\t\t\t'fogFactor = smoothstep( fogNear, fogFar, depth );',\n\n\t\t\t\t\t\t'} else {',\n\n\t\t\t\t\t\t\t'const float LOG2 = 1.442695;',\n\t\t\t\t\t\t\t'fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );',\n\t\t\t\t\t\t\t'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );',\n\n\t\t\t\t\t\t'}',\n\n\t\t\t\t\t\t'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );',\n\n\t\t\t\t\t'}',\n\n\t\t\t\t'}'\n\n\t\t\t].join( '\\n' ) );\n\n\t\t\tgl.compileShader( vertexShader );\n\t\t\tgl.compileShader( fragmentShader );\n\n\t\t\tgl.attachShader( program, vertexShader );\n\t\t\tgl.attachShader( program, fragmentShader );\n\n\t\t\tgl.linkProgram( program );\n\n\t\t\treturn program;\n\n\t\t}\n\n\t\tfunction painterSortStable( a, b ) {\n\n\t\t\tif ( a.renderOrder !== b.renderOrder ) {\n\n\t\t\t\treturn a.renderOrder - b.renderOrder;\n\n\t\t\t} else if ( a.z !== b.z ) {\n\n\t\t\t\treturn b.z - a.z;\n\n\t\t\t} else {\n\n\t\t\t\treturn b.id - a.id;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tvar materialId = 0;\n\n\tfunction Material() {\n\n\t\tObject.defineProperty( this, 'id', { value: materialId ++ } );\n\n\t\tthis.uuid = _Math.generateUUID();\n\n\t\tthis.name = '';\n\t\tthis.type = 'Material';\n\n\t\tthis.fog = true;\n\t\tthis.lights = true;\n\n\t\tthis.blending = NormalBlending;\n\t\tthis.side = FrontSide;\n\t\tthis.flatShading = false;\n\t\tthis.vertexColors = NoColors; // THREE.NoColors, THREE.VertexColors, THREE.FaceColors\n\n\t\tthis.opacity = 1;\n\t\tthis.transparent = false;\n\n\t\tthis.blendSrc = SrcAlphaFactor;\n\t\tthis.blendDst = OneMinusSrcAlphaFactor;\n\t\tthis.blendEquation = AddEquation;\n\t\tthis.blendSrcAlpha = null;\n\t\tthis.blendDstAlpha = null;\n\t\tthis.blendEquationAlpha = null;\n\n\t\tthis.depthFunc = LessEqualDepth;\n\t\tthis.depthTest = true;\n\t\tthis.depthWrite = true;\n\n\t\tthis.clippingPlanes = null;\n\t\tthis.clipIntersection = false;\n\t\tthis.clipShadows = false;\n\n\t\tthis.colorWrite = true;\n\n\t\tthis.precision = null; // override the renderer's default precision for this material\n\n\t\tthis.polygonOffset = false;\n\t\tthis.polygonOffsetFactor = 0;\n\t\tthis.polygonOffsetUnits = 0;\n\n\t\tthis.dithering = false;\n\n\t\tthis.alphaTest = 0;\n\t\tthis.premultipliedAlpha = false;\n\n\t\tthis.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer\n\n\t\tthis.visible = true;\n\n\t\tthis.userData = {};\n\n\t\tthis.needsUpdate = true;\n\n\t}\n\n\tObject.assign( Material.prototype, EventDispatcher.prototype, {\n\n\t\tisMaterial: true,\n\n\t\tonBeforeCompile: function () {},\n\n\t\tsetValues: function ( values ) {\n\n\t\t\tif ( values === undefined ) return;\n\n\t\t\tfor ( var key in values ) {\n\n\t\t\t\tvar newValue = values[ key ];\n\n\t\t\t\tif ( newValue === undefined ) {\n\n\t\t\t\t\tconsole.warn( \"THREE.Material: '\" + key + \"' parameter is undefined.\" );\n\t\t\t\t\tcontinue;\n\n\t\t\t\t}\n\n\t\t\t\t// for backward compatability if shading is set in the constructor\n\t\t\t\tif ( key === 'shading' ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );\n\t\t\t\t\tthis.flatShading = ( newValue === FlatShading ) ? true : false;\n\t\t\t\t\tcontinue;\n\n\t\t\t\t}\n\n\t\t\t\tvar currentValue = this[ key ];\n\n\t\t\t\tif ( currentValue === undefined ) {\n\n\t\t\t\t\tconsole.warn( \"THREE.\" + this.type + \": '\" + key + \"' is not a property of this material.\" );\n\t\t\t\t\tcontinue;\n\n\t\t\t\t}\n\n\t\t\t\tif ( currentValue && currentValue.isColor ) {\n\n\t\t\t\t\tcurrentValue.set( newValue );\n\n\t\t\t\t} else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {\n\n\t\t\t\t\tcurrentValue.copy( newValue );\n\n\t\t\t\t} else if ( key === 'overdraw' ) {\n\n\t\t\t\t\t// ensure overdraw is backwards-compatible with legacy boolean type\n\t\t\t\t\tthis[ key ] = Number( newValue );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis[ key ] = newValue;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t},\n\n\t\ttoJSON: function ( meta ) {\n\n\t\t\tvar isRoot = meta === undefined;\n\n\t\t\tif ( isRoot ) {\n\n\t\t\t\tmeta = {\n\t\t\t\t\ttextures: {},\n\t\t\t\t\timages: {}\n\t\t\t\t};\n\n\t\t\t}\n\n\t\t\tvar data = {\n\t\t\t\tmetadata: {\n\t\t\t\t\tversion: 4.5,\n\t\t\t\t\ttype: 'Material',\n\t\t\t\t\tgenerator: 'Material.toJSON'\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// standard Material serialization\n\t\t\tdata.uuid = this.uuid;\n\t\t\tdata.type = this.type;\n\n\t\t\tif ( this.name !== '' ) data.name = this.name;\n\n\t\t\tif ( this.color && this.color.isColor ) data.color = this.color.getHex();\n\n\t\t\tif ( this.roughness !== undefined ) data.roughness = this.roughness;\n\t\t\tif ( this.metalness !== undefined ) data.metalness = this.metalness;\n\n\t\t\tif ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();\n\t\t\tif ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();\n\t\t\tif ( this.shininess !== undefined ) data.shininess = this.shininess;\n\t\t\tif ( this.clearCoat !== undefined ) data.clearCoat = this.clearCoat;\n\t\t\tif ( this.clearCoatRoughness !== undefined ) data.clearCoatRoughness = this.clearCoatRoughness;\n\n\t\t\tif ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;\n\t\t\tif ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;\n\t\t\tif ( this.lightMap && this.lightMap.isTexture ) data.lightMap = this.lightMap.toJSON( meta ).uuid;\n\t\t\tif ( this.bumpMap && this.bumpMap.isTexture ) {\n\n\t\t\t\tdata.bumpMap = this.bumpMap.toJSON( meta ).uuid;\n\t\t\t\tdata.bumpScale = this.bumpScale;\n\n\t\t\t}\n\t\t\tif ( this.normalMap && this.normalMap.isTexture ) {\n\n\t\t\t\tdata.normalMap = this.normalMap.toJSON( meta ).uuid;\n\t\t\t\tdata.normalScale = this.normalScale.toArray();\n\n\t\t\t}\n\t\t\tif ( this.displacementMap && this.displacementMap.isTexture ) {\n\n\t\t\t\tdata.displacementMap = this.displacementMap.toJSON( meta ).uuid;\n\t\t\t\tdata.displacementScale = this.displacementScale;\n\t\t\t\tdata.displacementBias = this.displacementBias;\n\n\t\t\t}\n\t\t\tif ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;\n\t\t\tif ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;\n\n\t\t\tif ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;\n\t\t\tif ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;\n\n\t\t\tif ( this.envMap && this.envMap.isTexture ) {\n\n\t\t\t\tdata.envMap = this.envMap.toJSON( meta ).uuid;\n\t\t\t\tdata.reflectivity = this.reflectivity; // Scale behind envMap\n\n\t\t\t}\n\n\t\t\tif ( this.gradientMap && this.gradientMap.isTexture ) {\n\n\t\t\t\tdata.gradientMap = this.gradientMap.toJSON( meta ).uuid;\n\n\t\t\t}\n\n\t\t\tif ( this.size !== undefined ) data.size = this.size;\n\t\t\tif ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;\n\n\t\t\tif ( this.blending !== NormalBlending ) data.blending = this.blending;\n\t\t\tif ( this.flatShading === true ) data.flatShading = this.flatShading;\n\t\t\tif ( this.side !== FrontSide ) data.side = this.side;\n\t\t\tif ( this.vertexColors !== NoColors ) data.vertexColors = this.vertexColors;\n\n\t\t\tif ( this.opacity < 1 ) data.opacity = this.opacity;\n\t\t\tif ( this.transparent === true ) data.transparent = this.transparent;\n\n\t\t\tdata.depthFunc = this.depthFunc;\n\t\t\tdata.depthTest = this.depthTest;\n\t\t\tdata.depthWrite = this.depthWrite;\n\n\t\t\tif ( this.dithering === true ) data.dithering = true;\n\n\t\t\tif ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;\n\t\t\tif ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha;\n\n\t\t\tif ( this.wireframe === true ) data.wireframe = this.wireframe;\n\t\t\tif ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;\n\t\t\tif ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;\n\t\t\tif ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;\n\n\t\t\tif ( this.morphTargets === true ) data.morphTargets = true;\n\t\t\tif ( this.skinning === true ) data.skinning = true;\n\n\t\t\tif ( this.visible === false ) data.visible = false;\n\t\t\tif ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;\n\n\t\t\t// TODO: Copied from Object3D.toJSON\n\n\t\t\tfunction extractFromCache( cache ) {\n\n\t\t\t\tvar values = [];\n\n\t\t\t\tfor ( var key in cache ) {\n\n\t\t\t\t\tvar data = cache[ key ];\n\t\t\t\t\tdelete data.metadata;\n\t\t\t\t\tvalues.push( data );\n\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\n\t\t\t}\n\n\t\t\tif ( isRoot ) {\n\n\t\t\t\tvar textures = extractFromCache( meta.textures );\n\t\t\t\tvar images = extractFromCache( meta.images );\n\n\t\t\t\tif ( textures.length > 0 ) data.textures = textures;\n\t\t\t\tif ( images.length > 0 ) data.images = images;\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor().copy( this );\n\n\t\t},\n\n\t\tcopy: function ( source ) {\n\n\t\t\tthis.name = source.name;\n\n\t\t\tthis.fog = source.fog;\n\t\t\tthis.lights = source.lights;\n\n\t\t\tthis.blending = source.blending;\n\t\t\tthis.side = source.side;\n\t\t\tthis.flatShading = source.flatShading;\n\t\t\tthis.vertexColors = source.vertexColors;\n\n\t\t\tthis.opacity = source.opacity;\n\t\t\tthis.transparent = source.transparent;\n\n\t\t\tthis.blendSrc = source.blendSrc;\n\t\t\tthis.blendDst = source.blendDst;\n\t\t\tthis.blendEquation = source.blendEquation;\n\t\t\tthis.blendSrcAlpha = source.blendSrcAlpha;\n\t\t\tthis.blendDstAlpha = source.blendDstAlpha;\n\t\t\tthis.blendEquationAlpha = source.blendEquationAlpha;\n\n\t\t\tthis.depthFunc = source.depthFunc;\n\t\t\tthis.depthTest = source.depthTest;\n\t\t\tthis.depthWrite = source.depthWrite;\n\n\t\t\tthis.colorWrite = source.colorWrite;\n\n\t\t\tthis.precision = source.precision;\n\n\t\t\tthis.polygonOffset = source.polygonOffset;\n\t\t\tthis.polygonOffsetFactor = source.polygonOffsetFactor;\n\t\t\tthis.polygonOffsetUnits = source.polygonOffsetUnits;\n\n\t\t\tthis.dithering = source.dithering;\n\n\t\t\tthis.alphaTest = source.alphaTest;\n\t\t\tthis.premultipliedAlpha = source.premultipliedAlpha;\n\n\t\t\tthis.overdraw = source.overdraw;\n\n\t\t\tthis.visible = source.visible;\n\t\t\tthis.userData = JSON.parse( JSON.stringify( source.userData ) );\n\n\t\t\tthis.clipShadows = source.clipShadows;\n\t\t\tthis.clipIntersection = source.clipIntersection;\n\n\t\t\tvar srcPlanes = source.clippingPlanes,\n\t\t\t\tdstPlanes = null;\n\n\t\t\tif ( srcPlanes !== null ) {\n\n\t\t\t\tvar n = srcPlanes.length;\n\t\t\t\tdstPlanes = new Array( n );\n\n\t\t\t\tfor ( var i = 0; i !== n; ++ i )\n\t\t\t\t\tdstPlanes[ i ] = srcPlanes[ i ].clone();\n\n\t\t\t}\n\n\t\t\tthis.clippingPlanes = dstPlanes;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tdispose: function () {\n\n\t\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t *\n\t * parameters = {\n\t *  defines: { \"label\" : \"value\" },\n\t *  uniforms: { \"parameter1\": { value: 1.0 }, \"parameter2\": { value2: 2 } },\n\t *\n\t *  fragmentShader: <string>,\n\t *  vertexShader: <string>,\n\t *\n\t *  wireframe: <boolean>,\n\t *  wireframeLinewidth: <float>,\n\t *\n\t *  lights: <bool>,\n\t *\n\t *  skinning: <bool>,\n\t *  morphTargets: <bool>,\n\t *  morphNormals: <bool>\n\t * }\n\t */\n\n\tfunction ShaderMaterial( parameters ) {\n\n\t\tMaterial.call( this );\n\n\t\tthis.type = 'ShaderMaterial';\n\n\t\tthis.defines = {};\n\t\tthis.uniforms = {};\n\n\t\tthis.vertexShader = 'void main() {\\n\\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\\n}';\n\t\tthis.fragmentShader = 'void main() {\\n\\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\\n}';\n\n\t\tthis.linewidth = 1;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\n\t\tthis.fog = false; // set to use scene fog\n\t\tthis.lights = false; // set to use scene lights\n\t\tthis.clipping = false; // set to use user-defined clipping planes\n\n\t\tthis.skinning = false; // set to use skinning attribute streams\n\t\tthis.morphTargets = false; // set to use morph targets\n\t\tthis.morphNormals = false; // set to use morph normals\n\n\t\tthis.extensions = {\n\t\t\tderivatives: false, // set to use derivatives\n\t\t\tfragDepth: false, // set to use fragment depth values\n\t\t\tdrawBuffers: false, // set to use draw buffers\n\t\t\tshaderTextureLOD: false // set to use shader texture LOD\n\t\t};\n\n\t\t// When rendered geometry doesn't include these attributes but the material does,\n\t\t// use these default values in WebGL. This avoids errors when buffer data is missing.\n\t\tthis.defaultAttributeValues = {\n\t\t\t'color': [ 1, 1, 1 ],\n\t\t\t'uv': [ 0, 0 ],\n\t\t\t'uv2': [ 0, 0 ]\n\t\t};\n\n\t\tthis.index0AttributeName = undefined;\n\n\t\tif ( parameters !== undefined ) {\n\n\t\t\tif ( parameters.attributes !== undefined ) {\n\n\t\t\t\tconsole.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' );\n\n\t\t\t}\n\n\t\t\tthis.setValues( parameters );\n\n\t\t}\n\n\t}\n\n\tShaderMaterial.prototype = Object.create( Material.prototype );\n\tShaderMaterial.prototype.constructor = ShaderMaterial;\n\n\tShaderMaterial.prototype.isShaderMaterial = true;\n\n\tShaderMaterial.prototype.copy = function ( source ) {\n\n\t\tMaterial.prototype.copy.call( this, source );\n\n\t\tthis.fragmentShader = source.fragmentShader;\n\t\tthis.vertexShader = source.vertexShader;\n\n\t\tthis.uniforms = UniformsUtils.clone( source.uniforms );\n\n\t\tthis.defines = source.defines;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\n\t\tthis.lights = source.lights;\n\t\tthis.clipping = source.clipping;\n\n\t\tthis.skinning = source.skinning;\n\n\t\tthis.morphTargets = source.morphTargets;\n\t\tthis.morphNormals = source.morphNormals;\n\n\t\tthis.extensions = source.extensions;\n\n\t\treturn this;\n\n\t};\n\n\tShaderMaterial.prototype.toJSON = function ( meta ) {\n\n\t\tvar data = Material.prototype.toJSON.call( this, meta );\n\n\t\tdata.uniforms = this.uniforms;\n\t\tdata.vertexShader = this.vertexShader;\n\t\tdata.fragmentShader = this.fragmentShader;\n\n\t\treturn data;\n\n\t};\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author bhouston / https://clara.io\n\t * @author WestLangley / http://github.com/WestLangley\n\t *\n\t * parameters = {\n\t *\n\t *  opacity: <float>,\n\t *\n\t *  map: new THREE.Texture( <Image> ),\n\t *\n\t *  alphaMap: new THREE.Texture( <Image> ),\n\t *\n\t *  displacementMap: new THREE.Texture( <Image> ),\n\t *  displacementScale: <float>,\n\t *  displacementBias: <float>,\n\t *\n\t *  wireframe: <boolean>,\n\t *  wireframeLinewidth: <float>\n\t * }\n\t */\n\n\tfunction MeshDepthMaterial( parameters ) {\n\n\t\tMaterial.call( this );\n\n\t\tthis.type = 'MeshDepthMaterial';\n\n\t\tthis.depthPacking = BasicDepthPacking;\n\n\t\tthis.skinning = false;\n\t\tthis.morphTargets = false;\n\n\t\tthis.map = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\n\t\tthis.fog = false;\n\t\tthis.lights = false;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tMeshDepthMaterial.prototype = Object.create( Material.prototype );\n\tMeshDepthMaterial.prototype.constructor = MeshDepthMaterial;\n\n\tMeshDepthMaterial.prototype.isMeshDepthMaterial = true;\n\n\tMeshDepthMaterial.prototype.copy = function ( source ) {\n\n\t\tMaterial.prototype.copy.call( this, source );\n\n\t\tthis.depthPacking = source.depthPacking;\n\n\t\tthis.skinning = source.skinning;\n\t\tthis.morphTargets = source.morphTargets;\n\n\t\tthis.map = source.map;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\n\t\treturn this;\n\n\t};\n\n\t/**\n\t * @author WestLangley / http://github.com/WestLangley\n\t *\n\t * parameters = {\n\t *\n\t *  referencePosition: <float>,\n\t *  nearDistance: <float>,\n\t *  farDistance: <float>,\n\t *\n\t *  skinning: <bool>,\n\t *  morphTargets: <bool>,\n\t *\n\t *  map: new THREE.Texture( <Image> ),\n\t *\n\t *  alphaMap: new THREE.Texture( <Image> ),\n\t *\n\t *  displacementMap: new THREE.Texture( <Image> ),\n\t *  displacementScale: <float>,\n\t *  displacementBias: <float>\n\t *\n\t * }\n\t */\n\n\tfunction MeshDistanceMaterial( parameters ) {\n\n\t\tMaterial.call( this );\n\n\t\tthis.type = 'MeshDistanceMaterial';\n\n\t\tthis.referencePosition = new Vector3();\n\t\tthis.nearDistance = 1;\n\t\tthis.farDistance = 1000;\n\n\t\tthis.skinning = false;\n\t\tthis.morphTargets = false;\n\n\t\tthis.map = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.fog = false;\n\t\tthis.lights = false;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tMeshDistanceMaterial.prototype = Object.create( Material.prototype );\n\tMeshDistanceMaterial.prototype.constructor = MeshDistanceMaterial;\n\n\tMeshDistanceMaterial.prototype.isMeshDistanceMaterial = true;\n\n\tMeshDistanceMaterial.prototype.copy = function ( source ) {\n\n\t\tMaterial.prototype.copy.call( this, source );\n\n\t\tthis.referencePosition.copy( source.referencePosition );\n\t\tthis.nearDistance = source.nearDistance;\n\t\tthis.farDistance = source.farDistance;\n\n\t\tthis.skinning = source.skinning;\n\t\tthis.morphTargets = source.morphTargets;\n\n\t\tthis.map = source.map;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\treturn this;\n\n\t};\n\n\t/**\n\t * @author bhouston / http://clara.io\n\t * @author WestLangley / http://github.com/WestLangley\n\t */\n\n\tfunction Box3( min, max ) {\n\n\t\tthis.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity );\n\t\tthis.max = ( max !== undefined ) ? max : new Vector3( - Infinity, - Infinity, - Infinity );\n\n\t}\n\n\tObject.assign( Box3.prototype, {\n\n\t\tisBox3: true,\n\n\t\tset: function ( min, max ) {\n\n\t\t\tthis.min.copy( min );\n\t\t\tthis.max.copy( max );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromArray: function ( array ) {\n\n\t\t\tvar minX = + Infinity;\n\t\t\tvar minY = + Infinity;\n\t\t\tvar minZ = + Infinity;\n\n\t\t\tvar maxX = - Infinity;\n\t\t\tvar maxY = - Infinity;\n\t\t\tvar maxZ = - Infinity;\n\n\t\t\tfor ( var i = 0, l = array.length; i < l; i += 3 ) {\n\n\t\t\t\tvar x = array[ i ];\n\t\t\t\tvar y = array[ i + 1 ];\n\t\t\t\tvar z = array[ i + 2 ];\n\n\t\t\t\tif ( x < minX ) minX = x;\n\t\t\t\tif ( y < minY ) minY = y;\n\t\t\t\tif ( z < minZ ) minZ = z;\n\n\t\t\t\tif ( x > maxX ) maxX = x;\n\t\t\t\tif ( y > maxY ) maxY = y;\n\t\t\t\tif ( z > maxZ ) maxZ = z;\n\n\t\t\t}\n\n\t\t\tthis.min.set( minX, minY, minZ );\n\t\t\tthis.max.set( maxX, maxY, maxZ );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromBufferAttribute: function ( attribute ) {\n\n\t\t\tvar minX = + Infinity;\n\t\t\tvar minY = + Infinity;\n\t\t\tvar minZ = + Infinity;\n\n\t\t\tvar maxX = - Infinity;\n\t\t\tvar maxY = - Infinity;\n\t\t\tvar maxZ = - Infinity;\n\n\t\t\tfor ( var i = 0, l = attribute.count; i < l; i ++ ) {\n\n\t\t\t\tvar x = attribute.getX( i );\n\t\t\t\tvar y = attribute.getY( i );\n\t\t\t\tvar z = attribute.getZ( i );\n\n\t\t\t\tif ( x < minX ) minX = x;\n\t\t\t\tif ( y < minY ) minY = y;\n\t\t\t\tif ( z < minZ ) minZ = z;\n\n\t\t\t\tif ( x > maxX ) maxX = x;\n\t\t\t\tif ( y > maxY ) maxY = y;\n\t\t\t\tif ( z > maxZ ) maxZ = z;\n\n\t\t\t}\n\n\t\t\tthis.min.set( minX, minY, minZ );\n\t\t\tthis.max.set( maxX, maxY, maxZ );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromPoints: function ( points ) {\n\n\t\t\tthis.makeEmpty();\n\n\t\t\tfor ( var i = 0, il = points.length; i < il; i ++ ) {\n\n\t\t\t\tthis.expandByPoint( points[ i ] );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromCenterAndSize: function () {\n\n\t\t\tvar v1 = new Vector3();\n\n\t\t\treturn function setFromCenterAndSize( center, size ) {\n\n\t\t\t\tvar halfSize = v1.copy( size ).multiplyScalar( 0.5 );\n\n\t\t\t\tthis.min.copy( center ).sub( halfSize );\n\t\t\t\tthis.max.copy( center ).add( halfSize );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tsetFromObject: function ( object ) {\n\n\t\t\tthis.makeEmpty();\n\n\t\t\treturn this.expandByObject( object );\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor().copy( this );\n\n\t\t},\n\n\t\tcopy: function ( box ) {\n\n\t\t\tthis.min.copy( box.min );\n\t\t\tthis.max.copy( box.max );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmakeEmpty: function () {\n\n\t\t\tthis.min.x = this.min.y = this.min.z = + Infinity;\n\t\t\tthis.max.x = this.max.y = this.max.z = - Infinity;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tisEmpty: function () {\n\n\t\t\t// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes\n\n\t\t\treturn ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );\n\n\t\t},\n\n\t\tgetCenter: function ( optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Vector3();\n\t\t\treturn this.isEmpty() ? result.set( 0, 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );\n\n\t\t},\n\n\t\tgetSize: function ( optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Vector3();\n\t\t\treturn this.isEmpty() ? result.set( 0, 0, 0 ) : result.subVectors( this.max, this.min );\n\n\t\t},\n\n\t\texpandByPoint: function ( point ) {\n\n\t\t\tthis.min.min( point );\n\t\t\tthis.max.max( point );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\texpandByVector: function ( vector ) {\n\n\t\t\tthis.min.sub( vector );\n\t\t\tthis.max.add( vector );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\texpandByScalar: function ( scalar ) {\n\n\t\t\tthis.min.addScalar( - scalar );\n\t\t\tthis.max.addScalar( scalar );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\texpandByObject: function () {\n\n\t\t\t// Computes the world-axis-aligned bounding box of an object (including its children),\n\t\t\t// accounting for both the object's, and children's, world transforms\n\n\t\t\tvar v1 = new Vector3();\n\n\t\t\treturn function expandByObject( object ) {\n\n\t\t\t\tvar scope = this;\n\n\t\t\t\tobject.updateMatrixWorld( true );\n\n\t\t\t\tobject.traverse( function ( node ) {\n\n\t\t\t\t\tvar i, l;\n\n\t\t\t\t\tvar geometry = node.geometry;\n\n\t\t\t\t\tif ( geometry !== undefined ) {\n\n\t\t\t\t\t\tif ( geometry.isGeometry ) {\n\n\t\t\t\t\t\t\tvar vertices = geometry.vertices;\n\n\t\t\t\t\t\t\tfor ( i = 0, l = vertices.length; i < l; i ++ ) {\n\n\t\t\t\t\t\t\t\tv1.copy( vertices[ i ] );\n\t\t\t\t\t\t\t\tv1.applyMatrix4( node.matrixWorld );\n\n\t\t\t\t\t\t\t\tscope.expandByPoint( v1 );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else if ( geometry.isBufferGeometry ) {\n\n\t\t\t\t\t\t\tvar attribute = geometry.attributes.position;\n\n\t\t\t\t\t\t\tif ( attribute !== undefined ) {\n\n\t\t\t\t\t\t\t\tfor ( i = 0, l = attribute.count; i < l; i ++ ) {\n\n\t\t\t\t\t\t\t\t\tv1.fromBufferAttribute( attribute, i ).applyMatrix4( node.matrixWorld );\n\n\t\t\t\t\t\t\t\t\tscope.expandByPoint( v1 );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tcontainsPoint: function ( point ) {\n\n\t\t\treturn point.x < this.min.x || point.x > this.max.x ||\n\t\t\t\tpoint.y < this.min.y || point.y > this.max.y ||\n\t\t\t\tpoint.z < this.min.z || point.z > this.max.z ? false : true;\n\n\t\t},\n\n\t\tcontainsBox: function ( box ) {\n\n\t\t\treturn this.min.x <= box.min.x && box.max.x <= this.max.x &&\n\t\t\t\tthis.min.y <= box.min.y && box.max.y <= this.max.y &&\n\t\t\t\tthis.min.z <= box.min.z && box.max.z <= this.max.z;\n\n\t\t},\n\n\t\tgetParameter: function ( point, optionalTarget ) {\n\n\t\t\t// This can potentially have a divide by zero if the box\n\t\t\t// has a size dimension of 0.\n\n\t\t\tvar result = optionalTarget || new Vector3();\n\n\t\t\treturn result.set(\n\t\t\t\t( point.x - this.min.x ) / ( this.max.x - this.min.x ),\n\t\t\t\t( point.y - this.min.y ) / ( this.max.y - this.min.y ),\n\t\t\t\t( point.z - this.min.z ) / ( this.max.z - this.min.z )\n\t\t\t);\n\n\t\t},\n\n\t\tintersectsBox: function ( box ) {\n\n\t\t\t// using 6 splitting planes to rule out intersections.\n\t\t\treturn box.max.x < this.min.x || box.min.x > this.max.x ||\n\t\t\t\tbox.max.y < this.min.y || box.min.y > this.max.y ||\n\t\t\t\tbox.max.z < this.min.z || box.min.z > this.max.z ? false : true;\n\n\t\t},\n\n\t\tintersectsSphere: ( function () {\n\n\t\t\tvar closestPoint = new Vector3();\n\n\t\t\treturn function intersectsSphere( sphere ) {\n\n\t\t\t\t// Find the point on the AABB closest to the sphere center.\n\t\t\t\tthis.clampPoint( sphere.center, closestPoint );\n\n\t\t\t\t// If that point is inside the sphere, the AABB and sphere intersect.\n\t\t\t\treturn closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );\n\n\t\t\t};\n\n\t\t} )(),\n\n\t\tintersectsPlane: function ( plane ) {\n\n\t\t\t// We compute the minimum and maximum dot product values. If those values\n\t\t\t// are on the same side (back or front) of the plane, then there is no intersection.\n\n\t\t\tvar min, max;\n\n\t\t\tif ( plane.normal.x > 0 ) {\n\n\t\t\t\tmin = plane.normal.x * this.min.x;\n\t\t\t\tmax = plane.normal.x * this.max.x;\n\n\t\t\t} else {\n\n\t\t\t\tmin = plane.normal.x * this.max.x;\n\t\t\t\tmax = plane.normal.x * this.min.x;\n\n\t\t\t}\n\n\t\t\tif ( plane.normal.y > 0 ) {\n\n\t\t\t\tmin += plane.normal.y * this.min.y;\n\t\t\t\tmax += plane.normal.y * this.max.y;\n\n\t\t\t} else {\n\n\t\t\t\tmin += plane.normal.y * this.max.y;\n\t\t\t\tmax += plane.normal.y * this.min.y;\n\n\t\t\t}\n\n\t\t\tif ( plane.normal.z > 0 ) {\n\n\t\t\t\tmin += plane.normal.z * this.min.z;\n\t\t\t\tmax += plane.normal.z * this.max.z;\n\n\t\t\t} else {\n\n\t\t\t\tmin += plane.normal.z * this.max.z;\n\t\t\t\tmax += plane.normal.z * this.min.z;\n\n\t\t\t}\n\n\t\t\treturn ( min <= plane.constant && max >= plane.constant );\n\n\t\t},\n\n\t\tclampPoint: function ( point, optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Vector3();\n\t\t\treturn result.copy( point ).clamp( this.min, this.max );\n\n\t\t},\n\n\t\tdistanceToPoint: function () {\n\n\t\t\tvar v1 = new Vector3();\n\n\t\t\treturn function distanceToPoint( point ) {\n\n\t\t\t\tvar clampedPoint = v1.copy( point ).clamp( this.min, this.max );\n\t\t\t\treturn clampedPoint.sub( point ).length();\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tgetBoundingSphere: function () {\n\n\t\t\tvar v1 = new Vector3();\n\n\t\t\treturn function getBoundingSphere( optionalTarget ) {\n\n\t\t\t\tvar result = optionalTarget || new Sphere();\n\n\t\t\t\tthis.getCenter( result.center );\n\n\t\t\t\tresult.radius = this.getSize( v1 ).length() * 0.5;\n\n\t\t\t\treturn result;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tintersect: function ( box ) {\n\n\t\t\tthis.min.max( box.min );\n\t\t\tthis.max.min( box.max );\n\n\t\t\t// ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values.\n\t\t\tif( this.isEmpty() ) this.makeEmpty();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tunion: function ( box ) {\n\n\t\t\tthis.min.min( box.min );\n\t\t\tthis.max.max( box.max );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tapplyMatrix4: function () {\n\n\t\t\tvar points = [\n\t\t\t\tnew Vector3(),\n\t\t\t\tnew Vector3(),\n\t\t\t\tnew Vector3(),\n\t\t\t\tnew Vector3(),\n\t\t\t\tnew Vector3(),\n\t\t\t\tnew Vector3(),\n\t\t\t\tnew Vector3(),\n\t\t\t\tnew Vector3()\n\t\t\t];\n\n\t\t\treturn function applyMatrix4( matrix ) {\n\n\t\t\t\t// transform of empty box is an empty box.\n\t\t\t\tif( this.isEmpty() ) return this;\n\n\t\t\t\t// NOTE: I am using a binary pattern to specify all 2^3 combinations below\n\t\t\t\tpoints[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000\n\t\t\t\tpoints[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001\n\t\t\t\tpoints[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010\n\t\t\t\tpoints[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011\n\t\t\t\tpoints[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100\n\t\t\t\tpoints[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101\n\t\t\t\tpoints[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110\n\t\t\t\tpoints[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix );\t// 111\n\n\t\t\t\tthis.setFromPoints( points );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\ttranslate: function ( offset ) {\n\n\t\t\tthis.min.add( offset );\n\t\t\tthis.max.add( offset );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tequals: function ( box ) {\n\n\t\t\treturn box.min.equals( this.min ) && box.max.equals( this.max );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author bhouston / http://clara.io\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction Sphere( center, radius ) {\n\n\t\tthis.center = ( center !== undefined ) ? center : new Vector3();\n\t\tthis.radius = ( radius !== undefined ) ? radius : 0;\n\n\t}\n\n\tObject.assign( Sphere.prototype, {\n\n\t\tset: function ( center, radius ) {\n\n\t\t\tthis.center.copy( center );\n\t\t\tthis.radius = radius;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromPoints: function () {\n\n\t\t\tvar box = new Box3();\n\n\t\t\treturn function setFromPoints( points, optionalCenter ) {\n\n\t\t\t\tvar center = this.center;\n\n\t\t\t\tif ( optionalCenter !== undefined ) {\n\n\t\t\t\t\tcenter.copy( optionalCenter );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tbox.setFromPoints( points ).getCenter( center );\n\n\t\t\t\t}\n\n\t\t\t\tvar maxRadiusSq = 0;\n\n\t\t\t\tfor ( var i = 0, il = points.length; i < il; i ++ ) {\n\n\t\t\t\t\tmaxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );\n\n\t\t\t\t}\n\n\t\t\t\tthis.radius = Math.sqrt( maxRadiusSq );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor().copy( this );\n\n\t\t},\n\n\t\tcopy: function ( sphere ) {\n\n\t\t\tthis.center.copy( sphere.center );\n\t\t\tthis.radius = sphere.radius;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tempty: function () {\n\n\t\t\treturn ( this.radius <= 0 );\n\n\t\t},\n\n\t\tcontainsPoint: function ( point ) {\n\n\t\t\treturn ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );\n\n\t\t},\n\n\t\tdistanceToPoint: function ( point ) {\n\n\t\t\treturn ( point.distanceTo( this.center ) - this.radius );\n\n\t\t},\n\n\t\tintersectsSphere: function ( sphere ) {\n\n\t\t\tvar radiusSum = this.radius + sphere.radius;\n\n\t\t\treturn sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );\n\n\t\t},\n\n\t\tintersectsBox: function ( box ) {\n\n\t\t\treturn box.intersectsSphere( this );\n\n\t\t},\n\n\t\tintersectsPlane: function ( plane ) {\n\n\t\t\treturn Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius;\n\n\t\t},\n\n\t\tclampPoint: function ( point, optionalTarget ) {\n\n\t\t\tvar deltaLengthSq = this.center.distanceToSquared( point );\n\n\t\t\tvar result = optionalTarget || new Vector3();\n\n\t\t\tresult.copy( point );\n\n\t\t\tif ( deltaLengthSq > ( this.radius * this.radius ) ) {\n\n\t\t\t\tresult.sub( this.center ).normalize();\n\t\t\t\tresult.multiplyScalar( this.radius ).add( this.center );\n\n\t\t\t}\n\n\t\t\treturn result;\n\n\t\t},\n\n\t\tgetBoundingBox: function ( optionalTarget ) {\n\n\t\t\tvar box = optionalTarget || new Box3();\n\n\t\t\tbox.set( this.center, this.center );\n\t\t\tbox.expandByScalar( this.radius );\n\n\t\t\treturn box;\n\n\t\t},\n\n\t\tapplyMatrix4: function ( matrix ) {\n\n\t\t\tthis.center.applyMatrix4( matrix );\n\t\t\tthis.radius = this.radius * matrix.getMaxScaleOnAxis();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\ttranslate: function ( offset ) {\n\n\t\t\tthis.center.add( offset );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tequals: function ( sphere ) {\n\n\t\t\treturn sphere.center.equals( this.center ) && ( sphere.radius === this.radius );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author WestLangley / http://github.com/WestLangley\n\t * @author bhouston / http://clara.io\n\t * @author tschw\n\t */\n\n\tfunction Matrix3() {\n\n\t\tthis.elements = [\n\n\t\t\t1, 0, 0,\n\t\t\t0, 1, 0,\n\t\t\t0, 0, 1\n\n\t\t];\n\n\t\tif ( arguments.length > 0 ) {\n\n\t\t\tconsole.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' );\n\n\t\t}\n\n\t}\n\n\tObject.assign( Matrix3.prototype, {\n\n\t\tisMatrix3: true,\n\n\t\tset: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {\n\n\t\t\tvar te = this.elements;\n\n\t\t\tte[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;\n\t\t\tte[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;\n\t\t\tte[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tidentity: function () {\n\n\t\t\tthis.set(\n\n\t\t\t\t1, 0, 0,\n\t\t\t\t0, 1, 0,\n\t\t\t\t0, 0, 1\n\n\t\t\t);\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor().fromArray( this.elements );\n\n\t\t},\n\n\t\tcopy: function ( m ) {\n\n\t\t\tvar te = this.elements;\n\t\t\tvar me = m.elements;\n\n\t\t\tte[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ];\n\t\t\tte[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ];\n\t\t\tte[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ];\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromMatrix4: function ( m ) {\n\n\t\t\tvar me = m.elements;\n\n\t\t\tthis.set(\n\n\t\t\t\tme[ 0 ], me[ 4 ], me[  8 ],\n\t\t\t\tme[ 1 ], me[ 5 ], me[  9 ],\n\t\t\t\tme[ 2 ], me[ 6 ], me[ 10 ]\n\n\t\t\t);\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tapplyToBufferAttribute: function () {\n\n\t\t\tvar v1 = new Vector3();\n\n\t\t\treturn function applyToBufferAttribute( attribute ) {\n\n\t\t\t\tfor ( var i = 0, l = attribute.count; i < l; i ++ ) {\n\n\t\t\t\t\tv1.x = attribute.getX( i );\n\t\t\t\t\tv1.y = attribute.getY( i );\n\t\t\t\t\tv1.z = attribute.getZ( i );\n\n\t\t\t\t\tv1.applyMatrix3( this );\n\n\t\t\t\t\tattribute.setXYZ( i, v1.x, v1.y, v1.z );\n\n\t\t\t\t}\n\n\t\t\t\treturn attribute;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tmultiply: function ( m ) {\n\n\t\t\treturn this.multiplyMatrices( this, m );\n\n\t\t},\n\n\t\tpremultiply: function ( m ) {\n\n\t\t\treturn this.multiplyMatrices( m, this );\n\n\t\t},\n\n\t\tmultiplyMatrices: function ( a, b ) {\n\n\t\t\tvar ae = a.elements;\n\t\t\tvar be = b.elements;\n\t\t\tvar te = this.elements;\n\n\t\t\tvar a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];\n\t\t\tvar a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];\n\t\t\tvar a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];\n\n\t\t\tvar b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];\n\t\t\tvar b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];\n\t\t\tvar b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];\n\n\t\t\tte[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;\n\t\t\tte[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32;\n\t\t\tte[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33;\n\n\t\t\tte[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31;\n\t\t\tte[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32;\n\t\t\tte[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33;\n\n\t\t\tte[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31;\n\t\t\tte[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32;\n\t\t\tte[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tmultiplyScalar: function ( s ) {\n\n\t\t\tvar te = this.elements;\n\n\t\t\tte[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;\n\t\t\tte[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;\n\t\t\tte[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tdeterminant: function () {\n\n\t\t\tvar te = this.elements;\n\n\t\t\tvar a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],\n\t\t\t\td = te[ 3 ], e = te[ 4 ], f = te[ 5 ],\n\t\t\t\tg = te[ 6 ], h = te[ 7 ], i = te[ 8 ];\n\n\t\t\treturn a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;\n\n\t\t},\n\n\t\tgetInverse: function ( matrix, throwOnDegenerate ) {\n\n\t\t\tif ( matrix && matrix.isMatrix4 ) {\n\n\t\t\t\tconsole.error( \"THREE.Matrix3: .getInverse() no longer takes a Matrix4 argument.\" );\n\n\t\t\t}\n\n\t\t\tvar me = matrix.elements,\n\t\t\t\tte = this.elements,\n\n\t\t\t\tn11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ],\n\t\t\t\tn12 = me[ 3 ], n22 = me[ 4 ], n32 = me[ 5 ],\n\t\t\t\tn13 = me[ 6 ], n23 = me[ 7 ], n33 = me[ 8 ],\n\n\t\t\t\tt11 = n33 * n22 - n32 * n23,\n\t\t\t\tt12 = n32 * n13 - n33 * n12,\n\t\t\t\tt13 = n23 * n12 - n22 * n13,\n\n\t\t\t\tdet = n11 * t11 + n21 * t12 + n31 * t13;\n\n\t\t\tif ( det === 0 ) {\n\n\t\t\t\tvar msg = \"THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0\";\n\n\t\t\t\tif ( throwOnDegenerate === true ) {\n\n\t\t\t\t\tthrow new Error( msg );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.warn( msg );\n\n\t\t\t\t}\n\n\t\t\t\treturn this.identity();\n\n\t\t\t}\n\n\t\t\tvar detInv = 1 / det;\n\n\t\t\tte[ 0 ] = t11 * detInv;\n\t\t\tte[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;\n\t\t\tte[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;\n\n\t\t\tte[ 3 ] = t12 * detInv;\n\t\t\tte[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;\n\t\t\tte[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;\n\n\t\t\tte[ 6 ] = t13 * detInv;\n\t\t\tte[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;\n\t\t\tte[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\ttranspose: function () {\n\n\t\t\tvar tmp, m = this.elements;\n\n\t\t\ttmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;\n\t\t\ttmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;\n\t\t\ttmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetNormalMatrix: function ( matrix4 ) {\n\n\t\t\treturn this.setFromMatrix4( matrix4 ).getInverse( this ).transpose();\n\n\t\t},\n\n\t\ttransposeIntoArray: function ( r ) {\n\n\t\t\tvar m = this.elements;\n\n\t\t\tr[ 0 ] = m[ 0 ];\n\t\t\tr[ 1 ] = m[ 3 ];\n\t\t\tr[ 2 ] = m[ 6 ];\n\t\t\tr[ 3 ] = m[ 1 ];\n\t\t\tr[ 4 ] = m[ 4 ];\n\t\t\tr[ 5 ] = m[ 7 ];\n\t\t\tr[ 6 ] = m[ 2 ];\n\t\t\tr[ 7 ] = m[ 5 ];\n\t\t\tr[ 8 ] = m[ 8 ];\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tequals: function ( matrix ) {\n\n\t\t\tvar te = this.elements;\n\t\t\tvar me = matrix.elements;\n\n\t\t\tfor ( var i = 0; i < 9; i ++ ) {\n\n\t\t\t\tif ( te[ i ] !== me[ i ] ) return false;\n\n\t\t\t}\n\n\t\t\treturn true;\n\n\t\t},\n\n\t\tfromArray: function ( array, offset ) {\n\n\t\t\tif ( offset === undefined ) offset = 0;\n\n\t\t\tfor ( var i = 0; i < 9; i ++ ) {\n\n\t\t\t\tthis.elements[ i ] = array[ i + offset ];\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\ttoArray: function ( array, offset ) {\n\n\t\t\tif ( array === undefined ) array = [];\n\t\t\tif ( offset === undefined ) offset = 0;\n\n\t\t\tvar te = this.elements;\n\n\t\t\tarray[ offset ] = te[ 0 ];\n\t\t\tarray[ offset + 1 ] = te[ 1 ];\n\t\t\tarray[ offset + 2 ] = te[ 2 ];\n\n\t\t\tarray[ offset + 3 ] = te[ 3 ];\n\t\t\tarray[ offset + 4 ] = te[ 4 ];\n\t\t\tarray[ offset + 5 ] = te[ 5 ];\n\n\t\t\tarray[ offset + 6 ] = te[ 6 ];\n\t\t\tarray[ offset + 7 ] = te[ 7 ];\n\t\t\tarray[ offset + 8 ] = te[ 8 ];\n\n\t\t\treturn array;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author bhouston / http://clara.io\n\t */\n\n\tfunction Plane( normal, constant ) {\n\n\t\t// normal is assumed to be normalized\n\n\t\tthis.normal = ( normal !== undefined ) ? normal : new Vector3( 1, 0, 0 );\n\t\tthis.constant = ( constant !== undefined ) ? constant : 0;\n\n\t}\n\n\tObject.assign( Plane.prototype, {\n\n\t\tset: function ( normal, constant ) {\n\n\t\t\tthis.normal.copy( normal );\n\t\t\tthis.constant = constant;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetComponents: function ( x, y, z, w ) {\n\n\t\t\tthis.normal.set( x, y, z );\n\t\t\tthis.constant = w;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromNormalAndCoplanarPoint: function ( normal, point ) {\n\n\t\t\tthis.normal.copy( normal );\n\t\t\tthis.constant = - point.dot( this.normal );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromCoplanarPoints: function () {\n\n\t\t\tvar v1 = new Vector3();\n\t\t\tvar v2 = new Vector3();\n\n\t\t\treturn function setFromCoplanarPoints( a, b, c ) {\n\n\t\t\t\tvar normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize();\n\n\t\t\t\t// Q: should an error be thrown if normal is zero (e.g. degenerate plane)?\n\n\t\t\t\tthis.setFromNormalAndCoplanarPoint( normal, a );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor().copy( this );\n\n\t\t},\n\n\t\tcopy: function ( plane ) {\n\n\t\t\tthis.normal.copy( plane.normal );\n\t\t\tthis.constant = plane.constant;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tnormalize: function () {\n\n\t\t\t// Note: will lead to a divide by zero if the plane is invalid.\n\n\t\t\tvar inverseNormalLength = 1.0 / this.normal.length();\n\t\t\tthis.normal.multiplyScalar( inverseNormalLength );\n\t\t\tthis.constant *= inverseNormalLength;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tnegate: function () {\n\n\t\t\tthis.constant *= - 1;\n\t\t\tthis.normal.negate();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tdistanceToPoint: function ( point ) {\n\n\t\t\treturn this.normal.dot( point ) + this.constant;\n\n\t\t},\n\n\t\tdistanceToSphere: function ( sphere ) {\n\n\t\t\treturn this.distanceToPoint( sphere.center ) - sphere.radius;\n\n\t\t},\n\n\t\tprojectPoint: function ( point, optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Vector3();\n\n\t\t\treturn result.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point );\n\n\t\t},\n\n\t\tintersectLine: function () {\n\n\t\t\tvar v1 = new Vector3();\n\n\t\t\treturn function intersectLine( line, optionalTarget ) {\n\n\t\t\t\tvar result = optionalTarget || new Vector3();\n\n\t\t\t\tvar direction = line.delta( v1 );\n\n\t\t\t\tvar denominator = this.normal.dot( direction );\n\n\t\t\t\tif ( denominator === 0 ) {\n\n\t\t\t\t\t// line is coplanar, return origin\n\t\t\t\t\tif ( this.distanceToPoint( line.start ) === 0 ) {\n\n\t\t\t\t\t\treturn result.copy( line.start );\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// Unsure if this is the correct method to handle this case.\n\t\t\t\t\treturn undefined;\n\n\t\t\t\t}\n\n\t\t\t\tvar t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;\n\n\t\t\t\tif ( t < 0 || t > 1 ) {\n\n\t\t\t\t\treturn undefined;\n\n\t\t\t\t}\n\n\t\t\t\treturn result.copy( direction ).multiplyScalar( t ).add( line.start );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tintersectsLine: function ( line ) {\n\n\t\t\t// Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.\n\n\t\t\tvar startSign = this.distanceToPoint( line.start );\n\t\t\tvar endSign = this.distanceToPoint( line.end );\n\n\t\t\treturn ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );\n\n\t\t},\n\n\t\tintersectsBox: function ( box ) {\n\n\t\t\treturn box.intersectsPlane( this );\n\n\t\t},\n\n\t\tintersectsSphere: function ( sphere ) {\n\n\t\t\treturn sphere.intersectsPlane( this );\n\n\t\t},\n\n\t\tcoplanarPoint: function ( optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Vector3();\n\n\t\t\treturn result.copy( this.normal ).multiplyScalar( - this.constant );\n\n\t\t},\n\n\t\tapplyMatrix4: function () {\n\n\t\t\tvar v1 = new Vector3();\n\t\t\tvar m1 = new Matrix3();\n\n\t\t\treturn function applyMatrix4( matrix, optionalNormalMatrix ) {\n\n\t\t\t\tvar normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix );\n\n\t\t\t\tvar referencePoint = this.coplanarPoint( v1 ).applyMatrix4( matrix );\n\n\t\t\t\tvar normal = this.normal.applyMatrix3( normalMatrix ).normalize();\n\n\t\t\t\tthis.constant = - referencePoint.dot( normal );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\ttranslate: function ( offset ) {\n\n\t\t\tthis.constant -= offset.dot( this.normal );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tequals: function ( plane ) {\n\n\t\t\treturn plane.normal.equals( this.normal ) && ( plane.constant === this.constant );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author bhouston / http://clara.io\n\t */\n\n\tfunction Frustum( p0, p1, p2, p3, p4, p5 ) {\n\n\t\tthis.planes = [\n\n\t\t\t( p0 !== undefined ) ? p0 : new Plane(),\n\t\t\t( p1 !== undefined ) ? p1 : new Plane(),\n\t\t\t( p2 !== undefined ) ? p2 : new Plane(),\n\t\t\t( p3 !== undefined ) ? p3 : new Plane(),\n\t\t\t( p4 !== undefined ) ? p4 : new Plane(),\n\t\t\t( p5 !== undefined ) ? p5 : new Plane()\n\n\t\t];\n\n\t}\n\n\tObject.assign( Frustum.prototype, {\n\n\t\tset: function ( p0, p1, p2, p3, p4, p5 ) {\n\n\t\t\tvar planes = this.planes;\n\n\t\t\tplanes[ 0 ].copy( p0 );\n\t\t\tplanes[ 1 ].copy( p1 );\n\t\t\tplanes[ 2 ].copy( p2 );\n\t\t\tplanes[ 3 ].copy( p3 );\n\t\t\tplanes[ 4 ].copy( p4 );\n\t\t\tplanes[ 5 ].copy( p5 );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor().copy( this );\n\n\t\t},\n\n\t\tcopy: function ( frustum ) {\n\n\t\t\tvar planes = this.planes;\n\n\t\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\t\tplanes[ i ].copy( frustum.planes[ i ] );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromMatrix: function ( m ) {\n\n\t\t\tvar planes = this.planes;\n\t\t\tvar me = m.elements;\n\t\t\tvar me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];\n\t\t\tvar me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];\n\t\t\tvar me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];\n\t\t\tvar me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];\n\n\t\t\tplanes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();\n\t\t\tplanes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();\n\t\t\tplanes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();\n\t\t\tplanes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();\n\t\t\tplanes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();\n\t\t\tplanes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tintersectsObject: function () {\n\n\t\t\tvar sphere = new Sphere();\n\n\t\t\treturn function intersectsObject( object ) {\n\n\t\t\t\tvar geometry = object.geometry;\n\n\t\t\t\tif ( geometry.boundingSphere === null )\n\t\t\t\t\tgeometry.computeBoundingSphere();\n\n\t\t\t\tsphere.copy( geometry.boundingSphere )\n\t\t\t\t\t.applyMatrix4( object.matrixWorld );\n\n\t\t\t\treturn this.intersectsSphere( sphere );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tintersectsSprite: function () {\n\n\t\t\tvar sphere = new Sphere();\n\n\t\t\treturn function intersectsSprite( sprite ) {\n\n\t\t\t\tsphere.center.set( 0, 0, 0 );\n\t\t\t\tsphere.radius = 0.7071067811865476;\n\t\t\t\tsphere.applyMatrix4( sprite.matrixWorld );\n\n\t\t\t\treturn this.intersectsSphere( sphere );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tintersectsSphere: function ( sphere ) {\n\n\t\t\tvar planes = this.planes;\n\t\t\tvar center = sphere.center;\n\t\t\tvar negRadius = - sphere.radius;\n\n\t\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\t\tvar distance = planes[ i ].distanceToPoint( center );\n\n\t\t\t\tif ( distance < negRadius ) {\n\n\t\t\t\t\treturn false;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn true;\n\n\t\t},\n\n\t\tintersectsBox: function () {\n\n\t\t\tvar p1 = new Vector3(),\n\t\t\t\tp2 = new Vector3();\n\n\t\t\treturn function intersectsBox( box ) {\n\n\t\t\t\tvar planes = this.planes;\n\n\t\t\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\t\t\tvar plane = planes[ i ];\n\n\t\t\t\t\tp1.x = plane.normal.x > 0 ? box.min.x : box.max.x;\n\t\t\t\t\tp2.x = plane.normal.x > 0 ? box.max.x : box.min.x;\n\t\t\t\t\tp1.y = plane.normal.y > 0 ? box.min.y : box.max.y;\n\t\t\t\t\tp2.y = plane.normal.y > 0 ? box.max.y : box.min.y;\n\t\t\t\t\tp1.z = plane.normal.z > 0 ? box.min.z : box.max.z;\n\t\t\t\t\tp2.z = plane.normal.z > 0 ? box.max.z : box.min.z;\n\n\t\t\t\t\tvar d1 = plane.distanceToPoint( p1 );\n\t\t\t\t\tvar d2 = plane.distanceToPoint( p2 );\n\n\t\t\t\t\t// if both outside plane, no intersection\n\n\t\t\t\t\tif ( d1 < 0 && d2 < 0 ) {\n\n\t\t\t\t\t\treturn false;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tcontainsPoint: function ( point ) {\n\n\t\t\tvar planes = this.planes;\n\n\t\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\t\tif ( planes[ i ].distanceToPoint( point ) < 0 ) {\n\n\t\t\t\t\treturn false;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn true;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction WebGLShadowMap( _renderer, _objects, maxTextureSize ) {\n\n\t\tvar _frustum = new Frustum(),\n\t\t\t_projScreenMatrix = new Matrix4(),\n\n\t\t\t_shadowMapSize = new Vector2(),\n\t\t\t_maxShadowMapSize = new Vector2( maxTextureSize, maxTextureSize ),\n\n\t\t\t_lookTarget = new Vector3(),\n\t\t\t_lightPositionWorld = new Vector3(),\n\n\t\t\t_MorphingFlag = 1,\n\t\t\t_SkinningFlag = 2,\n\n\t\t\t_NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1,\n\n\t\t\t_depthMaterials = new Array( _NumberOfMaterialVariants ),\n\t\t\t_distanceMaterials = new Array( _NumberOfMaterialVariants ),\n\n\t\t\t_materialCache = {};\n\n\t\tvar cubeDirections = [\n\t\t\tnew Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),\n\t\t\tnew Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )\n\t\t];\n\n\t\tvar cubeUps = [\n\t\t\tnew Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),\n\t\t\tnew Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ),\tnew Vector3( 0, 0, - 1 )\n\t\t];\n\n\t\tvar cube2DViewPorts = [\n\t\t\tnew Vector4(), new Vector4(), new Vector4(),\n\t\t\tnew Vector4(), new Vector4(), new Vector4()\n\t\t];\n\n\t\t// init\n\n\t\tfor ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) {\n\n\t\t\tvar useMorphing = ( i & _MorphingFlag ) !== 0;\n\t\t\tvar useSkinning = ( i & _SkinningFlag ) !== 0;\n\n\t\t\tvar depthMaterial = new MeshDepthMaterial( {\n\n\t\t\t\tdepthPacking: RGBADepthPacking,\n\n\t\t\t\tmorphTargets: useMorphing,\n\t\t\t\tskinning: useSkinning\n\n\t\t\t} );\n\n\t\t\t_depthMaterials[ i ] = depthMaterial;\n\n\t\t\t//\n\n\t\t\tvar distanceMaterial = new MeshDistanceMaterial( {\n\n\t\t\t\tmorphTargets: useMorphing,\n\t\t\t\tskinning: useSkinning\n\n\t\t\t} );\n\n\t\t\t_distanceMaterials[ i ] = distanceMaterial;\n\n\t\t}\n\n\t\t//\n\n\t\tvar scope = this;\n\n\t\tthis.enabled = false;\n\n\t\tthis.autoUpdate = true;\n\t\tthis.needsUpdate = false;\n\n\t\tthis.type = PCFShadowMap;\n\n\t\tthis.renderReverseSided = true;\n\t\tthis.renderSingleSided = true;\n\n\t\tthis.render = function ( lights, scene, camera ) {\n\n\t\t\tif ( scope.enabled === false ) return;\n\t\t\tif ( scope.autoUpdate === false && scope.needsUpdate === false ) return;\n\n\t\t\tif ( lights.length === 0 ) return;\n\n\t\t\t// TODO Clean up (needed in case of contextlost)\n\t\t\tvar _gl = _renderer.context;\n\t\t\tvar _state = _renderer.state;\n\n\t\t\t// Set GL state for depth map.\n\t\t\t_state.disable( _gl.BLEND );\n\t\t\t_state.buffers.color.setClear( 1, 1, 1, 1 );\n\t\t\t_state.buffers.depth.setTest( true );\n\t\t\t_state.setScissorTest( false );\n\n\t\t\t// render depth map\n\n\t\t\tvar faceCount;\n\n\t\t\tfor ( var i = 0, il = lights.length; i < il; i ++ ) {\n\n\t\t\t\tvar light = lights[ i ];\n\t\t\t\tvar shadow = light.shadow;\n\t\t\t\tvar isPointLight = light && light.isPointLight;\n\n\t\t\t\tif ( shadow === undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );\n\t\t\t\t\tcontinue;\n\n\t\t\t\t}\n\n\t\t\t\tvar shadowCamera = shadow.camera;\n\n\t\t\t\t_shadowMapSize.copy( shadow.mapSize );\n\t\t\t\t_shadowMapSize.min( _maxShadowMapSize );\n\n\t\t\t\tif ( isPointLight ) {\n\n\t\t\t\t\tvar vpWidth = _shadowMapSize.x;\n\t\t\t\t\tvar vpHeight = _shadowMapSize.y;\n\n\t\t\t\t\t// These viewports map a cube-map onto a 2D texture with the\n\t\t\t\t\t// following orientation:\n\t\t\t\t\t//\n\t\t\t\t\t//  xzXZ\n\t\t\t\t\t//   y Y\n\t\t\t\t\t//\n\t\t\t\t\t// X - Positive x direction\n\t\t\t\t\t// x - Negative x direction\n\t\t\t\t\t// Y - Positive y direction\n\t\t\t\t\t// y - Negative y direction\n\t\t\t\t\t// Z - Positive z direction\n\t\t\t\t\t// z - Negative z direction\n\n\t\t\t\t\t// positive X\n\t\t\t\t\tcube2DViewPorts[ 0 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight );\n\t\t\t\t\t// negative X\n\t\t\t\t\tcube2DViewPorts[ 1 ].set( 0, vpHeight, vpWidth, vpHeight );\n\t\t\t\t\t// positive Z\n\t\t\t\t\tcube2DViewPorts[ 2 ].set( vpWidth * 3, vpHeight, vpWidth, vpHeight );\n\t\t\t\t\t// negative Z\n\t\t\t\t\tcube2DViewPorts[ 3 ].set( vpWidth, vpHeight, vpWidth, vpHeight );\n\t\t\t\t\t// positive Y\n\t\t\t\t\tcube2DViewPorts[ 4 ].set( vpWidth * 3, 0, vpWidth, vpHeight );\n\t\t\t\t\t// negative Y\n\t\t\t\t\tcube2DViewPorts[ 5 ].set( vpWidth, 0, vpWidth, vpHeight );\n\n\t\t\t\t\t_shadowMapSize.x *= 4.0;\n\t\t\t\t\t_shadowMapSize.y *= 2.0;\n\n\t\t\t\t}\n\n\t\t\t\tif ( shadow.map === null ) {\n\n\t\t\t\t\tvar pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat };\n\n\t\t\t\t\tshadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );\n\t\t\t\t\tshadow.map.texture.name = light.name + \".shadowMap\";\n\n\t\t\t\t\tshadowCamera.updateProjectionMatrix();\n\n\t\t\t\t}\n\n\t\t\t\tif ( shadow.isSpotLightShadow ) {\n\n\t\t\t\t\tshadow.update( light );\n\n\t\t\t\t}\n\n\t\t\t\tvar shadowMap = shadow.map;\n\t\t\t\tvar shadowMatrix = shadow.matrix;\n\n\t\t\t\t_lightPositionWorld.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\tshadowCamera.position.copy( _lightPositionWorld );\n\n\t\t\t\tif ( isPointLight ) {\n\n\t\t\t\t\tfaceCount = 6;\n\n\t\t\t\t\t// for point lights we set the shadow matrix to be a translation-only matrix\n\t\t\t\t\t// equal to inverse of the light's position\n\n\t\t\t\t\tshadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tfaceCount = 1;\n\n\t\t\t\t\t_lookTarget.setFromMatrixPosition( light.target.matrixWorld );\n\t\t\t\t\tshadowCamera.lookAt( _lookTarget );\n\t\t\t\t\tshadowCamera.updateMatrixWorld();\n\n\t\t\t\t\t// compute shadow matrix\n\n\t\t\t\t\tshadowMatrix.set(\n\t\t\t\t\t\t0.5, 0.0, 0.0, 0.5,\n\t\t\t\t\t\t0.0, 0.5, 0.0, 0.5,\n\t\t\t\t\t\t0.0, 0.0, 0.5, 0.5,\n\t\t\t\t\t\t0.0, 0.0, 0.0, 1.0\n\t\t\t\t\t);\n\n\t\t\t\t\tshadowMatrix.multiply( shadowCamera.projectionMatrix );\n\t\t\t\t\tshadowMatrix.multiply( shadowCamera.matrixWorldInverse );\n\n\t\t\t\t}\n\n\t\t\t\t_renderer.setRenderTarget( shadowMap );\n\t\t\t\t_renderer.clear();\n\n\t\t\t\t// render shadow map for each cube face (if omni-directional) or\n\t\t\t\t// run a single pass if not\n\n\t\t\t\tfor ( var face = 0; face < faceCount; face ++ ) {\n\n\t\t\t\t\tif ( isPointLight ) {\n\n\t\t\t\t\t\t_lookTarget.copy( shadowCamera.position );\n\t\t\t\t\t\t_lookTarget.add( cubeDirections[ face ] );\n\t\t\t\t\t\tshadowCamera.up.copy( cubeUps[ face ] );\n\t\t\t\t\t\tshadowCamera.lookAt( _lookTarget );\n\t\t\t\t\t\tshadowCamera.updateMatrixWorld();\n\n\t\t\t\t\t\tvar vpDimensions = cube2DViewPorts[ face ];\n\t\t\t\t\t\t_state.viewport( vpDimensions );\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// update camera matrices and frustum\n\n\t\t\t\t\t_projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );\n\t\t\t\t\t_frustum.setFromMatrix( _projScreenMatrix );\n\n\t\t\t\t\t// set object matrices & frustum culling\n\n\t\t\t\t\trenderObject( scene, camera, shadowCamera, isPointLight );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tscope.needsUpdate = false;\n\n\t\t};\n\n\t\tfunction getDepthMaterial( object, material, isPointLight, lightPositionWorld, shadowCameraNear, shadowCameraFar ) {\n\n\t\t\tvar geometry = object.geometry;\n\n\t\t\tvar result = null;\n\n\t\t\tvar materialVariants = _depthMaterials;\n\t\t\tvar customMaterial = object.customDepthMaterial;\n\n\t\t\tif ( isPointLight ) {\n\n\t\t\t\tmaterialVariants = _distanceMaterials;\n\t\t\t\tcustomMaterial = object.customDistanceMaterial;\n\n\t\t\t}\n\n\t\t\tif ( ! customMaterial ) {\n\n\t\t\t\tvar useMorphing = false;\n\n\t\t\t\tif ( material.morphTargets ) {\n\n\t\t\t\t\tif ( geometry && geometry.isBufferGeometry ) {\n\n\t\t\t\t\t\tuseMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0;\n\n\t\t\t\t\t} else if ( geometry && geometry.isGeometry ) {\n\n\t\t\t\t\t\tuseMorphing = geometry.morphTargets && geometry.morphTargets.length > 0;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( object.isSkinnedMesh && material.skinning === false ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:', object );\n\n\t\t\t\t}\n\n\t\t\t\tvar useSkinning = object.isSkinnedMesh && material.skinning;\n\n\t\t\t\tvar variantIndex = 0;\n\n\t\t\t\tif ( useMorphing ) variantIndex |= _MorphingFlag;\n\t\t\t\tif ( useSkinning ) variantIndex |= _SkinningFlag;\n\n\t\t\t\tresult = materialVariants[ variantIndex ];\n\n\t\t\t} else {\n\n\t\t\t\tresult = customMaterial;\n\n\t\t\t}\n\n\t\t\tif ( _renderer.localClippingEnabled &&\n\t\t\t\t\tmaterial.clipShadows === true &&\n\t\t\t\t\tmaterial.clippingPlanes.length !== 0 ) {\n\n\t\t\t\t// in this case we need a unique material instance reflecting the\n\t\t\t\t// appropriate state\n\n\t\t\t\tvar keyA = result.uuid, keyB = material.uuid;\n\n\t\t\t\tvar materialsForVariant = _materialCache[ keyA ];\n\n\t\t\t\tif ( materialsForVariant === undefined ) {\n\n\t\t\t\t\tmaterialsForVariant = {};\n\t\t\t\t\t_materialCache[ keyA ] = materialsForVariant;\n\n\t\t\t\t}\n\n\t\t\t\tvar cachedMaterial = materialsForVariant[ keyB ];\n\n\t\t\t\tif ( cachedMaterial === undefined ) {\n\n\t\t\t\t\tcachedMaterial = result.clone();\n\t\t\t\t\tmaterialsForVariant[ keyB ] = cachedMaterial;\n\n\t\t\t\t}\n\n\t\t\t\tresult = cachedMaterial;\n\n\t\t\t}\n\n\t\t\tresult.visible = material.visible;\n\t\t\tresult.wireframe = material.wireframe;\n\n\t\t\tvar side = material.side;\n\n\t\t\tif ( scope.renderSingleSided && side == DoubleSide ) {\n\n\t\t\t\tside = FrontSide;\n\n\t\t\t}\n\n\t\t\tif ( scope.renderReverseSided ) {\n\n\t\t\t\tif ( side === FrontSide ) side = BackSide;\n\t\t\t\telse if ( side === BackSide ) side = FrontSide;\n\n\t\t\t}\n\n\t\t\tresult.side = side;\n\n\t\t\tresult.clipShadows = material.clipShadows;\n\t\t\tresult.clippingPlanes = material.clippingPlanes;\n\t\t\tresult.clipIntersection = material.clipIntersection;\n\n\t\t\tresult.wireframeLinewidth = material.wireframeLinewidth;\n\t\t\tresult.linewidth = material.linewidth;\n\n\t\t\tif ( isPointLight && result.isMeshDistanceMaterial ) {\n\n\t\t\t\tresult.referencePosition.copy( lightPositionWorld );\n\t\t\t\tresult.nearDistance = shadowCameraNear;\n\t\t\t\tresult.farDistance = shadowCameraFar;\n\n\t\t\t}\n\n\t\t\treturn result;\n\n\t\t}\n\n\t\tfunction renderObject( object, camera, shadowCamera, isPointLight ) {\n\n\t\t\tif ( object.visible === false ) return;\n\n\t\t\tvar visible = object.layers.test( camera.layers );\n\n\t\t\tif ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {\n\n\t\t\t\tif ( object.castShadow && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {\n\n\t\t\t\t\tobject.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );\n\n\t\t\t\t\tvar geometry = _objects.update( object );\n\t\t\t\t\tvar material = object.material;\n\n\t\t\t\t\tif ( Array.isArray( material ) ) {\n\n\t\t\t\t\t\tvar groups = geometry.groups;\n\n\t\t\t\t\t\tfor ( var k = 0, kl = groups.length; k < kl; k ++ ) {\n\n\t\t\t\t\t\t\tvar group = groups[ k ];\n\t\t\t\t\t\t\tvar groupMaterial = material[ group.materialIndex ];\n\n\t\t\t\t\t\t\tif ( groupMaterial && groupMaterial.visible ) {\n\n\t\t\t\t\t\t\t\tvar depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far );\n\t\t\t\t\t\t\t\t_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else if ( material.visible ) {\n\n\t\t\t\t\t\tvar depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far );\n\t\t\t\t\t\t_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tvar children = object.children;\n\n\t\t\tfor ( var i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\t\trenderObject( children[ i ], camera, shadowCamera, isPointLight );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction WebGLAttributes( gl ) {\n\n\t\tvar buffers = {};\n\n\t\tfunction createBuffer( attribute, bufferType ) {\n\n\t\t\tvar array = attribute.array;\n\t\t\tvar usage = attribute.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW;\n\n\t\t\tvar buffer = gl.createBuffer();\n\n\t\t\tgl.bindBuffer( bufferType, buffer );\n\t\t\tgl.bufferData( bufferType, array, usage );\n\n\t\t\tattribute.onUploadCallback();\n\n\t\t\tvar type = gl.FLOAT;\n\n\t\t\tif ( array instanceof Float32Array ) {\n\n\t\t\t\ttype = gl.FLOAT;\n\n\t\t\t} else if ( array instanceof Float64Array ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.' );\n\n\t\t\t} else if ( array instanceof Uint16Array ) {\n\n\t\t\t\ttype = gl.UNSIGNED_SHORT;\n\n\t\t\t} else if ( array instanceof Int16Array ) {\n\n\t\t\t\ttype = gl.SHORT;\n\n\t\t\t} else if ( array instanceof Uint32Array ) {\n\n\t\t\t\ttype = gl.UNSIGNED_INT;\n\n\t\t\t} else if ( array instanceof Int32Array ) {\n\n\t\t\t\ttype = gl.INT;\n\n\t\t\t} else if ( array instanceof Int8Array ) {\n\n\t\t\t\ttype = gl.BYTE;\n\n\t\t\t} else if ( array instanceof Uint8Array ) {\n\n\t\t\t\ttype = gl.UNSIGNED_BYTE;\n\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tbuffer: buffer,\n\t\t\t\ttype: type,\n\t\t\t\tbytesPerElement: array.BYTES_PER_ELEMENT,\n\t\t\t\tversion: attribute.version\n\t\t\t};\n\n\t\t}\n\n\t\tfunction updateBuffer( buffer, attribute, bufferType ) {\n\n\t\t\tvar array = attribute.array;\n\t\t\tvar updateRange = attribute.updateRange;\n\n\t\t\tgl.bindBuffer( bufferType, buffer );\n\n\t\t\tif ( attribute.dynamic === false ) {\n\n\t\t\t\tgl.bufferData( bufferType, array, gl.STATIC_DRAW );\n\n\t\t\t} else if ( updateRange.count === - 1 ) {\n\n\t\t\t\t// Not using update ranges\n\n\t\t\t\tgl.bufferSubData( bufferType, 0, array );\n\n\t\t\t} else if ( updateRange.count === 0 ) {\n\n\t\t\t\tconsole.error( 'THREE.WebGLObjects.updateBuffer: dynamic THREE.BufferAttribute marked as needsUpdate but updateRange.count is 0, ensure you are using set methods or updating manually.' );\n\n\t\t\t} else {\n\n\t\t\t\tgl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,\n\t\t\t\t\tarray.subarray( updateRange.offset, updateRange.offset + updateRange.count ) );\n\n\t\t\t\tupdateRange.count = -1; // reset range\n\n\t\t\t}\n\n\t\t}\n\n\t\t//\n\n\t\tfunction get( attribute ) {\n\n\t\t\tif ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;\n\n\t\t\treturn buffers[ attribute.uuid ];\n\n\t\t}\n\n\t\tfunction remove( attribute ) {\n\n\t\t\tif ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;\n\t\t\t\n\t\t\tvar data = buffers[ attribute.uuid ];\n\n\t\t\tif ( data ) {\n\n\t\t\t\tgl.deleteBuffer( data.buffer );\n\n\t\t\t\tdelete buffers[ attribute.uuid ];\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction update( attribute, bufferType ) {\n\n\t\t\tif ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;\n\n\t\t\tvar data = buffers[ attribute.uuid ];\n\n\t\t\tif ( data === undefined ) {\n\n\t\t\t\tbuffers[ attribute.uuid ] = createBuffer( attribute, bufferType );\n\n\t\t\t} else if ( data.version < attribute.version ) {\n\n\t\t\t\tupdateBuffer( data.buffer, attribute, bufferType );\n\n\t\t\t\tdata.version = attribute.version;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn {\n\n\t\t\tget: get,\n\t\t\tremove: remove,\n\t\t\tupdate: update\n\n\t\t};\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author WestLangley / http://github.com/WestLangley\n\t * @author bhouston / http://clara.io\n\t */\n\n\tfunction Euler( x, y, z, order ) {\n\n\t\tthis._x = x || 0;\n\t\tthis._y = y || 0;\n\t\tthis._z = z || 0;\n\t\tthis._order = order || Euler.DefaultOrder;\n\n\t}\n\n\tEuler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];\n\n\tEuler.DefaultOrder = 'XYZ';\n\n\tObject.defineProperties( Euler.prototype, {\n\n\t\tx: {\n\n\t\t\tget: function () {\n\n\t\t\t\treturn this._x;\n\n\t\t\t},\n\n\t\t\tset: function ( value ) {\n\n\t\t\t\tthis._x = value;\n\t\t\t\tthis.onChangeCallback();\n\n\t\t\t}\n\n\t\t},\n\n\t\ty: {\n\n\t\t\tget: function () {\n\n\t\t\t\treturn this._y;\n\n\t\t\t},\n\n\t\t\tset: function ( value ) {\n\n\t\t\t\tthis._y = value;\n\t\t\t\tthis.onChangeCallback();\n\n\t\t\t}\n\n\t\t},\n\n\t\tz: {\n\n\t\t\tget: function () {\n\n\t\t\t\treturn this._z;\n\n\t\t\t},\n\n\t\t\tset: function ( value ) {\n\n\t\t\t\tthis._z = value;\n\t\t\t\tthis.onChangeCallback();\n\n\t\t\t}\n\n\t\t},\n\n\t\torder: {\n\n\t\t\tget: function () {\n\n\t\t\t\treturn this._order;\n\n\t\t\t},\n\n\t\t\tset: function ( value ) {\n\n\t\t\t\tthis._order = value;\n\t\t\t\tthis.onChangeCallback();\n\n\t\t\t}\n\n\t\t}\n\n\t} );\n\n\tObject.assign( Euler.prototype, {\n\n\t\tisEuler: true,\n\n\t\tset: function ( x, y, z, order ) {\n\n\t\t\tthis._x = x;\n\t\t\tthis._y = y;\n\t\t\tthis._z = z;\n\t\t\tthis._order = order || this._order;\n\n\t\t\tthis.onChangeCallback();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor( this._x, this._y, this._z, this._order );\n\n\t\t},\n\n\t\tcopy: function ( euler ) {\n\n\t\t\tthis._x = euler._x;\n\t\t\tthis._y = euler._y;\n\t\t\tthis._z = euler._z;\n\t\t\tthis._order = euler._order;\n\n\t\t\tthis.onChangeCallback();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromRotationMatrix: function ( m, order, update ) {\n\n\t\t\tvar clamp = _Math.clamp;\n\n\t\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\n\n\t\t\tvar te = m.elements;\n\t\t\tvar m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];\n\t\t\tvar m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];\n\t\t\tvar m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];\n\n\t\t\torder = order || this._order;\n\n\t\t\tif ( order === 'XYZ' ) {\n\n\t\t\t\tthis._y = Math.asin( clamp( m13, - 1, 1 ) );\n\n\t\t\t\tif ( Math.abs( m13 ) < 0.99999 ) {\n\n\t\t\t\t\tthis._x = Math.atan2( - m23, m33 );\n\t\t\t\t\tthis._z = Math.atan2( - m12, m11 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis._x = Math.atan2( m32, m22 );\n\t\t\t\t\tthis._z = 0;\n\n\t\t\t\t}\n\n\t\t\t} else if ( order === 'YXZ' ) {\n\n\t\t\t\tthis._x = Math.asin( - clamp( m23, - 1, 1 ) );\n\n\t\t\t\tif ( Math.abs( m23 ) < 0.99999 ) {\n\n\t\t\t\t\tthis._y = Math.atan2( m13, m33 );\n\t\t\t\t\tthis._z = Math.atan2( m21, m22 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis._y = Math.atan2( - m31, m11 );\n\t\t\t\t\tthis._z = 0;\n\n\t\t\t\t}\n\n\t\t\t} else if ( order === 'ZXY' ) {\n\n\t\t\t\tthis._x = Math.asin( clamp( m32, - 1, 1 ) );\n\n\t\t\t\tif ( Math.abs( m32 ) < 0.99999 ) {\n\n\t\t\t\t\tthis._y = Math.atan2( - m31, m33 );\n\t\t\t\t\tthis._z = Math.atan2( - m12, m22 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis._y = 0;\n\t\t\t\t\tthis._z = Math.atan2( m21, m11 );\n\n\t\t\t\t}\n\n\t\t\t} else if ( order === 'ZYX' ) {\n\n\t\t\t\tthis._y = Math.asin( - clamp( m31, - 1, 1 ) );\n\n\t\t\t\tif ( Math.abs( m31 ) < 0.99999 ) {\n\n\t\t\t\t\tthis._x = Math.atan2( m32, m33 );\n\t\t\t\t\tthis._z = Math.atan2( m21, m11 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis._x = 0;\n\t\t\t\t\tthis._z = Math.atan2( - m12, m22 );\n\n\t\t\t\t}\n\n\t\t\t} else if ( order === 'YZX' ) {\n\n\t\t\t\tthis._z = Math.asin( clamp( m21, - 1, 1 ) );\n\n\t\t\t\tif ( Math.abs( m21 ) < 0.99999 ) {\n\n\t\t\t\t\tthis._x = Math.atan2( - m23, m22 );\n\t\t\t\t\tthis._y = Math.atan2( - m31, m11 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis._x = 0;\n\t\t\t\t\tthis._y = Math.atan2( m13, m33 );\n\n\t\t\t\t}\n\n\t\t\t} else if ( order === 'XZY' ) {\n\n\t\t\t\tthis._z = Math.asin( - clamp( m12, - 1, 1 ) );\n\n\t\t\t\tif ( Math.abs( m12 ) < 0.99999 ) {\n\n\t\t\t\t\tthis._x = Math.atan2( m32, m22 );\n\t\t\t\t\tthis._y = Math.atan2( m13, m11 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis._x = Math.atan2( - m23, m33 );\n\t\t\t\t\tthis._y = 0;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order );\n\n\t\t\t}\n\n\t\t\tthis._order = order;\n\n\t\t\tif ( update !== false ) this.onChangeCallback();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromQuaternion: function () {\n\n\t\t\tvar matrix = new Matrix4();\n\n\t\t\treturn function setFromQuaternion( q, order, update ) {\n\n\t\t\t\tmatrix.makeRotationFromQuaternion( q );\n\n\t\t\t\treturn this.setFromRotationMatrix( matrix, order, update );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tsetFromVector3: function ( v, order ) {\n\n\t\t\treturn this.set( v.x, v.y, v.z, order || this._order );\n\n\t\t},\n\n\t\treorder: function () {\n\n\t\t\t// WARNING: this discards revolution information -bhouston\n\n\t\t\tvar q = new Quaternion();\n\n\t\t\treturn function reorder( newOrder ) {\n\n\t\t\t\tq.setFromEuler( this );\n\n\t\t\t\treturn this.setFromQuaternion( q, newOrder );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tequals: function ( euler ) {\n\n\t\t\treturn ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );\n\n\t\t},\n\n\t\tfromArray: function ( array ) {\n\n\t\t\tthis._x = array[ 0 ];\n\t\t\tthis._y = array[ 1 ];\n\t\t\tthis._z = array[ 2 ];\n\t\t\tif ( array[ 3 ] !== undefined ) this._order = array[ 3 ];\n\n\t\t\tthis.onChangeCallback();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\ttoArray: function ( array, offset ) {\n\n\t\t\tif ( array === undefined ) array = [];\n\t\t\tif ( offset === undefined ) offset = 0;\n\n\t\t\tarray[ offset ] = this._x;\n\t\t\tarray[ offset + 1 ] = this._y;\n\t\t\tarray[ offset + 2 ] = this._z;\n\t\t\tarray[ offset + 3 ] = this._order;\n\n\t\t\treturn array;\n\n\t\t},\n\n\t\ttoVector3: function ( optionalResult ) {\n\n\t\t\tif ( optionalResult ) {\n\n\t\t\t\treturn optionalResult.set( this._x, this._y, this._z );\n\n\t\t\t} else {\n\n\t\t\t\treturn new Vector3( this._x, this._y, this._z );\n\n\t\t\t}\n\n\t\t},\n\n\t\tonChange: function ( callback ) {\n\n\t\t\tthis.onChangeCallback = callback;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tonChangeCallback: function () {}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction Layers() {\n\n\t\tthis.mask = 1 | 0;\n\n\t}\n\n\tObject.assign( Layers.prototype, {\n\n\t\tset: function ( channel ) {\n\n\t\t\tthis.mask = 1 << channel | 0;\n\n\t\t},\n\n\t\tenable: function ( channel ) {\n\n\t\t\tthis.mask |= 1 << channel | 0;\n\n\t\t},\n\n\t\ttoggle: function ( channel ) {\n\n\t\t\tthis.mask ^= 1 << channel | 0;\n\n\t\t},\n\n\t\tdisable: function ( channel ) {\n\n\t\t\tthis.mask &= ~ ( 1 << channel | 0 );\n\n\t\t},\n\n\t\ttest: function ( layers ) {\n\n\t\t\treturn ( this.mask & layers.mask ) !== 0;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author mikael emtinger / http://gomo.se/\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author WestLangley / http://github.com/WestLangley\n\t * @author elephantatwork / www.elephantatwork.ch\n\t */\n\n\tvar object3DId = 0;\n\n\tfunction Object3D() {\n\n\t\tObject.defineProperty( this, 'id', { value: object3DId ++ } );\n\n\t\tthis.uuid = _Math.generateUUID();\n\n\t\tthis.name = '';\n\t\tthis.type = 'Object3D';\n\n\t\tthis.parent = null;\n\t\tthis.children = [];\n\n\t\tthis.up = Object3D.DefaultUp.clone();\n\n\t\tvar position = new Vector3();\n\t\tvar rotation = new Euler();\n\t\tvar quaternion = new Quaternion();\n\t\tvar scale = new Vector3( 1, 1, 1 );\n\n\t\tfunction onRotationChange() {\n\n\t\t\tquaternion.setFromEuler( rotation, false );\n\n\t\t}\n\n\t\tfunction onQuaternionChange() {\n\n\t\t\trotation.setFromQuaternion( quaternion, undefined, false );\n\n\t\t}\n\n\t\trotation.onChange( onRotationChange );\n\t\tquaternion.onChange( onQuaternionChange );\n\n\t\tObject.defineProperties( this, {\n\t\t\tposition: {\n\t\t\t\tenumerable: true,\n\t\t\t\tvalue: position\n\t\t\t},\n\t\t\trotation: {\n\t\t\t\tenumerable: true,\n\t\t\t\tvalue: rotation\n\t\t\t},\n\t\t\tquaternion: {\n\t\t\t\tenumerable: true,\n\t\t\t\tvalue: quaternion\n\t\t\t},\n\t\t\tscale: {\n\t\t\t\tenumerable: true,\n\t\t\t\tvalue: scale\n\t\t\t},\n\t\t\tmodelViewMatrix: {\n\t\t\t\tvalue: new Matrix4()\n\t\t\t},\n\t\t\tnormalMatrix: {\n\t\t\t\tvalue: new Matrix3()\n\t\t\t}\n\t\t} );\n\n\t\tthis.matrix = new Matrix4();\n\t\tthis.matrixWorld = new Matrix4();\n\n\t\tthis.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;\n\t\tthis.matrixWorldNeedsUpdate = false;\n\n\t\tthis.layers = new Layers();\n\t\tthis.visible = true;\n\n\t\tthis.castShadow = false;\n\t\tthis.receiveShadow = false;\n\n\t\tthis.frustumCulled = false;\n\t\tthis.renderOrder = 0;\n\n\t\tthis.userData = {};\n\t}\n\n\tObject3D.DefaultUp = new Vector3( 0, 1, 0 );\n\tObject3D.DefaultMatrixAutoUpdate = true;\n\n\tObject.assign( Object3D.prototype, EventDispatcher.prototype, {\n\n\t\tisObject3D: true,\n\n\t\tonBeforeRender: function () {},\n\t\tonAfterRender: function () {},\n\n\t\tapplyMatrix: function ( matrix ) {\n\n\t\t\tthis.matrix.multiplyMatrices( matrix, this.matrix );\n\n\t\t\tthis.matrix.decompose( this.position, this.quaternion, this.scale );\n\n\t\t},\n\n\t\tapplyQuaternion: function ( q ) {\n\n\t\t\tthis.quaternion.premultiply( q );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetRotationFromAxisAngle: function ( axis, angle ) {\n\n\t\t\t// assumes axis is normalized\n\n\t\t\tthis.quaternion.setFromAxisAngle( axis, angle );\n\n\t\t},\n\n\t\tsetRotationFromEuler: function ( euler ) {\n\n\t\t\tthis.quaternion.setFromEuler( euler, true );\n\n\t\t},\n\n\t\tsetRotationFromMatrix: function ( m ) {\n\n\t\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\n\n\t\t\tthis.quaternion.setFromRotationMatrix( m );\n\n\t\t},\n\n\t\tsetRotationFromQuaternion: function ( q ) {\n\n\t\t\t// assumes q is normalized\n\n\t\t\tthis.quaternion.copy( q );\n\n\t\t},\n\n\t\trotateOnAxis: function () {\n\n\t\t\t// rotate object on axis in object space\n\t\t\t// axis is assumed to be normalized\n\n\t\t\tvar q1 = new Quaternion();\n\n\t\t\treturn function rotateOnAxis( axis, angle ) {\n\n\t\t\t\tq1.setFromAxisAngle( axis, angle );\n\n\t\t\t\tthis.quaternion.multiply( q1 );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\trotateX: function () {\n\n\t\t\tvar v1 = new Vector3( 1, 0, 0 );\n\n\t\t\treturn function rotateX( angle ) {\n\n\t\t\t\treturn this.rotateOnAxis( v1, angle );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\trotateY: function () {\n\n\t\t\tvar v1 = new Vector3( 0, 1, 0 );\n\n\t\t\treturn function rotateY( angle ) {\n\n\t\t\t\treturn this.rotateOnAxis( v1, angle );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\trotateZ: function () {\n\n\t\t\tvar v1 = new Vector3( 0, 0, 1 );\n\n\t\t\treturn function rotateZ( angle ) {\n\n\t\t\t\treturn this.rotateOnAxis( v1, angle );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\ttranslateOnAxis: function () {\n\n\t\t\t// translate object by distance along axis in object space\n\t\t\t// axis is assumed to be normalized\n\n\t\t\tvar v1 = new Vector3();\n\n\t\t\treturn function translateOnAxis( axis, distance ) {\n\n\t\t\t\tv1.copy( axis ).applyQuaternion( this.quaternion );\n\n\t\t\t\tthis.position.add( v1.multiplyScalar( distance ) );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\ttranslateX: function () {\n\n\t\t\tvar v1 = new Vector3( 1, 0, 0 );\n\n\t\t\treturn function translateX( distance ) {\n\n\t\t\t\treturn this.translateOnAxis( v1, distance );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\ttranslateY: function () {\n\n\t\t\tvar v1 = new Vector3( 0, 1, 0 );\n\n\t\t\treturn function translateY( distance ) {\n\n\t\t\t\treturn this.translateOnAxis( v1, distance );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\ttranslateZ: function () {\n\n\t\t\tvar v1 = new Vector3( 0, 0, 1 );\n\n\t\t\treturn function translateZ( distance ) {\n\n\t\t\t\treturn this.translateOnAxis( v1, distance );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tlocalToWorld: function ( vector ) {\n\n\t\t\treturn vector.applyMatrix4( this.matrixWorld );\n\n\t\t},\n\n\t\tworldToLocal: function () {\n\n\t\t\tvar m1 = new Matrix4();\n\n\t\t\treturn function worldToLocal( vector ) {\n\n\t\t\t\treturn vector.applyMatrix4( m1.getInverse( this.matrixWorld ) );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tlookAt: function () {\n\n\t\t\t// This method does not support objects with rotated and/or translated parent(s)\n\n\t\t\tvar m1 = new Matrix4();\n\n\t\t\treturn function lookAt( vector ) {\n\n\t\t\t\tif ( this.isCamera ) {\n\n\t\t\t\t\tm1.lookAt( this.position, vector, this.up );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tm1.lookAt( vector, this.position, this.up );\n\n\t\t\t\t}\n\n\t\t\t\tthis.quaternion.setFromRotationMatrix( m1 );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tadd: function ( object ) {\n\n\t\t\tif ( arguments.length > 1 ) {\n\n\t\t\t\tfor ( var i = 0; i < arguments.length; i ++ ) {\n\n\t\t\t\t\tthis.add( arguments[ i ] );\n\n\t\t\t\t}\n\n\t\t\t\treturn this;\n\n\t\t\t}\n\n\t\t\tif ( object === this ) {\n\n\t\t\t\tconsole.error( \"THREE.Object3D.add: object can't be added as a child of itself.\", object );\n\t\t\t\treturn this;\n\n\t\t\t}\n\n\t\t\tif ( ( object && object.isObject3D ) ) {\n\n\t\t\t\tif ( object.parent !== null ) {\n\n\t\t\t\t\tobject.parent.remove( object );\n\n\t\t\t\t}\n\n\t\t\t\tobject.parent = this;\n\t\t\t\tobject.dispatchEvent( { type: 'added' } );\n\n\t\t\t\tthis.children.push( object );\n\n\t\t\t} else {\n\n\t\t\t\tconsole.error( \"THREE.Object3D.add: object not an instance of THREE.Object3D.\", object );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tremove: function ( object ) {\n\n\t\t\tif ( arguments.length > 1 ) {\n\n\t\t\t\tfor ( var i = 0; i < arguments.length; i ++ ) {\n\n\t\t\t\t\tthis.remove( arguments[ i ] );\n\n\t\t\t\t}\n\n\t\t\t\treturn this;\n\n\t\t\t}\n\n\t\t\tvar index = this.children.indexOf( object );\n\n\t\t\tif ( index !== - 1 ) {\n\n\t\t\t\tobject.parent = null;\n\n\t\t\t\tobject.dispatchEvent( { type: 'removed' } );\n\n\t\t\t\tthis.children.splice( index, 1 );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetObjectById: function ( id ) {\n\n\t\t\treturn this.getObjectByProperty( 'id', id );\n\n\t\t},\n\n\t\tgetObjectByName: function ( name ) {\n\n\t\t\treturn this.getObjectByProperty( 'name', name );\n\n\t\t},\n\n\t\tgetObjectByProperty: function ( name, value ) {\n\n\t\t\tif ( this[ name ] === value ) return this;\n\n\t\t\tfor ( var i = 0, l = this.children.length; i < l; i ++ ) {\n\n\t\t\t\tvar child = this.children[ i ];\n\t\t\t\tvar object = child.getObjectByProperty( name, value );\n\n\t\t\t\tif ( object !== undefined ) {\n\n\t\t\t\t\treturn object;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn undefined;\n\n\t\t},\n\n\t\tgetWorldPosition: function ( optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Vector3();\n\n\t\t\tthis.updateMatrixWorld( true );\n\n\t\t\treturn result.setFromMatrixPosition( this.matrixWorld );\n\n\t\t},\n\n\t\tgetWorldQuaternion: function () {\n\n\t\t\tvar position = new Vector3();\n\t\t\tvar scale = new Vector3();\n\n\t\t\treturn function getWorldQuaternion( optionalTarget ) {\n\n\t\t\t\tvar result = optionalTarget || new Quaternion();\n\n\t\t\t\tthis.updateMatrixWorld( true );\n\n\t\t\t\tthis.matrixWorld.decompose( position, result, scale );\n\n\t\t\t\treturn result;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tgetWorldRotation: function () {\n\n\t\t\tvar quaternion = new Quaternion();\n\n\t\t\treturn function getWorldRotation( optionalTarget ) {\n\n\t\t\t\tvar result = optionalTarget || new Euler();\n\n\t\t\t\tthis.getWorldQuaternion( quaternion );\n\n\t\t\t\treturn result.setFromQuaternion( quaternion, this.rotation.order, false );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tgetWorldScale: function () {\n\n\t\t\tvar position = new Vector3();\n\t\t\tvar quaternion = new Quaternion();\n\n\t\t\treturn function getWorldScale( optionalTarget ) {\n\n\t\t\t\tvar result = optionalTarget || new Vector3();\n\n\t\t\t\tthis.updateMatrixWorld( true );\n\n\t\t\t\tthis.matrixWorld.decompose( position, quaternion, result );\n\n\t\t\t\treturn result;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tgetWorldDirection: function () {\n\n\t\t\tvar quaternion = new Quaternion();\n\n\t\t\treturn function getWorldDirection( optionalTarget ) {\n\n\t\t\t\tvar result = optionalTarget || new Vector3();\n\n\t\t\t\tthis.getWorldQuaternion( quaternion );\n\n\t\t\t\treturn result.set( 0, 0, 1 ).applyQuaternion( quaternion );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\traycast: function () {},\n\n\t\ttraverse: function ( callback ) {\n\n\t\t\tcallback( this );\n\n\t\t\tvar children = this.children;\n\n\t\t\tfor ( var i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\t\tchildren[ i ].traverse( callback );\n\n\t\t\t}\n\n\t\t},\n\n\t\ttraverseVisible: function ( callback ) {\n\n\t\t\tif ( this.visible === false ) return;\n\n\t\t\tcallback( this );\n\n\t\t\tvar children = this.children;\n\n\t\t\tfor ( var i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\t\tchildren[ i ].traverseVisible( callback );\n\n\t\t\t}\n\n\t\t},\n\n\t\ttraverseAncestors: function ( callback ) {\n\n\t\t\tvar parent = this.parent;\n\n\t\t\tif ( parent !== null ) {\n\n\t\t\t\tcallback( parent );\n\n\t\t\t\tparent.traverseAncestors( callback );\n\n\t\t\t}\n\n\t\t},\n\n\t\tupdateMatrix: function () {\n\n\t\t\tthis.matrix.compose( this.position, this.quaternion, this.scale );\n\n\t\t\tthis.matrixWorldNeedsUpdate = true;\n\n\t\t},\n\n\t\tupdateMatrixWorld: function ( force ) {\n\n\t\t\tif ( this.matrixAutoUpdate ) this.updateMatrix();\n\n\t\t\tif ( this.matrixWorldNeedsUpdate || force ) {\n\n\t\t\t\tif ( this.parent === null ) {\n\n\t\t\t\t\tthis.matrixWorld.copy( this.matrix );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );\n\n\t\t\t\t}\n\n\t\t\t\tthis.matrixWorldNeedsUpdate = false;\n\n\t\t\t\tforce = true;\n\n\t\t\t}\n\n\t\t\t// update children\n\n\t\t\tvar children = this.children;\n\n\t\t\tfor ( var i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\t\tchildren[ i ].updateMatrixWorld( force );\n\n\t\t\t}\n\n\t\t},\n\n\t\ttoJSON: function ( meta ) {\n\n\t\t\t// meta is '' when called from JSON.stringify\n\t\t\tvar isRootObject = ( meta === undefined || meta === '' );\n\n\t\t\tvar output = {};\n\n\t\t\t// meta is a hash used to collect geometries, materials.\n\t\t\t// not providing it implies that this is the root object\n\t\t\t// being serialized.\n\t\t\tif ( isRootObject ) {\n\n\t\t\t\t// initialize meta obj\n\t\t\t\tmeta = {\n\t\t\t\t\tgeometries: {},\n\t\t\t\t\tmaterials: {},\n\t\t\t\t\ttextures: {},\n\t\t\t\t\timages: {}\n\t\t\t\t};\n\n\t\t\t\toutput.metadata = {\n\t\t\t\t\tversion: 4.5,\n\t\t\t\t\ttype: 'Object',\n\t\t\t\t\tgenerator: 'Object3D.toJSON'\n\t\t\t\t};\n\n\t\t\t}\n\n\t\t\t// standard Object3D serialization\n\n\t\t\tvar object = {};\n\n\t\t\tobject.uuid = this.uuid;\n\t\t\tobject.type = this.type;\n\n\t\t\tif ( this.name !== '' ) object.name = this.name;\n\t\t\tif ( this.castShadow === true ) object.castShadow = true;\n\t\t\tif ( this.receiveShadow === true ) object.receiveShadow = true;\n\t\t\tif ( this.visible === false ) object.visible = false;\n\t\t\tif ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData;\n\n\t\t\tobject.matrix = this.matrix.toArray();\n\n\t\t\t//\n\n\t\t\tfunction serialize( library, element ) {\n\n\t\t\t\tif ( library[ element.uuid ] === undefined ) {\n\n\t\t\t\t\tlibrary[ element.uuid ] = element.toJSON( meta );\n\n\t\t\t\t}\n\n\t\t\t\treturn element.uuid;\n\n\t\t\t}\n\n\t\t\tif ( this.geometry !== undefined ) {\n\n\t\t\t\tobject.geometry = serialize( meta.geometries, this.geometry );\n\n\t\t\t}\n\n\t\t\tif ( this.material !== undefined ) {\n\n\t\t\t\tif ( Array.isArray( this.material ) ) {\n\n\t\t\t\t\tvar uuids = [];\n\n\t\t\t\t\tfor ( var i = 0, l = this.material.length; i < l; i ++ ) {\n\n\t\t\t\t\t\tuuids.push( serialize( meta.materials, this.material[ i ] ) );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tobject.material = uuids;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tobject.material = serialize( meta.materials, this.material );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tif ( this.children.length > 0 ) {\n\n\t\t\t\tobject.children = [];\n\n\t\t\t\tfor ( var i = 0; i < this.children.length; i ++ ) {\n\n\t\t\t\t\tobject.children.push( this.children[ i ].toJSON( meta ).object );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( isRootObject ) {\n\n\t\t\t\tvar geometries = extractFromCache( meta.geometries );\n\t\t\t\tvar materials = extractFromCache( meta.materials );\n\t\t\t\tvar textures = extractFromCache( meta.textures );\n\t\t\t\tvar images = extractFromCache( meta.images );\n\n\t\t\t\tif ( geometries.length > 0 ) output.geometries = geometries;\n\t\t\t\tif ( materials.length > 0 ) output.materials = materials;\n\t\t\t\tif ( textures.length > 0 ) output.textures = textures;\n\t\t\t\tif ( images.length > 0 ) output.images = images;\n\n\t\t\t}\n\n\t\t\toutput.object = object;\n\n\t\t\treturn output;\n\n\t\t\t// extract data from the cache hash\n\t\t\t// remove metadata on each item\n\t\t\t// and return as array\n\t\t\tfunction extractFromCache( cache ) {\n\n\t\t\t\tvar values = [];\n\t\t\t\tfor ( var key in cache ) {\n\n\t\t\t\t\tvar data = cache[ key ];\n\t\t\t\t\tdelete data.metadata;\n\t\t\t\t\tvalues.push( data );\n\n\t\t\t\t}\n\t\t\t\treturn values;\n\n\t\t\t}\n\n\t\t},\n\n\t\tclone: function ( recursive ) {\n\n\t\t\treturn new this.constructor().copy( this, recursive );\n\n\t\t},\n\n\t\tcopy: function ( source, recursive ) {\n\n\t\t\tif ( recursive === undefined ) recursive = true;\n\n\t\t\tthis.name = source.name;\n\n\t\t\tthis.up.copy( source.up );\n\n\t\t\tthis.position.copy( source.position );\n\t\t\tthis.quaternion.copy( source.quaternion );\n\t\t\tthis.scale.copy( source.scale );\n\n\t\t\tthis.matrix.copy( source.matrix );\n\t\t\tthis.matrixWorld.copy( source.matrixWorld );\n\n\t\t\tthis.matrixAutoUpdate = source.matrixAutoUpdate;\n\t\t\tthis.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;\n\n\t\t\tthis.layers.mask = source.layers.mask;\n\t\t\tthis.visible = source.visible;\n\n\t\t\tthis.castShadow = source.castShadow;\n\t\t\tthis.receiveShadow = source.receiveShadow;\n\n\t\t\tthis.frustumCulled = source.frustumCulled;\n\t\t\tthis.renderOrder = source.renderOrder;\n\n\t\t\tthis.userData = JSON.parse( JSON.stringify( source.userData ) );\n\n\t\t\tif ( recursive === true ) {\n\n\t\t\t\tfor ( var i = 0; i < source.children.length; i ++ ) {\n\n\t\t\t\t\tvar child = source.children[ i ];\n\t\t\t\t\tthis.add( child.clone() );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author mikael emtinger / http://gomo.se/\n\t * @author WestLangley / http://github.com/WestLangley\n\t*/\n\n\tfunction Camera() {\n\n\t\tObject3D.call( this );\n\n\t\tthis.type = 'Camera';\n\n\t\tthis.matrixWorldInverse = new Matrix4();\n\t\tthis.projectionMatrix = new Matrix4();\n\n\t}\n\n\tCamera.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\t\tconstructor: Camera,\n\n\t\tisCamera: true,\n\n\t\tcopy: function ( source, recursive ) {\n\n\t\t\tObject3D.prototype.copy.call( this, source, recursive );\n\n\t\t\tthis.matrixWorldInverse.copy( source.matrixWorldInverse );\n\t\t\tthis.projectionMatrix.copy( source.projectionMatrix );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetWorldDirection: function () {\n\n\t\t\tvar quaternion = new Quaternion();\n\n\t\t\treturn function getWorldDirection( optionalTarget ) {\n\n\t\t\t\tvar result = optionalTarget || new Vector3();\n\n\t\t\t\tthis.getWorldQuaternion( quaternion );\n\n\t\t\t\treturn result.set( 0, 0, - 1 ).applyQuaternion( quaternion );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tupdateMatrixWorld: function ( force ) {\n\n\t\t\tObject3D.prototype.updateMatrixWorld.call( this, force );\n\n\t\t\tthis.matrixWorldInverse.getInverse( this.matrixWorld );\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor().copy( this );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author arose / http://github.com/arose\n\t */\n\n\tfunction OrthographicCamera( left, right, top, bottom, near, far ) {\n\n\t\tCamera.call( this );\n\n\t\tthis.type = 'OrthographicCamera';\n\n\t\tthis.zoom = 1;\n\t\tthis.view = null;\n\n\t\tthis.left = left;\n\t\tthis.right = right;\n\t\tthis.top = top;\n\t\tthis.bottom = bottom;\n\n\t\tthis.near = ( near !== undefined ) ? near : 0.1;\n\t\tthis.far = ( far !== undefined ) ? far : 2000;\n\n\t\tthis.updateProjectionMatrix();\n\n\t}\n\n\tOrthographicCamera.prototype = Object.assign( Object.create( Camera.prototype ), {\n\n\t\tconstructor: OrthographicCamera,\n\n\t\tisOrthographicCamera: true,\n\n\t\tcopy: function ( source, recursive ) {\n\n\t\t\tCamera.prototype.copy.call( this, source, recursive );\n\n\t\t\tthis.left = source.left;\n\t\t\tthis.right = source.right;\n\t\t\tthis.top = source.top;\n\t\t\tthis.bottom = source.bottom;\n\t\t\tthis.near = source.near;\n\t\t\tthis.far = source.far;\n\n\t\t\tthis.zoom = source.zoom;\n\t\t\tthis.view = source.view === null ? null : Object.assign( {}, source.view );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetViewOffset: function( fullWidth, fullHeight, x, y, width, height ) {\n\n\t\t\tthis.view = {\n\t\t\t\tfullWidth: fullWidth,\n\t\t\t\tfullHeight: fullHeight,\n\t\t\t\toffsetX: x,\n\t\t\t\toffsetY: y,\n\t\t\t\twidth: width,\n\t\t\t\theight: height\n\t\t\t};\n\n\t\t\tthis.updateProjectionMatrix();\n\n\t\t},\n\n\t\tclearViewOffset: function() {\n\n\t\t\tthis.view = null;\n\t\t\tthis.updateProjectionMatrix();\n\n\t\t},\n\n\t\tupdateProjectionMatrix: function () {\n\n\t\t\tvar dx = ( this.right - this.left ) / ( 2 * this.zoom );\n\t\t\tvar dy = ( this.top - this.bottom ) / ( 2 * this.zoom );\n\t\t\tvar cx = ( this.right + this.left ) / 2;\n\t\t\tvar cy = ( this.top + this.bottom ) / 2;\n\n\t\t\tvar left = cx - dx;\n\t\t\tvar right = cx + dx;\n\t\t\tvar top = cy + dy;\n\t\t\tvar bottom = cy - dy;\n\n\t\t\tif ( this.view !== null ) {\n\n\t\t\t\tvar zoomW = this.zoom / ( this.view.width / this.view.fullWidth );\n\t\t\t\tvar zoomH = this.zoom / ( this.view.height / this.view.fullHeight );\n\t\t\t\tvar scaleW = ( this.right - this.left ) / this.view.width;\n\t\t\t\tvar scaleH = ( this.top - this.bottom ) / this.view.height;\n\n\t\t\t\tleft += scaleW * ( this.view.offsetX / zoomW );\n\t\t\t\tright = left + scaleW * ( this.view.width / zoomW );\n\t\t\t\ttop -= scaleH * ( this.view.offsetY / zoomH );\n\t\t\t\tbottom = top - scaleH * ( this.view.height / zoomH );\n\n\t\t\t}\n\n\t\t\tthis.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far );\n\n\t\t},\n\n\t\ttoJSON: function ( meta ) {\n\n\t\t\tvar data = Object3D.prototype.toJSON.call( this, meta );\n\n\t\t\tdata.object.zoom = this.zoom;\n\t\t\tdata.object.left = this.left;\n\t\t\tdata.object.right = this.right;\n\t\t\tdata.object.top = this.top;\n\t\t\tdata.object.bottom = this.bottom;\n\t\t\tdata.object.near = this.near;\n\t\t\tdata.object.far = this.far;\n\n\t\t\tif ( this.view !== null ) data.object.view = Object.assign( {}, this.view );\n\n\t\t\treturn data;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author greggman / http://games.greggman.com/\n\t * @author zz85 / http://www.lab4games.net/zz85/blog\n\t * @author tschw\n\t */\n\n\tfunction PerspectiveCamera( fov, aspect, near, far ) {\n\n\t\tCamera.call( this );\n\n\t\tthis.type = 'PerspectiveCamera';\n\n\t\tthis.fov = fov !== undefined ? fov : 50;\n\t\tthis.zoom = 1;\n\n\t\tthis.near = near !== undefined ? near : 0.1;\n\t\tthis.far = far !== undefined ? far : 2000;\n\t\tthis.focus = 10;\n\n\t\tthis.aspect = aspect !== undefined ? aspect : 1;\n\t\tthis.view = null;\n\n\t\tthis.filmGauge = 35;\t// width of the film (default in millimeters)\n\t\tthis.filmOffset = 0;\t// horizontal film offset (same unit as gauge)\n\n\t\tthis.updateProjectionMatrix();\n\n\t}\n\n\tPerspectiveCamera.prototype = Object.assign( Object.create( Camera.prototype ), {\n\n\t\tconstructor: PerspectiveCamera,\n\n\t\tisPerspectiveCamera: true,\n\n\t\tcopy: function ( source, recursive ) {\n\n\t\t\tCamera.prototype.copy.call( this, source, recursive );\n\n\t\t\tthis.fov = source.fov;\n\t\t\tthis.zoom = source.zoom;\n\n\t\t\tthis.near = source.near;\n\t\t\tthis.far = source.far;\n\t\t\tthis.focus = source.focus;\n\n\t\t\tthis.aspect = source.aspect;\n\t\t\tthis.view = source.view === null ? null : Object.assign( {}, source.view );\n\n\t\t\tthis.filmGauge = source.filmGauge;\n\t\t\tthis.filmOffset = source.filmOffset;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\t/**\n\t\t * Sets the FOV by focal length in respect to the current .filmGauge.\n\t\t *\n\t\t * The default film gauge is 35, so that the focal length can be specified for\n\t\t * a 35mm (full frame) camera.\n\t\t *\n\t\t * Values for focal length and film gauge must have the same unit.\n\t\t */\n\t\tsetFocalLength: function ( focalLength ) {\n\n\t\t\t// see http://www.bobatkins.com/photography/technical/field_of_view.html\n\t\t\tvar vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;\n\n\t\t\tthis.fov = _Math.RAD2DEG * 2 * Math.atan( vExtentSlope );\n\t\t\tthis.updateProjectionMatrix();\n\n\t\t},\n\n\t\t/**\n\t\t * Calculates the focal length from the current .fov and .filmGauge.\n\t\t */\n\t\tgetFocalLength: function () {\n\n\t\t\tvar vExtentSlope = Math.tan( _Math.DEG2RAD * 0.5 * this.fov );\n\n\t\t\treturn 0.5 * this.getFilmHeight() / vExtentSlope;\n\n\t\t},\n\n\t\tgetEffectiveFOV: function () {\n\n\t\t\treturn _Math.RAD2DEG * 2 * Math.atan(\n\t\t\t\t\tMath.tan( _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom );\n\n\t\t},\n\n\t\tgetFilmWidth: function () {\n\n\t\t\t// film not completely covered in portrait format (aspect < 1)\n\t\t\treturn this.filmGauge * Math.min( this.aspect, 1 );\n\n\t\t},\n\n\t\tgetFilmHeight: function () {\n\n\t\t\t// film not completely covered in landscape format (aspect > 1)\n\t\t\treturn this.filmGauge / Math.max( this.aspect, 1 );\n\n\t\t},\n\n\t\t/**\n\t\t * Sets an offset in a larger frustum. This is useful for multi-window or\n\t\t * multi-monitor/multi-machine setups.\n\t\t *\n\t\t * For example, if you have 3x2 monitors and each monitor is 1920x1080 and\n\t\t * the monitors are in grid like this\n\t\t *\n\t\t *   +---+---+---+\n\t\t *   | A | B | C |\n\t\t *   +---+---+---+\n\t\t *   | D | E | F |\n\t\t *   +---+---+---+\n\t\t *\n\t\t * then for each monitor you would call it like this\n\t\t *\n\t\t *   var w = 1920;\n\t\t *   var h = 1080;\n\t\t *   var fullWidth = w * 3;\n\t\t *   var fullHeight = h * 2;\n\t\t *\n\t\t *   --A--\n\t\t *   camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );\n\t\t *   --B--\n\t\t *   camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );\n\t\t *   --C--\n\t\t *   camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );\n\t\t *   --D--\n\t\t *   camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );\n\t\t *   --E--\n\t\t *   camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );\n\t\t *   --F--\n\t\t *   camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );\n\t\t *\n\t\t *   Note there is no reason monitors have to be the same size or in a grid.\n\t\t */\n\t\tsetViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) {\n\n\t\t\tthis.aspect = fullWidth / fullHeight;\n\n\t\t\tthis.view = {\n\t\t\t\tfullWidth: fullWidth,\n\t\t\t\tfullHeight: fullHeight,\n\t\t\t\toffsetX: x,\n\t\t\t\toffsetY: y,\n\t\t\t\twidth: width,\n\t\t\t\theight: height\n\t\t\t};\n\n\t\t\tthis.updateProjectionMatrix();\n\n\t\t},\n\n\t\tclearViewOffset: function () {\n\n\t\t\tthis.view = null;\n\t\t\tthis.updateProjectionMatrix();\n\n\t\t},\n\n\t\tupdateProjectionMatrix: function () {\n\n\t\t\tvar near = this.near,\n\t\t\t\ttop = near * Math.tan(\n\t\t\t\t\t\t_Math.DEG2RAD * 0.5 * this.fov ) / this.zoom,\n\t\t\t\theight = 2 * top,\n\t\t\t\twidth = this.aspect * height,\n\t\t\t\tleft = - 0.5 * width,\n\t\t\t\tview = this.view;\n\n\t\t\tif ( view !== null ) {\n\n\t\t\t\tvar fullWidth = view.fullWidth,\n\t\t\t\t\tfullHeight = view.fullHeight;\n\n\t\t\t\tleft += view.offsetX * width / fullWidth;\n\t\t\t\ttop -= view.offsetY * height / fullHeight;\n\t\t\t\twidth *= view.width / fullWidth;\n\t\t\t\theight *= view.height / fullHeight;\n\n\t\t\t}\n\n\t\t\tvar skew = this.filmOffset;\n\t\t\tif ( skew !== 0 ) left += near * skew / this.getFilmWidth();\n\n\t\t\tthis.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far );\n\n\t\t},\n\n\t\ttoJSON: function ( meta ) {\n\n\t\t\tvar data = Object3D.prototype.toJSON.call( this, meta );\n\n\t\t\tdata.object.fov = this.fov;\n\t\t\tdata.object.zoom = this.zoom;\n\n\t\t\tdata.object.near = this.near;\n\t\t\tdata.object.far = this.far;\n\t\t\tdata.object.focus = this.focus;\n\n\t\t\tdata.object.aspect = this.aspect;\n\n\t\t\tif ( this.view !== null ) data.object.view = Object.assign( {}, this.view );\n\n\t\t\tdata.object.filmGauge = this.filmGauge;\n\t\t\tdata.object.filmOffset = this.filmOffset;\n\n\t\t\treturn data;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tfunction Face3( a, b, c, normal, color, materialIndex ) {\n\n\t\tthis.a = a;\n\t\tthis.b = b;\n\t\tthis.c = c;\n\n\t\tthis.normal = ( normal && normal.isVector3 ) ? normal : new Vector3();\n\t\tthis.vertexNormals = Array.isArray( normal ) ? normal : [];\n\n\t\tthis.color = ( color && color.isColor ) ? color : new Color();\n\t\tthis.vertexColors = Array.isArray( color ) ? color : [];\n\n\t\tthis.materialIndex = materialIndex !== undefined ? materialIndex : 0;\n\n\t}\n\n\tObject.assign( Face3.prototype, {\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor().copy( this );\n\n\t\t},\n\n\t\tcopy: function ( source ) {\n\n\t\t\tthis.a = source.a;\n\t\t\tthis.b = source.b;\n\t\t\tthis.c = source.c;\n\n\t\t\tthis.normal.copy( source.normal );\n\t\t\tthis.color.copy( source.color );\n\n\t\t\tthis.materialIndex = source.materialIndex;\n\n\t\t\tfor ( var i = 0, il = source.vertexNormals.length; i < il; i ++ ) {\n\n\t\t\t\tthis.vertexNormals[ i ] = source.vertexNormals[ i ].clone();\n\n\t\t\t}\n\n\t\t\tfor ( var i = 0, il = source.vertexColors.length; i < il; i ++ ) {\n\n\t\t\t\tthis.vertexColors[ i ] = source.vertexColors[ i ].clone();\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author kile / http://kile.stravaganza.org/\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author mikael emtinger / http://gomo.se/\n\t * @author zz85 / http://www.lab4games.net/zz85/blog\n\t * @author bhouston / http://clara.io\n\t */\n\n\tvar count = 0;\n\tfunction GeometryIdCount() { return count++; }\n\n\tfunction Geometry() {\n\n\t\tObject.defineProperty( this, 'id', { value: GeometryIdCount() } );\n\n\t\tthis.uuid = _Math.generateUUID();\n\n\t\tthis.name = '';\n\t\tthis.type = 'Geometry';\n\n\t\tthis.vertices = [];\n\t\tthis.colors = [];\n\t\tthis.faces = [];\n\t\tthis.faceVertexUvs = [[]];\n\n\t\tthis.morphTargets = [];\n\t\tthis.morphNormals = [];\n\n\t\tthis.skinWeights = [];\n\t\tthis.skinIndices = [];\n\n\t\tthis.lineDistances = [];\n\n\t\tthis.boundingBox = null;\n\t\tthis.boundingSphere = null;\n\n\t\t// update flags\n\n\t\tthis.elementsNeedUpdate = false;\n\t\tthis.verticesNeedUpdate = false;\n\t\tthis.uvsNeedUpdate = false;\n\t\tthis.normalsNeedUpdate = false;\n\t\tthis.colorsNeedUpdate = false;\n\t\tthis.lineDistancesNeedUpdate = false;\n\t\tthis.groupsNeedUpdate = false;\n\n\t}\n\n\tObject.assign( Geometry.prototype, EventDispatcher.prototype, {\n\n\t\tisGeometry: true,\n\n\t\tapplyMatrix: function ( matrix ) {\n\n\t\t\tvar normalMatrix = new Matrix3().getNormalMatrix( matrix );\n\n\t\t\tfor ( var i = 0, il = this.vertices.length; i < il; i ++ ) {\n\n\t\t\t\tvar vertex = this.vertices[ i ];\n\t\t\t\tvertex.applyMatrix4( matrix );\n\n\t\t\t}\n\n\t\t\tfor ( var i = 0, il = this.faces.length; i < il; i ++ ) {\n\n\t\t\t\tvar face = this.faces[ i ];\n\t\t\t\tface.normal.applyMatrix3( normalMatrix ).normalize();\n\n\t\t\t\tfor ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {\n\n\t\t\t\t\tface.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( this.boundingBox !== null ) {\n\n\t\t\t\tthis.computeBoundingBox();\n\n\t\t\t}\n\n\t\t\tif ( this.boundingSphere !== null ) {\n\n\t\t\t\tthis.computeBoundingSphere();\n\n\t\t\t}\n\n\t\t\tthis.verticesNeedUpdate = true;\n\t\t\tthis.normalsNeedUpdate = true;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\trotateX: function () {\n\n\t\t\t// rotate geometry around world x-axis\n\n\t\t\tvar m1 = new Matrix4();\n\n\t\t\treturn function rotateX( angle ) {\n\n\t\t\t\tm1.makeRotationX( angle );\n\n\t\t\t\tthis.applyMatrix( m1 );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\trotateY: function () {\n\n\t\t\t// rotate geometry around world y-axis\n\n\t\t\tvar m1 = new Matrix4();\n\n\t\t\treturn function rotateY( angle ) {\n\n\t\t\t\tm1.makeRotationY( angle );\n\n\t\t\t\tthis.applyMatrix( m1 );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\trotateZ: function () {\n\n\t\t\t// rotate geometry around world z-axis\n\n\t\t\tvar m1 = new Matrix4();\n\n\t\t\treturn function rotateZ( angle ) {\n\n\t\t\t\tm1.makeRotationZ( angle );\n\n\t\t\t\tthis.applyMatrix( m1 );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\ttranslate: function () {\n\n\t\t\t// translate geometry\n\n\t\t\tvar m1 = new Matrix4();\n\n\t\t\treturn function translate( x, y, z ) {\n\n\t\t\t\tm1.makeTranslation( x, y, z );\n\n\t\t\t\tthis.applyMatrix( m1 );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tscale: function () {\n\n\t\t\t// scale geometry\n\n\t\t\tvar m1 = new Matrix4();\n\n\t\t\treturn function scale( x, y, z ) {\n\n\t\t\t\tm1.makeScale( x, y, z );\n\n\t\t\t\tthis.applyMatrix( m1 );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tlookAt: function () {\n\n\t\t\tvar obj = new Object3D();\n\n\t\t\treturn function lookAt( vector ) {\n\n\t\t\t\tobj.lookAt( vector );\n\n\t\t\t\tobj.updateMatrix();\n\n\t\t\t\tthis.applyMatrix( obj.matrix );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tfromBufferGeometry: function ( geometry ) {\n\n\t\t\tvar scope = this;\n\n\t\t\tvar indices = geometry.index !== null ? geometry.index.array : undefined;\n\t\t\tvar attributes = geometry.attributes;\n\n\t\t\tvar positions = attributes.position.array;\n\t\t\tvar normals = attributes.normal !== undefined ? attributes.normal.array : undefined;\n\t\t\tvar colors = attributes.color !== undefined ? attributes.color.array : undefined;\n\t\t\tvar uvs = attributes.uv !== undefined ? attributes.uv.array : undefined;\n\t\t\tvar uvs2 = attributes.uv2 !== undefined ? attributes.uv2.array : undefined;\n\n\t\t\tif ( uvs2 !== undefined ) this.faceVertexUvs[ 1 ] = [];\n\n\t\t\tvar tempNormals = [];\n\t\t\tvar tempUVs = [];\n\t\t\tvar tempUVs2 = [];\n\n\t\t\tfor ( var i = 0, j = 0; i < positions.length; i += 3, j += 2 ) {\n\n\t\t\t\tscope.vertices.push( new Vector3( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ) );\n\n\t\t\t\tif ( normals !== undefined ) {\n\n\t\t\t\t\ttempNormals.push( new Vector3( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ) );\n\n\t\t\t\t}\n\n\t\t\t\tif ( colors !== undefined ) {\n\n\t\t\t\t\tscope.colors.push( new Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) );\n\n\t\t\t\t}\n\n\t\t\t\tif ( uvs !== undefined ) {\n\n\t\t\t\t\ttempUVs.push( new Vector2( uvs[ j ], uvs[ j + 1 ] ) );\n\n\t\t\t\t}\n\n\t\t\t\tif ( uvs2 !== undefined ) {\n\n\t\t\t\t\ttempUVs2.push( new Vector2( uvs2[ j ], uvs2[ j + 1 ] ) );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tfunction addFace( a, b, c, materialIndex ) {\n\n\t\t\t\tvar vertexNormals = normals !== undefined ? [ tempNormals[ a ].clone(), tempNormals[ b ].clone(), tempNormals[ c ].clone() ] : [];\n\t\t\t\tvar vertexColors = colors !== undefined ? [ scope.colors[ a ].clone(), scope.colors[ b ].clone(), scope.colors[ c ].clone() ] : [];\n\n\t\t\t\tvar face = new Face3( a, b, c, vertexNormals, vertexColors, materialIndex );\n\n\t\t\t\tscope.faces.push( face );\n\n\t\t\t\tif ( uvs !== undefined ) {\n\n\t\t\t\t\tscope.faceVertexUvs[ 0 ].push( [ tempUVs[ a ].clone(), tempUVs[ b ].clone(), tempUVs[ c ].clone() ] );\n\n\t\t\t\t}\n\n\t\t\t\tif ( uvs2 !== undefined ) {\n\n\t\t\t\t\tscope.faceVertexUvs[ 1 ].push( [ tempUVs2[ a ].clone(), tempUVs2[ b ].clone(), tempUVs2[ c ].clone() ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tvar groups = geometry.groups;\n\n\t\t\tif ( groups.length > 0 ) {\n\n\t\t\t\tfor ( var i = 0; i < groups.length; i ++ ) {\n\n\t\t\t\t\tvar group = groups[ i ];\n\n\t\t\t\t\tvar start = group.start;\n\t\t\t\t\tvar count = group.count;\n\n\t\t\t\t\tfor ( var j = start, jl = start + count; j < jl; j += 3 ) {\n\n\t\t\t\t\t\tif ( indices !== undefined ) {\n\n\t\t\t\t\t\t\taddFace( indices[ j ], indices[ j + 1 ], indices[ j + 2 ], group.materialIndex );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\taddFace( j, j + 1, j + 2, group.materialIndex );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tif ( indices !== undefined ) {\n\n\t\t\t\t\tfor ( var i = 0; i < indices.length; i += 3 ) {\n\n\t\t\t\t\t\taddFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tfor ( var i = 0; i < positions.length / 3; i += 3 ) {\n\n\t\t\t\t\t\taddFace( i, i + 1, i + 2 );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.computeFaceNormals();\n\n\t\t\tif ( geometry.boundingBox !== null ) {\n\n\t\t\t\tthis.boundingBox = geometry.boundingBox.clone();\n\n\t\t\t}\n\n\t\t\tif ( geometry.boundingSphere !== null ) {\n\n\t\t\t\tthis.boundingSphere = geometry.boundingSphere.clone();\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcenter: function () {\n\n\t\t\tthis.computeBoundingBox();\n\n\t\t\tvar offset = this.boundingBox.getCenter().negate();\n\n\t\t\tthis.translate( offset.x, offset.y, offset.z );\n\n\t\t\treturn offset;\n\n\t\t},\n\n\t\tnormalize: function () {\n\n\t\t\tthis.computeBoundingSphere();\n\n\t\t\tvar center = this.boundingSphere.center;\n\t\t\tvar radius = this.boundingSphere.radius;\n\n\t\t\tvar s = radius === 0 ? 1 : 1.0 / radius;\n\n\t\t\tvar matrix = new Matrix4();\n\t\t\tmatrix.set(\n\t\t\t\ts, 0, 0, - s * center.x,\n\t\t\t\t0, s, 0, - s * center.y,\n\t\t\t\t0, 0, s, - s * center.z,\n\t\t\t\t0, 0, 0, 1\n\t\t\t);\n\n\t\t\tthis.applyMatrix( matrix );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcomputeFaceNormals: function () {\n\n\t\t\tvar cb = new Vector3(), ab = new Vector3();\n\n\t\t\tfor ( var f = 0, fl = this.faces.length; f < fl; f ++ ) {\n\n\t\t\t\tvar face = this.faces[ f ];\n\n\t\t\t\tvar vA = this.vertices[ face.a ];\n\t\t\t\tvar vB = this.vertices[ face.b ];\n\t\t\t\tvar vC = this.vertices[ face.c ];\n\n\t\t\t\tcb.subVectors( vC, vB );\n\t\t\t\tab.subVectors( vA, vB );\n\t\t\t\tcb.cross( ab );\n\n\t\t\t\tcb.normalize();\n\n\t\t\t\tface.normal.copy( cb );\n\n\t\t\t}\n\n\t\t},\n\n\t\tcomputeVertexNormals: function ( areaWeighted ) {\n\n\t\t\tif ( areaWeighted === undefined ) areaWeighted = true;\n\n\t\t\tvar v, vl, f, fl, face, vertices;\n\n\t\t\tvertices = new Array( this.vertices.length );\n\n\t\t\tfor ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {\n\n\t\t\t\tvertices[ v ] = new Vector3();\n\n\t\t\t}\n\n\t\t\tif ( areaWeighted ) {\n\n\t\t\t\t// vertex normals weighted by triangle areas\n\t\t\t\t// http://www.iquilezles.org/www/articles/normals/normals.htm\n\n\t\t\t\tvar vA, vB, vC;\n\t\t\t\tvar cb = new Vector3(), ab = new Vector3();\n\n\t\t\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\n\n\t\t\t\t\tface = this.faces[ f ];\n\n\t\t\t\t\tvA = this.vertices[ face.a ];\n\t\t\t\t\tvB = this.vertices[ face.b ];\n\t\t\t\t\tvC = this.vertices[ face.c ];\n\n\t\t\t\t\tcb.subVectors( vC, vB );\n\t\t\t\t\tab.subVectors( vA, vB );\n\t\t\t\t\tcb.cross( ab );\n\n\t\t\t\t\tvertices[ face.a ].add( cb );\n\t\t\t\t\tvertices[ face.b ].add( cb );\n\t\t\t\t\tvertices[ face.c ].add( cb );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tthis.computeFaceNormals();\n\n\t\t\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\n\n\t\t\t\t\tface = this.faces[ f ];\n\n\t\t\t\t\tvertices[ face.a ].add( face.normal );\n\t\t\t\t\tvertices[ face.b ].add( face.normal );\n\t\t\t\t\tvertices[ face.c ].add( face.normal );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tfor ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {\n\n\t\t\t\tvertices[ v ].normalize();\n\n\t\t\t}\n\n\t\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\n\n\t\t\t\tface = this.faces[ f ];\n\n\t\t\t\tvar vertexNormals = face.vertexNormals;\n\n\t\t\t\tif ( vertexNormals.length === 3 ) {\n\n\t\t\t\t\tvertexNormals[ 0 ].copy( vertices[ face.a ] );\n\t\t\t\t\tvertexNormals[ 1 ].copy( vertices[ face.b ] );\n\t\t\t\t\tvertexNormals[ 2 ].copy( vertices[ face.c ] );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tvertexNormals[ 0 ] = vertices[ face.a ].clone();\n\t\t\t\t\tvertexNormals[ 1 ] = vertices[ face.b ].clone();\n\t\t\t\t\tvertexNormals[ 2 ] = vertices[ face.c ].clone();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( this.faces.length > 0 ) {\n\n\t\t\t\tthis.normalsNeedUpdate = true;\n\n\t\t\t}\n\n\t\t},\n\n\t\tcomputeFlatVertexNormals: function () {\n\n\t\t\tvar f, fl, face;\n\n\t\t\tthis.computeFaceNormals();\n\n\t\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\n\n\t\t\t\tface = this.faces[ f ];\n\n\t\t\t\tvar vertexNormals = face.vertexNormals;\n\n\t\t\t\tif ( vertexNormals.length === 3 ) {\n\n\t\t\t\t\tvertexNormals[ 0 ].copy( face.normal );\n\t\t\t\t\tvertexNormals[ 1 ].copy( face.normal );\n\t\t\t\t\tvertexNormals[ 2 ].copy( face.normal );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tvertexNormals[ 0 ] = face.normal.clone();\n\t\t\t\t\tvertexNormals[ 1 ] = face.normal.clone();\n\t\t\t\t\tvertexNormals[ 2 ] = face.normal.clone();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( this.faces.length > 0 ) {\n\n\t\t\t\tthis.normalsNeedUpdate = true;\n\n\t\t\t}\n\n\t\t},\n\n\t\tcomputeMorphNormals: function () {\n\n\t\t\tvar i, il, f, fl, face;\n\n\t\t\t// save original normals\n\t\t\t// - create temp variables on first access\n\t\t\t//   otherwise just copy (for faster repeated calls)\n\n\t\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\n\n\t\t\t\tface = this.faces[ f ];\n\n\t\t\t\tif ( ! face.__originalFaceNormal ) {\n\n\t\t\t\t\tface.__originalFaceNormal = face.normal.clone();\n\n\t\t\t\t} else {\n\n\t\t\t\t\tface.__originalFaceNormal.copy( face.normal );\n\n\t\t\t\t}\n\n\t\t\t\tif ( ! face.__originalVertexNormals ) face.__originalVertexNormals = [];\n\n\t\t\t\tfor ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) {\n\n\t\t\t\t\tif ( ! face.__originalVertexNormals[ i ] ) {\n\n\t\t\t\t\t\tface.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone();\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tface.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// use temp geometry to compute face and vertex normals for each morph\n\n\t\t\tvar tmpGeo = new Geometry();\n\t\t\ttmpGeo.faces = this.faces;\n\n\t\t\tfor ( i = 0, il = this.morphTargets.length; i < il; i ++ ) {\n\n\t\t\t\t// create on first access\n\n\t\t\t\tif ( ! this.morphNormals[ i ] ) {\n\n\t\t\t\t\tthis.morphNormals[ i ] = {};\n\t\t\t\t\tthis.morphNormals[ i ].faceNormals = [];\n\t\t\t\t\tthis.morphNormals[ i ].vertexNormals = [];\n\n\t\t\t\t\tvar dstNormalsFace = this.morphNormals[ i ].faceNormals;\n\t\t\t\t\tvar dstNormalsVertex = this.morphNormals[ i ].vertexNormals;\n\n\t\t\t\t\tvar faceNormal, vertexNormals;\n\n\t\t\t\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\n\n\t\t\t\t\t\tfaceNormal = new Vector3();\n\t\t\t\t\t\tvertexNormals = { a: new Vector3(), b: new Vector3(), c: new Vector3() };\n\n\t\t\t\t\t\tdstNormalsFace.push( faceNormal );\n\t\t\t\t\t\tdstNormalsVertex.push( vertexNormals );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tvar morphNormals = this.morphNormals[ i ];\n\n\t\t\t\t// set vertices to morph target\n\n\t\t\t\ttmpGeo.vertices = this.morphTargets[ i ].vertices;\n\n\t\t\t\t// compute morph normals\n\n\t\t\t\ttmpGeo.computeFaceNormals();\n\t\t\t\ttmpGeo.computeVertexNormals();\n\n\t\t\t\t// store morph normals\n\n\t\t\t\tvar faceNormal, vertexNormals;\n\n\t\t\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\n\n\t\t\t\t\tface = this.faces[ f ];\n\n\t\t\t\t\tfaceNormal = morphNormals.faceNormals[ f ];\n\t\t\t\t\tvertexNormals = morphNormals.vertexNormals[ f ];\n\n\t\t\t\t\tfaceNormal.copy( face.normal );\n\n\t\t\t\t\tvertexNormals.a.copy( face.vertexNormals[ 0 ] );\n\t\t\t\t\tvertexNormals.b.copy( face.vertexNormals[ 1 ] );\n\t\t\t\t\tvertexNormals.c.copy( face.vertexNormals[ 2 ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// restore original normals\n\n\t\t\tfor ( f = 0, fl = this.faces.length; f < fl; f ++ ) {\n\n\t\t\t\tface = this.faces[ f ];\n\n\t\t\t\tface.normal = face.__originalFaceNormal;\n\t\t\t\tface.vertexNormals = face.__originalVertexNormals;\n\n\t\t\t}\n\n\t\t},\n\n\t\tcomputeLineDistances: function () {\n\n\t\t\tvar d = 0;\n\t\t\tvar vertices = this.vertices;\n\n\t\t\tfor ( var i = 0, il = vertices.length; i < il; i ++ ) {\n\n\t\t\t\tif ( i > 0 ) {\n\n\t\t\t\t\td += vertices[ i ].distanceTo( vertices[ i - 1 ] );\n\n\t\t\t\t}\n\n\t\t\t\tthis.lineDistances[ i ] = d;\n\n\t\t\t}\n\n\t\t},\n\n\t\tcomputeBoundingBox: function () {\n\n\t\t\tif ( this.boundingBox === null ) {\n\n\t\t\t\tthis.boundingBox = new Box3();\n\n\t\t\t}\n\n\t\t\tthis.boundingBox.setFromPoints( this.vertices );\n\n\t\t},\n\n\t\tcomputeBoundingSphere: function () {\n\n\t\t\tif ( this.boundingSphere === null ) {\n\n\t\t\t\tthis.boundingSphere = new Sphere();\n\n\t\t\t}\n\n\t\t\tthis.boundingSphere.setFromPoints( this.vertices );\n\n\t\t},\n\n\t\tmerge: function ( geometry, matrix, materialIndexOffset ) {\n\n\t\t\tif ( ! ( geometry && geometry.isGeometry ) ) {\n\n\t\t\t\tconsole.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tvar normalMatrix,\n\t\t\t\tvertexOffset = this.vertices.length,\n\t\t\t\tvertices1 = this.vertices,\n\t\t\t\tvertices2 = geometry.vertices,\n\t\t\t\tfaces1 = this.faces,\n\t\t\t\tfaces2 = geometry.faces,\n\t\t\t\tuvs1 = this.faceVertexUvs[ 0 ],\n\t\t\t\tuvs2 = geometry.faceVertexUvs[ 0 ],\n\t\t\t\tcolors1 = this.colors,\n\t\t\t\tcolors2 = geometry.colors;\n\n\t\t\tif ( materialIndexOffset === undefined ) materialIndexOffset = 0;\n\n\t\t\tif ( matrix !== undefined ) {\n\n\t\t\t\tnormalMatrix = new Matrix3().getNormalMatrix( matrix );\n\n\t\t\t}\n\n\t\t\t// vertices\n\n\t\t\tfor ( var i = 0, il = vertices2.length; i < il; i ++ ) {\n\n\t\t\t\tvar vertex = vertices2[ i ];\n\n\t\t\t\tvar vertexCopy = vertex.clone();\n\n\t\t\t\tif ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix );\n\n\t\t\t\tvertices1.push( vertexCopy );\n\n\t\t\t}\n\n\t\t\t// colors\n\n\t\t\tfor ( var i = 0, il = colors2.length; i < il; i ++ ) {\n\n\t\t\t\tcolors1.push( colors2[ i ].clone() );\n\n\t\t\t}\n\n\t\t\t// faces\n\n\t\t\tfor ( i = 0, il = faces2.length; i < il; i ++ ) {\n\n\t\t\t\tvar face = faces2[ i ], faceCopy, normal, color,\n\t\t\t\t\tfaceVertexNormals = face.vertexNormals,\n\t\t\t\t\tfaceVertexColors = face.vertexColors;\n\n\t\t\t\tfaceCopy = new Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );\n\t\t\t\tfaceCopy.normal.copy( face.normal );\n\n\t\t\t\tif ( normalMatrix !== undefined ) {\n\n\t\t\t\t\tfaceCopy.normal.applyMatrix3( normalMatrix ).normalize();\n\n\t\t\t\t}\n\n\t\t\t\tfor ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {\n\n\t\t\t\t\tnormal = faceVertexNormals[ j ].clone();\n\n\t\t\t\t\tif ( normalMatrix !== undefined ) {\n\n\t\t\t\t\t\tnormal.applyMatrix3( normalMatrix ).normalize();\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfaceCopy.vertexNormals.push( normal );\n\n\t\t\t\t}\n\n\t\t\t\tfaceCopy.color.copy( face.color );\n\n\t\t\t\tfor ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) {\n\n\t\t\t\t\tcolor = faceVertexColors[ j ];\n\t\t\t\t\tfaceCopy.vertexColors.push( color.clone() );\n\n\t\t\t\t}\n\n\t\t\t\tfaceCopy.materialIndex = face.materialIndex + materialIndexOffset;\n\n\t\t\t\tfaces1.push( faceCopy );\n\n\t\t\t}\n\n\t\t\t// uvs\n\n\t\t\tfor ( i = 0, il = uvs2.length; i < il; i ++ ) {\n\n\t\t\t\tvar uv = uvs2[ i ], uvCopy = [];\n\n\t\t\t\tif ( uv === undefined ) {\n\n\t\t\t\t\tcontinue;\n\n\t\t\t\t}\n\n\t\t\t\tfor ( var j = 0, jl = uv.length; j < jl; j ++ ) {\n\n\t\t\t\t\tuvCopy.push( uv[ j ].clone() );\n\n\t\t\t\t}\n\n\t\t\t\tuvs1.push( uvCopy );\n\n\t\t\t}\n\n\t\t},\n\n\t\tmergeMesh: function ( mesh ) {\n\n\t\t\tif ( ! ( mesh && mesh.isMesh ) ) {\n\n\t\t\t\tconsole.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tmesh.matrixAutoUpdate && mesh.updateMatrix();\n\n\t\t\tthis.merge( mesh.geometry, mesh.matrix );\n\n\t\t},\n\n\t\t/*\n\t\t * Checks for duplicate vertices with hashmap.\n\t\t * Duplicated vertices are removed\n\t\t * and faces' vertices are updated.\n\t\t */\n\n\t\tmergeVertices: function () {\n\n\t\t\tvar verticesMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique)\n\t\t\tvar unique = [], changes = [];\n\n\t\t\tvar v, key;\n\t\t\tvar precisionPoints = 4; // number of decimal points, e.g. 4 for epsilon of 0.0001\n\t\t\tvar precision = Math.pow( 10, precisionPoints );\n\t\t\tvar i, il, face;\n\t\t\tvar indices, j, jl;\n\n\t\t\tfor ( i = 0, il = this.vertices.length; i < il; i ++ ) {\n\n\t\t\t\tv = this.vertices[ i ];\n\t\t\t\tkey = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision );\n\n\t\t\t\tif ( verticesMap[ key ] === undefined ) {\n\n\t\t\t\t\tverticesMap[ key ] = i;\n\t\t\t\t\tunique.push( this.vertices[ i ] );\n\t\t\t\t\tchanges[ i ] = unique.length - 1;\n\n\t\t\t\t} else {\n\n\t\t\t\t\t//console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]);\n\t\t\t\t\tchanges[ i ] = changes[ verticesMap[ key ] ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\n\t\t\t// if faces are completely degenerate after merging vertices, we\n\t\t\t// have to remove them from the geometry.\n\t\t\tvar faceIndicesToRemove = [];\n\n\t\t\tfor ( i = 0, il = this.faces.length; i < il; i ++ ) {\n\n\t\t\t\tface = this.faces[ i ];\n\n\t\t\t\tface.a = changes[ face.a ];\n\t\t\t\tface.b = changes[ face.b ];\n\t\t\t\tface.c = changes[ face.c ];\n\n\t\t\t\tindices = [ face.a, face.b, face.c ];\n\n\t\t\t\t// if any duplicate vertices are found in a Face3\n\t\t\t\t// we have to remove the face as nothing can be saved\n\t\t\t\tfor ( var n = 0; n < 3; n ++ ) {\n\n\t\t\t\t\tif ( indices[ n ] === indices[ ( n + 1 ) % 3 ] ) {\n\n\t\t\t\t\t\tfaceIndicesToRemove.push( i );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tfor ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) {\n\n\t\t\t\tvar idx = faceIndicesToRemove[ i ];\n\n\t\t\t\tthis.faces.splice( idx, 1 );\n\n\t\t\t\tfor ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) {\n\n\t\t\t\t\tthis.faceVertexUvs[ j ].splice( idx, 1 );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// Use unique set of vertices\n\n\t\t\tvar diff = this.vertices.length - unique.length;\n\t\t\tthis.vertices = unique;\n\t\t\treturn diff;\n\n\t\t},\n\n\t\tsortFacesByMaterialIndex: function () {\n\n\t\t\tvar faces = this.faces;\n\t\t\tvar length = faces.length;\n\n\t\t\t// tag faces\n\n\t\t\tfor ( var i = 0; i < length; i ++ ) {\n\n\t\t\t\tfaces[ i ]._id = i;\n\n\t\t\t}\n\n\t\t\t// sort faces\n\n\t\t\tfunction materialIndexSort( a, b ) {\n\n\t\t\t\treturn a.materialIndex - b.materialIndex;\n\n\t\t\t}\n\n\t\t\tfaces.sort( materialIndexSort );\n\n\t\t\t// sort uvs\n\n\t\t\tvar uvs1 = this.faceVertexUvs[ 0 ];\n\t\t\tvar uvs2 = this.faceVertexUvs[ 1 ];\n\n\t\t\tvar newUvs1, newUvs2;\n\n\t\t\tif ( uvs1 && uvs1.length === length ) newUvs1 = [];\n\t\t\tif ( uvs2 && uvs2.length === length ) newUvs2 = [];\n\n\t\t\tfor ( var i = 0; i < length; i ++ ) {\n\n\t\t\t\tvar id = faces[ i ]._id;\n\n\t\t\t\tif ( newUvs1 ) newUvs1.push( uvs1[ id ] );\n\t\t\t\tif ( newUvs2 ) newUvs2.push( uvs2[ id ] );\n\n\t\t\t}\n\n\t\t\tif ( newUvs1 ) this.faceVertexUvs[ 0 ] = newUvs1;\n\t\t\tif ( newUvs2 ) this.faceVertexUvs[ 1 ] = newUvs2;\n\n\t\t},\n\n\t\ttoJSON: function () {\n\n\t\t\tvar data = {\n\t\t\t\tmetadata: {\n\t\t\t\t\tversion: 4.5,\n\t\t\t\t\ttype: 'Geometry',\n\t\t\t\t\tgenerator: 'Geometry.toJSON'\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// standard Geometry serialization\n\n\t\t\tdata.uuid = this.uuid;\n\t\t\tdata.type = this.type;\n\t\t\tif ( this.name !== '' ) data.name = this.name;\n\n\t\t\tif ( this.parameters !== undefined ) {\n\n\t\t\t\tvar parameters = this.parameters;\n\n\t\t\t\tfor ( var key in parameters ) {\n\n\t\t\t\t\tif ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];\n\n\t\t\t\t}\n\n\t\t\t\treturn data;\n\n\t\t\t}\n\n\t\t\tvar vertices = [];\n\n\t\t\tfor ( var i = 0; i < this.vertices.length; i ++ ) {\n\n\t\t\t\tvar vertex = this.vertices[ i ];\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t}\n\n\t\t\tvar faces = [];\n\t\t\tvar normals = [];\n\t\t\tvar normalsHash = {};\n\t\t\tvar colors = [];\n\t\t\tvar colorsHash = {};\n\t\t\tvar uvs = [];\n\t\t\tvar uvsHash = {};\n\n\t\t\tfor ( var i = 0; i < this.faces.length; i ++ ) {\n\n\t\t\t\tvar face = this.faces[ i ];\n\n\t\t\t\tvar hasMaterial = true;\n\t\t\t\tvar hasFaceUv = false; // deprecated\n\t\t\t\tvar hasFaceVertexUv = this.faceVertexUvs[ 0 ][ i ] !== undefined;\n\t\t\t\tvar hasFaceNormal = face.normal.length() > 0;\n\t\t\t\tvar hasFaceVertexNormal = face.vertexNormals.length > 0;\n\t\t\t\tvar hasFaceColor = face.color.r !== 1 || face.color.g !== 1 || face.color.b !== 1;\n\t\t\t\tvar hasFaceVertexColor = face.vertexColors.length > 0;\n\n\t\t\t\tvar faceType = 0;\n\n\t\t\t\tfaceType = setBit( faceType, 0, 0 ); // isQuad\n\t\t\t\tfaceType = setBit( faceType, 1, hasMaterial );\n\t\t\t\tfaceType = setBit( faceType, 2, hasFaceUv );\n\t\t\t\tfaceType = setBit( faceType, 3, hasFaceVertexUv );\n\t\t\t\tfaceType = setBit( faceType, 4, hasFaceNormal );\n\t\t\t\tfaceType = setBit( faceType, 5, hasFaceVertexNormal );\n\t\t\t\tfaceType = setBit( faceType, 6, hasFaceColor );\n\t\t\t\tfaceType = setBit( faceType, 7, hasFaceVertexColor );\n\n\t\t\t\tfaces.push( faceType );\n\t\t\t\tfaces.push( face.a, face.b, face.c );\n\t\t\t\tfaces.push( face.materialIndex );\n\n\t\t\t\tif ( hasFaceVertexUv ) {\n\n\t\t\t\t\tvar faceVertexUvs = this.faceVertexUvs[ 0 ][ i ];\n\n\t\t\t\t\tfaces.push(\n\t\t\t\t\t\tgetUvIndex( faceVertexUvs[ 0 ] ),\n\t\t\t\t\t\tgetUvIndex( faceVertexUvs[ 1 ] ),\n\t\t\t\t\t\tgetUvIndex( faceVertexUvs[ 2 ] )\n\t\t\t\t\t);\n\n\t\t\t\t}\n\n\t\t\t\tif ( hasFaceNormal ) {\n\n\t\t\t\t\tfaces.push( getNormalIndex( face.normal ) );\n\n\t\t\t\t}\n\n\t\t\t\tif ( hasFaceVertexNormal ) {\n\n\t\t\t\t\tvar vertexNormals = face.vertexNormals;\n\n\t\t\t\t\tfaces.push(\n\t\t\t\t\t\tgetNormalIndex( vertexNormals[ 0 ] ),\n\t\t\t\t\t\tgetNormalIndex( vertexNormals[ 1 ] ),\n\t\t\t\t\t\tgetNormalIndex( vertexNormals[ 2 ] )\n\t\t\t\t\t);\n\n\t\t\t\t}\n\n\t\t\t\tif ( hasFaceColor ) {\n\n\t\t\t\t\tfaces.push( getColorIndex( face.color ) );\n\n\t\t\t\t}\n\n\t\t\t\tif ( hasFaceVertexColor ) {\n\n\t\t\t\t\tvar vertexColors = face.vertexColors;\n\n\t\t\t\t\tfaces.push(\n\t\t\t\t\t\tgetColorIndex( vertexColors[ 0 ] ),\n\t\t\t\t\t\tgetColorIndex( vertexColors[ 1 ] ),\n\t\t\t\t\t\tgetColorIndex( vertexColors[ 2 ] )\n\t\t\t\t\t);\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tfunction setBit( value, position, enabled ) {\n\n\t\t\t\treturn enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position ) );\n\n\t\t\t}\n\n\t\t\tfunction getNormalIndex( normal ) {\n\n\t\t\t\tvar hash = normal.x.toString() + normal.y.toString() + normal.z.toString();\n\n\t\t\t\tif ( normalsHash[ hash ] !== undefined ) {\n\n\t\t\t\t\treturn normalsHash[ hash ];\n\n\t\t\t\t}\n\n\t\t\t\tnormalsHash[ hash ] = normals.length / 3;\n\t\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\treturn normalsHash[ hash ];\n\n\t\t\t}\n\n\t\t\tfunction getColorIndex( color ) {\n\n\t\t\t\tvar hash = color.r.toString() + color.g.toString() + color.b.toString();\n\n\t\t\t\tif ( colorsHash[ hash ] !== undefined ) {\n\n\t\t\t\t\treturn colorsHash[ hash ];\n\n\t\t\t\t}\n\n\t\t\t\tcolorsHash[ hash ] = colors.length;\n\t\t\t\tcolors.push( color.getHex() );\n\n\t\t\t\treturn colorsHash[ hash ];\n\n\t\t\t}\n\n\t\t\tfunction getUvIndex( uv ) {\n\n\t\t\t\tvar hash = uv.x.toString() + uv.y.toString();\n\n\t\t\t\tif ( uvsHash[ hash ] !== undefined ) {\n\n\t\t\t\t\treturn uvsHash[ hash ];\n\n\t\t\t\t}\n\n\t\t\t\tuvsHash[ hash ] = uvs.length / 2;\n\t\t\t\tuvs.push( uv.x, uv.y );\n\n\t\t\t\treturn uvsHash[ hash ];\n\n\t\t\t}\n\n\t\t\tdata.data = {};\n\n\t\t\tdata.data.vertices = vertices;\n\t\t\tdata.data.normals = normals;\n\t\t\tif ( colors.length > 0 ) data.data.colors = colors;\n\t\t\tif ( uvs.length > 0 ) data.data.uvs = [ uvs ]; // temporal backward compatibility\n\t\t\tdata.data.faces = faces;\n\n\t\t\treturn data;\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\t/*\n\t\t\t // Handle primitives\n\n\t\t\t var parameters = this.parameters;\n\n\t\t\t if ( parameters !== undefined ) {\n\n\t\t\t var values = [];\n\n\t\t\t for ( var key in parameters ) {\n\n\t\t\t values.push( parameters[ key ] );\n\n\t\t\t }\n\n\t\t\t var geometry = Object.create( this.constructor.prototype );\n\t\t\t this.constructor.apply( geometry, values );\n\t\t\t return geometry;\n\n\t\t\t }\n\n\t\t\t return new this.constructor().copy( this );\n\t\t\t */\n\n\t\t\treturn new Geometry().copy( this );\n\n\t\t},\n\n\t\tcopy: function ( source ) {\n\n\t\t\tvar i, il, j, jl, k, kl;\n\n\t\t\t// reset\n\n\t\t\tthis.vertices = [];\n\t\t\tthis.colors = [];\n\t\t\tthis.faces = [];\n\t\t\tthis.faceVertexUvs = [[]];\n\t\t\tthis.morphTargets = [];\n\t\t\tthis.morphNormals = [];\n\t\t\tthis.skinWeights = [];\n\t\t\tthis.skinIndices = [];\n\t\t\tthis.lineDistances = [];\n\t\t\tthis.boundingBox = null;\n\t\t\tthis.boundingSphere = null;\n\n\t\t\t// name\n\n\t\t\tthis.name = source.name;\n\n\t\t\t// vertices\n\n\t\t\tvar vertices = source.vertices;\n\n\t\t\tfor ( i = 0, il = vertices.length; i < il; i ++ ) {\n\n\t\t\t\tthis.vertices.push( vertices[ i ].clone() );\n\n\t\t\t}\n\n\t\t\t// colors\n\n\t\t\tvar colors = source.colors;\n\n\t\t\tfor ( i = 0, il = colors.length; i < il; i ++ ) {\n\n\t\t\t\tthis.colors.push( colors[ i ].clone() );\n\n\t\t\t}\n\n\t\t\t// faces\n\n\t\t\tvar faces = source.faces;\n\n\t\t\tfor ( i = 0, il = faces.length; i < il; i ++ ) {\n\n\t\t\t\tthis.faces.push( faces[ i ].clone() );\n\n\t\t\t}\n\n\t\t\t// face vertex uvs\n\n\t\t\tfor ( i = 0, il = source.faceVertexUvs.length; i < il; i ++ ) {\n\n\t\t\t\tvar faceVertexUvs = source.faceVertexUvs[ i ];\n\n\t\t\t\tif ( this.faceVertexUvs[ i ] === undefined ) {\n\n\t\t\t\t\tthis.faceVertexUvs[ i ] = [];\n\n\t\t\t\t}\n\n\t\t\t\tfor ( j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) {\n\n\t\t\t\t\tvar uvs = faceVertexUvs[ j ], uvsCopy = [];\n\n\t\t\t\t\tfor ( k = 0, kl = uvs.length; k < kl; k ++ ) {\n\n\t\t\t\t\t\tvar uv = uvs[ k ];\n\n\t\t\t\t\t\tuvsCopy.push( uv.clone() );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.faceVertexUvs[ i ].push( uvsCopy );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// morph targets\n\n\t\t\tvar morphTargets = source.morphTargets;\n\n\t\t\tfor ( i = 0, il = morphTargets.length; i < il; i ++ ) {\n\n\t\t\t\tvar morphTarget = {};\n\t\t\t\tmorphTarget.name = morphTargets[ i ].name;\n\n\t\t\t\t// vertices\n\n\t\t\t\tif ( morphTargets[ i ].vertices !== undefined ) {\n\n\t\t\t\t\tmorphTarget.vertices = [];\n\n\t\t\t\t\tfor ( j = 0, jl = morphTargets[ i ].vertices.length; j < jl; j ++ ) {\n\n\t\t\t\t\t\tmorphTarget.vertices.push( morphTargets[ i ].vertices[ j ].clone() );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t// normals\n\n\t\t\t\tif ( morphTargets[ i ].normals !== undefined ) {\n\n\t\t\t\t\tmorphTarget.normals = [];\n\n\t\t\t\t\tfor ( j = 0, jl = morphTargets[ i ].normals.length; j < jl; j ++ ) {\n\n\t\t\t\t\t\tmorphTarget.normals.push( morphTargets[ i ].normals[ j ].clone() );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tthis.morphTargets.push( morphTarget );\n\n\t\t\t}\n\n\t\t\t// morph normals\n\n\t\t\tvar morphNormals = source.morphNormals;\n\n\t\t\tfor ( i = 0, il = morphNormals.length; i < il; i ++ ) {\n\n\t\t\t\tvar morphNormal = {};\n\n\t\t\t\t// vertex normals\n\n\t\t\t\tif ( morphNormals[ i ].vertexNormals !== undefined ) {\n\n\t\t\t\t\tmorphNormal.vertexNormals = [];\n\n\t\t\t\t\tfor ( j = 0, jl = morphNormals[ i ].vertexNormals.length; j < jl; j ++ ) {\n\n\t\t\t\t\t\tvar srcVertexNormal = morphNormals[ i ].vertexNormals[ j ];\n\t\t\t\t\t\tvar destVertexNormal = {};\n\n\t\t\t\t\t\tdestVertexNormal.a = srcVertexNormal.a.clone();\n\t\t\t\t\t\tdestVertexNormal.b = srcVertexNormal.b.clone();\n\t\t\t\t\t\tdestVertexNormal.c = srcVertexNormal.c.clone();\n\n\t\t\t\t\t\tmorphNormal.vertexNormals.push( destVertexNormal );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t// face normals\n\n\t\t\t\tif ( morphNormals[ i ].faceNormals !== undefined ) {\n\n\t\t\t\t\tmorphNormal.faceNormals = [];\n\n\t\t\t\t\tfor ( j = 0, jl = morphNormals[ i ].faceNormals.length; j < jl; j ++ ) {\n\n\t\t\t\t\t\tmorphNormal.faceNormals.push( morphNormals[ i ].faceNormals[ j ].clone() );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tthis.morphNormals.push( morphNormal );\n\n\t\t\t}\n\n\t\t\t// skin weights\n\n\t\t\tvar skinWeights = source.skinWeights;\n\n\t\t\tfor ( i = 0, il = skinWeights.length; i < il; i ++ ) {\n\n\t\t\t\tthis.skinWeights.push( skinWeights[ i ].clone() );\n\n\t\t\t}\n\n\t\t\t// skin indices\n\n\t\t\tvar skinIndices = source.skinIndices;\n\n\t\t\tfor ( i = 0, il = skinIndices.length; i < il; i ++ ) {\n\n\t\t\t\tthis.skinIndices.push( skinIndices[ i ].clone() );\n\n\t\t\t}\n\n\t\t\t// line distances\n\n\t\t\tvar lineDistances = source.lineDistances;\n\n\t\t\tfor ( i = 0, il = lineDistances.length; i < il; i ++ ) {\n\n\t\t\t\tthis.lineDistances.push( lineDistances[ i ] );\n\n\t\t\t}\n\n\t\t\t// bounding box\n\n\t\t\tvar boundingBox = source.boundingBox;\n\n\t\t\tif ( boundingBox !== null ) {\n\n\t\t\t\tthis.boundingBox = boundingBox.clone();\n\n\t\t\t}\n\n\t\t\t// bounding sphere\n\n\t\t\tvar boundingSphere = source.boundingSphere;\n\n\t\t\tif ( boundingSphere !== null ) {\n\n\t\t\t\tthis.boundingSphere = boundingSphere.clone();\n\n\t\t\t}\n\n\t\t\t// update flags\n\n\t\t\tthis.elementsNeedUpdate = source.elementsNeedUpdate;\n\t\t\tthis.verticesNeedUpdate = source.verticesNeedUpdate;\n\t\t\tthis.uvsNeedUpdate = source.uvsNeedUpdate;\n\t\t\tthis.normalsNeedUpdate = source.normalsNeedUpdate;\n\t\t\tthis.colorsNeedUpdate = source.colorsNeedUpdate;\n\t\t\tthis.lineDistancesNeedUpdate = source.lineDistancesNeedUpdate;\n\t\t\tthis.groupsNeedUpdate = source.groupsNeedUpdate;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tdispose: function () {\n\n\t\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction BufferAttribute( array, itemSize, normalized ) {\n\n\t\tif ( Array.isArray( array ) ) {\n\n\t\t\tthrow new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );\n\n\t\t}\n\n\t\tthis.uuid = _Math.generateUUID();\n\t\tthis.name = '';\n\n\t\tthis.array = array;\n\t\tthis.itemSize = itemSize;\n\t\tthis.count = array !== undefined ? array.length / itemSize : 0;\n\t\tthis.normalized = normalized === true;\n\n\t\tthis.dynamic = false;\n\t\tthis.updateRange = { offset: 0, count: - 1 };\n\n\t\tthis.onUploadCallback = function () {};\n\n\t\tthis.version = 0;\n\n\t}\n\n\tObject.defineProperty( BufferAttribute.prototype, 'needsUpdate', {\n\n\t\tset: function ( value ) {\n\n\t\t\tif ( value === true ) this.version ++;\n\n\t\t}\n\n\t} );\n\n\tObject.assign( BufferAttribute.prototype, {\n\n\t\tisBufferAttribute: true,\n\n\t\tsetArray: function ( array ) {\n\n\t\t\tif ( Array.isArray( array ) ) {\n\n\t\t\t\tthrow new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );\n\n\t\t\t}\n\n\t\t\tthis.count = array !== undefined ? array.length / this.itemSize : 0;\n\t\t\tthis.array = array;\n\n\t\t},\n\n\t\tsetDynamic: function ( value ) {\n\n\t\t\tthis.dynamic = value;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcopy: function ( source ) {\n\n\t\t\tthis.array = new source.array.constructor( source.array );\n\t\t\tthis.itemSize = source.itemSize;\n\t\t\tthis.count = source.count;\n\t\t\tthis.normalized = source.normalized;\n\n\t\t\tthis.dynamic = source.dynamic;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcopyAt: function ( index1, attribute, index2 ) {\n\n\t\t\tindex1 *= this.itemSize;\n\t\t\tindex2 *= attribute.itemSize;\n\n\t\t\tfor ( var i = 0, l = this.itemSize; i < l; i ++ ) {\n\n\t\t\t\tthis.array[ index1 + i ] = attribute.array[ index2 + i ];\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcopyArray: function ( array ) {\n\n\t\t\tthis.array.set( array );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcopyColorsArray: function ( colors ) {\n\n\t\t\tvar array = this.array, offset = 0;\n\n\t\t\tfor ( var i = 0, l = colors.length; i < l; i ++ ) {\n\n\t\t\t\tvar color = colors[ i ];\n\n\t\t\t\tif ( color === undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i );\n\t\t\t\t\tcolor = new Color();\n\n\t\t\t\t}\n\n\t\t\t\tarray[ offset ++ ] = color.r;\n\t\t\t\tarray[ offset ++ ] = color.g;\n\t\t\t\tarray[ offset ++ ] = color.b;\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcopyIndicesArray: function ( indices ) {\n\n\t\t\tvar array = this.array, offset = 0;\n\n\t\t\tfor ( var i = 0, l = indices.length; i < l; i ++ ) {\n\n\t\t\t\tvar index = indices[ i ];\n\n\t\t\t\tarray[ offset ++ ] = index.a;\n\t\t\t\tarray[ offset ++ ] = index.b;\n\t\t\t\tarray[ offset ++ ] = index.c;\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcopyVector2sArray: function ( vectors ) {\n\n\t\t\tvar array = this.array, offset = 0;\n\n\t\t\tfor ( var i = 0, l = vectors.length; i < l; i ++ ) {\n\n\t\t\t\tvar vector = vectors[ i ];\n\n\t\t\t\tif ( vector === undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i );\n\t\t\t\t\tvector = new Vector2();\n\n\t\t\t\t}\n\n\t\t\t\tarray[ offset ++ ] = vector.x;\n\t\t\t\tarray[ offset ++ ] = vector.y;\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcopyVector3sArray: function ( vectors ) {\n\n\t\t\tvar array = this.array, offset = 0;\n\n\t\t\tfor ( var i = 0, l = vectors.length; i < l; i ++ ) {\n\n\t\t\t\tvar vector = vectors[ i ];\n\n\t\t\t\tif ( vector === undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i );\n\t\t\t\t\tvector = new Vector3();\n\n\t\t\t\t}\n\n\t\t\t\tarray[ offset ++ ] = vector.x;\n\t\t\t\tarray[ offset ++ ] = vector.y;\n\t\t\t\tarray[ offset ++ ] = vector.z;\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcopyVector4sArray: function ( vectors ) {\n\n\t\t\tvar array = this.array, offset = 0;\n\n\t\t\tfor ( var i = 0, l = vectors.length; i < l; i ++ ) {\n\n\t\t\t\tvar vector = vectors[ i ];\n\n\t\t\t\tif ( vector === undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i );\n\t\t\t\t\tvector = new Vector4();\n\n\t\t\t\t}\n\n\t\t\t\tarray[ offset ++ ] = vector.x;\n\t\t\t\tarray[ offset ++ ] = vector.y;\n\t\t\t\tarray[ offset ++ ] = vector.z;\n\t\t\t\tarray[ offset ++ ] = vector.w;\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tset: function ( value, offset ) {\n\n\t\t\tif ( offset === undefined ) offset = 0;\n\n\t\t\tthis.array.set( value, offset );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetX: function ( index ) {\n\n\t\t\treturn this.array[ index * this.itemSize ];\n\n\t\t},\n\n\t\tsetX: function ( index, x ) {\n\n\t\t\tthis.array[ index * this.itemSize ] = x;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetY: function ( index ) {\n\n\t\t\treturn this.array[ index * this.itemSize + 1 ];\n\n\t\t},\n\n\t\tsetY: function ( index, y ) {\n\n\t\t\tthis.array[ index * this.itemSize + 1 ] = y;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetZ: function ( index ) {\n\n\t\t\treturn this.array[ index * this.itemSize + 2 ];\n\n\t\t},\n\n\t\tsetZ: function ( index, z ) {\n\n\t\t\tthis.array[ index * this.itemSize + 2 ] = z;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetW: function ( index ) {\n\n\t\t\treturn this.array[ index * this.itemSize + 3 ];\n\n\t\t},\n\n\t\tsetW: function ( index, w ) {\n\n\t\t\tthis.array[ index * this.itemSize + 3 ] = w;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetXY: function ( index, x, y ) {\n\n\t\t\tindex *= this.itemSize;\n\n\t\t\tthis.array[ index + 0 ] = x;\n\t\t\tthis.array[ index + 1 ] = y;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetXYZ: function ( index, x, y, z ) {\n\n\t\t\tindex *= this.itemSize;\n\n\t\t\tthis.array[ index + 0 ] = x;\n\t\t\tthis.array[ index + 1 ] = y;\n\t\t\tthis.array[ index + 2 ] = z;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetXYZW: function ( index, x, y, z, w ) {\n\n\t\t\tindex *= this.itemSize;\n\n\t\t\tthis.array[ index + 0 ] = x;\n\t\t\tthis.array[ index + 1 ] = y;\n\t\t\tthis.array[ index + 2 ] = z;\n\t\t\tthis.array[ index + 3 ] = w;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tonUpload: function ( callback ) {\n\n\t\t\tthis.onUploadCallback = callback;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor( this.array, this.itemSize ).copy( this );\n\n\t\t}\n\n\t} );\n\n\t//\n\n\tfunction Int8BufferAttribute( array, itemSize ) {\n\n\t\tBufferAttribute.call( this, new Int8Array( array ), itemSize );\n\n\t}\n\n\tInt8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );\n\tInt8BufferAttribute.prototype.constructor = Int8BufferAttribute;\n\n\n\tfunction Uint8BufferAttribute( array, itemSize ) {\n\n\t\tBufferAttribute.call( this, new Uint8Array( array ), itemSize );\n\n\t}\n\n\tUint8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );\n\tUint8BufferAttribute.prototype.constructor = Uint8BufferAttribute;\n\n\n\tfunction Uint8ClampedBufferAttribute( array, itemSize ) {\n\n\t\tBufferAttribute.call( this, new Uint8ClampedArray( array ), itemSize );\n\n\t}\n\n\tUint8ClampedBufferAttribute.prototype = Object.create( BufferAttribute.prototype );\n\tUint8ClampedBufferAttribute.prototype.constructor = Uint8ClampedBufferAttribute;\n\n\n\tfunction Int16BufferAttribute( array, itemSize ) {\n\n\t\tBufferAttribute.call( this, new Int16Array( array ), itemSize );\n\n\t}\n\n\tInt16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );\n\tInt16BufferAttribute.prototype.constructor = Int16BufferAttribute;\n\n\n\tfunction Uint16BufferAttribute( array, itemSize ) {\n\n\t\tBufferAttribute.call( this, new Uint16Array( array ), itemSize );\n\n\t}\n\n\tUint16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );\n\tUint16BufferAttribute.prototype.constructor = Uint16BufferAttribute;\n\n\n\tfunction Int32BufferAttribute( array, itemSize ) {\n\n\t\tBufferAttribute.call( this, new Int32Array( array ), itemSize );\n\n\t}\n\n\tInt32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );\n\tInt32BufferAttribute.prototype.constructor = Int32BufferAttribute;\n\n\n\tfunction Uint32BufferAttribute( array, itemSize ) {\n\n\t\tBufferAttribute.call( this, new Uint32Array( array ), itemSize );\n\n\t}\n\n\tUint32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );\n\tUint32BufferAttribute.prototype.constructor = Uint32BufferAttribute;\n\n\n\tfunction Float32BufferAttribute( array, itemSize ) {\n\n\t\tBufferAttribute.call( this, new Float32Array( array ), itemSize );\n\n\t}\n\n\tFloat32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );\n\tFloat32BufferAttribute.prototype.constructor = Float32BufferAttribute;\n\n\n\tfunction Float64BufferAttribute( array, itemSize ) {\n\n\t\tBufferAttribute.call( this, new Float64Array( array ), itemSize );\n\n\t}\n\n\tFloat64BufferAttribute.prototype = Object.create( BufferAttribute.prototype );\n\tFloat64BufferAttribute.prototype.constructor = Float64BufferAttribute;\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction DirectGeometry() {\n\n\t\tthis.indices = [];\n\t\tthis.vertices = [];\n\t\tthis.normals = [];\n\t\tthis.colors = [];\n\t\tthis.uvs = [];\n\t\tthis.uvs2 = [];\n\n\t\tthis.groups = [];\n\n\t\tthis.morphTargets = {};\n\n\t\tthis.skinWeights = [];\n\t\tthis.skinIndices = [];\n\n\t\t// this.lineDistances = [];\n\n\t\tthis.boundingBox = null;\n\t\tthis.boundingSphere = null;\n\n\t\t// update flags\n\n\t\tthis.verticesNeedUpdate = false;\n\t\tthis.normalsNeedUpdate = false;\n\t\tthis.colorsNeedUpdate = false;\n\t\tthis.uvsNeedUpdate = false;\n\t\tthis.groupsNeedUpdate = false;\n\n\t}\n\n\tObject.assign( DirectGeometry.prototype, {\n\n\t\tcomputeGroups: function ( geometry ) {\n\n\t\t\tvar group;\n\t\t\tvar groups = [];\n\t\t\tvar materialIndex = undefined;\n\n\t\t\tvar faces = geometry.faces;\n\n\t\t\tfor ( var i = 0; i < faces.length; i ++ ) {\n\n\t\t\t\tvar face = faces[ i ];\n\n\t\t\t\t// materials\n\n\t\t\t\tif ( face.materialIndex !== materialIndex ) {\n\n\t\t\t\t\tmaterialIndex = face.materialIndex;\n\n\t\t\t\t\tif ( group !== undefined ) {\n\n\t\t\t\t\t\tgroup.count = ( i * 3 ) - group.start;\n\t\t\t\t\t\tgroups.push( group );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tgroup = {\n\t\t\t\t\t\tstart: i * 3,\n\t\t\t\t\t\tmaterialIndex: materialIndex\n\t\t\t\t\t};\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( group !== undefined ) {\n\n\t\t\t\tgroup.count = ( i * 3 ) - group.start;\n\t\t\t\tgroups.push( group );\n\n\t\t\t}\n\n\t\t\tthis.groups = groups;\n\n\t\t},\n\n\t\tfromGeometry: function ( geometry ) {\n\n\t\t\tvar faces = geometry.faces;\n\t\t\tvar vertices = geometry.vertices;\n\t\t\tvar faceVertexUvs = geometry.faceVertexUvs;\n\n\t\t\tvar hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0;\n\t\t\tvar hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0;\n\n\t\t\t// morphs\n\n\t\t\tvar morphTargets = geometry.morphTargets;\n\t\t\tvar morphTargetsLength = morphTargets.length;\n\n\t\t\tvar morphTargetsPosition;\n\n\t\t\tif ( morphTargetsLength > 0 ) {\n\n\t\t\t\tmorphTargetsPosition = [];\n\n\t\t\t\tfor ( var i = 0; i < morphTargetsLength; i ++ ) {\n\n\t\t\t\t\tmorphTargetsPosition[ i ] = [];\n\n\t\t\t\t}\n\n\t\t\t\tthis.morphTargets.position = morphTargetsPosition;\n\n\t\t\t}\n\n\t\t\tvar morphNormals = geometry.morphNormals;\n\t\t\tvar morphNormalsLength = morphNormals.length;\n\n\t\t\tvar morphTargetsNormal;\n\n\t\t\tif ( morphNormalsLength > 0 ) {\n\n\t\t\t\tmorphTargetsNormal = [];\n\n\t\t\t\tfor ( var i = 0; i < morphNormalsLength; i ++ ) {\n\n\t\t\t\t\tmorphTargetsNormal[ i ] = [];\n\n\t\t\t\t}\n\n\t\t\t\tthis.morphTargets.normal = morphTargetsNormal;\n\n\t\t\t}\n\n\t\t\t// skins\n\n\t\t\tvar skinIndices = geometry.skinIndices;\n\t\t\tvar skinWeights = geometry.skinWeights;\n\n\t\t\tvar hasSkinIndices = skinIndices.length === vertices.length;\n\t\t\tvar hasSkinWeights = skinWeights.length === vertices.length;\n\n\t\t\t//\n\n\t\t\tfor ( var i = 0; i < faces.length; i ++ ) {\n\n\t\t\t\tvar face = faces[ i ];\n\n\t\t\t\tthis.vertices.push( vertices[ face.a ], vertices[ face.b ], vertices[ face.c ] );\n\n\t\t\t\tvar vertexNormals = face.vertexNormals;\n\n\t\t\t\tif ( vertexNormals.length === 3 ) {\n\n\t\t\t\t\tthis.normals.push( vertexNormals[ 0 ], vertexNormals[ 1 ], vertexNormals[ 2 ] );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tvar normal = face.normal;\n\n\t\t\t\t\tthis.normals.push( normal, normal, normal );\n\n\t\t\t\t}\n\n\t\t\t\tvar vertexColors = face.vertexColors;\n\n\t\t\t\tif ( vertexColors.length === 3 ) {\n\n\t\t\t\t\tthis.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tvar color = face.color;\n\n\t\t\t\t\tthis.colors.push( color, color, color );\n\n\t\t\t\t}\n\n\t\t\t\tif ( hasFaceVertexUv === true ) {\n\n\t\t\t\t\tvar vertexUvs = faceVertexUvs[ 0 ][ i ];\n\n\t\t\t\t\tif ( vertexUvs !== undefined ) {\n\n\t\t\t\t\t\tthis.uvs.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tconsole.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i );\n\n\t\t\t\t\t\tthis.uvs.push( new Vector2(), new Vector2(), new Vector2() );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( hasFaceVertexUv2 === true ) {\n\n\t\t\t\t\tvar vertexUvs = faceVertexUvs[ 1 ][ i ];\n\n\t\t\t\t\tif ( vertexUvs !== undefined ) {\n\n\t\t\t\t\t\tthis.uvs2.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tconsole.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i );\n\n\t\t\t\t\t\tthis.uvs2.push( new Vector2(), new Vector2(), new Vector2() );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t// morphs\n\n\t\t\t\tfor ( var j = 0; j < morphTargetsLength; j ++ ) {\n\n\t\t\t\t\tvar morphTarget = morphTargets[ j ].vertices;\n\n\t\t\t\t\tmorphTargetsPosition[ j ].push( morphTarget[ face.a ], morphTarget[ face.b ], morphTarget[ face.c ] );\n\n\t\t\t\t}\n\n\t\t\t\tfor ( var j = 0; j < morphNormalsLength; j ++ ) {\n\n\t\t\t\t\tvar morphNormal = morphNormals[ j ].vertexNormals[ i ];\n\n\t\t\t\t\tmorphTargetsNormal[ j ].push( morphNormal.a, morphNormal.b, morphNormal.c );\n\n\t\t\t\t}\n\n\t\t\t\t// skins\n\n\t\t\t\tif ( hasSkinIndices ) {\n\n\t\t\t\t\tthis.skinIndices.push( skinIndices[ face.a ], skinIndices[ face.b ], skinIndices[ face.c ] );\n\n\t\t\t\t}\n\n\t\t\t\tif ( hasSkinWeights ) {\n\n\t\t\t\t\tthis.skinWeights.push( skinWeights[ face.a ], skinWeights[ face.b ], skinWeights[ face.c ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.computeGroups( geometry );\n\n\t\t\tthis.verticesNeedUpdate = geometry.verticesNeedUpdate;\n\t\t\tthis.normalsNeedUpdate = geometry.normalsNeedUpdate;\n\t\t\tthis.colorsNeedUpdate = geometry.colorsNeedUpdate;\n\t\t\tthis.uvsNeedUpdate = geometry.uvsNeedUpdate;\n\t\t\tthis.groupsNeedUpdate = geometry.groupsNeedUpdate;\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction arrayMax( array ) {\n\n\t\tif ( array.length === 0 ) return - Infinity;\n\n\t\tvar max = array[ 0 ];\n\n\t\tfor ( var i = 1, l = array.length; i < l; ++ i ) {\n\n\t\t\tif ( array[ i ] > max ) max = array[ i ];\n\n\t\t}\n\n\t\treturn max;\n\n\t}\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction BufferGeometry() {\n\n\t\tObject.defineProperty( this, 'id', { value: GeometryIdCount() } );\n\n\t\tthis.uuid = _Math.generateUUID();\n\n\t\tthis.name = '';\n\t\tthis.type = 'BufferGeometry';\n\n\t\tthis.index = null;\n\t\tthis.attributes = {};\n\n\t\tthis.morphAttributes = {};\n\n\t\tthis.groups = [];\n\n\t\tthis.boundingBox = null;\n\t\tthis.boundingSphere = null;\n\n\t\tthis.drawRange = { start: 0, count: Infinity };\n\n\t}\n\n\tBufferGeometry.MaxIndex = 65535;\n\n\tObject.assign( BufferGeometry.prototype, EventDispatcher.prototype, {\n\n\t\tisBufferGeometry: true,\n\n\t\tgetIndex: function () {\n\n\t\t\treturn this.index;\n\n\t\t},\n\n\t\tsetIndex: function ( index ) {\n\n\t\t\tif ( Array.isArray( index ) ) {\n\n\t\t\t\tthis.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 );\n\n\t\t\t} else {\n\n\t\t\t\tthis.index = index;\n\n\t\t\t}\n\n\t\t},\n\n\t\taddAttribute: function ( name, attribute ) {\n\n\t\t\tif ( ! ( attribute && attribute.isBufferAttribute ) && ! ( attribute && attribute.isInterleavedBufferAttribute ) ) {\n\n\t\t\t\tconsole.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );\n\n\t\t\t\tthis.addAttribute( name, new BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) );\n\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tif ( name === 'index' ) {\n\n\t\t\t\tconsole.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' );\n\t\t\t\tthis.setIndex( attribute );\n\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tthis.attributes[ name ] = attribute;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetAttribute: function ( name ) {\n\n\t\t\treturn this.attributes[ name ];\n\n\t\t},\n\n\t\tremoveAttribute: function ( name ) {\n\n\t\t\tdelete this.attributes[ name ];\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\taddGroup: function ( start, count, materialIndex ) {\n\n\t\t\tthis.groups.push( {\n\n\t\t\t\tstart: start,\n\t\t\t\tcount: count,\n\t\t\t\tmaterialIndex: materialIndex !== undefined ? materialIndex : 0\n\n\t\t\t} );\n\n\t\t},\n\n\t\tclearGroups: function () {\n\n\t\t\tthis.groups = [];\n\n\t\t},\n\n\t\tsetDrawRange: function ( start, count ) {\n\n\t\t\tthis.drawRange.start = start;\n\t\t\tthis.drawRange.count = count;\n\n\t\t},\n\n\t\tapplyMatrix: function ( matrix ) {\n\n\t\t\tvar position = this.attributes.position;\n\n\t\t\tif ( position !== undefined ) {\n\n\t\t\t\tmatrix.applyToBufferAttribute( position );\n\t\t\t\tposition.needsUpdate = true;\n\n\t\t\t}\n\n\t\t\tvar normal = this.attributes.normal;\n\n\t\t\tif ( normal !== undefined ) {\n\n\t\t\t\tvar normalMatrix = new Matrix3().getNormalMatrix( matrix );\n\n\t\t\t\tnormalMatrix.applyToBufferAttribute( normal );\n\t\t\t\tnormal.needsUpdate = true;\n\n\t\t\t}\n\n\t\t\tif ( this.boundingBox !== null ) {\n\n\t\t\t\tthis.computeBoundingBox();\n\n\t\t\t}\n\n\t\t\tif ( this.boundingSphere !== null ) {\n\n\t\t\t\tthis.computeBoundingSphere();\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\trotateX: function () {\n\n\t\t\t// rotate geometry around world x-axis\n\n\t\t\tvar m1 = new Matrix4();\n\n\t\t\treturn function rotateX( angle ) {\n\n\t\t\t\tm1.makeRotationX( angle );\n\n\t\t\t\tthis.applyMatrix( m1 );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\trotateY: function () {\n\n\t\t\t// rotate geometry around world y-axis\n\n\t\t\tvar m1 = new Matrix4();\n\n\t\t\treturn function rotateY( angle ) {\n\n\t\t\t\tm1.makeRotationY( angle );\n\n\t\t\t\tthis.applyMatrix( m1 );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\trotateZ: function () {\n\n\t\t\t// rotate geometry around world z-axis\n\n\t\t\tvar m1 = new Matrix4();\n\n\t\t\treturn function rotateZ( angle ) {\n\n\t\t\t\tm1.makeRotationZ( angle );\n\n\t\t\t\tthis.applyMatrix( m1 );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\ttranslate: function () {\n\n\t\t\t// translate geometry\n\n\t\t\tvar m1 = new Matrix4();\n\n\t\t\treturn function translate( x, y, z ) {\n\n\t\t\t\tm1.makeTranslation( x, y, z );\n\n\t\t\t\tthis.applyMatrix( m1 );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tscale: function () {\n\n\t\t\t// scale geometry\n\n\t\t\tvar m1 = new Matrix4();\n\n\t\t\treturn function scale( x, y, z ) {\n\n\t\t\t\tm1.makeScale( x, y, z );\n\n\t\t\t\tthis.applyMatrix( m1 );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tlookAt: function () {\n\n\t\t\tvar obj = new Object3D();\n\n\t\t\treturn function lookAt( vector ) {\n\n\t\t\t\tobj.lookAt( vector );\n\n\t\t\t\tobj.updateMatrix();\n\n\t\t\t\tthis.applyMatrix( obj.matrix );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tcenter: function () {\n\n\t\t\tthis.computeBoundingBox();\n\n\t\t\tvar offset = this.boundingBox.getCenter().negate();\n\n\t\t\tthis.translate( offset.x, offset.y, offset.z );\n\n\t\t\treturn offset;\n\n\t\t},\n\n\t\tsetFromObject: function ( object ) {\n\n\t\t\t// console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this );\n\n\t\t\tvar geometry = object.geometry;\n\n\t\t\tif ( object.isPoints || object.isLine ) {\n\n\t\t\t\tvar positions = new Float32BufferAttribute( geometry.vertices.length * 3, 3 );\n\t\t\t\tvar colors = new Float32BufferAttribute( geometry.colors.length * 3, 3 );\n\n\t\t\t\tthis.addAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) );\n\t\t\t\tthis.addAttribute( 'color', colors.copyColorsArray( geometry.colors ) );\n\n\t\t\t\tif ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) {\n\n\t\t\t\t\tvar lineDistances = new Float32BufferAttribute( geometry.lineDistances.length, 1 );\n\n\t\t\t\t\tthis.addAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) );\n\n\t\t\t\t}\n\n\t\t\t\tif ( geometry.boundingSphere !== null ) {\n\n\t\t\t\t\tthis.boundingSphere = geometry.boundingSphere.clone();\n\n\t\t\t\t}\n\n\t\t\t\tif ( geometry.boundingBox !== null ) {\n\n\t\t\t\t\tthis.boundingBox = geometry.boundingBox.clone();\n\n\t\t\t\t}\n\n\t\t\t} else if ( object.isMesh ) {\n\n\t\t\t\tif ( geometry && geometry.isGeometry ) {\n\n\t\t\t\t\tthis.fromGeometry( geometry );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tupdateFromObject: function ( object ) {\n\n\t\t\tvar geometry = object.geometry;\n\n\t\t\tif ( object.isMesh ) {\n\n\t\t\t\tvar direct = geometry.__directGeometry;\n\n\t\t\t\tif ( geometry.elementsNeedUpdate === true ) {\n\n\t\t\t\t\tdirect = undefined;\n\t\t\t\t\tgeometry.elementsNeedUpdate = false;\n\n\t\t\t\t}\n\n\t\t\t\tif ( direct === undefined ) {\n\n\t\t\t\t\treturn this.fromGeometry( geometry );\n\n\t\t\t\t}\n\n\t\t\t\tdirect.verticesNeedUpdate = geometry.verticesNeedUpdate;\n\t\t\t\tdirect.normalsNeedUpdate = geometry.normalsNeedUpdate;\n\t\t\t\tdirect.colorsNeedUpdate = geometry.colorsNeedUpdate;\n\t\t\t\tdirect.uvsNeedUpdate = geometry.uvsNeedUpdate;\n\t\t\t\tdirect.groupsNeedUpdate = geometry.groupsNeedUpdate;\n\n\t\t\t\tgeometry.verticesNeedUpdate = false;\n\t\t\t\tgeometry.normalsNeedUpdate = false;\n\t\t\t\tgeometry.colorsNeedUpdate = false;\n\t\t\t\tgeometry.uvsNeedUpdate = false;\n\t\t\t\tgeometry.groupsNeedUpdate = false;\n\n\t\t\t\tgeometry = direct;\n\n\t\t\t}\n\n\t\t\tvar attribute;\n\n\t\t\tif ( geometry.verticesNeedUpdate === true ) {\n\n\t\t\t\tattribute = this.attributes.position;\n\n\t\t\t\tif ( attribute !== undefined ) {\n\n\t\t\t\t\tattribute.copyVector3sArray( geometry.vertices );\n\t\t\t\t\tattribute.needsUpdate = true;\n\n\t\t\t\t}\n\n\t\t\t\tgeometry.verticesNeedUpdate = false;\n\n\t\t\t}\n\n\t\t\tif ( geometry.normalsNeedUpdate === true ) {\n\n\t\t\t\tattribute = this.attributes.normal;\n\n\t\t\t\tif ( attribute !== undefined ) {\n\n\t\t\t\t\tattribute.copyVector3sArray( geometry.normals );\n\t\t\t\t\tattribute.needsUpdate = true;\n\n\t\t\t\t}\n\n\t\t\t\tgeometry.normalsNeedUpdate = false;\n\n\t\t\t}\n\n\t\t\tif ( geometry.colorsNeedUpdate === true ) {\n\n\t\t\t\tattribute = this.attributes.color;\n\n\t\t\t\tif ( attribute !== undefined ) {\n\n\t\t\t\t\tattribute.copyColorsArray( geometry.colors );\n\t\t\t\t\tattribute.needsUpdate = true;\n\n\t\t\t\t}\n\n\t\t\t\tgeometry.colorsNeedUpdate = false;\n\n\t\t\t}\n\n\t\t\tif ( geometry.uvsNeedUpdate ) {\n\n\t\t\t\tattribute = this.attributes.uv;\n\n\t\t\t\tif ( attribute !== undefined ) {\n\n\t\t\t\t\tattribute.copyVector2sArray( geometry.uvs );\n\t\t\t\t\tattribute.needsUpdate = true;\n\n\t\t\t\t}\n\n\t\t\t\tgeometry.uvsNeedUpdate = false;\n\n\t\t\t}\n\n\t\t\tif ( geometry.lineDistancesNeedUpdate ) {\n\n\t\t\t\tattribute = this.attributes.lineDistance;\n\n\t\t\t\tif ( attribute !== undefined ) {\n\n\t\t\t\t\tattribute.copyArray( geometry.lineDistances );\n\t\t\t\t\tattribute.needsUpdate = true;\n\n\t\t\t\t}\n\n\t\t\t\tgeometry.lineDistancesNeedUpdate = false;\n\n\t\t\t}\n\n\t\t\tif ( geometry.groupsNeedUpdate ) {\n\n\t\t\t\tgeometry.computeGroups( object.geometry );\n\t\t\t\tthis.groups = geometry.groups;\n\n\t\t\t\tgeometry.groupsNeedUpdate = false;\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tfromGeometry: function ( geometry ) {\n\n\t\t\tgeometry.__directGeometry = new DirectGeometry().fromGeometry( geometry );\n\n\t\t\treturn this.fromDirectGeometry( geometry.__directGeometry );\n\n\t\t},\n\n\t\tfromDirectGeometry: function ( geometry ) {\n\n\t\t\tvar positions = new Float32Array( geometry.vertices.length * 3 );\n\t\t\tthis.addAttribute( 'position', new BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) );\n\n\t\t\tif ( geometry.normals.length > 0 ) {\n\n\t\t\t\tvar normals = new Float32Array( geometry.normals.length * 3 );\n\t\t\t\tthis.addAttribute( 'normal', new BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) );\n\n\t\t\t}\n\n\t\t\tif ( geometry.colors.length > 0 ) {\n\n\t\t\t\tvar colors = new Float32Array( geometry.colors.length * 3 );\n\t\t\t\tthis.addAttribute( 'color', new BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) );\n\n\t\t\t}\n\n\t\t\tif ( geometry.uvs.length > 0 ) {\n\n\t\t\t\tvar uvs = new Float32Array( geometry.uvs.length * 2 );\n\t\t\t\tthis.addAttribute( 'uv', new BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) );\n\n\t\t\t}\n\n\t\t\tif ( geometry.uvs2.length > 0 ) {\n\n\t\t\t\tvar uvs2 = new Float32Array( geometry.uvs2.length * 2 );\n\t\t\t\tthis.addAttribute( 'uv2', new BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) );\n\n\t\t\t}\n\n\t\t\tif ( geometry.indices.length > 0 ) {\n\n\t\t\t\tvar TypeArray = arrayMax( geometry.indices ) > 65535 ? Uint32Array : Uint16Array;\n\t\t\t\tvar indices = new TypeArray( geometry.indices.length * 3 );\n\t\t\t\tthis.setIndex( new BufferAttribute( indices, 1 ).copyIndicesArray( geometry.indices ) );\n\n\t\t\t}\n\n\t\t\t// groups\n\n\t\t\tthis.groups = geometry.groups;\n\n\t\t\t// morphs\n\n\t\t\tfor ( var name in geometry.morphTargets ) {\n\n\t\t\t\tvar array = [];\n\t\t\t\tvar morphTargets = geometry.morphTargets[ name ];\n\n\t\t\t\tfor ( var i = 0, l = morphTargets.length; i < l; i ++ ) {\n\n\t\t\t\t\tvar morphTarget = morphTargets[ i ];\n\n\t\t\t\t\tvar attribute = new Float32BufferAttribute( morphTarget.length * 3, 3 );\n\n\t\t\t\t\tarray.push( attribute.copyVector3sArray( morphTarget ) );\n\n\t\t\t\t}\n\n\t\t\t\tthis.morphAttributes[ name ] = array;\n\n\t\t\t}\n\n\t\t\t// skinning\n\n\t\t\tif ( geometry.skinIndices.length > 0 ) {\n\n\t\t\t\tvar skinIndices = new Float32BufferAttribute( geometry.skinIndices.length * 4, 4 );\n\t\t\t\tthis.addAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) );\n\n\t\t\t}\n\n\t\t\tif ( geometry.skinWeights.length > 0 ) {\n\n\t\t\t\tvar skinWeights = new Float32BufferAttribute( geometry.skinWeights.length * 4, 4 );\n\t\t\t\tthis.addAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) );\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tif ( geometry.boundingSphere !== null ) {\n\n\t\t\t\tthis.boundingSphere = geometry.boundingSphere.clone();\n\n\t\t\t}\n\n\t\t\tif ( geometry.boundingBox !== null ) {\n\n\t\t\t\tthis.boundingBox = geometry.boundingBox.clone();\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcomputeBoundingBox: function () {\n\n\t\t\tif ( this.boundingBox === null ) {\n\n\t\t\t\tthis.boundingBox = new Box3();\n\n\t\t\t}\n\n\t\t\tvar position = this.attributes.position;\n\n\t\t\tif ( position !== undefined ) {\n\n\t\t\t\tthis.boundingBox.setFromBufferAttribute( position );\n\n\t\t\t} else {\n\n\t\t\t\tthis.boundingBox.makeEmpty();\n\n\t\t\t}\n\n\t\t\tif ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {\n\n\t\t\t\tconsole.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The \"position\" attribute is likely to have NaN values.', this );\n\n\t\t\t}\n\n\t\t},\n\n\t\tcomputeBoundingSphere: function () {\n\n\t\t\tvar box = new Box3();\n\t\t\tvar vector = new Vector3();\n\n\t\t\treturn function computeBoundingSphere() {\n\n\t\t\t\tif ( this.boundingSphere === null ) {\n\n\t\t\t\t\tthis.boundingSphere = new Sphere();\n\n\t\t\t\t}\n\n\t\t\t\tvar position = this.attributes.position;\n\n\t\t\t\tif ( position ) {\n\n\t\t\t\t\tvar center = this.boundingSphere.center;\n\n\t\t\t\t\tbox.setFromBufferAttribute( position );\n\t\t\t\t\tbox.getCenter( center );\n\n\t\t\t\t\t// hoping to find a boundingSphere with a radius smaller than the\n\t\t\t\t\t// boundingSphere of the boundingBox: sqrt(3) smaller in the best case\n\n\t\t\t\t\tvar maxRadiusSq = 0;\n\n\t\t\t\t\tfor ( var i = 0, il = position.count; i < il; i ++ ) {\n\n\t\t\t\t\t\tvector.x = position.getX( i );\n\t\t\t\t\t\tvector.y = position.getY( i );\n\t\t\t\t\t\tvector.z = position.getZ( i );\n\t\t\t\t\t\tmaxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.boundingSphere.radius = Math.sqrt( maxRadiusSq );\n\n\t\t\t\t\tif ( isNaN( this.boundingSphere.radius ) ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The \"position\" attribute is likely to have NaN values.', this );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tcomputeFaceNormals: function () {\n\n\t\t\t// backwards compatibility\n\n\t\t},\n\n\t\tcomputeVertexNormals: function () {\n\n\t\t\tvar index = this.index;\n\t\t\tvar attributes = this.attributes;\n\t\t\tvar groups = this.groups;\n\n\t\t\tif ( attributes.position ) {\n\n\t\t\t\tvar positions = attributes.position.array;\n\n\t\t\t\tif ( attributes.normal === undefined ) {\n\n\t\t\t\t\tthis.addAttribute( 'normal', new BufferAttribute( new Float32Array( positions.length ), 3 ) );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// reset existing normals to zero\n\n\t\t\t\t\tvar array = attributes.normal.array;\n\n\t\t\t\t\tfor ( var i = 0, il = array.length; i < il; i ++ ) {\n\n\t\t\t\t\t\tarray[ i ] = 0;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tvar normals = attributes.normal.array;\n\n\t\t\t\tvar vA, vB, vC;\n\t\t\t\tvar pA = new Vector3(), pB = new Vector3(), pC = new Vector3();\n\t\t\t\tvar cb = new Vector3(), ab = new Vector3();\n\n\t\t\t\t// indexed elements\n\n\t\t\t\tif ( index ) {\n\n\t\t\t\t\tvar indices = index.array;\n\n\t\t\t\t\tif ( groups.length === 0 ) {\n\n\t\t\t\t\t\tthis.addGroup( 0, indices.length );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfor ( var j = 0, jl = groups.length; j < jl; ++ j ) {\n\n\t\t\t\t\t\tvar group = groups[ j ];\n\n\t\t\t\t\t\tvar start = group.start;\n\t\t\t\t\t\tvar count = group.count;\n\n\t\t\t\t\t\tfor ( var i = start, il = start + count; i < il; i += 3 ) {\n\n\t\t\t\t\t\t\tvA = indices[ i + 0 ] * 3;\n\t\t\t\t\t\t\tvB = indices[ i + 1 ] * 3;\n\t\t\t\t\t\t\tvC = indices[ i + 2 ] * 3;\n\n\t\t\t\t\t\t\tpA.fromArray( positions, vA );\n\t\t\t\t\t\t\tpB.fromArray( positions, vB );\n\t\t\t\t\t\t\tpC.fromArray( positions, vC );\n\n\t\t\t\t\t\t\tcb.subVectors( pC, pB );\n\t\t\t\t\t\t\tab.subVectors( pA, pB );\n\t\t\t\t\t\t\tcb.cross( ab );\n\n\t\t\t\t\t\t\tnormals[ vA ] += cb.x;\n\t\t\t\t\t\t\tnormals[ vA + 1 ] += cb.y;\n\t\t\t\t\t\t\tnormals[ vA + 2 ] += cb.z;\n\n\t\t\t\t\t\t\tnormals[ vB ] += cb.x;\n\t\t\t\t\t\t\tnormals[ vB + 1 ] += cb.y;\n\t\t\t\t\t\t\tnormals[ vB + 2 ] += cb.z;\n\n\t\t\t\t\t\t\tnormals[ vC ] += cb.x;\n\t\t\t\t\t\t\tnormals[ vC + 1 ] += cb.y;\n\t\t\t\t\t\t\tnormals[ vC + 2 ] += cb.z;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// non-indexed elements (unconnected triangle soup)\n\n\t\t\t\t\tfor ( var i = 0, il = positions.length; i < il; i += 9 ) {\n\n\t\t\t\t\t\tpA.fromArray( positions, i );\n\t\t\t\t\t\tpB.fromArray( positions, i + 3 );\n\t\t\t\t\t\tpC.fromArray( positions, i + 6 );\n\n\t\t\t\t\t\tcb.subVectors( pC, pB );\n\t\t\t\t\t\tab.subVectors( pA, pB );\n\t\t\t\t\t\tcb.cross( ab );\n\n\t\t\t\t\t\tnormals[ i ] = cb.x;\n\t\t\t\t\t\tnormals[ i + 1 ] = cb.y;\n\t\t\t\t\t\tnormals[ i + 2 ] = cb.z;\n\n\t\t\t\t\t\tnormals[ i + 3 ] = cb.x;\n\t\t\t\t\t\tnormals[ i + 4 ] = cb.y;\n\t\t\t\t\t\tnormals[ i + 5 ] = cb.z;\n\n\t\t\t\t\t\tnormals[ i + 6 ] = cb.x;\n\t\t\t\t\t\tnormals[ i + 7 ] = cb.y;\n\t\t\t\t\t\tnormals[ i + 8 ] = cb.z;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tthis.normalizeNormals();\n\n\t\t\t\tattributes.normal.needsUpdate = true;\n\n\t\t\t}\n\n\t\t},\n\n\t\tmerge: function ( geometry, offset ) {\n\n\t\t\tif ( ! ( geometry && geometry.isBufferGeometry ) ) {\n\n\t\t\t\tconsole.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tif ( offset === undefined ) offset = 0;\n\n\t\t\tvar attributes = this.attributes;\n\n\t\t\tfor ( var key in attributes ) {\n\n\t\t\t\tif ( geometry.attributes[ key ] === undefined ) continue;\n\n\t\t\t\tvar attribute1 = attributes[ key ];\n\t\t\t\tvar attributeArray1 = attribute1.array;\n\n\t\t\t\tvar attribute2 = geometry.attributes[ key ];\n\t\t\t\tvar attributeArray2 = attribute2.array;\n\n\t\t\t\tvar attributeSize = attribute2.itemSize;\n\n\t\t\t\tfor ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) {\n\n\t\t\t\t\tattributeArray1[ j ] = attributeArray2[ i ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tnormalizeNormals: function () {\n\n\t\t\tvar vector = new Vector3();\n\n\t\t\treturn function normalizeNormals() {\n\n\t\t\t\tvar normals = this.attributes.normal;\n\n\t\t\t\tfor ( var i = 0, il = normals.count; i < il; i ++ ) {\n\n\t\t\t\t\tvector.x = normals.getX( i );\n\t\t\t\t\tvector.y = normals.getY( i );\n\t\t\t\t\tvector.z = normals.getZ( i );\n\n\t\t\t\t\tvector.normalize();\n\n\t\t\t\t\tnormals.setXYZ( i, vector.x, vector.y, vector.z );\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t}(),\n\n\t\ttoNonIndexed: function () {\n\n\t\t\tif ( this.index === null ) {\n\n\t\t\t\tconsole.warn( 'THREE.BufferGeometry.toNonIndexed(): Geometry is already non-indexed.' );\n\t\t\t\treturn this;\n\n\t\t\t}\n\n\t\t\tvar geometry2 = new BufferGeometry();\n\n\t\t\tvar indices = this.index.array;\n\t\t\tvar attributes = this.attributes;\n\n\t\t\tfor ( var name in attributes ) {\n\n\t\t\t\tvar attribute = attributes[ name ];\n\n\t\t\t\tvar array = attribute.array;\n\t\t\t\tvar itemSize = attribute.itemSize;\n\n\t\t\t\tvar array2 = new array.constructor( indices.length * itemSize );\n\n\t\t\t\tvar index = 0, index2 = 0;\n\n\t\t\t\tfor ( var i = 0, l = indices.length; i < l; i ++ ) {\n\n\t\t\t\t\tindex = indices[ i ] * itemSize;\n\n\t\t\t\t\tfor ( var j = 0; j < itemSize; j ++ ) {\n\n\t\t\t\t\t\tarray2[ index2 ++ ] = array[ index ++ ];\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tgeometry2.addAttribute( name, new BufferAttribute( array2, itemSize ) );\n\n\t\t\t}\n\n\t\t\treturn geometry2;\n\n\t\t},\n\n\t\ttoJSON: function () {\n\n\t\t\tvar data = {\n\t\t\t\tmetadata: {\n\t\t\t\t\tversion: 4.5,\n\t\t\t\t\ttype: 'BufferGeometry',\n\t\t\t\t\tgenerator: 'BufferGeometry.toJSON'\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// standard BufferGeometry serialization\n\n\t\t\tdata.uuid = this.uuid;\n\t\t\tdata.type = this.type;\n\t\t\tif ( this.name !== '' ) data.name = this.name;\n\n\t\t\tif ( this.parameters !== undefined ) {\n\n\t\t\t\tvar parameters = this.parameters;\n\n\t\t\t\tfor ( var key in parameters ) {\n\n\t\t\t\t\tif ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];\n\n\t\t\t\t}\n\n\t\t\t\treturn data;\n\n\t\t\t}\n\n\t\t\tdata.data = { attributes: {} };\n\n\t\t\tvar index = this.index;\n\n\t\t\tif ( index !== null ) {\n\n\t\t\t\tvar array = Array.prototype.slice.call( index.array );\n\n\t\t\t\tdata.data.index = {\n\t\t\t\t\ttype: index.array.constructor.name,\n\t\t\t\t\tarray: array\n\t\t\t\t};\n\n\t\t\t}\n\n\t\t\tvar attributes = this.attributes;\n\n\t\t\tfor ( var key in attributes ) {\n\n\t\t\t\tvar attribute = attributes[ key ];\n\n\t\t\t\tvar array = Array.prototype.slice.call( attribute.array );\n\n\t\t\t\tdata.data.attributes[ key ] = {\n\t\t\t\t\titemSize: attribute.itemSize,\n\t\t\t\t\ttype: attribute.array.constructor.name,\n\t\t\t\t\tarray: array,\n\t\t\t\t\tnormalized: attribute.normalized\n\t\t\t\t};\n\n\t\t\t}\n\n\t\t\tvar groups = this.groups;\n\n\t\t\tif ( groups.length > 0 ) {\n\n\t\t\t\tdata.data.groups = JSON.parse( JSON.stringify( groups ) );\n\n\t\t\t}\n\n\t\t\tvar boundingSphere = this.boundingSphere;\n\n\t\t\tif ( boundingSphere !== null ) {\n\n\t\t\t\tdata.data.boundingSphere = {\n\t\t\t\t\tcenter: boundingSphere.center.toArray(),\n\t\t\t\t\tradius: boundingSphere.radius\n\t\t\t\t};\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\t/*\n\t\t\t // Handle primitives\n\n\t\t\t var parameters = this.parameters;\n\n\t\t\t if ( parameters !== undefined ) {\n\n\t\t\t var values = [];\n\n\t\t\t for ( var key in parameters ) {\n\n\t\t\t values.push( parameters[ key ] );\n\n\t\t\t }\n\n\t\t\t var geometry = Object.create( this.constructor.prototype );\n\t\t\t this.constructor.apply( geometry, values );\n\t\t\t return geometry;\n\n\t\t\t }\n\n\t\t\t return new this.constructor().copy( this );\n\t\t\t */\n\n\t\t\treturn new BufferGeometry().copy( this );\n\n\t\t},\n\n\t\tcopy: function ( source ) {\n\n\t\t\tvar name, i, l;\n\n\t\t\t// reset\n\n\t\t\tthis.index = null;\n\t\t\tthis.attributes = {};\n\t\t\tthis.morphAttributes = {};\n\t\t\tthis.groups = [];\n\t\t\tthis.boundingBox = null;\n\t\t\tthis.boundingSphere = null;\n\n\t\t\t// name\n\n\t\t\tthis.name = source.name;\n\n\t\t\t// index\n\n\t\t\tvar index = source.index;\n\n\t\t\tif ( index !== null ) {\n\n\t\t\t\tthis.setIndex( index.clone() );\n\n\t\t\t}\n\n\t\t\t// attributes\n\n\t\t\tvar attributes = source.attributes;\n\n\t\t\tfor ( name in attributes ) {\n\n\t\t\t\tvar attribute = attributes[ name ];\n\t\t\t\tthis.addAttribute( name, attribute.clone() );\n\n\t\t\t}\n\n\t\t\t// morph attributes\n\n\t\t\tvar morphAttributes = source.morphAttributes;\n\n\t\t\tfor ( name in morphAttributes ) {\n\n\t\t\t\tvar array = [];\n\t\t\t\tvar morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes\n\n\t\t\t\tfor ( i = 0, l = morphAttribute.length; i < l; i ++ ) {\n\n\t\t\t\t\tarray.push( morphAttribute[ i ].clone() );\n\n\t\t\t\t}\n\n\t\t\t\tthis.morphAttributes[ name ] = array;\n\n\t\t\t}\n\n\t\t\t// groups\n\n\t\t\tvar groups = source.groups;\n\n\t\t\tfor ( i = 0, l = groups.length; i < l; i ++ ) {\n\n\t\t\t\tvar group = groups[ i ];\n\t\t\t\tthis.addGroup( group.start, group.count, group.materialIndex );\n\n\t\t\t}\n\n\t\t\t// bounding box\n\n\t\t\tvar boundingBox = source.boundingBox;\n\n\t\t\tif ( boundingBox !== null ) {\n\n\t\t\t\tthis.boundingBox = boundingBox.clone();\n\n\t\t\t}\n\n\t\t\t// bounding sphere\n\n\t\t\tvar boundingSphere = source.boundingSphere;\n\n\t\t\tif ( boundingSphere !== null ) {\n\n\t\t\t\tthis.boundingSphere = boundingSphere.clone();\n\n\t\t\t}\n\n\t\t\t// draw range\n\n\t\t\tthis.drawRange.start = source.drawRange.start;\n\t\t\tthis.drawRange.count = source.drawRange.count;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tdispose: function () {\n\n\t\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author Mugen87 / https://github.com/Mugen87\n\t */\n\n\t// BoxGeometry\n\n\tfunction BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) {\n\n\t\tGeometry.call( this );\n\n\t\tthis.type = 'BoxGeometry';\n\n\t\tthis.parameters = {\n\t\t\twidth: width,\n\t\t\theight: height,\n\t\t\tdepth: depth,\n\t\t\twidthSegments: widthSegments,\n\t\t\theightSegments: heightSegments,\n\t\t\tdepthSegments: depthSegments\n\t\t};\n\n\t\tthis.fromBufferGeometry( new BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) );\n\t\tthis.mergeVertices();\n\n\t}\n\n\tBoxGeometry.prototype = Object.create( Geometry.prototype );\n\tBoxGeometry.prototype.constructor = BoxGeometry;\n\n\t// BoxBufferGeometry\n\n\tfunction BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) {\n\n\t\tBufferGeometry.call( this );\n\n\t\tthis.type = 'BoxBufferGeometry';\n\n\t\tthis.parameters = {\n\t\t\twidth: width,\n\t\t\theight: height,\n\t\t\tdepth: depth,\n\t\t\twidthSegments: widthSegments,\n\t\t\theightSegments: heightSegments,\n\t\t\tdepthSegments: depthSegments\n\t\t};\n\n\t\tvar scope = this;\n\n\t\t// segments\n\n\t\twidthSegments = Math.floor( widthSegments ) || 1;\n\t\theightSegments = Math.floor( heightSegments ) || 1;\n\t\tdepthSegments = Math.floor( depthSegments ) || 1;\n\n\t\t// buffers\n\n\t\tvar indices = [];\n\t\tvar vertices = [];\n\t\tvar normals = [];\n\t\tvar uvs = [];\n\n\t\t// helper variables\n\n\t\tvar numberOfVertices = 0;\n\t\tvar groupStart = 0;\n\n\t\t// build each side of the box geometry\n\n\t\tbuildPlane( 'z', 'y', 'x', - 1, - 1, depth, height,   width,  depthSegments, heightSegments, 0 ); // px\n\t\tbuildPlane( 'z', 'y', 'x',   1, - 1, depth, height, - width,  depthSegments, heightSegments, 1 ); // nx\n\t\tbuildPlane( 'x', 'z', 'y',   1,   1, width, depth,    height, widthSegments, depthSegments,  2 ); // py\n\t\tbuildPlane( 'x', 'z', 'y',   1, - 1, width, depth,  - height, widthSegments, depthSegments,  3 ); // ny\n\t\tbuildPlane( 'x', 'y', 'z',   1, - 1, width, height,   depth,  widthSegments, heightSegments, 4 ); // pz\n\t\tbuildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth,  widthSegments, heightSegments, 5 ); // nz\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t\tfunction buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {\n\n\t\t\tvar segmentWidth = width / gridX;\n\t\t\tvar segmentHeight = height / gridY;\n\n\t\t\tvar widthHalf = width / 2;\n\t\t\tvar heightHalf = height / 2;\n\t\t\tvar depthHalf = depth / 2;\n\n\t\t\tvar gridX1 = gridX + 1;\n\t\t\tvar gridY1 = gridY + 1;\n\n\t\t\tvar vertexCounter = 0;\n\t\t\tvar groupCount = 0;\n\n\t\t\tvar ix, iy;\n\n\t\t\tvar vector = new Vector3();\n\n\t\t\t// generate vertices, normals and uvs\n\n\t\t\tfor ( iy = 0; iy < gridY1; iy ++ ) {\n\n\t\t\t\tvar y = iy * segmentHeight - heightHalf;\n\n\t\t\t\tfor ( ix = 0; ix < gridX1; ix ++ ) {\n\n\t\t\t\t\tvar x = ix * segmentWidth - widthHalf;\n\n\t\t\t\t\t// set values to correct vector component\n\n\t\t\t\t\tvector[ u ] = x * udir;\n\t\t\t\t\tvector[ v ] = y * vdir;\n\t\t\t\t\tvector[ w ] = depthHalf;\n\n\t\t\t\t\t// now apply vector to vertex buffer\n\n\t\t\t\t\tvertices.push( vector.x, vector.y, vector.z );\n\n\t\t\t\t\t// set values to correct vector component\n\n\t\t\t\t\tvector[ u ] = 0;\n\t\t\t\t\tvector[ v ] = 0;\n\t\t\t\t\tvector[ w ] = depth > 0 ? 1 : - 1;\n\n\t\t\t\t\t// now apply vector to normal buffer\n\n\t\t\t\t\tnormals.push( vector.x, vector.y, vector.z );\n\n\t\t\t\t\t// uvs\n\n\t\t\t\t\tuvs.push( ix / gridX );\n\t\t\t\t\tuvs.push( 1 - ( iy / gridY ) );\n\n\t\t\t\t\t// counters\n\n\t\t\t\t\tvertexCounter += 1;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// indices\n\n\t\t\t// 1. you need three indices to draw a single face\n\t\t\t// 2. a single segment consists of two faces\n\t\t\t// 3. so we need to generate six (2*3) indices per segment\n\n\t\t\tfor ( iy = 0; iy < gridY; iy ++ ) {\n\n\t\t\t\tfor ( ix = 0; ix < gridX; ix ++ ) {\n\n\t\t\t\t\tvar a = numberOfVertices + ix + gridX1 * iy;\n\t\t\t\t\tvar b = numberOfVertices + ix + gridX1 * ( iy + 1 );\n\t\t\t\t\tvar c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );\n\t\t\t\t\tvar d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;\n\n\t\t\t\t\t// faces\n\n\t\t\t\t\tindices.push( a, b, d );\n\t\t\t\t\tindices.push( b, c, d );\n\n\t\t\t\t\t// increase counter\n\n\t\t\t\t\tgroupCount += 6;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// add a group to the geometry. this will ensure multi material support\n\n\t\t\tscope.addGroup( groupStart, groupCount, materialIndex );\n\n\t\t\t// calculate new start value for groups\n\n\t\t\tgroupStart += groupCount;\n\n\t\t\t// update total number of vertices\n\n\t\t\tnumberOfVertices += vertexCounter;\n\n\t\t}\n\n\t}\n\n\tBoxBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\n\tBoxBufferGeometry.prototype.constructor = BoxBufferGeometry;\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author Mugen87 / https://github.com/Mugen87\n\t */\n\n\t// PlaneGeometry\n\n\tfunction PlaneGeometry( width, height, widthSegments, heightSegments ) {\n\n\t\tGeometry.call( this );\n\n\t\tthis.type = 'PlaneGeometry';\n\n\t\tthis.parameters = {\n\t\t\twidth: width,\n\t\t\theight: height,\n\t\t\twidthSegments: widthSegments,\n\t\t\theightSegments: heightSegments\n\t\t};\n\n\t\tthis.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) );\n\t\tthis.mergeVertices();\n\n\t}\n\n\tPlaneGeometry.prototype = Object.create( Geometry.prototype );\n\tPlaneGeometry.prototype.constructor = PlaneGeometry;\n\n\t// PlaneBufferGeometry\n\n\tfunction PlaneBufferGeometry( width, height, widthSegments, heightSegments ) {\n\n\t\tBufferGeometry.call( this );\n\n\t\tthis.type = 'PlaneBufferGeometry';\n\n\t\tthis.parameters = {\n\t\t\twidth: width,\n\t\t\theight: height,\n\t\t\twidthSegments: widthSegments,\n\t\t\theightSegments: heightSegments\n\t\t};\n\n\t\tvar width_half = width / 2;\n\t\tvar height_half = height / 2;\n\n\t\tvar gridX = Math.floor( widthSegments ) || 1;\n\t\tvar gridY = Math.floor( heightSegments ) || 1;\n\n\t\tvar gridX1 = gridX + 1;\n\t\tvar gridY1 = gridY + 1;\n\n\t\tvar segment_width = width / gridX;\n\t\tvar segment_height = height / gridY;\n\n\t\tvar ix, iy;\n\n\t\t// buffers\n\n\t\tvar indices = [];\n\t\tvar vertices = [];\n\t\tvar normals = [];\n\t\tvar uvs = [];\n\n\t\t// generate vertices, normals and uvs\n\n\t\tfor ( iy = 0; iy < gridY1; iy ++ ) {\n\n\t\t\tvar y = iy * segment_height - height_half;\n\n\t\t\tfor ( ix = 0; ix < gridX1; ix ++ ) {\n\n\t\t\t\tvar x = ix * segment_width - width_half;\n\n\t\t\t\tvertices.push( x, - y, 0 );\n\n\t\t\t\tnormals.push( 0, 0, 1 );\n\n\t\t\t\tuvs.push( ix / gridX );\n\t\t\t\tuvs.push( 1 - ( iy / gridY ) );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// indices\n\n\t\tfor ( iy = 0; iy < gridY; iy ++ ) {\n\n\t\t\tfor ( ix = 0; ix < gridX; ix ++ ) {\n\n\t\t\t\tvar a = ix + gridX1 * iy;\n\t\t\t\tvar b = ix + gridX1 * ( iy + 1 );\n\t\t\t\tvar c = ( ix + 1 ) + gridX1 * ( iy + 1 );\n\t\t\t\tvar d = ( ix + 1 ) + gridX1 * iy;\n\n\t\t\t\t// faces\n\n\t\t\t\tindices.push( a, b, d );\n\t\t\t\tindices.push( b, c, d );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t}\n\n\tPlaneBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\n\tPlaneBufferGeometry.prototype.constructor = PlaneBufferGeometry;\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author alteredq / http://alteredqualia.com/\n\t *\n\t * parameters = {\n\t *  color: <hex>,\n\t *  opacity: <float>,\n\t *  map: new THREE.Texture( <Image> ),\n\t *\n\t *  lightMap: new THREE.Texture( <Image> ),\n\t *  lightMapIntensity: <float>\n\t *\n\t *  aoMap: new THREE.Texture( <Image> ),\n\t *  aoMapIntensity: <float>\n\t *\n\t *  specularMap: new THREE.Texture( <Image> ),\n\t *\n\t *  alphaMap: new THREE.Texture( <Image> ),\n\t *\n\t *  envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),\n\t *  combine: THREE.Multiply,\n\t *  reflectivity: <float>,\n\t *  refractionRatio: <float>,\n\t *\n\t *  depthTest: <bool>,\n\t *  depthWrite: <bool>,\n\t *\n\t *  wireframe: <boolean>,\n\t *  wireframeLinewidth: <float>,\n\t *\n\t *  skinning: <bool>,\n\t *  morphTargets: <bool>\n\t * }\n\t */\n\n\tfunction MeshBasicMaterial( parameters ) {\n\n\t\tMaterial.call( this );\n\n\t\tthis.type = 'MeshBasicMaterial';\n\n\t\tthis.color = new Color( 0xffffff ); // emissive\n\n\t\tthis.map = null;\n\n\t\tthis.lightMap = null;\n\t\tthis.lightMapIntensity = 1.0;\n\n\t\tthis.aoMap = null;\n\t\tthis.aoMapIntensity = 1.0;\n\n\t\tthis.specularMap = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.envMap = null;\n\t\tthis.combine = MultiplyOperation;\n\t\tthis.reflectivity = 1;\n\t\tthis.refractionRatio = 0.98;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\t\tthis.wireframeLinecap = 'round';\n\t\tthis.wireframeLinejoin = 'round';\n\n\t\tthis.skinning = false;\n\t\tthis.morphTargets = false;\n\n\t\tthis.lights = false;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tMeshBasicMaterial.prototype = Object.create( Material.prototype );\n\tMeshBasicMaterial.prototype.constructor = MeshBasicMaterial;\n\n\tMeshBasicMaterial.prototype.isMeshBasicMaterial = true;\n\n\tMeshBasicMaterial.prototype.copy = function ( source ) {\n\n\t\tMaterial.prototype.copy.call( this, source );\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.map = source.map;\n\n\t\tthis.lightMap = source.lightMap;\n\t\tthis.lightMapIntensity = source.lightMapIntensity;\n\n\t\tthis.aoMap = source.aoMap;\n\t\tthis.aoMapIntensity = source.aoMapIntensity;\n\n\t\tthis.specularMap = source.specularMap;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.envMap = source.envMap;\n\t\tthis.combine = source.combine;\n\t\tthis.reflectivity = source.reflectivity;\n\t\tthis.refractionRatio = source.refractionRatio;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\t\tthis.wireframeLinecap = source.wireframeLinecap;\n\t\tthis.wireframeLinejoin = source.wireframeLinejoin;\n\n\t\tthis.skinning = source.skinning;\n\t\tthis.morphTargets = source.morphTargets;\n\n\t\treturn this;\n\n\t};\n\n\t/**\n\t * @author bhouston / http://clara.io\n\t */\n\n\tfunction Ray( origin, direction ) {\n\n\t\tthis.origin = ( origin !== undefined ) ? origin : new Vector3();\n\t\tthis.direction = ( direction !== undefined ) ? direction : new Vector3();\n\n\t}\n\n\tObject.assign( Ray.prototype, {\n\n\t\tset: function ( origin, direction ) {\n\n\t\t\tthis.origin.copy( origin );\n\t\t\tthis.direction.copy( direction );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor().copy( this );\n\n\t\t},\n\n\t\tcopy: function ( ray ) {\n\n\t\t\tthis.origin.copy( ray.origin );\n\t\t\tthis.direction.copy( ray.direction );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tat: function ( t, optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Vector3();\n\n\t\t\treturn result.copy( this.direction ).multiplyScalar( t ).add( this.origin );\n\n\t\t},\n\n\t\tlookAt: function ( v ) {\n\n\t\t\tthis.direction.copy( v ).sub( this.origin ).normalize();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\trecast: function () {\n\n\t\t\tvar v1 = new Vector3();\n\n\t\t\treturn function recast( t ) {\n\n\t\t\t\tthis.origin.copy( this.at( t, v1 ) );\n\n\t\t\t\treturn this;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tclosestPointToPoint: function ( point, optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Vector3();\n\t\t\tresult.subVectors( point, this.origin );\n\t\t\tvar directionDistance = result.dot( this.direction );\n\n\t\t\tif ( directionDistance < 0 ) {\n\n\t\t\t\treturn result.copy( this.origin );\n\n\t\t\t}\n\n\t\t\treturn result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );\n\n\t\t},\n\n\t\tdistanceToPoint: function ( point ) {\n\n\t\t\treturn Math.sqrt( this.distanceSqToPoint( point ) );\n\n\t\t},\n\n\t\tdistanceSqToPoint: function () {\n\n\t\t\tvar v1 = new Vector3();\n\n\t\t\treturn function distanceSqToPoint( point ) {\n\n\t\t\t\tvar directionDistance = v1.subVectors( point, this.origin ).dot( this.direction );\n\n\t\t\t\t// point behind the ray\n\n\t\t\t\tif ( directionDistance < 0 ) {\n\n\t\t\t\t\treturn this.origin.distanceToSquared( point );\n\n\t\t\t\t}\n\n\t\t\t\tv1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );\n\n\t\t\t\treturn v1.distanceToSquared( point );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tdistanceSqToSegment: function () {\n\n\t\t\tvar segCenter = new Vector3();\n\t\t\tvar segDir = new Vector3();\n\t\t\tvar diff = new Vector3();\n\n\t\t\treturn function distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {\n\n\t\t\t\t// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h\n\t\t\t\t// It returns the min distance between the ray and the segment\n\t\t\t\t// defined by v0 and v1\n\t\t\t\t// It can also set two optional targets :\n\t\t\t\t// - The closest point on the ray\n\t\t\t\t// - The closest point on the segment\n\n\t\t\t\tsegCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );\n\t\t\t\tsegDir.copy( v1 ).sub( v0 ).normalize();\n\t\t\t\tdiff.copy( this.origin ).sub( segCenter );\n\n\t\t\t\tvar segExtent = v0.distanceTo( v1 ) * 0.5;\n\t\t\t\tvar a01 = - this.direction.dot( segDir );\n\t\t\t\tvar b0 = diff.dot( this.direction );\n\t\t\t\tvar b1 = - diff.dot( segDir );\n\t\t\t\tvar c = diff.lengthSq();\n\t\t\t\tvar det = Math.abs( 1 - a01 * a01 );\n\t\t\t\tvar s0, s1, sqrDist, extDet;\n\n\t\t\t\tif ( det > 0 ) {\n\n\t\t\t\t\t// The ray and segment are not parallel.\n\n\t\t\t\t\ts0 = a01 * b1 - b0;\n\t\t\t\t\ts1 = a01 * b0 - b1;\n\t\t\t\t\textDet = segExtent * det;\n\n\t\t\t\t\tif ( s0 >= 0 ) {\n\n\t\t\t\t\t\tif ( s1 >= - extDet ) {\n\n\t\t\t\t\t\t\tif ( s1 <= extDet ) {\n\n\t\t\t\t\t\t\t\t// region 0\n\t\t\t\t\t\t\t\t// Minimum at interior points of ray and segment.\n\n\t\t\t\t\t\t\t\tvar invDet = 1 / det;\n\t\t\t\t\t\t\t\ts0 *= invDet;\n\t\t\t\t\t\t\t\ts1 *= invDet;\n\t\t\t\t\t\t\t\tsqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t// region 1\n\n\t\t\t\t\t\t\t\ts1 = segExtent;\n\t\t\t\t\t\t\t\ts0 = Math.max( 0, - ( a01 * s1 + b0 ) );\n\t\t\t\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// region 5\n\n\t\t\t\t\t\t\ts1 = - segExtent;\n\t\t\t\t\t\t\ts0 = Math.max( 0, - ( a01 * s1 + b0 ) );\n\t\t\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( s1 <= - extDet ) {\n\n\t\t\t\t\t\t\t// region 4\n\n\t\t\t\t\t\t\ts0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );\n\t\t\t\t\t\t\ts1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );\n\t\t\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t\t\t} else if ( s1 <= extDet ) {\n\n\t\t\t\t\t\t\t// region 3\n\n\t\t\t\t\t\t\ts0 = 0;\n\t\t\t\t\t\t\ts1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );\n\t\t\t\t\t\t\tsqrDist = s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// region 2\n\n\t\t\t\t\t\t\ts0 = Math.max( 0, - ( a01 * segExtent + b0 ) );\n\t\t\t\t\t\t\ts1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );\n\t\t\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// Ray and segment are parallel.\n\n\t\t\t\t\ts1 = ( a01 > 0 ) ? - segExtent : segExtent;\n\t\t\t\t\ts0 = Math.max( 0, - ( a01 * s1 + b0 ) );\n\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t}\n\n\t\t\t\tif ( optionalPointOnRay ) {\n\n\t\t\t\t\toptionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin );\n\n\t\t\t\t}\n\n\t\t\t\tif ( optionalPointOnSegment ) {\n\n\t\t\t\t\toptionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter );\n\n\t\t\t\t}\n\n\t\t\t\treturn sqrDist;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tintersectSphere: function () {\n\n\t\t\tvar v1 = new Vector3();\n\n\t\t\treturn function intersectSphere( sphere, optionalTarget ) {\n\n\t\t\t\tv1.subVectors( sphere.center, this.origin );\n\t\t\t\tvar tca = v1.dot( this.direction );\n\t\t\t\tvar d2 = v1.dot( v1 ) - tca * tca;\n\t\t\t\tvar radius2 = sphere.radius * sphere.radius;\n\n\t\t\t\tif ( d2 > radius2 ) return null;\n\n\t\t\t\tvar thc = Math.sqrt( radius2 - d2 );\n\n\t\t\t\t// t0 = first intersect point - entrance on front of sphere\n\t\t\t\tvar t0 = tca - thc;\n\n\t\t\t\t// t1 = second intersect point - exit point on back of sphere\n\t\t\t\tvar t1 = tca + thc;\n\n\t\t\t\t// test to see if both t0 and t1 are behind the ray - if so, return null\n\t\t\t\tif ( t0 < 0 && t1 < 0 ) return null;\n\n\t\t\t\t// test to see if t0 is behind the ray:\n\t\t\t\t// if it is, the ray is inside the sphere, so return the second exit point scaled by t1,\n\t\t\t\t// in order to always return an intersect point that is in front of the ray.\n\t\t\t\tif ( t0 < 0 ) return this.at( t1, optionalTarget );\n\n\t\t\t\t// else t0 is in front of the ray, so return the first collision point scaled by t0\n\t\t\t\treturn this.at( t0, optionalTarget );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tintersectsSphere: function ( sphere ) {\n\n\t\t\treturn this.distanceToPoint( sphere.center ) <= sphere.radius;\n\n\t\t},\n\n\t\tdistanceToPlane: function ( plane ) {\n\n\t\t\tvar denominator = plane.normal.dot( this.direction );\n\n\t\t\tif ( denominator === 0 ) {\n\n\t\t\t\t// line is coplanar, return origin\n\t\t\t\tif ( plane.distanceToPoint( this.origin ) === 0 ) {\n\n\t\t\t\t\treturn 0;\n\n\t\t\t\t}\n\n\t\t\t\t// Null is preferable to undefined since undefined means.... it is undefined\n\n\t\t\t\treturn null;\n\n\t\t\t}\n\n\t\t\tvar t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;\n\n\t\t\t// Return if the ray never intersects the plane\n\n\t\t\treturn t >= 0 ? t :  null;\n\n\t\t},\n\n\t\tintersectPlane: function ( plane, optionalTarget ) {\n\n\t\t\tvar t = this.distanceToPlane( plane );\n\n\t\t\tif ( t === null ) {\n\n\t\t\t\treturn null;\n\n\t\t\t}\n\n\t\t\treturn this.at( t, optionalTarget );\n\n\t\t},\n\n\t\tintersectsPlane: function ( plane ) {\n\n\t\t\t// check if the ray lies on the plane first\n\n\t\t\tvar distToPoint = plane.distanceToPoint( this.origin );\n\n\t\t\tif ( distToPoint === 0 ) {\n\n\t\t\t\treturn true;\n\n\t\t\t}\n\n\t\t\tvar denominator = plane.normal.dot( this.direction );\n\n\t\t\tif ( denominator * distToPoint < 0 ) {\n\n\t\t\t\treturn true;\n\n\t\t\t}\n\n\t\t\t// ray origin is behind the plane (and is pointing behind it)\n\n\t\t\treturn false;\n\n\t\t},\n\n\t\tintersectBox: function ( box, optionalTarget ) {\n\n\t\t\tvar tmin, tmax, tymin, tymax, tzmin, tzmax;\n\n\t\t\tvar invdirx = 1 / this.direction.x,\n\t\t\t\tinvdiry = 1 / this.direction.y,\n\t\t\t\tinvdirz = 1 / this.direction.z;\n\n\t\t\tvar origin = this.origin;\n\n\t\t\tif ( invdirx >= 0 ) {\n\n\t\t\t\ttmin = ( box.min.x - origin.x ) * invdirx;\n\t\t\t\ttmax = ( box.max.x - origin.x ) * invdirx;\n\n\t\t\t} else {\n\n\t\t\t\ttmin = ( box.max.x - origin.x ) * invdirx;\n\t\t\t\ttmax = ( box.min.x - origin.x ) * invdirx;\n\n\t\t\t}\n\n\t\t\tif ( invdiry >= 0 ) {\n\n\t\t\t\ttymin = ( box.min.y - origin.y ) * invdiry;\n\t\t\t\ttymax = ( box.max.y - origin.y ) * invdiry;\n\n\t\t\t} else {\n\n\t\t\t\ttymin = ( box.max.y - origin.y ) * invdiry;\n\t\t\t\ttymax = ( box.min.y - origin.y ) * invdiry;\n\n\t\t\t}\n\n\t\t\tif ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;\n\n\t\t\t// These lines also handle the case where tmin or tmax is NaN\n\t\t\t// (result of 0 * Infinity). x !== x returns true if x is NaN\n\n\t\t\tif ( tymin > tmin || tmin !== tmin ) tmin = tymin;\n\n\t\t\tif ( tymax < tmax || tmax !== tmax ) tmax = tymax;\n\n\t\t\tif ( invdirz >= 0 ) {\n\n\t\t\t\ttzmin = ( box.min.z - origin.z ) * invdirz;\n\t\t\t\ttzmax = ( box.max.z - origin.z ) * invdirz;\n\n\t\t\t} else {\n\n\t\t\t\ttzmin = ( box.max.z - origin.z ) * invdirz;\n\t\t\t\ttzmax = ( box.min.z - origin.z ) * invdirz;\n\n\t\t\t}\n\n\t\t\tif ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;\n\n\t\t\tif ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;\n\n\t\t\tif ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;\n\n\t\t\t//return point closest to the ray (positive side)\n\n\t\t\tif ( tmax < 0 ) return null;\n\n\t\t\treturn this.at( tmin >= 0 ? tmin : tmax, optionalTarget );\n\n\t\t},\n\n\t\tintersectsBox: ( function () {\n\n\t\t\tvar v = new Vector3();\n\n\t\t\treturn function intersectsBox( box ) {\n\n\t\t\t\treturn this.intersectBox( box, v ) !== null;\n\n\t\t\t};\n\n\t\t} )(),\n\n\t\tintersectTriangle: function () {\n\n\t\t\t// Compute the offset origin, edges, and normal.\n\t\t\tvar diff = new Vector3();\n\t\t\tvar edge1 = new Vector3();\n\t\t\tvar edge2 = new Vector3();\n\t\t\tvar normal = new Vector3();\n\n\t\t\treturn function intersectTriangle( a, b, c, backfaceCulling, optionalTarget ) {\n\n\t\t\t\t// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h\n\n\t\t\t\tedge1.subVectors( b, a );\n\t\t\t\tedge2.subVectors( c, a );\n\t\t\t\tnormal.crossVectors( edge1, edge2 );\n\n\t\t\t\t// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,\n\t\t\t\t// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by\n\t\t\t\t//   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))\n\t\t\t\t//   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))\n\t\t\t\t//   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)\n\t\t\t\tvar DdN = this.direction.dot( normal );\n\t\t\t\tvar sign;\n\n\t\t\t\tif ( DdN > 0 ) {\n\n\t\t\t\t\tif ( backfaceCulling ) return null;\n\t\t\t\t\tsign = 1;\n\n\t\t\t\t} else if ( DdN < 0 ) {\n\n\t\t\t\t\tsign = - 1;\n\t\t\t\t\tDdN = - DdN;\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn null;\n\n\t\t\t\t}\n\n\t\t\t\tdiff.subVectors( this.origin, a );\n\t\t\t\tvar DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) );\n\n\t\t\t\t// b1 < 0, no intersection\n\t\t\t\tif ( DdQxE2 < 0 ) {\n\n\t\t\t\t\treturn null;\n\n\t\t\t\t}\n\n\t\t\t\tvar DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) );\n\n\t\t\t\t// b2 < 0, no intersection\n\t\t\t\tif ( DdE1xQ < 0 ) {\n\n\t\t\t\t\treturn null;\n\n\t\t\t\t}\n\n\t\t\t\t// b1+b2 > 1, no intersection\n\t\t\t\tif ( DdQxE2 + DdE1xQ > DdN ) {\n\n\t\t\t\t\treturn null;\n\n\t\t\t\t}\n\n\t\t\t\t// Line intersects triangle, check if ray does.\n\t\t\t\tvar QdN = - sign * diff.dot( normal );\n\n\t\t\t\t// t < 0, no intersection\n\t\t\t\tif ( QdN < 0 ) {\n\n\t\t\t\t\treturn null;\n\n\t\t\t\t}\n\n\t\t\t\t// Ray intersects triangle.\n\t\t\t\treturn this.at( QdN / DdN, optionalTarget );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tapplyMatrix4: function ( matrix4 ) {\n\n\t\t\tthis.origin.applyMatrix4( matrix4 );\n\t\t\tthis.direction.transformDirection( matrix4 );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tequals: function ( ray ) {\n\n\t\t\treturn ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author bhouston / http://clara.io\n\t */\n\n\tfunction Line3( start, end ) {\n\n\t\tthis.start = ( start !== undefined ) ? start : new Vector3();\n\t\tthis.end = ( end !== undefined ) ? end : new Vector3();\n\n\t}\n\n\tObject.assign( Line3.prototype, {\n\n\t\tset: function ( start, end ) {\n\n\t\t\tthis.start.copy( start );\n\t\t\tthis.end.copy( end );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor().copy( this );\n\n\t\t},\n\n\t\tcopy: function ( line ) {\n\n\t\t\tthis.start.copy( line.start );\n\t\t\tthis.end.copy( line.end );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetCenter: function ( optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Vector3();\n\t\t\treturn result.addVectors( this.start, this.end ).multiplyScalar( 0.5 );\n\n\t\t},\n\n\t\tdelta: function ( optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Vector3();\n\t\t\treturn result.subVectors( this.end, this.start );\n\n\t\t},\n\n\t\tdistanceSq: function () {\n\n\t\t\treturn this.start.distanceToSquared( this.end );\n\n\t\t},\n\n\t\tdistance: function () {\n\n\t\t\treturn this.start.distanceTo( this.end );\n\n\t\t},\n\n\t\tat: function ( t, optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Vector3();\n\n\t\t\treturn this.delta( result ).multiplyScalar( t ).add( this.start );\n\n\t\t},\n\n\t\tclosestPointToPointParameter: function () {\n\n\t\t\tvar startP = new Vector3();\n\t\t\tvar startEnd = new Vector3();\n\n\t\t\treturn function closestPointToPointParameter( point, clampToLine ) {\n\n\t\t\t\tstartP.subVectors( point, this.start );\n\t\t\t\tstartEnd.subVectors( this.end, this.start );\n\n\t\t\t\tvar startEnd2 = startEnd.dot( startEnd );\n\t\t\t\tvar startEnd_startP = startEnd.dot( startP );\n\n\t\t\t\tvar t = startEnd_startP / startEnd2;\n\n\t\t\t\tif ( clampToLine ) {\n\n\t\t\t\t\tt = _Math.clamp( t, 0, 1 );\n\n\t\t\t\t}\n\n\t\t\t\treturn t;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tclosestPointToPoint: function ( point, clampToLine, optionalTarget ) {\n\n\t\t\tvar t = this.closestPointToPointParameter( point, clampToLine );\n\n\t\t\tvar result = optionalTarget || new Vector3();\n\n\t\t\treturn this.delta( result ).multiplyScalar( t ).add( this.start );\n\n\t\t},\n\n\t\tapplyMatrix4: function ( matrix ) {\n\n\t\t\tthis.start.applyMatrix4( matrix );\n\t\t\tthis.end.applyMatrix4( matrix );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tequals: function ( line ) {\n\n\t\t\treturn line.start.equals( this.start ) && line.end.equals( this.end );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author bhouston / http://clara.io\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction Triangle( a, b, c ) {\n\n\t\tthis.a = ( a !== undefined ) ? a : new Vector3();\n\t\tthis.b = ( b !== undefined ) ? b : new Vector3();\n\t\tthis.c = ( c !== undefined ) ? c : new Vector3();\n\n\t}\n\n\tObject.assign( Triangle, {\n\n\t\tnormal: function () {\n\n\t\t\tvar v0 = new Vector3();\n\n\t\t\treturn function normal( a, b, c, optionalTarget ) {\n\n\t\t\t\tvar result = optionalTarget || new Vector3();\n\n\t\t\t\tresult.subVectors( c, b );\n\t\t\t\tv0.subVectors( a, b );\n\t\t\t\tresult.cross( v0 );\n\n\t\t\t\tvar resultLengthSq = result.lengthSq();\n\t\t\t\tif ( resultLengthSq > 0 ) {\n\n\t\t\t\t\treturn result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) );\n\n\t\t\t\t}\n\n\t\t\t\treturn result.set( 0, 0, 0 );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\t// static/instance method to calculate barycentric coordinates\n\t\t// based on: http://www.blackpawn.com/texts/pointinpoly/default.html\n\t\tbarycoordFromPoint: function () {\n\n\t\t\tvar v0 = new Vector3();\n\t\t\tvar v1 = new Vector3();\n\t\t\tvar v2 = new Vector3();\n\n\t\t\treturn function barycoordFromPoint( point, a, b, c, optionalTarget ) {\n\n\t\t\t\tv0.subVectors( c, a );\n\t\t\t\tv1.subVectors( b, a );\n\t\t\t\tv2.subVectors( point, a );\n\n\t\t\t\tvar dot00 = v0.dot( v0 );\n\t\t\t\tvar dot01 = v0.dot( v1 );\n\t\t\t\tvar dot02 = v0.dot( v2 );\n\t\t\t\tvar dot11 = v1.dot( v1 );\n\t\t\t\tvar dot12 = v1.dot( v2 );\n\n\t\t\t\tvar denom = ( dot00 * dot11 - dot01 * dot01 );\n\n\t\t\t\tvar result = optionalTarget || new Vector3();\n\n\t\t\t\t// collinear or singular triangle\n\t\t\t\tif ( denom === 0 ) {\n\n\t\t\t\t\t// arbitrary location outside of triangle?\n\t\t\t\t\t// not sure if this is the best idea, maybe should be returning undefined\n\t\t\t\t\treturn result.set( - 2, - 1, - 1 );\n\n\t\t\t\t}\n\n\t\t\t\tvar invDenom = 1 / denom;\n\t\t\t\tvar u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;\n\t\t\t\tvar v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;\n\n\t\t\t\t// barycentric coordinates must always sum to 1\n\t\t\t\treturn result.set( 1 - u - v, v, u );\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tcontainsPoint: function () {\n\n\t\t\tvar v1 = new Vector3();\n\n\t\t\treturn function containsPoint( point, a, b, c ) {\n\n\t\t\t\tvar result = Triangle.barycoordFromPoint( point, a, b, c, v1 );\n\n\t\t\t\treturn ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 );\n\n\t\t\t};\n\n\t\t}()\n\n\t} );\n\n\tObject.assign( Triangle.prototype, {\n\n\t\tset: function ( a, b, c ) {\n\n\t\t\tthis.a.copy( a );\n\t\t\tthis.b.copy( b );\n\t\t\tthis.c.copy( c );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromPointsAndIndices: function ( points, i0, i1, i2 ) {\n\n\t\t\tthis.a.copy( points[ i0 ] );\n\t\t\tthis.b.copy( points[ i1 ] );\n\t\t\tthis.c.copy( points[ i2 ] );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor().copy( this );\n\n\t\t},\n\n\t\tcopy: function ( triangle ) {\n\n\t\t\tthis.a.copy( triangle.a );\n\t\t\tthis.b.copy( triangle.b );\n\t\t\tthis.c.copy( triangle.c );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tarea: function () {\n\n\t\t\tvar v0 = new Vector3();\n\t\t\tvar v1 = new Vector3();\n\n\t\t\treturn function area() {\n\n\t\t\t\tv0.subVectors( this.c, this.b );\n\t\t\t\tv1.subVectors( this.a, this.b );\n\n\t\t\t\treturn v0.cross( v1 ).length() * 0.5;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tmidpoint: function ( optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Vector3();\n\t\t\treturn result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );\n\n\t\t},\n\n\t\tnormal: function ( optionalTarget ) {\n\n\t\t\treturn Triangle.normal( this.a, this.b, this.c, optionalTarget );\n\n\t\t},\n\n\t\tplane: function ( optionalTarget ) {\n\n\t\t\tvar result = optionalTarget || new Plane();\n\n\t\t\treturn result.setFromCoplanarPoints( this.a, this.b, this.c );\n\n\t\t},\n\n\t\tbarycoordFromPoint: function ( point, optionalTarget ) {\n\n\t\t\treturn Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget );\n\n\t\t},\n\n\t\tcontainsPoint: function ( point ) {\n\n\t\t\treturn Triangle.containsPoint( point, this.a, this.b, this.c );\n\n\t\t},\n\n\t\tclosestPointToPoint: function () {\n\n\t\t\tvar plane = new Plane();\n\t\t\tvar edgeList = [ new Line3(), new Line3(), new Line3() ];\n\t\t\tvar projectedPoint = new Vector3();\n\t\t\tvar closestPoint = new Vector3();\n\n\t\t\treturn function closestPointToPoint( point, optionalTarget ) {\n\n\t\t\t\tvar result = optionalTarget || new Vector3();\n\t\t\t\tvar minDistance = Infinity;\n\n\t\t\t\t// project the point onto the plane of the triangle\n\n\t\t\t\tplane.setFromCoplanarPoints( this.a, this.b, this.c );\n\t\t\t\tplane.projectPoint( point, projectedPoint );\n\n\t\t\t\t// check if the projection lies within the triangle\n\n\t\t\t\tif( this.containsPoint( projectedPoint ) === true ) {\n\n\t\t\t\t\t// if so, this is the closest point\n\n\t\t\t\t\tresult.copy( projectedPoint );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// if not, the point falls outside the triangle. the result is the closest point to the triangle's edges or vertices\n\n\t\t\t\t\tedgeList[ 0 ].set( this.a, this.b );\n\t\t\t\t\tedgeList[ 1 ].set( this.b, this.c );\n\t\t\t\t\tedgeList[ 2 ].set( this.c, this.a );\n\n\t\t\t\t\tfor( var i = 0; i < edgeList.length; i ++ ) {\n\n\t\t\t\t\t\tedgeList[ i ].closestPointToPoint( projectedPoint, true, closestPoint );\n\n\t\t\t\t\t\tvar distance = projectedPoint.distanceToSquared( closestPoint );\n\n\t\t\t\t\t\tif( distance < minDistance ) {\n\n\t\t\t\t\t\t\tminDistance = distance;\n\n\t\t\t\t\t\t\tresult.copy( closestPoint );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\n\t\t\t};\n\n\t\t}(),\n\n\t\tequals: function ( triangle ) {\n\n\t\t\treturn triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author mikael emtinger / http://gomo.se/\n\t * @author jonobr1 / http://jonobr1.com/\n\t */\n\n\tfunction Mesh( geometry, material ) {\n\n\t\tObject3D.call( this );\n\n\t\tthis.type = 'Mesh';\n\n\t\tthis.geometry = geometry !== undefined ? geometry : new BufferGeometry();\n\t\tthis.material = material !== undefined ? material : new MeshBasicMaterial( { color: Math.random() * 0xffffff } );\n\n\t\tthis.drawMode = TrianglesDrawMode;\n\n\t\tthis.updateMorphTargets();\n\n\t}\n\n\tMesh.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\t\tconstructor: Mesh,\n\n\t\tisMesh: true,\n\n\t\tsetDrawMode: function ( value ) {\n\n\t\t\tthis.drawMode = value;\n\n\t\t},\n\n\t\tcopy: function ( source ) {\n\n\t\t\tObject3D.prototype.copy.call( this, source );\n\n\t\t\tthis.drawMode = source.drawMode;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tupdateMorphTargets: function () {\n\n\t\t\tvar geometry = this.geometry;\n\t\t\tvar m, ml, name;\n\n\t\t\tif ( geometry.isBufferGeometry ) {\n\n\t\t\t\tvar morphAttributes = geometry.morphAttributes;\n\t\t\t\tvar keys = Object.keys( morphAttributes );\n\n\t\t\t\tif ( keys.length > 0 ) {\n\n\t\t\t\t\tvar morphAttribute = morphAttributes[ keys[ 0 ] ];\n\n\t\t\t\t\tif ( morphAttribute !== undefined ) {\n\n\t\t\t\t\t\tthis.morphTargetInfluences = [];\n\t\t\t\t\t\tthis.morphTargetDictionary = {};\n\n\t\t\t\t\t\tfor ( m = 0, ml = morphAttribute.length; m < ml; m ++ ) {\n\n\t\t\t\t\t\t\tname = morphAttribute[ m ].name || String( m );\n\n\t\t\t\t\t\t\tthis.morphTargetInfluences.push( 0 );\n\t\t\t\t\t\t\tthis.morphTargetDictionary[ name ] = m;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tvar morphTargets = geometry.morphTargets;\n\n\t\t\t\tif ( morphTargets !== undefined && morphTargets.length > 0 ) {\n\n\t\t\t\t\tthis.morphTargetInfluences = [];\n\t\t\t\t\tthis.morphTargetDictionary = {};\n\n\t\t\t\t\tfor ( m = 0, ml = morphTargets.length; m < ml; m ++ ) {\n\n\t\t\t\t\t\tname = morphTargets[ m ].name || String( m );\n\n\t\t\t\t\t\tthis.morphTargetInfluences.push( 0 );\n\t\t\t\t\t\tthis.morphTargetDictionary[ name ] = m;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t},\n\n\t\traycast: ( function () {\n\n\t\t\tvar inverseMatrix = new Matrix4();\n\t\t\tvar ray = new Ray();\n\t\t\tvar sphere = new Sphere();\n\n\t\t\tvar vA = new Vector3();\n\t\t\tvar vB = new Vector3();\n\t\t\tvar vC = new Vector3();\n\n\t\t\tvar tempA = new Vector3();\n\t\t\tvar tempB = new Vector3();\n\t\t\tvar tempC = new Vector3();\n\n\t\t\tvar uvA = new Vector2();\n\t\t\tvar uvB = new Vector2();\n\t\t\tvar uvC = new Vector2();\n\n\t\t\tvar barycoord = new Vector3();\n\n\t\t\tvar intersectionPoint = new Vector3();\n\t\t\tvar intersectionPointWorld = new Vector3();\n\n\t\t\tfunction uvIntersection( point, p1, p2, p3, uv1, uv2, uv3 ) {\n\n\t\t\t\tTriangle.barycoordFromPoint( point, p1, p2, p3, barycoord );\n\n\t\t\t\tuv1.multiplyScalar( barycoord.x );\n\t\t\t\tuv2.multiplyScalar( barycoord.y );\n\t\t\t\tuv3.multiplyScalar( barycoord.z );\n\n\t\t\t\tuv1.add( uv2 ).add( uv3 );\n\n\t\t\t\treturn uv1.clone();\n\n\t\t\t}\n\n\t\t\tfunction checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) {\n\n\t\t\t\tvar intersect;\n\n\t\t\t\tif ( material.side === BackSide ) {\n\n\t\t\t\t\tintersect = ray.intersectTriangle( pC, pB, pA, true, point );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tintersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point );\n\n\t\t\t\t}\n\n\t\t\t\tif ( intersect === null ) return null;\n\n\t\t\t\tintersectionPointWorld.copy( point );\n\t\t\t\tintersectionPointWorld.applyMatrix4( object.matrixWorld );\n\n\t\t\t\tvar distance = raycaster.ray.origin.distanceTo( intersectionPointWorld );\n\n\t\t\t\tif ( distance < raycaster.near || distance > raycaster.far ) return null;\n\n\t\t\t\treturn {\n\t\t\t\t\tdistance: distance,\n\t\t\t\t\tpoint: intersectionPointWorld.clone(),\n\t\t\t\t\tobject: object\n\t\t\t\t};\n\n\t\t\t}\n\n\t\t\tfunction checkBufferGeometryIntersection( object, raycaster, ray, position, uv, a, b, c ) {\n\n\t\t\t\tvA.fromBufferAttribute( position, a );\n\t\t\t\tvB.fromBufferAttribute( position, b );\n\t\t\t\tvC.fromBufferAttribute( position, c );\n\n\t\t\t\tvar intersection = checkIntersection( object, object.material, raycaster, ray, vA, vB, vC, intersectionPoint );\n\n\t\t\t\tif ( intersection ) {\n\n\t\t\t\t\tif ( uv ) {\n\n\t\t\t\t\t\tuvA.fromBufferAttribute( uv, a );\n\t\t\t\t\t\tuvB.fromBufferAttribute( uv, b );\n\t\t\t\t\t\tuvC.fromBufferAttribute( uv, c );\n\n\t\t\t\t\t\tintersection.uv = uvIntersection( intersectionPoint, vA, vB, vC, uvA, uvB, uvC );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tintersection.face = new Face3( a, b, c, Triangle.normal( vA, vB, vC ) );\n\t\t\t\t\tintersection.faceIndex = a;\n\n\t\t\t\t}\n\n\t\t\t\treturn intersection;\n\n\t\t\t}\n\n\t\t\treturn function raycast( raycaster, intersects ) {\n\n\t\t\t\tvar geometry = this.geometry;\n\t\t\t\tvar material = this.material;\n\t\t\t\tvar matrixWorld = this.matrixWorld;\n\n\t\t\t\tif ( material === undefined ) return;\n\n\t\t\t\t// Checking boundingSphere distance to ray\n\n\t\t\t\tif ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();\n\n\t\t\t\tsphere.copy( geometry.boundingSphere );\n\t\t\t\tsphere.applyMatrix4( matrixWorld );\n\n\t\t\t\tif ( raycaster.ray.intersectsSphere( sphere ) === false ) return;\n\n\t\t\t\t//\n\n\t\t\t\tinverseMatrix.getInverse( matrixWorld );\n\t\t\t\tray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );\n\n\t\t\t\t// Check boundingBox before continuing\n\n\t\t\t\tif ( geometry.boundingBox !== null ) {\n\n\t\t\t\t\tif ( ray.intersectsBox( geometry.boundingBox ) === false ) return;\n\n\t\t\t\t}\n\n\t\t\t\tvar intersection;\n\n\t\t\t\tif ( geometry.isBufferGeometry ) {\n\n\t\t\t\t\tvar a, b, c;\n\t\t\t\t\tvar index = geometry.index;\n\t\t\t\t\tvar position = geometry.attributes.position;\n\t\t\t\t\tvar uv = geometry.attributes.uv;\n\t\t\t\t\tvar i, l;\n\n\t\t\t\t\tif ( index !== null ) {\n\n\t\t\t\t\t\t// indexed buffer geometry\n\n\t\t\t\t\t\tfor ( i = 0, l = index.count; i < l; i += 3 ) {\n\n\t\t\t\t\t\t\ta = index.getX( i );\n\t\t\t\t\t\t\tb = index.getX( i + 1 );\n\t\t\t\t\t\t\tc = index.getX( i + 2 );\n\n\t\t\t\t\t\t\tintersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c );\n\n\t\t\t\t\t\t\tif ( intersection ) {\n\n\t\t\t\t\t\t\t\tintersection.faceIndex = Math.floor( i / 3 ); // triangle number in indices buffer semantics\n\t\t\t\t\t\t\t\tintersects.push( intersection );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// non-indexed buffer geometry\n\n\t\t\t\t\t\tfor ( i = 0, l = position.count; i < l; i += 3 ) {\n\n\t\t\t\t\t\t\ta = i;\n\t\t\t\t\t\t\tb = i + 1;\n\t\t\t\t\t\t\tc = i + 2;\n\n\t\t\t\t\t\t\tintersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c );\n\n\t\t\t\t\t\t\tif ( intersection ) {\n\n\t\t\t\t\t\t\t\tintersection.index = a; // triangle number in positions buffer semantics\n\t\t\t\t\t\t\t\tintersects.push( intersection );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( geometry.isGeometry ) {\n\n\t\t\t\t\tvar fvA, fvB, fvC;\n\t\t\t\t\tvar isMultiMaterial = Array.isArray( material );\n\n\t\t\t\t\tvar vertices = geometry.vertices;\n\t\t\t\t\tvar faces = geometry.faces;\n\t\t\t\t\tvar uvs;\n\n\t\t\t\t\tvar faceVertexUvs = geometry.faceVertexUvs[ 0 ];\n\t\t\t\t\tif ( faceVertexUvs.length > 0 ) uvs = faceVertexUvs;\n\n\t\t\t\t\tfor ( var f = 0, fl = faces.length; f < fl; f ++ ) {\n\n\t\t\t\t\t\tvar face = faces[ f ];\n\t\t\t\t\t\tvar faceMaterial = isMultiMaterial ? material[ face.materialIndex ] : material;\n\n\t\t\t\t\t\tif ( faceMaterial === undefined ) continue;\n\n\t\t\t\t\t\tfvA = vertices[ face.a ];\n\t\t\t\t\t\tfvB = vertices[ face.b ];\n\t\t\t\t\t\tfvC = vertices[ face.c ];\n\n\t\t\t\t\t\tif ( faceMaterial.morphTargets === true ) {\n\n\t\t\t\t\t\t\tvar morphTargets = geometry.morphTargets;\n\t\t\t\t\t\t\tvar morphInfluences = this.morphTargetInfluences;\n\n\t\t\t\t\t\t\tvA.set( 0, 0, 0 );\n\t\t\t\t\t\t\tvB.set( 0, 0, 0 );\n\t\t\t\t\t\t\tvC.set( 0, 0, 0 );\n\n\t\t\t\t\t\t\tfor ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {\n\n\t\t\t\t\t\t\t\tvar influence = morphInfluences[ t ];\n\n\t\t\t\t\t\t\t\tif ( influence === 0 ) continue;\n\n\t\t\t\t\t\t\t\tvar targets = morphTargets[ t ].vertices;\n\n\t\t\t\t\t\t\t\tvA.addScaledVector( tempA.subVectors( targets[ face.a ], fvA ), influence );\n\t\t\t\t\t\t\t\tvB.addScaledVector( tempB.subVectors( targets[ face.b ], fvB ), influence );\n\t\t\t\t\t\t\t\tvC.addScaledVector( tempC.subVectors( targets[ face.c ], fvC ), influence );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tvA.add( fvA );\n\t\t\t\t\t\t\tvB.add( fvB );\n\t\t\t\t\t\t\tvC.add( fvC );\n\n\t\t\t\t\t\t\tfvA = vA;\n\t\t\t\t\t\t\tfvB = vB;\n\t\t\t\t\t\t\tfvC = vC;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tintersection = checkIntersection( this, faceMaterial, raycaster, ray, fvA, fvB, fvC, intersectionPoint );\n\n\t\t\t\t\t\tif ( intersection ) {\n\n\t\t\t\t\t\t\tif ( uvs && uvs[ f ] ) {\n\n\t\t\t\t\t\t\t\tvar uvs_f = uvs[ f ];\n\t\t\t\t\t\t\t\tuvA.copy( uvs_f[ 0 ] );\n\t\t\t\t\t\t\t\tuvB.copy( uvs_f[ 1 ] );\n\t\t\t\t\t\t\t\tuvC.copy( uvs_f[ 2 ] );\n\n\t\t\t\t\t\t\t\tintersection.uv = uvIntersection( intersectionPoint, fvA, fvB, fvC, uvA, uvB, uvC );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tintersection.face = face;\n\t\t\t\t\t\t\tintersection.faceIndex = f;\n\t\t\t\t\t\t\tintersects.push( intersection );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t}() ),\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor( this.geometry, this.material ).copy( this );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction WebGLBackground( renderer, state, geometries, premultipliedAlpha ) {\n\n\t\tvar clearColor = new Color( 0x000000 );\n\t\tvar clearAlpha = 0;\n\n\t\tvar planeCamera, planeMesh;\n\t\tvar boxMesh;\n\n\t\tfunction render( renderList, scene, camera, forceClear ) {\n\n\t\t\tvar background = scene.background;\n\n\t\t\tif ( background === null ) {\n\n\t\t\t\tsetClear( clearColor, clearAlpha );\n\n\t\t\t} else if ( background && background.isColor ) {\n\n\t\t\t\tsetClear( background, 1 );\n\t\t\t\tforceClear = true;\n\n\t\t\t}\n\n\t\t\tif ( renderer.autoClear || forceClear ) {\n\n\t\t\t\trenderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );\n\n\t\t\t}\n\n\t\t\tif ( background && background.isCubeTexture ) {\n\n\t\t\t\tif ( boxMesh === undefined ) {\n\n\t\t\t\t\tboxMesh = new Mesh(\n\t\t\t\t\t\tnew BoxBufferGeometry( 1, 1, 1 ),\n\t\t\t\t\t\tnew ShaderMaterial( {\n\t\t\t\t\t\t\tuniforms: ShaderLib.cube.uniforms,\n\t\t\t\t\t\t\tvertexShader: ShaderLib.cube.vertexShader,\n\t\t\t\t\t\t\tfragmentShader: ShaderLib.cube.fragmentShader,\n\t\t\t\t\t\t\tside: BackSide,\n\t\t\t\t\t\t\tdepthTest: true,\n\t\t\t\t\t\t\tdepthWrite: false,\n\t\t\t\t\t\t\tpolygonOffset: true,\n\t\t\t\t\t\t\tfog: false\n\t\t\t\t\t\t} )\n\t\t\t\t\t);\n\n\t\t\t\t\tboxMesh.geometry.removeAttribute( 'normal' );\n\t\t\t\t\tboxMesh.geometry.removeAttribute( 'uv' );\n\n\t\t\t\t\tboxMesh.onBeforeRender = function ( renderer, scene, camera ) {\n\n\t\t\t\t\t\tvar scale = camera.far;\n\n\t\t\t\t\t\tthis.matrixWorld.makeScale( scale, scale, scale );\n\t\t\t\t\t\tthis.matrixWorld.copyPosition( camera.matrixWorld );\n\n\t\t\t\t\t\tthis.material.polygonOffsetUnits = scale * 10;\n\n\t\t\t\t\t};\n\n\t\t\t\t\tgeometries.update( boxMesh.geometry );\n\n\t\t\t\t}\n\n\t\t\t\tboxMesh.material.uniforms.tCube.value = background;\n\n\t\t\t\trenderList.push( boxMesh, boxMesh.geometry, boxMesh.material, 0, null );\n\n\t\t\t} else if ( background && background.isTexture ) {\n\n\t\t\t\tif ( planeCamera === undefined ) {\n\n\t\t\t\t\tplaneCamera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );\n\n\t\t\t\t\tplaneMesh = new Mesh(\n\t\t\t\t\t\tnew PlaneBufferGeometry( 2, 2 ),\n\t\t\t\t\t\tnew MeshBasicMaterial( { depthTest: false, depthWrite: false, fog: false } )\n\t\t\t\t\t);\n\n\t\t\t\t\tgeometries.update( planeMesh.geometry );\n\n\t\t\t\t}\n\n\t\t\t\tplaneMesh.material.map = background;\n\n\t\t\t\t// TODO Push this to renderList\n\n\t\t\t\trenderer.renderBufferDirect( planeCamera, null, planeMesh.geometry, planeMesh.material, planeMesh, null );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction setClear( color, alpha ) {\n\n\t\t\tstate.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha );\n\n\t\t}\n\n\t\treturn {\n\n\t\t\tgetClearColor: function () {\n\n\t\t\t\treturn clearColor;\n\n\t\t\t},\n\t\t\tsetClearColor: function ( color, alpha ) {\n\n\t\t\t\tclearColor.set( color );\n\t\t\t\tclearAlpha = alpha !== undefined ? alpha : 1;\n\t\t\t\tsetClear( clearColor, clearAlpha );\n\n\t\t\t},\n\t\t\tgetClearAlpha: function () {\n\n\t\t\t\treturn clearAlpha;\n\n\t\t\t},\n\t\t\tsetClearAlpha: function ( alpha ) {\n\n\t\t\t\tclearAlpha = alpha;\n\t\t\t\tsetClear( clearColor, clearAlpha );\n\n\t\t\t},\n\t\t\trender: render\n\n\t\t};\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction painterSortStable( a, b ) {\n\n\t\tif ( a.renderOrder !== b.renderOrder ) {\n\n\t\t\treturn a.renderOrder - b.renderOrder;\n\n\t\t} else if ( a.program && b.program && a.program !== b.program ) {\n\n\t\t\treturn a.program.id - b.program.id;\n\n\t\t} else if ( a.material.id !== b.material.id ) {\n\n\t\t\treturn a.material.id - b.material.id;\n\n\t\t} else if ( a.z !== b.z ) {\n\n\t\t\treturn a.z - b.z;\n\n\t\t} else {\n\n\t\t\treturn a.id - b.id;\n\n\t\t}\n\n\t}\n\n\tfunction reversePainterSortStable( a, b ) {\n\n\t\tif ( a.renderOrder !== b.renderOrder ) {\n\n\t\t\treturn a.renderOrder - b.renderOrder;\n\n\t\t} if ( a.z !== b.z ) {\n\n\t\t\treturn b.z - a.z;\n\n\t\t} else {\n\n\t\t\treturn a.id - b.id;\n\n\t\t}\n\n\t}\n\n\tfunction WebGLRenderList() {\n\n\t\tvar renderItems = [];\n\t\tvar renderItemsIndex = 0;\n\n\t\tvar opaque = [];\n\t\tvar transparent = [];\n\n\t\tfunction init() {\n\n\t\t\trenderItemsIndex = 0;\n\n\t\t\topaque.length = 0;\n\t\t\ttransparent.length = 0;\n\n\t\t}\n\n\t\tfunction push( object, geometry, material, z, group ) {\n\n\t\t\tvar renderItem = renderItems[ renderItemsIndex ];\n\n\t\t\tif ( renderItem === undefined ) {\n\n\t\t\t\trenderItem = {\n\t\t\t\t\tid: object.id,\n\t\t\t\t\tobject: object,\n\t\t\t\t\tgeometry: geometry,\n\t\t\t\t\tmaterial: material,\n\t\t\t\t\tprogram: material.program,\n\t\t\t\t\trenderOrder: object.renderOrder,\n\t\t\t\t\tz: z,\n\t\t\t\t\tgroup: group\n\t\t\t\t};\n\n\t\t\t\trenderItems[ renderItemsIndex ] = renderItem;\n\n\t\t\t} else {\n\n\t\t\t\trenderItem.id = object.id;\n\t\t\t\trenderItem.object = object;\n\t\t\t\trenderItem.geometry = geometry;\n\t\t\t\trenderItem.material = material;\n\t\t\t\trenderItem.program = material.program;\n\t\t\t\trenderItem.renderOrder = object.renderOrder;\n\t\t\t\trenderItem.z = z;\n\t\t\t\trenderItem.group = group;\n\n\t\t\t}\n\n\t\t\t( material.transparent === true ? transparent : opaque ).push( renderItem );\n\n\t\t\trenderItemsIndex ++;\n\n\t\t}\n\n\t\tfunction sort() {\n\n\t\t\tif ( opaque.length > 1 ) opaque.sort( painterSortStable );\n\t\t\tif ( transparent.length > 1 ) transparent.sort( reversePainterSortStable );\n\n\t\t}\n\n\t\treturn {\n\t\t\topaque: opaque,\n\t\t\ttransparent: transparent,\n\n\t\t\tinit: init,\n\t\t\tpush: push,\n\n\t\t\tsort: sort\n\t\t};\n\n\t}\n\n\tfunction WebGLRenderLists() {\n\n\t\tvar lists = {};\n\n\t\tfunction get( scene, camera ) {\n\n\t\t\tvar hash = scene.id + ',' + camera.id;\n\t\t\tvar list = lists[ hash ];\n\n\t\t\tif ( list === undefined ) {\n\n\t\t\t\t// console.log( 'THREE.WebGLRenderLists:', hash );\n\n\t\t\t\tlist = new WebGLRenderList();\n\t\t\t\tlists[ hash ] = list;\n\n\t\t\t}\n\n\t\t\treturn list;\n\n\t\t}\n\n\t\tfunction dispose() {\n\n\t\t\tlists = {};\n\n\t\t}\n\n\t\treturn {\n\t\t\tget: get,\n\t\t\tdispose: dispose\n\t\t};\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction absNumericalSort( a, b ) {\n\n\t\treturn Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] );\n\n\t}\n\n\tfunction WebGLMorphtargets( gl ) {\n\n\t\tvar influencesList = {};\n\t\tvar morphInfluences = new Float32Array( 8 );\n\n\t\tfunction update( object, geometry, material, program ) {\n\n\t\t\tvar objectInfluences = object.morphTargetInfluences;\n\n\t\t\tvar length = objectInfluences.length;\n\n\t\t\tvar influences = influencesList[ geometry.id ];\n\n\t\t\tif ( influences === undefined ) {\n\n\t\t\t\t// initialise list\n\n\t\t\t\tinfluences = [];\n\n\t\t\t\tfor ( var i = 0; i < length; i ++ ) {\n\n\t\t\t\t\tinfluences[ i ] = [ i, 0 ];\n\n\t\t\t\t}\n\n\t\t\t\tinfluencesList[ geometry.id ] = influences;\n\n\t\t\t}\n\n\t\t\tvar morphTargets = material.morphTargets && geometry.morphAttributes.position;\n\t\t\tvar morphNormals = material.morphNormals && geometry.morphAttributes.normal;\n\n\t\t\t// Remove current morphAttributes\n\n\t\t\tfor ( var i = 0; i < length; i ++ ) {\n\n\t\t\t\tvar influence = influences[ i ];\n\n\t\t\t\tif ( influence[ 1 ] !== 0 ) {\n\n\t\t\t\t\tif ( morphTargets ) geometry.removeAttribute( 'morphTarget' + i );\n\t\t\t\t\tif ( morphNormals ) geometry.removeAttribute( 'morphNormal' + i );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// Collect influences\n\n\t\t\tfor ( var i = 0; i < length; i ++ ) {\n\n\t\t\t\tvar influence = influences[ i ];\n\n\t\t\t\tinfluence[ 0 ] = i;\n\t\t\t\tinfluence[ 1 ] = objectInfluences[ i ];\n\n\t\t\t}\n\n\t\t\tinfluences.sort( absNumericalSort );\n\n\t\t\t// Add morphAttributes\n\n\t\t\tfor ( var i = 0; i < 8; i ++ ) {\n\n\t\t\t\tvar influence = influences[ i ];\n\n\t\t\t\tif ( influence ) {\n\n\t\t\t\t\tvar index = influence[ 0 ];\n\t\t\t\t\tvar value = influence[ 1 ];\n\n\t\t\t\t\tif ( value ) {\n\n\t\t\t\t\t\tif ( morphTargets ) geometry.addAttribute( 'morphTarget' + i, morphTargets[ index ] );\n\t\t\t\t\t\tif ( morphNormals ) geometry.addAttribute( 'morphNormal' + i, morphNormals[ index ] );\n\n\t\t\t\t\t\tmorphInfluences[ i ] = value;\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tmorphInfluences[ i ] = 0;\n\n\t\t\t}\n\n\t\t\tprogram.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences );\n\n\t\t}\n\n\t\treturn {\n\n\t\t\tupdate: update\n\n\t\t}\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction WebGLIndexedBufferRenderer( gl, extensions, infoRender ) {\n\n\t\tvar mode;\n\n\t\tfunction setMode( value ) {\n\n\t\t\tmode = value;\n\n\t\t}\n\n\t\tvar type, bytesPerElement;\n\n\t\tfunction setIndex( value ) {\n\n\t\t\ttype = value.type;\n\t\t\tbytesPerElement = value.bytesPerElement;\n\n\t\t}\n\n\t\tfunction render( start, count ) {\n\n\t\t\tgl.drawElements( mode, count, type, start * bytesPerElement );\n\n\t\t\tinfoRender.calls ++;\n\t\t\tinfoRender.vertices += count;\n\n\t\t\tif ( mode === gl.TRIANGLES ) infoRender.faces += count / 3;\n\t\t\telse if ( mode === gl.POINTS ) infoRender.points += count;\n\n\t\t}\n\n\t\tfunction renderInstances( geometry, start, count ) {\n\n\t\t\tvar extension = extensions.get( 'ANGLE_instanced_arrays' );\n\n\t\t\tif ( extension === null ) {\n\n\t\t\t\tconsole.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\textension.drawElementsInstancedANGLE( mode, count, type, start * bytesPerElement, geometry.maxInstancedCount );\n\n\t\t\tinfoRender.calls ++;\n\t\t\tinfoRender.vertices += count * geometry.maxInstancedCount;\n\n\t\t\tif ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3;\n\t\t\telse if ( mode === gl.POINTS ) infoRender.points += geometry.maxInstancedCount * count;\n\n\t\t}\n\n\t\t//\n\n\t\tthis.setMode = setMode;\n\t\tthis.setIndex = setIndex;\n\t\tthis.render = render;\n\t\tthis.renderInstances = renderInstances;\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction WebGLBufferRenderer( gl, extensions, infoRender ) {\n\n\t\tvar mode;\n\n\t\tfunction setMode( value ) {\n\n\t\t\tmode = value;\n\n\t\t}\n\n\t\tfunction render( start, count ) {\n\n\t\t\tgl.drawArrays( mode, start, count );\n\n\t\t\tinfoRender.calls ++;\n\t\t\tinfoRender.vertices += count;\n\n\t\t\tif ( mode === gl.TRIANGLES ) infoRender.faces += count / 3;\n\t\t\telse if ( mode === gl.POINTS ) infoRender.points += count;\n\n\t\t}\n\n\t\tfunction renderInstances( geometry, start, count ) {\n\n\t\t\tvar extension = extensions.get( 'ANGLE_instanced_arrays' );\n\n\t\t\tif ( extension === null ) {\n\n\t\t\t\tconsole.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tvar position = geometry.attributes.position;\n\n\t\t\tif ( position.isInterleavedBufferAttribute ) {\n\n\t\t\t\tcount = position.data.count;\n\n\t\t\t\textension.drawArraysInstancedANGLE( mode, 0, count, geometry.maxInstancedCount );\n\n\t\t\t} else {\n\n\t\t\t\textension.drawArraysInstancedANGLE( mode, start, count, geometry.maxInstancedCount );\n\n\t\t\t}\n\n\t\t\tinfoRender.calls ++;\n\t\t\tinfoRender.vertices += count * geometry.maxInstancedCount;\n\n\t\t\tif ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3;\n\t\t\telse if ( mode === gl.POINTS ) infoRender.points += geometry.maxInstancedCount * count;\n\n\t\t}\n\n\t\t//\n\n\t\tthis.setMode = setMode;\n\t\tthis.render = render;\n\t\tthis.renderInstances = renderInstances;\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction WebGLGeometries( gl, attributes, infoMemory ) {\n\n\t\tvar geometries = {};\n\t\tvar wireframeAttributes = {};\n\n\t\tfunction onGeometryDispose( event ) {\n\n\t\t\tvar geometry = event.target;\n\t\t\tvar buffergeometry = geometries[ geometry.id ];\n\n\t\t\tif ( buffergeometry.index !== null ) {\n\n\t\t\t\tattributes.remove( buffergeometry.index );\n\n\t\t\t}\n\n\t\t\tfor ( var name in buffergeometry.attributes ) {\n\n\t\t\t\tattributes.remove( buffergeometry.attributes[ name ] );\n\n\t\t\t}\n\n\t\t\tgeometry.removeEventListener( 'dispose', onGeometryDispose );\n\n\t\t\tdelete geometries[ geometry.id ];\n\n\t\t\t// TODO Remove duplicate code\n\n\t\t\tvar attribute = wireframeAttributes[ geometry.id ];\n\n\t\t\tif ( attribute ) {\n\n\t\t\t\tattributes.remove( attribute );\n\t\t\t\tdelete wireframeAttributes[ geometry.id ];\n\n\t\t\t}\n\n\t\t\tattribute = wireframeAttributes[ buffergeometry.id ];\n\n\t\t\tif ( attribute ) {\n\n\t\t\t\tattributes.remove( attribute );\n\t\t\t\tdelete wireframeAttributes[ buffergeometry.id ];\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tinfoMemory.geometries --;\n\n\t\t}\n\n\t\tfunction get( object, geometry ) {\n\n\t\t\tvar buffergeometry = geometries[ geometry.id ];\n\n\t\t\tif ( buffergeometry ) return buffergeometry;\n\n\t\t\tgeometry.addEventListener( 'dispose', onGeometryDispose );\n\n\t\t\tif ( geometry.isBufferGeometry ) {\n\n\t\t\t\tbuffergeometry = geometry;\n\n\t\t\t} else if ( geometry.isGeometry ) {\n\n\t\t\t\tif ( geometry._bufferGeometry === undefined ) {\n\n\t\t\t\t\tgeometry._bufferGeometry = new BufferGeometry().setFromObject( object );\n\n\t\t\t\t}\n\n\t\t\t\tbuffergeometry = geometry._bufferGeometry;\n\n\t\t\t}\n\n\t\t\tgeometries[ geometry.id ] = buffergeometry;\n\n\t\t\tinfoMemory.geometries ++;\n\n\t\t\treturn buffergeometry;\n\n\t\t}\n\n\t\tfunction update( geometry ) {\n\n\t\t\tvar index = geometry.index;\n\t\t\tvar geometryAttributes = geometry.attributes;\n\n\t\t\tif ( index !== null ) {\n\n\t\t\t\tattributes.update( index, gl.ELEMENT_ARRAY_BUFFER );\n\n\t\t\t}\n\n\t\t\tfor ( var name in geometryAttributes ) {\n\n\t\t\t\tattributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER );\n\n\t\t\t}\n\n\t\t\t// morph targets\n\n\t\t\tvar morphAttributes = geometry.morphAttributes;\n\n\t\t\tfor ( var name in morphAttributes ) {\n\n\t\t\t\tvar array = morphAttributes[ name ];\n\n\t\t\t\tfor ( var i = 0, l = array.length; i < l; i ++ ) {\n\n\t\t\t\t\tattributes.update( array[ i ], gl.ARRAY_BUFFER );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction getWireframeAttribute( geometry ) {\n\n\t\t\tvar attribute = wireframeAttributes[ geometry.id ];\n\n\t\t\tif ( attribute ) return attribute;\n\n\t\t\tvar indices = [];\n\n\t\t\tvar geometryIndex = geometry.index;\n\t\t\tvar geometryAttributes = geometry.attributes;\n\n\t\t\t// console.time( 'wireframe' );\n\n\t\t\tif ( geometryIndex !== null ) {\n\n\t\t\t\tvar array = geometryIndex.array;\n\n\t\t\t\tfor ( var i = 0, l = array.length; i < l; i += 3 ) {\n\n\t\t\t\t\tvar a = array[ i + 0 ];\n\t\t\t\t\tvar b = array[ i + 1 ];\n\t\t\t\t\tvar c = array[ i + 2 ];\n\n\t\t\t\t\tindices.push( a, b, b, c, c, a );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tvar array = geometryAttributes.position.array;\n\n\t\t\t\tfor ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {\n\n\t\t\t\t\tvar a = i + 0;\n\t\t\t\t\tvar b = i + 1;\n\t\t\t\t\tvar c = i + 2;\n\n\t\t\t\t\tindices.push( a, b, b, c, c, a );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// console.timeEnd( 'wireframe' );\n\n\t\t\tattribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );\n\n\t\t\tattributes.update( attribute, gl.ELEMENT_ARRAY_BUFFER );\n\n\t\t\twireframeAttributes[ geometry.id ] = attribute;\n\n\t\t\treturn attribute;\n\n\t\t}\n\n\t\treturn {\n\n\t\t\tget: get,\n\t\t\tupdate: update,\n\n\t\t\tgetWireframeAttribute: getWireframeAttribute\n\n\t\t};\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction UniformsCache() {\n\n\t\tvar lights = {};\n\n\t\treturn {\n\n\t\t\tget: function ( light ) {\n\n\t\t\t\tif ( lights[ light.id ] !== undefined ) {\n\n\t\t\t\t\treturn lights[ light.id ];\n\n\t\t\t\t}\n\n\t\t\t\tvar uniforms;\n\n\t\t\t\tswitch ( light.type ) {\n\n\t\t\t\t\tcase 'DirectionalLight':\n\t\t\t\t\t\tuniforms = {\n\t\t\t\t\t\t\tdirection: new Vector3(),\n\t\t\t\t\t\t\tcolor: new Color(),\n\n\t\t\t\t\t\t\tshadow: false,\n\t\t\t\t\t\t\tshadowBias: 0,\n\t\t\t\t\t\t\tshadowRadius: 1,\n\t\t\t\t\t\t\tshadowMapSize: new Vector2()\n\t\t\t\t\t\t};\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'SpotLight':\n\t\t\t\t\t\tuniforms = {\n\t\t\t\t\t\t\tposition: new Vector3(),\n\t\t\t\t\t\t\tdirection: new Vector3(),\n\t\t\t\t\t\t\tcolor: new Color(),\n\t\t\t\t\t\t\tdistance: 0,\n\t\t\t\t\t\t\tconeCos: 0,\n\t\t\t\t\t\t\tpenumbraCos: 0,\n\t\t\t\t\t\t\tdecay: 0,\n\n\t\t\t\t\t\t\tshadow: false,\n\t\t\t\t\t\t\tshadowBias: 0,\n\t\t\t\t\t\t\tshadowRadius: 1,\n\t\t\t\t\t\t\tshadowMapSize: new Vector2()\n\t\t\t\t\t\t};\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'PointLight':\n\t\t\t\t\t\tuniforms = {\n\t\t\t\t\t\t\tposition: new Vector3(),\n\t\t\t\t\t\t\tcolor: new Color(),\n\t\t\t\t\t\t\tdistance: 0,\n\t\t\t\t\t\t\tdecay: 0,\n\n\t\t\t\t\t\t\tshadow: false,\n\t\t\t\t\t\t\tshadowBias: 0,\n\t\t\t\t\t\t\tshadowRadius: 1,\n\t\t\t\t\t\t\tshadowMapSize: new Vector2(),\n\t\t\t\t\t\t\tshadowCameraNear: 1,\n\t\t\t\t\t\t\tshadowCameraFar: 1000\n\t\t\t\t\t\t};\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'HemisphereLight':\n\t\t\t\t\t\tuniforms = {\n\t\t\t\t\t\t\tdirection: new Vector3(),\n\t\t\t\t\t\t\tskyColor: new Color(),\n\t\t\t\t\t\t\tgroundColor: new Color()\n\t\t\t\t\t\t};\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'RectAreaLight':\n\t\t\t\t\t\tuniforms = {\n\t\t\t\t\t\t\tcolor: new Color(),\n\t\t\t\t\t\t\tposition: new Vector3(),\n\t\t\t\t\t\t\thalfWidth: new Vector3(),\n\t\t\t\t\t\t\thalfHeight: new Vector3()\n\t\t\t\t\t\t\t// TODO (abelnation): set RectAreaLight shadow uniforms\n\t\t\t\t\t\t};\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t\tlights[ light.id ] = uniforms;\n\n\t\t\t\treturn uniforms;\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\tfunction WebGLLights() {\n\n\t\tvar cache = new UniformsCache();\n\n\t\tvar state = {\n\n\t\t\thash: '',\n\n\t\t\tambient: [ 0, 0, 0 ],\n\t\t\tdirectional: [],\n\t\t\tdirectionalShadowMap: [],\n\t\t\tdirectionalShadowMatrix: [],\n\t\t\tspot: [],\n\t\t\tspotShadowMap: [],\n\t\t\tspotShadowMatrix: [],\n\t\t\trectArea: [],\n\t\t\tpoint: [],\n\t\t\tpointShadowMap: [],\n\t\t\tpointShadowMatrix: [],\n\t\t\themi: []\n\n\t\t};\n\n\t\tvar vector3 = new Vector3();\n\t\tvar matrix4 = new Matrix4();\n\t\tvar matrix42 = new Matrix4();\n\n\t\tfunction setup( lights, shadows, camera ) {\n\n\t\t\tvar r = 0, g = 0, b = 0;\n\n\t\t\tvar directionalLength = 0;\n\t\t\tvar pointLength = 0;\n\t\t\tvar spotLength = 0;\n\t\t\tvar rectAreaLength = 0;\n\t\t\tvar hemiLength = 0;\n\n\t\t\tvar viewMatrix = camera.matrixWorldInverse;\n\n\t\t\tfor ( var i = 0, l = lights.length; i < l; i ++ ) {\n\n\t\t\t\tvar light = lights[ i ];\n\n\t\t\t\tvar color = light.color;\n\t\t\t\tvar intensity = light.intensity;\n\t\t\t\tvar distance = light.distance;\n\n\t\t\t\tvar shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;\n\n\t\t\t\tif ( light.isAmbientLight ) {\n\n\t\t\t\t\tr += color.r * intensity;\n\t\t\t\t\tg += color.g * intensity;\n\t\t\t\t\tb += color.b * intensity;\n\n\t\t\t\t} else if ( light.isDirectionalLight ) {\n\n\t\t\t\t\tvar uniforms = cache.get( light );\n\n\t\t\t\t\tuniforms.color.copy( light.color ).multiplyScalar( light.intensity );\n\t\t\t\t\tuniforms.direction.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\t\tvector3.setFromMatrixPosition( light.target.matrixWorld );\n\t\t\t\t\tuniforms.direction.sub( vector3 );\n\t\t\t\t\tuniforms.direction.transformDirection( viewMatrix );\n\n\t\t\t\t\tuniforms.shadow = light.castShadow;\n\n\t\t\t\t\tif ( light.castShadow ) {\n\n\t\t\t\t\t\tvar shadow = light.shadow;\n\n\t\t\t\t\t\tuniforms.shadowBias = shadow.bias;\n\t\t\t\t\t\tuniforms.shadowRadius = shadow.radius;\n\t\t\t\t\t\tuniforms.shadowMapSize = shadow.mapSize;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tstate.directionalShadowMap[ directionalLength ] = shadowMap;\n\t\t\t\t\tstate.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;\n\t\t\t\t\tstate.directional[ directionalLength ] = uniforms;\n\n\t\t\t\t\tdirectionalLength ++;\n\n\t\t\t\t} else if ( light.isSpotLight ) {\n\n\t\t\t\t\tvar uniforms = cache.get( light );\n\n\t\t\t\t\tuniforms.position.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\t\tuniforms.position.applyMatrix4( viewMatrix );\n\n\t\t\t\t\tuniforms.color.copy( color ).multiplyScalar( intensity );\n\t\t\t\t\tuniforms.distance = distance;\n\n\t\t\t\t\tuniforms.direction.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\t\tvector3.setFromMatrixPosition( light.target.matrixWorld );\n\t\t\t\t\tuniforms.direction.sub( vector3 );\n\t\t\t\t\tuniforms.direction.transformDirection( viewMatrix );\n\n\t\t\t\t\tuniforms.coneCos = Math.cos( light.angle );\n\t\t\t\t\tuniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );\n\t\t\t\t\tuniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay;\n\n\t\t\t\t\tuniforms.shadow = light.castShadow;\n\n\t\t\t\t\tif ( light.castShadow ) {\n\n\t\t\t\t\t\tvar shadow = light.shadow;\n\n\t\t\t\t\t\tuniforms.shadowBias = shadow.bias;\n\t\t\t\t\t\tuniforms.shadowRadius = shadow.radius;\n\t\t\t\t\t\tuniforms.shadowMapSize = shadow.mapSize;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tstate.spotShadowMap[ spotLength ] = shadowMap;\n\t\t\t\t\tstate.spotShadowMatrix[ spotLength ] = light.shadow.matrix;\n\t\t\t\t\tstate.spot[ spotLength ] = uniforms;\n\n\t\t\t\t\tspotLength ++;\n\n\t\t\t\t} else if ( light.isRectAreaLight ) {\n\n\t\t\t\t\tvar uniforms = cache.get( light );\n\n\t\t\t\t\t// (a) intensity controls irradiance of entire light\n\t\t\t\t\tuniforms.color\n\t\t\t\t\t\t.copy( color )\n\t\t\t\t\t\t.multiplyScalar( intensity / ( light.width * light.height ) );\n\n\t\t\t\t\t// (b) intensity controls the radiance per light area\n\t\t\t\t\t// uniforms.color.copy( color ).multiplyScalar( intensity );\n\n\t\t\t\t\tuniforms.position.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\t\tuniforms.position.applyMatrix4( viewMatrix );\n\n\t\t\t\t\t// extract local rotation of light to derive width/height half vectors\n\t\t\t\t\tmatrix42.identity();\n\t\t\t\t\tmatrix4.copy( light.matrixWorld );\n\t\t\t\t\tmatrix4.premultiply( viewMatrix );\n\t\t\t\t\tmatrix42.extractRotation( matrix4 );\n\n\t\t\t\t\tuniforms.halfWidth.set( light.width * 0.5,                0.0, 0.0 );\n\t\t\t\t\tuniforms.halfHeight.set(              0.0, light.height * 0.5, 0.0 );\n\n\t\t\t\t\tuniforms.halfWidth.applyMatrix4( matrix42 );\n\t\t\t\t\tuniforms.halfHeight.applyMatrix4( matrix42 );\n\n\t\t\t\t\t// TODO (abelnation): RectAreaLight distance?\n\t\t\t\t\t// uniforms.distance = distance;\n\n\t\t\t\t\tstate.rectArea[ rectAreaLength ] = uniforms;\n\n\t\t\t\t\trectAreaLength ++;\n\n\t\t\t\t} else if ( light.isPointLight ) {\n\n\t\t\t\t\tvar uniforms = cache.get( light );\n\n\t\t\t\t\tuniforms.position.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\t\tuniforms.position.applyMatrix4( viewMatrix );\n\n\t\t\t\t\tuniforms.color.copy( light.color ).multiplyScalar( light.intensity );\n\t\t\t\t\tuniforms.distance = light.distance;\n\t\t\t\t\tuniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay;\n\n\t\t\t\t\tuniforms.shadow = light.castShadow;\n\n\t\t\t\t\tif ( light.castShadow ) {\n\n\t\t\t\t\t\tvar shadow = light.shadow;\n\n\t\t\t\t\t\tuniforms.shadowBias = shadow.bias;\n\t\t\t\t\t\tuniforms.shadowRadius = shadow.radius;\n\t\t\t\t\t\tuniforms.shadowMapSize = shadow.mapSize;\n\t\t\t\t\t\tuniforms.shadowCameraNear = shadow.camera.near;\n\t\t\t\t\t\tuniforms.shadowCameraFar = shadow.camera.far;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tstate.pointShadowMap[ pointLength ] = shadowMap;\n\t\t\t\t\tstate.pointShadowMatrix[ pointLength ] = light.shadow.matrix;\n\t\t\t\t\tstate.point[ pointLength ] = uniforms;\n\n\t\t\t\t\tpointLength ++;\n\n\t\t\t\t} else if ( light.isHemisphereLight ) {\n\n\t\t\t\t\tvar uniforms = cache.get( light );\n\n\t\t\t\t\tuniforms.direction.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\t\tuniforms.direction.transformDirection( viewMatrix );\n\t\t\t\t\tuniforms.direction.normalize();\n\n\t\t\t\t\tuniforms.skyColor.copy( light.color ).multiplyScalar( intensity );\n\t\t\t\t\tuniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );\n\n\t\t\t\t\tstate.hemi[ hemiLength ] = uniforms;\n\n\t\t\t\t\themiLength ++;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tstate.ambient[ 0 ] = r;\n\t\t\tstate.ambient[ 1 ] = g;\n\t\t\tstate.ambient[ 2 ] = b;\n\n\t\t\tstate.directional.length = directionalLength;\n\t\t\tstate.spot.length = spotLength;\n\t\t\tstate.rectArea.length = rectAreaLength;\n\t\t\tstate.point.length = pointLength;\n\t\t\tstate.hemi.length = hemiLength;\n\n\t\t\t// TODO (sam-g-steel) why aren't we using join\n\t\t\tstate.hash = directionalLength + ',' + pointLength + ',' + spotLength + ',' + rectAreaLength + ',' + hemiLength + ',' + shadows.length;\n\n\t\t}\n\n\t\treturn {\n\t\t\tsetup: setup,\n\t\t\tstate: state\n\t\t}\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction WebGLObjects( geometries, infoRender ) {\n\n\t\tvar updateList = {};\n\n\t\tfunction update( object ) {\n\n\t\t\tvar frame = infoRender.frame;\n\n\t\t\tvar geometry = object.geometry;\n\t\t\tvar buffergeometry = geometries.get( object, geometry );\n\n\t\t\t// Update once per frame\n\n\t\t\tif ( updateList[ buffergeometry.id ] !== frame ) {\n\n\t\t\t\tif ( geometry.isGeometry ) {\n\n\t\t\t\t\tbuffergeometry.updateFromObject( object );\n\n\t\t\t\t}\n\n\t\t\t\tgeometries.update( buffergeometry );\n\n\t\t\t\tupdateList[ buffergeometry.id ] = frame;\n\n\t\t\t}\n\n\t\t\treturn buffergeometry;\n\n\t\t}\n\n\t\tfunction clear() {\n\n\t\t\tupdateList = {};\n\n\t\t}\n\n\t\treturn {\n\n\t\t\tupdate: update,\n\t\t\tclear: clear\n\n\t\t};\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction addLineNumbers( string ) {\n\n\t\tvar lines = string.split( '\\n' );\n\n\t\tfor ( var i = 0; i < lines.length; i ++ ) {\n\n\t\t\tlines[ i ] = ( i + 1 ) + ': ' + lines[ i ];\n\n\t\t}\n\n\t\treturn lines.join( '\\n' );\n\n\t}\n\n\tfunction WebGLShader( gl, type, string ) {\n\n\t\tvar shader = gl.createShader( type );\n\n\t\tgl.shaderSource( shader, string );\n\t\tgl.compileShader( shader );\n\n\t\tif ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) {\n\n\t\t\tconsole.error( 'THREE.WebGLShader: Shader couldn\\'t compile.' );\n\n\t\t}\n\n\t\tif ( gl.getShaderInfoLog( shader ) !== '' ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', type === gl.VERTEX_SHADER ? 'vertex' : 'fragment', gl.getShaderInfoLog( shader ), addLineNumbers( string ) );\n\n\t\t}\n\n\t\t// --enable-privileged-webgl-extension\n\t\t// console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );\n\n\t\treturn shader;\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tvar programIdCount = 0;\n\n\tfunction getEncodingComponents( encoding ) {\n\n\t\tswitch ( encoding ) {\n\n\t\t\tcase LinearEncoding:\n\t\t\t\treturn [ 'Linear','( value )' ];\n\t\t\tcase sRGBEncoding:\n\t\t\t\treturn [ 'sRGB','( value )' ];\n\t\t\tcase RGBEEncoding:\n\t\t\t\treturn [ 'RGBE','( value )' ];\n\t\t\tcase RGBM7Encoding:\n\t\t\t\treturn [ 'RGBM','( value, 7.0 )' ];\n\t\t\tcase RGBM16Encoding:\n\t\t\t\treturn [ 'RGBM','( value, 16.0 )' ];\n\t\t\tcase RGBDEncoding:\n\t\t\t\treturn [ 'RGBD','( value, 256.0 )' ];\n\t\t\tcase GammaEncoding:\n\t\t\t\treturn [ 'Gamma','( value, float( GAMMA_FACTOR ) )' ];\n\t\t\tdefault:\n\t\t\t\tthrow new Error( 'unsupported encoding: ' + encoding );\n\n\t\t}\n\n\t}\n\n\tfunction getTexelDecodingFunction( functionName, encoding ) {\n\n\t\tvar components = getEncodingComponents( encoding );\n\t\treturn \"vec4 \" + functionName + \"( vec4 value ) { return \" + components[ 0 ] + \"ToLinear\" + components[ 1 ] + \"; }\";\n\n\t}\n\n\tfunction getTexelEncodingFunction( functionName, encoding ) {\n\n\t\tvar components = getEncodingComponents( encoding );\n\t\treturn \"vec4 \" + functionName + \"( vec4 value ) { return LinearTo\" + components[ 0 ] + components[ 1 ] + \"; }\";\n\n\t}\n\n\tfunction getToneMappingFunction( functionName, toneMapping ) {\n\n\t\tvar toneMappingName;\n\n\t\tswitch ( toneMapping ) {\n\n\t\t\tcase LinearToneMapping:\n\t\t\t\ttoneMappingName = \"Linear\";\n\t\t\t\tbreak;\n\n\t\t\tcase ReinhardToneMapping:\n\t\t\t\ttoneMappingName = \"Reinhard\";\n\t\t\t\tbreak;\n\n\t\t\tcase Uncharted2ToneMapping:\n\t\t\t\ttoneMappingName = \"Uncharted2\";\n\t\t\t\tbreak;\n\n\t\t\tcase CineonToneMapping:\n\t\t\t\ttoneMappingName = \"OptimizedCineon\";\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tthrow new Error( 'unsupported toneMapping: ' + toneMapping );\n\n\t\t}\n\n\t\treturn \"vec3 \" + functionName + \"( vec3 color ) { return \" + toneMappingName + \"ToneMapping( color ); }\";\n\n\t}\n\n\tfunction generateExtensions( extensions, parameters, rendererExtensions ) {\n\n\t\textensions = extensions || {};\n\n\t\tvar chunks = [\n\t\t\t( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '',\n\t\t\t( extensions.fragDepth || parameters.logarithmicDepthBuffer ) && rendererExtensions.get( 'EXT_frag_depth' ) ? '#extension GL_EXT_frag_depth : enable' : '',\n\t\t\t( extensions.drawBuffers ) && rendererExtensions.get( 'WEBGL_draw_buffers' ) ? '#extension GL_EXT_draw_buffers : require' : '',\n\t\t\t( extensions.shaderTextureLOD || parameters.envMap ) && rendererExtensions.get( 'EXT_shader_texture_lod' ) ? '#extension GL_EXT_shader_texture_lod : enable' : ''\n\t\t];\n\n\t\treturn chunks.filter( filterEmptyLine ).join( '\\n' );\n\n\t}\n\n\tfunction generateDefines( defines ) {\n\n\t\tvar chunks = [];\n\n\t\tfor ( var name in defines ) {\n\n\t\t\tvar value = defines[ name ];\n\n\t\t\tif ( value === false ) continue;\n\n\t\t\tchunks.push( '#define ' + name + ' ' + value );\n\n\t\t}\n\n\t\treturn chunks.join( '\\n' );\n\n\t}\n\n\tfunction fetchAttributeLocations( gl, program, identifiers ) {\n\n\t\tvar attributes = {};\n\n\t\tvar n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES );\n\n\t\tfor ( var i = 0; i < n; i ++ ) {\n\n\t\t\tvar info = gl.getActiveAttrib( program, i );\n\t\t\tvar name = info.name;\n\n\t\t\t// console.log(\"THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:\", name, i );\n\n\t\t\tattributes[ name ] = gl.getAttribLocation( program, name );\n\n\t\t}\n\n\t\treturn attributes;\n\n\t}\n\n\tfunction filterEmptyLine( string ) {\n\n\t\treturn string !== '';\n\n\t}\n\n\tfunction replaceLightNums( string, parameters ) {\n\n\t\treturn string\n\t\t\t.replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )\n\t\t\t.replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )\n\t\t\t.replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )\n\t\t\t.replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )\n\t\t\t.replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights );\n\n\t}\n\n\tfunction parseIncludes( string ) {\n\n\t\tvar pattern = /^[ \\t]*#include +<([\\w\\d.]+)>/gm;\n\n\t\tfunction replace( match, include ) {\n\n\t\t\tvar replace = ShaderChunk[ include ];\n\n\t\t\tif ( replace === undefined ) {\n\n\t\t\t\tthrow new Error( 'Can not resolve #include <' + include + '>' );\n\n\t\t\t}\n\n\t\t\treturn parseIncludes( replace );\n\n\t\t}\n\n\t\treturn string.replace( pattern, replace );\n\n\t}\n\n\tfunction unrollLoops( string ) {\n\n\t\tvar pattern = /for \\( int i \\= (\\d+)\\; i < (\\d+)\\; i \\+\\+ \\) \\{([\\s\\S]+?)(?=\\})\\}/g;\n\n\t\tfunction replace( match, start, end, snippet ) {\n\n\t\t\tvar unroll = '';\n\n\t\t\tfor ( var i = parseInt( start ); i < parseInt( end ); i ++ ) {\n\n\t\t\t\tunroll += snippet.replace( /\\[ i \\]/g, '[ ' + i + ' ]' );\n\n\t\t\t}\n\n\t\t\treturn unroll;\n\n\t\t}\n\n\t\treturn string.replace( pattern, replace );\n\n\t}\n\n\tfunction WebGLProgram( renderer, extensions, code, material, shader, parameters ) {\n\n\t\tvar gl = renderer.context;\n\n\t\tvar defines = material.defines;\n\n\t\tvar vertexShader = shader.vertexShader;\n\t\tvar fragmentShader = shader.fragmentShader;\n\n\t\tvar shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';\n\n\t\tif ( parameters.shadowMapType === PCFShadowMap ) {\n\n\t\t\tshadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';\n\n\t\t} else if ( parameters.shadowMapType === PCFSoftShadowMap ) {\n\n\t\t\tshadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';\n\n\t\t}\n\n\t\tvar envMapTypeDefine = 'ENVMAP_TYPE_CUBE';\n\t\tvar envMapModeDefine = 'ENVMAP_MODE_REFLECTION';\n\t\tvar envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';\n\n\t\tif ( parameters.envMap ) {\n\n\t\t\tswitch ( material.envMap.mapping ) {\n\n\t\t\t\tcase CubeReflectionMapping:\n\t\t\t\tcase CubeRefractionMapping:\n\t\t\t\t\tenvMapTypeDefine = 'ENVMAP_TYPE_CUBE';\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CubeUVReflectionMapping:\n\t\t\t\tcase CubeUVRefractionMapping:\n\t\t\t\t\tenvMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase EquirectangularReflectionMapping:\n\t\t\t\tcase EquirectangularRefractionMapping:\n\t\t\t\t\tenvMapTypeDefine = 'ENVMAP_TYPE_EQUIREC';\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase SphericalReflectionMapping:\n\t\t\t\t\tenvMapTypeDefine = 'ENVMAP_TYPE_SPHERE';\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tswitch ( material.envMap.mapping ) {\n\n\t\t\t\tcase CubeRefractionMapping:\n\t\t\t\tcase EquirectangularRefractionMapping:\n\t\t\t\t\tenvMapModeDefine = 'ENVMAP_MODE_REFRACTION';\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tswitch ( material.combine ) {\n\n\t\t\t\tcase MultiplyOperation:\n\t\t\t\t\tenvMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase MixOperation:\n\t\t\t\t\tenvMapBlendingDefine = 'ENVMAP_BLENDING_MIX';\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase AddOperation:\n\t\t\t\t\tenvMapBlendingDefine = 'ENVMAP_BLENDING_ADD';\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tvar gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0;\n\n\t\t// console.log( 'building new program ' );\n\n\t\t//\n\n\t\tvar customExtensions = generateExtensions( material.extensions, parameters, extensions );\n\n\t\tvar customDefines = generateDefines( defines );\n\n\t\t//\n\n\t\tvar program = gl.createProgram();\n\n\t\tvar prefixVertex, prefixFragment;\n\n\t\tif ( material.isRawShaderMaterial ) {\n\n\t\t\tprefixVertex = [\n\n\t\t\t\tcustomDefines,\n\n\t\t\t\t'\\n'\n\n\t\t\t].filter( filterEmptyLine ).join( '\\n' );\n\n\t\t\tprefixFragment = [\n\n\t\t\t\tcustomExtensions,\n\t\t\t\tcustomDefines,\n\n\t\t\t\t'\\n'\n\n\t\t\t].filter( filterEmptyLine ).join( '\\n' );\n\n\t\t} else {\n\n\t\t\tprefixVertex = [\n\n\t\t\t\t'precision ' + parameters.precision + ' float;',\n\t\t\t\t'precision ' + parameters.precision + ' int;',\n\n\t\t\t\t'#define SHADER_NAME ' + shader.name,\n\n\t\t\t\tcustomDefines,\n\n\t\t\t\tparameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '',\n\n\t\t\t\t'#define GAMMA_FACTOR ' + gammaFactorDefine,\n\n\t\t\t\t'#define MAX_BONES ' + parameters.maxBones,\n\t\t\t\t( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',\n\t\t\t\t( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '',\n\n\t\t\t\tparameters.map ? '#define USE_MAP' : '',\n\t\t\t\tparameters.envMap ? '#define USE_ENVMAP' : '',\n\t\t\t\tparameters.envMap ? '#define ' + envMapModeDefine : '',\n\t\t\t\tparameters.lightMap ? '#define USE_LIGHTMAP' : '',\n\t\t\t\tparameters.aoMap ? '#define USE_AOMAP' : '',\n\t\t\t\tparameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',\n\t\t\t\tparameters.bumpMap ? '#define USE_BUMPMAP' : '',\n\t\t\t\tparameters.normalMap ? '#define USE_NORMALMAP' : '',\n\t\t\t\tparameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '',\n\t\t\t\tparameters.specularMap ? '#define USE_SPECULARMAP' : '',\n\t\t\t\tparameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',\n\t\t\t\tparameters.metalnessMap ? '#define USE_METALNESSMAP' : '',\n\t\t\t\tparameters.alphaMap ? '#define USE_ALPHAMAP' : '',\n\t\t\t\tparameters.vertexColors ? '#define USE_COLOR' : '',\n\n\t\t\t\tparameters.flatShading ? '#define FLAT_SHADED' : '',\n\n\t\t\t\tparameters.skinning ? '#define USE_SKINNING' : '',\n\t\t\t\tparameters.useVertexTexture ? '#define BONE_TEXTURE' : '',\n\n\t\t\t\tparameters.morphTargets ? '#define USE_MORPHTARGETS' : '',\n\t\t\t\tparameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',\n\t\t\t\tparameters.doubleSided ? '#define DOUBLE_SIDED' : '',\n\t\t\t\tparameters.flipSided ? '#define FLIP_SIDED' : '',\n\n\t\t\t\t'#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes,\n\n\t\t\t\tparameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',\n\t\t\t\tparameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',\n\n\t\t\t\tparameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',\n\n\t\t\t\tparameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',\n\t\t\t\tparameters.logarithmicDepthBuffer && extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '',\n\n\t\t\t\t'uniform mat4 modelMatrix;',\n\t\t\t\t'uniform mat4 modelViewMatrix;',\n\t\t\t\t'uniform mat4 projectionMatrix;',\n\t\t\t\t'uniform mat4 viewMatrix;',\n\t\t\t\t'uniform mat3 normalMatrix;',\n\t\t\t\t'uniform vec3 cameraPosition;',\n\n\t\t\t\t'attribute vec3 position;',\n\t\t\t\t'attribute vec3 normal;',\n\t\t\t\t'attribute vec2 uv;',\n\n\t\t\t\t'#ifdef USE_COLOR',\n\n\t\t\t\t'\tattribute vec3 color;',\n\n\t\t\t\t'#endif',\n\n\t\t\t\t'#ifdef USE_MORPHTARGETS',\n\n\t\t\t\t'\tattribute vec3 morphTarget0;',\n\t\t\t\t'\tattribute vec3 morphTarget1;',\n\t\t\t\t'\tattribute vec3 morphTarget2;',\n\t\t\t\t'\tattribute vec3 morphTarget3;',\n\n\t\t\t\t'\t#ifdef USE_MORPHNORMALS',\n\n\t\t\t\t'\t\tattribute vec3 morphNormal0;',\n\t\t\t\t'\t\tattribute vec3 morphNormal1;',\n\t\t\t\t'\t\tattribute vec3 morphNormal2;',\n\t\t\t\t'\t\tattribute vec3 morphNormal3;',\n\n\t\t\t\t'\t#else',\n\n\t\t\t\t'\t\tattribute vec3 morphTarget4;',\n\t\t\t\t'\t\tattribute vec3 morphTarget5;',\n\t\t\t\t'\t\tattribute vec3 morphTarget6;',\n\t\t\t\t'\t\tattribute vec3 morphTarget7;',\n\n\t\t\t\t'\t#endif',\n\n\t\t\t\t'#endif',\n\n\t\t\t\t'#ifdef USE_SKINNING',\n\n\t\t\t\t'\tattribute vec4 skinIndex;',\n\t\t\t\t'\tattribute vec4 skinWeight;',\n\n\t\t\t\t'#endif',\n\n\t\t\t\t'\\n'\n\n\t\t\t].filter( filterEmptyLine ).join( '\\n' );\n\n\t\t\tprefixFragment = [\n\n\t\t\t\tcustomExtensions,\n\n\t\t\t\t'precision ' + parameters.precision + ' float;',\n\t\t\t\t'precision ' + parameters.precision + ' int;',\n\n\t\t\t\t'#define SHADER_NAME ' + shader.name,\n\n\t\t\t\tcustomDefines,\n\n\t\t\t\tparameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest : '',\n\n\t\t\t\t'#define GAMMA_FACTOR ' + gammaFactorDefine,\n\n\t\t\t\t( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',\n\t\t\t\t( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '',\n\n\t\t\t\tparameters.map ? '#define USE_MAP' : '',\n\t\t\t\tparameters.envMap ? '#define USE_ENVMAP' : '',\n\t\t\t\tparameters.envMap ? '#define ' + envMapTypeDefine : '',\n\t\t\t\tparameters.envMap ? '#define ' + envMapModeDefine : '',\n\t\t\t\tparameters.envMap ? '#define ' + envMapBlendingDefine : '',\n\t\t\t\tparameters.lightMap ? '#define USE_LIGHTMAP' : '',\n\t\t\t\tparameters.aoMap ? '#define USE_AOMAP' : '',\n\t\t\t\tparameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',\n\t\t\t\tparameters.bumpMap ? '#define USE_BUMPMAP' : '',\n\t\t\t\tparameters.normalMap ? '#define USE_NORMALMAP' : '',\n\t\t\t\tparameters.specularMap ? '#define USE_SPECULARMAP' : '',\n\t\t\t\tparameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',\n\t\t\t\tparameters.metalnessMap ? '#define USE_METALNESSMAP' : '',\n\t\t\t\tparameters.alphaMap ? '#define USE_ALPHAMAP' : '',\n\t\t\t\tparameters.vertexColors ? '#define USE_COLOR' : '',\n\n\t\t\t\tparameters.gradientMap ? '#define USE_GRADIENTMAP' : '',\n\n\t\t\t\tparameters.flatShading ? '#define FLAT_SHADED' : '',\n\n\t\t\t\tparameters.doubleSided ? '#define DOUBLE_SIDED' : '',\n\t\t\t\tparameters.flipSided ? '#define FLIP_SIDED' : '',\n\n\t\t\t\t'#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes,\n\t\t\t\t'#define UNION_CLIPPING_PLANES ' + (parameters.numClippingPlanes - parameters.numClipIntersection),\n\n\t\t\t\tparameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',\n\t\t\t\tparameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',\n\n\t\t\t\tparameters.premultipliedAlpha ? \"#define PREMULTIPLIED_ALPHA\" : '',\n\n\t\t\t\tparameters.physicallyCorrectLights ? \"#define PHYSICALLY_CORRECT_LIGHTS\" : '',\n\n\t\t\t\tparameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',\n\t\t\t\tparameters.logarithmicDepthBuffer && extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '',\n\n\t\t\t\tparameters.envMap && extensions.get( 'EXT_shader_texture_lod' ) ? '#define TEXTURE_LOD_EXT' : '',\n\n\t\t\t\t'uniform mat4 viewMatrix;',\n\t\t\t\t'uniform vec3 cameraPosition;',\n\n\t\t\t\t( parameters.toneMapping !== NoToneMapping ) ? \"#define TONE_MAPPING\" : '',\n\t\t\t\t( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '',  // this code is required here because it is used by the toneMapping() function defined below\n\t\t\t\t( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( \"toneMapping\", parameters.toneMapping ) : '',\n\n\t\t\t\tparameters.dithering ? '#define DITHERING' : '',\n\n\t\t\t\t( parameters.outputEncoding || parameters.mapEncoding || parameters.envMapEncoding || parameters.emissiveMapEncoding ) ? ShaderChunk[ 'encodings_pars_fragment' ] : '', // this code is required here because it is used by the various encoding/decoding function defined below\n\t\t\t\tparameters.mapEncoding ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '',\n\t\t\t\tparameters.envMapEncoding ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '',\n\t\t\t\tparameters.emissiveMapEncoding ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '',\n\t\t\t\tparameters.outputEncoding ? getTexelEncodingFunction( \"linearToOutputTexel\", parameters.outputEncoding ) : '',\n\n\t\t\t\tparameters.depthPacking ? \"#define DEPTH_PACKING \" + material.depthPacking : '',\n\n\t\t\t\t'\\n'\n\n\t\t\t].filter( filterEmptyLine ).join( '\\n' );\n\n\t\t}\n\n\t\tvertexShader = parseIncludes( vertexShader );\n\t\tvertexShader = replaceLightNums( vertexShader, parameters );\n\n\t\tfragmentShader = parseIncludes( fragmentShader );\n\t\tfragmentShader = replaceLightNums( fragmentShader, parameters );\n\n\t\tif ( ! material.isShaderMaterial ) {\n\n\t\t\tvertexShader = unrollLoops( vertexShader );\n\t\t\tfragmentShader = unrollLoops( fragmentShader );\n\n\t\t}\n\n\t\tvar vertexGlsl = prefixVertex + vertexShader;\n\t\tvar fragmentGlsl = prefixFragment + fragmentShader;\n\n\t\t// console.log( '*VERTEX*', vertexGlsl );\n\t\t// console.log( '*FRAGMENT*', fragmentGlsl );\n\n\t\tvar glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );\n\t\tvar glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );\n\n\t\tgl.attachShader( program, glVertexShader );\n\t\tgl.attachShader( program, glFragmentShader );\n\n\t\t// Force a particular attribute to index 0.\n\n\t\tif ( material.index0AttributeName !== undefined ) {\n\n\t\t\tgl.bindAttribLocation( program, 0, material.index0AttributeName );\n\n\t\t} else if ( parameters.morphTargets === true ) {\n\n\t\t\t// programs with morphTargets displace position out of attribute 0\n\t\t\tgl.bindAttribLocation( program, 0, 'position' );\n\n\t\t}\n\n\t\tgl.linkProgram( program );\n\n\t\tvar programLog = gl.getProgramInfoLog( program );\n\t\tvar vertexLog = gl.getShaderInfoLog( glVertexShader );\n\t\tvar fragmentLog = gl.getShaderInfoLog( glFragmentShader );\n\n\t\tvar runnable = true;\n\t\tvar haveDiagnostics = true;\n\n\t\t// console.log( '**VERTEX**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) );\n\t\t// console.log( '**FRAGMENT**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) );\n\n\t\tif ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) {\n\n\t\t\trunnable = false;\n\n\t\t\tconsole.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), 'gl.VALIDATE_STATUS', gl.getProgramParameter( program, gl.VALIDATE_STATUS ), 'gl.getProgramInfoLog', programLog, vertexLog, fragmentLog );\n\n\t\t} else if ( programLog !== '' ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog );\n\n\t\t} else if ( vertexLog === '' || fragmentLog === '' ) {\n\n\t\t\thaveDiagnostics = false;\n\n\t\t}\n\n\t\tif ( haveDiagnostics ) {\n\n\t\t\tthis.diagnostics = {\n\n\t\t\t\trunnable: runnable,\n\t\t\t\tmaterial: material,\n\n\t\t\t\tprogramLog: programLog,\n\n\t\t\t\tvertexShader: {\n\n\t\t\t\t\tlog: vertexLog,\n\t\t\t\t\tprefix: prefixVertex\n\n\t\t\t\t},\n\n\t\t\t\tfragmentShader: {\n\n\t\t\t\t\tlog: fragmentLog,\n\t\t\t\t\tprefix: prefixFragment\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t}\n\n\t\t// clean up\n\n\t\tgl.deleteShader( glVertexShader );\n\t\tgl.deleteShader( glFragmentShader );\n\n\t\t// set up caching for uniform locations\n\n\t\tvar cachedUniforms;\n\n\t\tthis.getUniforms = function () {\n\n\t\t\tif ( cachedUniforms === undefined ) {\n\n\t\t\t\tcachedUniforms = new WebGLUniforms( gl, program, renderer );\n\n\t\t\t}\n\n\t\t\treturn cachedUniforms;\n\n\t\t};\n\n\t\t// set up caching for attribute locations\n\n\t\tvar cachedAttributes;\n\n\t\tthis.getAttributes = function () {\n\n\t\t\tif ( cachedAttributes === undefined ) {\n\n\t\t\t\tcachedAttributes = fetchAttributeLocations( gl, program );\n\n\t\t\t}\n\n\t\t\treturn cachedAttributes;\n\n\t\t};\n\n\t\t// free resource\n\n\t\tthis.destroy = function() {\n\n\t\t\tgl.deleteProgram( program );\n\t\t\tthis.program = undefined;\n\n\t\t};\n\n\t\t// DEPRECATED\n\n\t\tObject.defineProperties( this, {\n\n\t\t\tuniforms: {\n\t\t\t\tget: function() {\n\n\t\t\t\t\tconsole.warn( 'THREE.WebGLProgram: .uniforms is now .getUniforms().' );\n\t\t\t\t\treturn this.getUniforms();\n\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tattributes: {\n\t\t\t\tget: function() {\n\n\t\t\t\t\tconsole.warn( 'THREE.WebGLProgram: .attributes is now .getAttributes().' );\n\t\t\t\t\treturn this.getAttributes();\n\n\t\t\t\t}\n\t\t\t}\n\n\t\t} );\n\n\n\t\t//\n\n\t\tthis.id = programIdCount ++;\n\t\tthis.code = code;\n\t\tthis.usedTimes = 1;\n\t\tthis.program = program;\n\t\tthis.vertexShader = glVertexShader;\n\t\tthis.fragmentShader = glFragmentShader;\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction WebGLPrograms( renderer, extensions, capabilities ) {\n\n\t\tvar programs = [];\n\n\t\tvar shaderIDs = {\n\t\t\tMeshDepthMaterial: 'depth',\n\t\t\tMeshDistanceMaterial: 'distanceRGBA',\n\t\t\tMeshNormalMaterial: 'normal',\n\t\t\tMeshBasicMaterial: 'basic',\n\t\t\tMeshLambertMaterial: 'lambert',\n\t\t\tMeshPhongMaterial: 'phong',\n\t\t\tMeshToonMaterial: 'phong',\n\t\t\tMeshStandardMaterial: 'physical',\n\t\t\tMeshPhysicalMaterial: 'physical',\n\t\t\tLineBasicMaterial: 'basic',\n\t\t\tLineDashedMaterial: 'dashed',\n\t\t\tPointsMaterial: 'points',\n\t\t\tShadowMaterial: 'shadow'\n\t\t};\n\n\t\tvar parameterNames = [\n\t\t\t\"precision\", \"supportsVertexTextures\", \"map\", \"mapEncoding\", \"envMap\", \"envMapMode\", \"envMapEncoding\",\n\t\t\t\"lightMap\", \"aoMap\", \"emissiveMap\", \"emissiveMapEncoding\", \"bumpMap\", \"normalMap\", \"displacementMap\", \"specularMap\",\n\t\t\t\"roughnessMap\", \"metalnessMap\", \"gradientMap\",\n\t\t\t\"alphaMap\", \"combine\", \"vertexColors\", \"fog\", \"useFog\", \"fogExp\",\n\t\t\t\"flatShading\", \"sizeAttenuation\", \"logarithmicDepthBuffer\", \"skinning\",\n\t\t\t\"maxBones\", \"useVertexTexture\", \"morphTargets\", \"morphNormals\",\n\t\t\t\"maxMorphTargets\", \"maxMorphNormals\", \"premultipliedAlpha\",\n\t\t\t\"numDirLights\", \"numPointLights\", \"numSpotLights\", \"numHemiLights\", \"numRectAreaLights\",\n\t\t\t\"shadowMapEnabled\", \"shadowMapType\", \"toneMapping\", 'physicallyCorrectLights',\n\t\t\t\"alphaTest\", \"doubleSided\", \"flipSided\", \"numClippingPlanes\", \"numClipIntersection\", \"depthPacking\", \"dithering\"\n\t\t];\n\n\n\t\tfunction allocateBones( object ) {\n\n\t\t\tvar skeleton = object.skeleton;\n\t\t\tvar bones = skeleton.bones;\n\n\t\t\tif ( capabilities.floatVertexTextures ) {\n\n\t\t\t\treturn 1024;\n\n\t\t\t} else {\n\n\t\t\t\t// default for when object is not specified\n\t\t\t\t// ( for example when prebuilding shader to be used with multiple objects )\n\t\t\t\t//\n\t\t\t\t//  - leave some extra space for other uniforms\n\t\t\t\t//  - limit here is ANGLE's 254 max uniform vectors\n\t\t\t\t//    (up to 54 should be safe)\n\n\t\t\t\tvar nVertexUniforms = capabilities.maxVertexUniforms;\n\t\t\t\tvar nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );\n\n\t\t\t\tvar maxBones = Math.min( nVertexMatrices, bones.length );\n\n\t\t\t\tif ( maxBones < bones.length ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.' );\n\t\t\t\t\treturn 0;\n\n\t\t\t\t}\n\n\t\t\t\treturn maxBones;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction getTextureEncodingFromMap( map, gammaOverrideLinear ) {\n\n\t\t\tvar encoding;\n\n\t\t\tif ( ! map ) {\n\n\t\t\t\tencoding = LinearEncoding;\n\n\t\t\t} else if ( map.isTexture ) {\n\n\t\t\t\tencoding = map.encoding;\n\n\t\t\t} else if ( map.isWebGLRenderTarget ) {\n\n\t\t\t\tconsole.warn( \"THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead.\" );\n\t\t\t\tencoding = map.texture.encoding;\n\n\t\t\t}\n\n\t\t\t// add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point.\n\t\t\tif ( encoding === LinearEncoding && gammaOverrideLinear ) {\n\n\t\t\t\tencoding = GammaEncoding;\n\n\t\t\t}\n\n\t\t\treturn encoding;\n\n\t\t}\n\n\t\tthis.getParameters = function ( material, lights, shadows, fog, nClipPlanes, nClipIntersection, object ) {\n\n\t\t\tvar shaderID = shaderIDs[ material.type ];\n\n\t\t\t// heuristics to create shader parameters according to lights in the scene\n\t\t\t// (not to blow over maxLights budget)\n\n\t\t\tvar maxBones = object.isSkinnedMesh ? allocateBones( object ) : 0;\n\t\t\tvar precision = capabilities.precision;\n\n\t\t\tif ( material.precision !== null ) {\n\n\t\t\t\tprecision = capabilities.getMaxPrecision( material.precision );\n\n\t\t\t\tif ( precision !== material.precision ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tvar currentRenderTarget = renderer.getRenderTarget();\n\n\t\t\tvar parameters = {\n\n\t\t\t\tshaderID: shaderID,\n\n\t\t\t\tprecision: precision,\n\t\t\t\tsupportsVertexTextures: capabilities.vertexTextures,\n\t\t\t\toutputEncoding: getTextureEncodingFromMap( ( ! currentRenderTarget ) ? null : currentRenderTarget.texture, renderer.gammaOutput ),\n\t\t\t\tmap: !! material.map,\n\t\t\t\tmapEncoding: getTextureEncodingFromMap( material.map, renderer.gammaInput ),\n\t\t\t\tenvMap: !! material.envMap,\n\t\t\t\tenvMapMode: material.envMap && material.envMap.mapping,\n\t\t\t\tenvMapEncoding: getTextureEncodingFromMap( material.envMap, renderer.gammaInput ),\n\t\t\t\tenvMapCubeUV: ( !! material.envMap ) && ( ( material.envMap.mapping === CubeUVReflectionMapping ) || ( material.envMap.mapping === CubeUVRefractionMapping ) ),\n\t\t\t\tlightMap: !! material.lightMap,\n\t\t\t\taoMap: !! material.aoMap,\n\t\t\t\temissiveMap: !! material.emissiveMap,\n\t\t\t\temissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap, renderer.gammaInput ),\n\t\t\t\tbumpMap: !! material.bumpMap,\n\t\t\t\tnormalMap: !! material.normalMap,\n\t\t\t\tdisplacementMap: !! material.displacementMap,\n\t\t\t\troughnessMap: !! material.roughnessMap,\n\t\t\t\tmetalnessMap: !! material.metalnessMap,\n\t\t\t\tspecularMap: !! material.specularMap,\n\t\t\t\talphaMap: !! material.alphaMap,\n\n\t\t\t\tgradientMap: !! material.gradientMap,\n\n\t\t\t\tcombine: material.combine,\n\n\t\t\t\tvertexColors: material.vertexColors,\n\n\t\t\t\tfog: !! fog,\n\t\t\t\tuseFog: material.fog,\n\t\t\t\tfogExp: ( fog && fog.isFogExp2 ),\n\n\t\t\t\tflatShading: material.flatShading,\n\n\t\t\t\tsizeAttenuation: material.sizeAttenuation,\n\t\t\t\tlogarithmicDepthBuffer: capabilities.logarithmicDepthBuffer,\n\n\t\t\t\tskinning: material.skinning && maxBones > 0,\n\t\t\t\tmaxBones: maxBones,\n\t\t\t\tuseVertexTexture: capabilities.floatVertexTextures,\n\n\t\t\t\tmorphTargets: material.morphTargets,\n\t\t\t\tmorphNormals: material.morphNormals,\n\t\t\t\tmaxMorphTargets: renderer.maxMorphTargets,\n\t\t\t\tmaxMorphNormals: renderer.maxMorphNormals,\n\n\t\t\t\tnumDirLights: lights.directional.length,\n\t\t\t\tnumPointLights: lights.point.length,\n\t\t\t\tnumSpotLights: lights.spot.length,\n\t\t\t\tnumRectAreaLights: lights.rectArea.length,\n\t\t\t\tnumHemiLights: lights.hemi.length,\n\n\t\t\t\tnumClippingPlanes: nClipPlanes,\n\t\t\t\tnumClipIntersection: nClipIntersection,\n\n\t\t\t\tdithering: material.dithering,\n\n\t\t\t\tshadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && shadows.length > 0,\n\t\t\t\tshadowMapType: renderer.shadowMap.type,\n\n\t\t\t\ttoneMapping: renderer.toneMapping,\n\t\t\t\tphysicallyCorrectLights: renderer.physicallyCorrectLights,\n\n\t\t\t\tpremultipliedAlpha: material.premultipliedAlpha,\n\n\t\t\t\talphaTest: material.alphaTest,\n\t\t\t\tdoubleSided: material.side === DoubleSide,\n\t\t\t\tflipSided: material.side === BackSide,\n\n\t\t\t\tdepthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false\n\n\t\t\t};\n\n\t\t\treturn parameters;\n\n\t\t};\n\n\t\tthis.getProgramCode = function ( material, parameters ) {\n\n\t\t\tvar array = [];\n\n\t\t\tif ( parameters.shaderID ) {\n\n\t\t\t\tarray.push( parameters.shaderID );\n\n\t\t\t} else {\n\n\t\t\t\tarray.push( material.fragmentShader );\n\t\t\t\tarray.push( material.vertexShader );\n\n\t\t\t}\n\n\t\t\tif ( material.defines !== undefined ) {\n\n\t\t\t\tfor ( var name in material.defines ) {\n\n\t\t\t\t\tarray.push( name );\n\t\t\t\t\tarray.push( material.defines[ name ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tfor ( var i = 0; i < parameterNames.length; i ++ ) {\n\n\t\t\t\tarray.push( parameters[ parameterNames[ i ] ] );\n\n\t\t\t}\n\n\t\t\tarray.push( material.onBeforeCompile.toString() );\n\n\t\t\tarray.push( renderer.gammaOutput );\n\n\t\t\treturn array.join();\n\n\t\t};\n\n\t\tthis.acquireProgram = function ( material, shader, parameters, code ) {\n\n\t\t\tvar program;\n\n\t\t\t// Check if code has been already compiled\n\t\t\tfor ( var p = 0, pl = programs.length; p < pl; p ++ ) {\n\n\t\t\t\tvar programInfo = programs[ p ];\n\n\t\t\t\tif ( programInfo.code === code ) {\n\n\t\t\t\t\tprogram = programInfo;\n\t\t\t\t\t++ program.usedTimes;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( program === undefined ) {\n\n\t\t\t\tprogram = new WebGLProgram( renderer, extensions, code, material, shader, parameters );\n\t\t\t\tprograms.push( program );\n\n\t\t\t}\n\n\t\t\treturn program;\n\n\t\t};\n\n\t\tthis.releaseProgram = function ( program ) {\n\n\t\t\tif ( -- program.usedTimes === 0 ) {\n\n\t\t\t\t// Remove from unordered set\n\t\t\t\tvar i = programs.indexOf( program );\n\t\t\t\tprograms[ i ] = programs[ programs.length - 1 ];\n\t\t\t\tprograms.pop();\n\n\t\t\t\t// Free WebGL resources\n\t\t\t\tprogram.destroy();\n\n\t\t\t}\n\n\t\t};\n\n\t\t// Exposed for resource monitoring & error feedback via renderer.info:\n\t\tthis.programs = programs;\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction WebGLTextures( _gl, extensions, state, properties, capabilities, utils, infoMemory ) {\n\n\t\tvar _isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && _gl instanceof WebGL2RenderingContext );\n\n\t\t//\n\n\t\tfunction clampToMaxSize( image, maxSize ) {\n\n\t\t\tif ( image.width > maxSize || image.height > maxSize ) {\n\n\t\t\t\t// Warning: Scaling through the canvas will only work with images that use\n\t\t\t\t// premultiplied alpha.\n\n\t\t\t\tvar scale = maxSize / Math.max( image.width, image.height );\n\n\t\t\t\tvar canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );\n\t\t\t\tcanvas.width = Math.floor( image.width * scale );\n\t\t\t\tcanvas.height = Math.floor( image.height * scale );\n\n\t\t\t\tvar context = canvas.getContext( '2d' );\n\t\t\t\tcontext.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height );\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image );\n\n\t\t\t\treturn canvas;\n\n\t\t\t}\n\n\t\t\treturn image;\n\n\t\t}\n\n\t\tfunction isPowerOfTwo( image ) {\n\n\t\t\treturn _Math.isPowerOfTwo( image.width ) && _Math.isPowerOfTwo( image.height );\n\n\t\t}\n\n\t\tfunction makePowerOfTwo( image ) {\n\n\t\t\tif ( image instanceof HTMLImageElement || image instanceof HTMLCanvasElement ) {\n\n\t\t\t\tvar canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );\n\t\t\t\tcanvas.width = _Math.nearestPowerOfTwo( image.width );\n\t\t\t\tcanvas.height = _Math.nearestPowerOfTwo( image.height );\n\n\t\t\t\tvar context = canvas.getContext( '2d' );\n\t\t\t\tcontext.drawImage( image, 0, 0, canvas.width, canvas.height );\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: image is not power of two (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image );\n\n\t\t\t\treturn canvas;\n\n\t\t\t}\n\n\t\t\treturn image;\n\n\t\t}\n\n\t\tfunction textureNeedsPowerOfTwo( texture ) {\n\n\t\t\treturn ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) ||\n\t\t\t\t( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter );\n\n\t\t}\n\n\t\tfunction textureNeedsGenerateMipmaps( texture, isPowerOfTwo ) {\n\n\t\t\treturn texture.generateMipmaps && isPowerOfTwo &&\n\t\t\t\ttexture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;\n\n\t\t}\n\n\t\t// Fallback filters for non-power-of-2 textures\n\n\t\tfunction filterFallback( f ) {\n\n\t\t\tif ( f === NearestFilter || f === NearestMipMapNearestFilter || f === NearestMipMapLinearFilter ) {\n\n\t\t\t\treturn _gl.NEAREST;\n\n\t\t\t}\n\n\t\t\treturn _gl.LINEAR;\n\n\t\t}\n\n\t\t//\n\n\t\tfunction onTextureDispose( event ) {\n\n\t\t\tvar texture = event.target;\n\n\t\t\ttexture.removeEventListener( 'dispose', onTextureDispose );\n\n\t\t\tdeallocateTexture( texture );\n\n\t\t\tinfoMemory.textures --;\n\n\n\t\t}\n\n\t\tfunction onRenderTargetDispose( event ) {\n\n\t\t\tvar renderTarget = event.target;\n\n\t\t\trenderTarget.removeEventListener( 'dispose', onRenderTargetDispose );\n\n\t\t\tdeallocateRenderTarget( renderTarget );\n\n\t\t\tinfoMemory.textures --;\n\n\t\t}\n\n\t\t//\n\n\t\tfunction deallocateTexture( texture ) {\n\n\t\t\tvar textureProperties = properties.get( texture );\n\n\t\t\tif ( texture.image && textureProperties.__image__webglTextureCube ) {\n\n\t\t\t\t// cube texture\n\n\t\t\t\t_gl.deleteTexture( textureProperties.__image__webglTextureCube );\n\n\t\t\t} else {\n\n\t\t\t\t// 2D texture\n\n\t\t\t\tif ( textureProperties.__webglInit === undefined ) return;\n\n\t\t\t\t_gl.deleteTexture( textureProperties.__webglTexture );\n\n\t\t\t}\n\n\t\t\t// remove all webgl properties\n\t\t\tproperties.remove( texture );\n\n\t\t}\n\n\t\tfunction deallocateRenderTarget( renderTarget ) {\n\n\t\t\tvar renderTargetProperties = properties.get( renderTarget );\n\t\t\tvar textureProperties = properties.get( renderTarget.texture );\n\n\t\t\tif ( ! renderTarget ) return;\n\n\t\t\tif ( textureProperties.__webglTexture !== undefined ) {\n\n\t\t\t\t_gl.deleteTexture( textureProperties.__webglTexture );\n\n\t\t\t}\n\n\t\t\tif ( renderTarget.depthTexture ) {\n\n\t\t\t\trenderTarget.depthTexture.dispose();\n\n\t\t\t}\n\n\t\t\tif ( renderTarget.isWebGLRenderTargetCube ) {\n\n\t\t\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\t\t\t_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );\n\t\t\t\t\tif ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );\n\t\t\t\tif ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );\n\n\t\t\t}\n\n\t\t\tproperties.remove( renderTarget.texture );\n\t\t\tproperties.remove( renderTarget );\n\n\t\t}\n\n\t\t//\n\n\n\n\t\tfunction setTexture2D( texture, slot ) {\n\n\t\t\tvar textureProperties = properties.get( texture );\n\n\t\t\tif ( texture.version > 0 && textureProperties.__version !== texture.version ) {\n\n\t\t\t\tvar image = texture.image;\n\n\t\t\t\tif ( image === undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined', texture );\n\n\t\t\t\t} else if ( image.complete === false ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete', texture );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tuploadTexture( textureProperties, texture, slot );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tstate.activeTexture( _gl.TEXTURE0 + slot );\n\t\t\tstate.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );\n\n\t\t}\n\n\t\tfunction setTextureCube( texture, slot ) {\n\n\t\t\tvar textureProperties = properties.get( texture );\n\n\t\t\tif ( texture.image.length === 6 ) {\n\n\t\t\t\tif ( texture.version > 0 && textureProperties.__version !== texture.version ) {\n\n\t\t\t\t\tif ( ! textureProperties.__image__webglTextureCube ) {\n\n\t\t\t\t\t\ttexture.addEventListener( 'dispose', onTextureDispose );\n\n\t\t\t\t\t\ttextureProperties.__image__webglTextureCube = _gl.createTexture();\n\n\t\t\t\t\t\tinfoMemory.textures ++;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tstate.activeTexture( _gl.TEXTURE0 + slot );\n\t\t\t\t\tstate.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube );\n\n\t\t\t\t\t_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );\n\n\t\t\t\t\tvar isCompressed = ( texture && texture.isCompressedTexture );\n\t\t\t\t\tvar isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );\n\n\t\t\t\t\tvar cubeImage = [];\n\n\t\t\t\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\t\t\t\tif ( ! isCompressed && ! isDataTexture ) {\n\n\t\t\t\t\t\t\tcubeImage[ i ] = clampToMaxSize( texture.image[ i ], capabilities.maxCubemapSize );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tcubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tvar image = cubeImage[ 0 ],\n\t\t\t\t\tisPowerOfTwoImage = isPowerOfTwo( image ),\n\t\t\t\t\tglFormat = utils.convert( texture.format ),\n\t\t\t\t\tglType = utils.convert( texture.type );\n\n\t\t\t\t\tsetTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isPowerOfTwoImage );\n\n\t\t\t\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\t\t\t\tif ( ! isCompressed ) {\n\n\t\t\t\t\t\t\tif ( isDataTexture ) {\n\n\t\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tvar mipmap, mipmaps = cubeImage[ i ].mipmaps;\n\n\t\t\t\t\t\t\tfor ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {\n\n\t\t\t\t\t\t\t\tmipmap = mipmaps[ j ];\n\n\t\t\t\t\t\t\t\tif ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {\n\n\t\t\t\t\t\t\t\t\tif ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {\n\n\t\t\t\t\t\t\t\t\t\tstate.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );\n\n\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' );\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) {\n\n\t\t\t\t\t\t_gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttextureProperties.__version = texture.version;\n\n\t\t\t\t\tif ( texture.onUpdate ) texture.onUpdate( texture );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tstate.activeTexture( _gl.TEXTURE0 + slot );\n\t\t\t\t\tstate.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction setTextureCubeDynamic( texture, slot ) {\n\n\t\t\tstate.activeTexture( _gl.TEXTURE0 + slot );\n\t\t\tstate.bindTexture( _gl.TEXTURE_CUBE_MAP, properties.get( texture ).__webglTexture );\n\n\t\t}\n\n\t\tfunction setTextureParameters( textureType, texture, isPowerOfTwoImage ) {\n\n\t\t\tvar extension;\n\n\t\t\tif ( isPowerOfTwoImage ) {\n\n\t\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, utils.convert( texture.wrapS ) );\n\t\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, utils.convert( texture.wrapT ) );\n\n\t\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, utils.convert( texture.magFilter ) );\n\t\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, utils.convert( texture.minFilter ) );\n\n\t\t\t} else {\n\n\t\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );\n\t\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );\n\n\t\t\t\tif ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.', texture );\n\n\t\t\t\t}\n\n\t\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );\n\t\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );\n\n\t\t\t\tif ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.', texture );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\textension = extensions.get( 'EXT_texture_filter_anisotropic' );\n\n\t\t\tif ( extension ) {\n\n\t\t\t\tif ( texture.type === FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return;\n\t\t\t\tif ( texture.type === HalfFloatType && extensions.get( 'OES_texture_half_float_linear' ) === null ) return;\n\n\t\t\t\tif ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {\n\n\t\t\t\t\t_gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );\n\t\t\t\t\tproperties.get( texture ).__currentAnisotropy = texture.anisotropy;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction uploadTexture( textureProperties, texture, slot ) {\n\n\t\t\tif ( textureProperties.__webglInit === undefined ) {\n\n\t\t\t\ttextureProperties.__webglInit = true;\n\n\t\t\t\ttexture.addEventListener( 'dispose', onTextureDispose );\n\n\t\t\t\ttextureProperties.__webglTexture = _gl.createTexture();\n\n\t\t\t\tinfoMemory.textures ++;\n\n\t\t\t}\n\n\t\t\tstate.activeTexture( _gl.TEXTURE0 + slot );\n\t\t\tstate.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );\n\n\t\t\t_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );\n\n\t\t\tvar image = clampToMaxSize( texture.image, capabilities.maxTextureSize );\n\n\t\t\tif ( textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( image ) === false ) {\n\n\t\t\t\timage = makePowerOfTwo( image );\n\n\t\t\t}\n\n\t\t\tvar isPowerOfTwoImage = isPowerOfTwo( image ),\n\t\t\tglFormat = utils.convert( texture.format ),\n\t\t\tglType = utils.convert( texture.type );\n\n\t\t\tsetTextureParameters( _gl.TEXTURE_2D, texture, isPowerOfTwoImage );\n\n\t\t\tvar mipmap, mipmaps = texture.mipmaps;\n\n\t\t\tif ( texture.isDepthTexture ) {\n\n\t\t\t\t// populate depth texture with dummy data\n\n\t\t\t\tvar internalFormat = _gl.DEPTH_COMPONENT;\n\n\t\t\t\tif ( texture.type === FloatType ) {\n\n\t\t\t\t\tif ( !_isWebGL2 ) throw new Error('Float Depth Texture only supported in WebGL2.0');\n\t\t\t\t\tinternalFormat = _gl.DEPTH_COMPONENT32F;\n\n\t\t\t\t} else if ( _isWebGL2 ) {\n\n\t\t\t\t\t// WebGL 2.0 requires signed internalformat for glTexImage2D\n\t\t\t\t\tinternalFormat = _gl.DEPTH_COMPONENT16;\n\n\t\t\t\t}\n\n\t\t\t\tif ( texture.format === DepthFormat && internalFormat === _gl.DEPTH_COMPONENT ) {\n\n\t\t\t\t\t// The error INVALID_OPERATION is generated by texImage2D if format and internalformat are\n\t\t\t\t\t// DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT\n\t\t\t\t\t// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)\n\t\t\t\t\tif ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) {\n\n\t\t\t\t\t        console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' );\n\n\t\t\t\t\t\ttexture.type = UnsignedShortType;\n\t\t\t\t\t\tglType = utils.convert( texture.type );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t// Depth stencil textures need the DEPTH_STENCIL internal format\n\t\t\t\t// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)\n\t\t\t\tif ( texture.format === DepthStencilFormat ) {\n\n\t\t\t\t\tinternalFormat = _gl.DEPTH_STENCIL;\n\n\t\t\t\t\t// The error INVALID_OPERATION is generated by texImage2D if format and internalformat are\n\t\t\t\t\t// DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.\n\t\t\t\t\t// (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)\n\t\t\t\t\tif ( texture.type !== UnsignedInt248Type ) {\n\n\t\t\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' );\n\n\t\t\t\t\t\ttexture.type = UnsignedInt248Type;\n\t\t\t\t\t\tglType = utils.convert( texture.type );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, 0, internalFormat, image.width, image.height, 0, glFormat, glType, null );\n\n\t\t\t} else if ( texture.isDataTexture ) {\n\n\t\t\t\t// use manually created mipmaps if available\n\t\t\t\t// if there are no manual mipmaps\n\t\t\t\t// set 0 level mipmap and then use GL to generate other mipmap levels\n\n\t\t\t\tif ( mipmaps.length > 0 && isPowerOfTwoImage ) {\n\n\t\t\t\t\tfor ( var i = 0, il = mipmaps.length; i < il; i ++ ) {\n\n\t\t\t\t\t\tmipmap = mipmaps[ i ];\n\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttexture.generateMipmaps = false;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );\n\n\t\t\t\t}\n\n\t\t\t} else if ( texture.isCompressedTexture ) {\n\n\t\t\t\tfor ( var i = 0, il = mipmaps.length; i < il; i ++ ) {\n\n\t\t\t\t\tmipmap = mipmaps[ i ];\n\n\t\t\t\t\tif ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {\n\n\t\t\t\t\t\tif ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {\n\n\t\t\t\t\t\t\tstate.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// regular Texture (image, video, canvas)\n\n\t\t\t\t// use manually created mipmaps if available\n\t\t\t\t// if there are no manual mipmaps\n\t\t\t\t// set 0 level mipmap and then use GL to generate other mipmap levels\n\n\t\t\t\tif ( mipmaps.length > 0 && isPowerOfTwoImage ) {\n\n\t\t\t\t\tfor ( var i = 0, il = mipmaps.length; i < il; i ++ ) {\n\n\t\t\t\t\t\tmipmap = mipmaps[ i ];\n\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap );\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttexture.generateMipmaps = false;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, image );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) _gl.generateMipmap( _gl.TEXTURE_2D );\n\n\t\t\ttextureProperties.__version = texture.version;\n\n\t\t\tif ( texture.onUpdate ) texture.onUpdate( texture );\n\n\t\t}\n\n\t\t// Render targets\n\n\t\t// Setup storage for target texture and bind it to correct framebuffer\n\t\tfunction setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) {\n\n\t\t\tvar glFormat = utils.convert( renderTarget.texture.format );\n\t\t\tvar glType = utils.convert( renderTarget.texture.type );\n\t\t\tstate.texImage2D( textureTarget, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );\n\t\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\t\t\t_gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 );\n\t\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );\n\n\t\t}\n\n\t\t// Setup storage for internal depth/stencil buffers and bind to correct framebuffer\n\t\tfunction setupRenderBufferStorage( renderbuffer, renderTarget ) {\n\n\t\t\t_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );\n\n\t\t\tif ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {\n\n\t\t\t\t_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );\n\t\t\t\t_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );\n\n\t\t\t} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {\n\n\t\t\t\t_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );\n\t\t\t\t_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );\n\n\t\t\t} else {\n\n\t\t\t\t// FIXME: We don't support !depth !stencil\n\t\t\t\t_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );\n\n\t\t\t}\n\n\t\t\t_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );\n\n\t\t}\n\n\t\t// Setup resources for a Depth Texture for a FBO (needs an extension)\n\t\tfunction setupDepthTexture( framebuffer, renderTarget ) {\n\n\t\t\tvar isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube );\n\t\t\tif ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' );\n\n\t\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\n\t\t\tif ( !( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {\n\n\t\t\t\tthrow new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' );\n\n\t\t\t}\n\n\t\t\t// upload an empty depth texture with framebuffer size\n\t\t\tif ( !properties.get( renderTarget.depthTexture ).__webglTexture ||\n\t\t\t\t\trenderTarget.depthTexture.image.width !== renderTarget.width ||\n\t\t\t\t\trenderTarget.depthTexture.image.height !== renderTarget.height ) {\n\t\t\t\trenderTarget.depthTexture.image.width = renderTarget.width;\n\t\t\t\trenderTarget.depthTexture.image.height = renderTarget.height;\n\t\t\t\trenderTarget.depthTexture.needsUpdate = true;\n\t\t\t}\n\n\t\t\tsetTexture2D( renderTarget.depthTexture, 0 );\n\n\t\t\tvar webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;\n\n\t\t\tif ( renderTarget.depthTexture.format === DepthFormat ) {\n\n\t\t\t\t_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );\n\n\t\t\t} else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {\n\n\t\t\t\t_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );\n\n\t\t\t} else {\n\n\t\t\t\tthrow new Error( 'Unknown depthTexture format' );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// Setup GL resources for a non-texture depth buffer\n\t\tfunction setupDepthRenderbuffer( renderTarget ) {\n\n\t\t\tvar renderTargetProperties = properties.get( renderTarget );\n\n\t\t\tvar isCube = ( renderTarget.isWebGLRenderTargetCube === true );\n\n\t\t\tif ( renderTarget.depthTexture ) {\n\n\t\t\t\tif ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );\n\n\t\t\t\tsetupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );\n\n\t\t\t} else {\n\n\t\t\t\tif ( isCube ) {\n\n\t\t\t\t\trenderTargetProperties.__webglDepthbuffer = [];\n\n\t\t\t\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\t\t\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] );\n\t\t\t\t\t\trenderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();\n\t\t\t\t\t\tsetupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );\n\t\t\t\t\trenderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();\n\t\t\t\t\tsetupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );\n\n\t\t}\n\n\t\t// Set up GL resources for the render target\n\t\tfunction setupRenderTarget( renderTarget ) {\n\n\t\t\tvar renderTargetProperties = properties.get( renderTarget );\n\t\t\tvar textureProperties = properties.get( renderTarget.texture );\n\n\t\t\trenderTarget.addEventListener( 'dispose', onRenderTargetDispose );\n\n\t\t\ttextureProperties.__webglTexture = _gl.createTexture();\n\n\t\t\tinfoMemory.textures ++;\n\n\t\t\tvar isCube = ( renderTarget.isWebGLRenderTargetCube === true );\n\t\t\tvar isTargetPowerOfTwo = isPowerOfTwo( renderTarget );\n\n\t\t\t// Setup framebuffer\n\n\t\t\tif ( isCube ) {\n\n\t\t\t\trenderTargetProperties.__webglFramebuffer = [];\n\n\t\t\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\t\t\trenderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\trenderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();\n\n\t\t\t}\n\n\t\t\t// Setup color buffer\n\n\t\t\tif ( isCube ) {\n\n\t\t\t\tstate.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );\n\t\t\t\tsetTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget.texture, isTargetPowerOfTwo );\n\n\t\t\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\t\t\tsetupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );\n\n\t\t\t\t}\n\n\t\t\t\tif ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );\n\t\t\t\tstate.bindTexture( _gl.TEXTURE_CUBE_MAP, null );\n\n\t\t\t} else {\n\n\t\t\t\tstate.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );\n\t\t\t\tsetTextureParameters( _gl.TEXTURE_2D, renderTarget.texture, isTargetPowerOfTwo );\n\t\t\t\tsetupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D );\n\n\t\t\t\tif ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) _gl.generateMipmap( _gl.TEXTURE_2D );\n\t\t\t\tstate.bindTexture( _gl.TEXTURE_2D, null );\n\n\t\t\t}\n\n\t\t\t// Setup depth and stencil buffers\n\n\t\t\tif ( renderTarget.depthBuffer ) {\n\n\t\t\t\tsetupDepthRenderbuffer( renderTarget );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction updateRenderTargetMipmap( renderTarget ) {\n\n\t\t\tvar texture = renderTarget.texture;\n\t\t\tvar isTargetPowerOfTwo = isPowerOfTwo( renderTarget );\n\n\t\t\tif ( textureNeedsGenerateMipmaps( texture, isTargetPowerOfTwo ) ) {\n\n\t\t\t\tvar target = renderTarget.isWebGLRenderTargetCube ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D;\n\t\t\t\tvar webglTexture = properties.get( texture ).__webglTexture;\n\n\t\t\t\tstate.bindTexture( target, webglTexture );\n\t\t\t\t_gl.generateMipmap( target );\n\t\t\t\tstate.bindTexture( target, null );\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.setTexture2D = setTexture2D;\n\t\tthis.setTextureCube = setTextureCube;\n\t\tthis.setTextureCubeDynamic = setTextureCubeDynamic;\n\t\tthis.setupRenderTarget = setupRenderTarget;\n\t\tthis.updateRenderTargetMipmap = updateRenderTargetMipmap;\n\n\t}\n\n\t/**\n\t * @author fordacious / fordacious.github.io\n\t */\n\n\tfunction WebGLProperties() {\n\n\t\tvar properties = {};\n\n\t\tfunction get( object ) {\n\n\t\t\tvar uuid = object.uuid;\n\t\t\tvar map = properties[ uuid ];\n\n\t\t\tif ( map === undefined ) {\n\n\t\t\t\tmap = {};\n\t\t\t\tproperties[ uuid ] = map;\n\n\t\t\t}\n\n\t\t\treturn map;\n\n\t\t}\n\n\t\tfunction remove( object ) {\n\n\t\t\tdelete properties[ object.uuid ];\n\n\t\t}\n\n\t\tfunction clear() {\n\n\t\t\tproperties = {};\n\n\t\t}\n\n\t\treturn {\n\t\t\tget: get,\n\t\t\tremove: remove,\n\t\t\tclear: clear\n\t\t};\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction WebGLState( gl, extensions, utils ) {\n\n\t\tfunction ColorBuffer() {\n\n\t\t\tvar locked = false;\n\n\t\t\tvar color = new Vector4();\n\t\t\tvar currentColorMask = null;\n\t\t\tvar currentColorClear = new Vector4( 0, 0, 0, 0 );\n\n\t\t\treturn {\n\n\t\t\t\tsetMask: function ( colorMask ) {\n\n\t\t\t\t\tif ( currentColorMask !== colorMask && ! locked ) {\n\n\t\t\t\t\t\tgl.colorMask( colorMask, colorMask, colorMask, colorMask );\n\t\t\t\t\t\tcurrentColorMask = colorMask;\n\n\t\t\t\t\t}\n\n\t\t\t\t},\n\n\t\t\t\tsetLocked: function ( lock ) {\n\n\t\t\t\t\tlocked = lock;\n\n\t\t\t\t},\n\n\t\t\t\tsetClear: function ( r, g, b, a, premultipliedAlpha ) {\n\n\t\t\t\t\tif ( premultipliedAlpha === true ) {\n\n\t\t\t\t\t\tr *= a; g *= a; b *= a;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tcolor.set( r, g, b, a );\n\n\t\t\t\t\tif ( currentColorClear.equals( color ) === false ) {\n\n\t\t\t\t\t\tgl.clearColor( r, g, b, a );\n\t\t\t\t\t\tcurrentColorClear.copy( color );\n\n\t\t\t\t\t}\n\n\t\t\t\t},\n\n\t\t\t\treset: function () {\n\n\t\t\t\t\tlocked = false;\n\n\t\t\t\t\tcurrentColorMask = null;\n\t\t\t\t\tcurrentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t}\n\n\t\tfunction DepthBuffer() {\n\n\t\t\tvar locked = false;\n\n\t\t\tvar currentDepthMask = null;\n\t\t\tvar currentDepthFunc = null;\n\t\t\tvar currentDepthClear = null;\n\n\t\t\treturn {\n\n\t\t\t\tsetTest: function ( depthTest ) {\n\n\t\t\t\t\tif ( depthTest ) {\n\n\t\t\t\t\t\tenable( gl.DEPTH_TEST );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tdisable( gl.DEPTH_TEST );\n\n\t\t\t\t\t}\n\n\t\t\t\t},\n\n\t\t\t\tsetMask: function ( depthMask ) {\n\n\t\t\t\t\tif ( currentDepthMask !== depthMask && ! locked ) {\n\n\t\t\t\t\t\tgl.depthMask( depthMask );\n\t\t\t\t\t\tcurrentDepthMask = depthMask;\n\n\t\t\t\t\t}\n\n\t\t\t\t},\n\n\t\t\t\tsetFunc: function ( depthFunc ) {\n\n\t\t\t\t\tif ( currentDepthFunc !== depthFunc ) {\n\n\t\t\t\t\t\tif ( depthFunc ) {\n\n\t\t\t\t\t\t\tswitch ( depthFunc ) {\n\n\t\t\t\t\t\t\t\tcase NeverDepth:\n\n\t\t\t\t\t\t\t\t\tgl.depthFunc( gl.NEVER );\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase AlwaysDepth:\n\n\t\t\t\t\t\t\t\t\tgl.depthFunc( gl.ALWAYS );\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase LessDepth:\n\n\t\t\t\t\t\t\t\t\tgl.depthFunc( gl.LESS );\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase LessEqualDepth:\n\n\t\t\t\t\t\t\t\t\tgl.depthFunc( gl.LEQUAL );\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase EqualDepth:\n\n\t\t\t\t\t\t\t\t\tgl.depthFunc( gl.EQUAL );\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase GreaterEqualDepth:\n\n\t\t\t\t\t\t\t\t\tgl.depthFunc( gl.GEQUAL );\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase GreaterDepth:\n\n\t\t\t\t\t\t\t\t\tgl.depthFunc( gl.GREATER );\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase NotEqualDepth:\n\n\t\t\t\t\t\t\t\t\tgl.depthFunc( gl.NOTEQUAL );\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tdefault:\n\n\t\t\t\t\t\t\t\t\tgl.depthFunc( gl.LEQUAL );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tgl.depthFunc( gl.LEQUAL );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcurrentDepthFunc = depthFunc;\n\n\t\t\t\t\t}\n\n\t\t\t\t},\n\n\t\t\t\tsetLocked: function ( lock ) {\n\n\t\t\t\t\tlocked = lock;\n\n\t\t\t\t},\n\n\t\t\t\tsetClear: function ( depth ) {\n\n\t\t\t\t\tif ( currentDepthClear !== depth ) {\n\n\t\t\t\t\t\tgl.clearDepth( depth );\n\t\t\t\t\t\tcurrentDepthClear = depth;\n\n\t\t\t\t\t}\n\n\t\t\t\t},\n\n\t\t\t\treset: function () {\n\n\t\t\t\t\tlocked = false;\n\n\t\t\t\t\tcurrentDepthMask = null;\n\t\t\t\t\tcurrentDepthFunc = null;\n\t\t\t\t\tcurrentDepthClear = null;\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t}\n\n\t\tfunction StencilBuffer() {\n\n\t\t\tvar locked = false;\n\n\t\t\tvar currentStencilMask = null;\n\t\t\tvar currentStencilFunc = null;\n\t\t\tvar currentStencilRef = null;\n\t\t\tvar currentStencilFuncMask = null;\n\t\t\tvar currentStencilFail = null;\n\t\t\tvar currentStencilZFail = null;\n\t\t\tvar currentStencilZPass = null;\n\t\t\tvar currentStencilClear = null;\n\n\t\t\treturn {\n\n\t\t\t\tsetTest: function ( stencilTest ) {\n\n\t\t\t\t\tif ( stencilTest ) {\n\n\t\t\t\t\t\tenable( gl.STENCIL_TEST );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tdisable( gl.STENCIL_TEST );\n\n\t\t\t\t\t}\n\n\t\t\t\t},\n\n\t\t\t\tsetMask: function ( stencilMask ) {\n\n\t\t\t\t\tif ( currentStencilMask !== stencilMask && ! locked ) {\n\n\t\t\t\t\t\tgl.stencilMask( stencilMask );\n\t\t\t\t\t\tcurrentStencilMask = stencilMask;\n\n\t\t\t\t\t}\n\n\t\t\t\t},\n\n\t\t\t\tsetFunc: function ( stencilFunc, stencilRef, stencilMask ) {\n\n\t\t\t\t\tif ( currentStencilFunc !== stencilFunc ||\n\t\t\t\t\t     currentStencilRef \t!== stencilRef \t||\n\t\t\t\t\t     currentStencilFuncMask !== stencilMask ) {\n\n\t\t\t\t\t\tgl.stencilFunc( stencilFunc, stencilRef, stencilMask );\n\n\t\t\t\t\t\tcurrentStencilFunc = stencilFunc;\n\t\t\t\t\t\tcurrentStencilRef = stencilRef;\n\t\t\t\t\t\tcurrentStencilFuncMask = stencilMask;\n\n\t\t\t\t\t}\n\n\t\t\t\t},\n\n\t\t\t\tsetOp: function ( stencilFail, stencilZFail, stencilZPass ) {\n\n\t\t\t\t\tif ( currentStencilFail\t !== stencilFail \t||\n\t\t\t\t\t     currentStencilZFail !== stencilZFail ||\n\t\t\t\t\t     currentStencilZPass !== stencilZPass ) {\n\n\t\t\t\t\t\tgl.stencilOp( stencilFail, stencilZFail, stencilZPass );\n\n\t\t\t\t\t\tcurrentStencilFail = stencilFail;\n\t\t\t\t\t\tcurrentStencilZFail = stencilZFail;\n\t\t\t\t\t\tcurrentStencilZPass = stencilZPass;\n\n\t\t\t\t\t}\n\n\t\t\t\t},\n\n\t\t\t\tsetLocked: function ( lock ) {\n\n\t\t\t\t\tlocked = lock;\n\n\t\t\t\t},\n\n\t\t\t\tsetClear: function ( stencil ) {\n\n\t\t\t\t\tif ( currentStencilClear !== stencil ) {\n\n\t\t\t\t\t\tgl.clearStencil( stencil );\n\t\t\t\t\t\tcurrentStencilClear = stencil;\n\n\t\t\t\t\t}\n\n\t\t\t\t},\n\n\t\t\t\treset: function () {\n\n\t\t\t\t\tlocked = false;\n\n\t\t\t\t\tcurrentStencilMask = null;\n\t\t\t\t\tcurrentStencilFunc = null;\n\t\t\t\t\tcurrentStencilRef = null;\n\t\t\t\t\tcurrentStencilFuncMask = null;\n\t\t\t\t\tcurrentStencilFail = null;\n\t\t\t\t\tcurrentStencilZFail = null;\n\t\t\t\t\tcurrentStencilZPass = null;\n\t\t\t\t\tcurrentStencilClear = null;\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t}\n\n\t\t//\n\n\t\tvar colorBuffer = new ColorBuffer();\n\t\tvar depthBuffer = new DepthBuffer();\n\t\tvar stencilBuffer = new StencilBuffer();\n\n\t\tvar maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );\n\t\tvar newAttributes = new Uint8Array( maxVertexAttributes );\n\t\tvar enabledAttributes = new Uint8Array( maxVertexAttributes );\n\t\tvar attributeDivisors = new Uint8Array( maxVertexAttributes );\n\n\t\tvar capabilities = {};\n\n\t\tvar compressedTextureFormats = null;\n\n\t\tvar currentProgram = null;\n\n\t\tvar currentBlending = null;\n\t\tvar currentBlendEquation = null;\n\t\tvar currentBlendSrc = null;\n\t\tvar currentBlendDst = null;\n\t\tvar currentBlendEquationAlpha = null;\n\t\tvar currentBlendSrcAlpha = null;\n\t\tvar currentBlendDstAlpha = null;\n\t\tvar currentPremultipledAlpha = false;\n\n\t\tvar currentFlipSided = null;\n\t\tvar currentCullFace = null;\n\n\t\tvar currentLineWidth = null;\n\n\t\tvar currentPolygonOffsetFactor = null;\n\t\tvar currentPolygonOffsetUnits = null;\n\n\t\tvar maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS );\n\n\t\tvar version = parseFloat( /^WebGL\\ ([0-9])/.exec( gl.getParameter( gl.VERSION ) )[ 1 ] );\n\t\tvar lineWidthAvailable = parseFloat( version ) >= 1.0;\n\n\t\tvar currentTextureSlot = null;\n\t\tvar currentBoundTextures = {};\n\n\t\tvar currentScissor = new Vector4();\n\t\tvar currentViewport = new Vector4();\n\n\t\tfunction createTexture( type, target, count ) {\n\n\t\t\tvar data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.\n\t\t\tvar texture = gl.createTexture();\n\n\t\t\tgl.bindTexture( type, texture );\n\t\t\tgl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST );\n\t\t\tgl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST );\n\n\t\t\tfor ( var i = 0; i < count; i ++ ) {\n\n\t\t\t\tgl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );\n\n\t\t\t}\n\n\t\t\treturn texture;\n\n\t\t}\n\n\t\tvar emptyTextures = {};\n\t\temptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 );\n\t\temptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 );\n\n\t\t// init\n\n\t\tcolorBuffer.setClear( 0, 0, 0, 1 );\n\t\tdepthBuffer.setClear( 1 );\n\t\tstencilBuffer.setClear( 0 );\n\n\t\tenable( gl.DEPTH_TEST );\n\t\tdepthBuffer.setFunc( LessEqualDepth );\n\n\t\tsetFlipSided( false );\n\t\tsetCullFace( CullFaceBack );\n\t\tenable( gl.CULL_FACE );\n\n\t\tenable( gl.BLEND );\n\t\tsetBlending( NormalBlending );\n\n\t\t//\n\n\t\tfunction initAttributes() {\n\n\t\t\tfor ( var i = 0, l = newAttributes.length; i < l; i ++ ) {\n\n\t\t\t\tnewAttributes[ i ] = 0;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction enableAttribute( attribute ) {\n\n\t\t\tnewAttributes[ attribute ] = 1;\n\n\t\t\tif ( enabledAttributes[ attribute ] === 0 ) {\n\n\t\t\t\tgl.enableVertexAttribArray( attribute );\n\t\t\t\tenabledAttributes[ attribute ] = 1;\n\n\t\t\t}\n\n\t\t\tif ( attributeDivisors[ attribute ] !== 0 ) {\n\n\t\t\t\tvar extension = extensions.get( 'ANGLE_instanced_arrays' );\n\n\t\t\t\textension.vertexAttribDivisorANGLE( attribute, 0 );\n\t\t\t\tattributeDivisors[ attribute ] = 0;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction enableAttributeAndDivisor( attribute, meshPerAttribute ) {\n\n\t\t\tnewAttributes[ attribute ] = 1;\n\n\t\t\tif ( enabledAttributes[ attribute ] === 0 ) {\n\n\t\t\t\tgl.enableVertexAttribArray( attribute );\n\t\t\t\tenabledAttributes[ attribute ] = 1;\n\n\t\t\t}\n\n\t\t\tif ( attributeDivisors[ attribute ] !== meshPerAttribute ) {\n\n\t\t\t\tvar extension = extensions.get( 'ANGLE_instanced_arrays' );\n\n\t\t\t\textension.vertexAttribDivisorANGLE( attribute, meshPerAttribute );\n\t\t\t\tattributeDivisors[ attribute ] = meshPerAttribute;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction disableUnusedAttributes() {\n\n\t\t\tfor ( var i = 0, l = enabledAttributes.length; i !== l; ++ i ) {\n\n\t\t\t\tif ( enabledAttributes[ i ] !== newAttributes[ i ] ) {\n\n\t\t\t\t\tgl.disableVertexAttribArray( i );\n\t\t\t\t\tenabledAttributes[ i ] = 0;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction enable( id ) {\n\n\t\t\tif ( capabilities[ id ] !== true ) {\n\n\t\t\t\tgl.enable( id );\n\t\t\t\tcapabilities[ id ] = true;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction disable( id ) {\n\n\t\t\tif ( capabilities[ id ] !== false ) {\n\n\t\t\t\tgl.disable( id );\n\t\t\t\tcapabilities[ id ] = false;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction getCompressedTextureFormats() {\n\n\t\t\tif ( compressedTextureFormats === null ) {\n\n\t\t\t\tcompressedTextureFormats = [];\n\n\t\t\t\tif ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) ||\n\t\t\t\t     extensions.get( 'WEBGL_compressed_texture_s3tc' ) ||\n\t\t\t\t     extensions.get( 'WEBGL_compressed_texture_etc1' ) ) {\n\n\t\t\t\t\tvar formats = gl.getParameter( gl.COMPRESSED_TEXTURE_FORMATS );\n\n\t\t\t\t\tfor ( var i = 0; i < formats.length; i ++ ) {\n\n\t\t\t\t\t\tcompressedTextureFormats.push( formats[ i ] );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn compressedTextureFormats;\n\n\t\t}\n\n\t\tfunction useProgram( program ) {\n\n\t\t\tif ( currentProgram !== program ) {\n\n\t\t\t\tgl.useProgram( program );\n\n\t\t\t\tcurrentProgram = program;\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\tfunction setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) {\n\n\t\t\tif ( blending !== NoBlending ) {\n\n\t\t\t\tenable( gl.BLEND );\n\n\t\t\t} else {\n\n\t\t\t\tdisable( gl.BLEND );\n\n\t\t\t}\n\n\t\t\tif ( blending !== CustomBlending ) {\n\n\t\t\t\tif ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) {\n\n\t\t\t\t\tswitch ( blending ) {\n\n\t\t\t\t\t\tcase AdditiveBlending:\n\n\t\t\t\t\t\t\tif ( premultipliedAlpha ) {\n\n\t\t\t\t\t\t\t\tgl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );\n\t\t\t\t\t\t\t\tgl.blendFuncSeparate( gl.ONE, gl.ONE, gl.ONE, gl.ONE );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tgl.blendEquation( gl.FUNC_ADD );\n\t\t\t\t\t\t\t\tgl.blendFunc( gl.SRC_ALPHA, gl.ONE );\n\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase SubtractiveBlending:\n\n\t\t\t\t\t\t\tif ( premultipliedAlpha ) {\n\n\t\t\t\t\t\t\t\tgl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );\n\t\t\t\t\t\t\t\tgl.blendFuncSeparate( gl.ZERO, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ONE_MINUS_SRC_ALPHA );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tgl.blendEquation( gl.FUNC_ADD );\n\t\t\t\t\t\t\t\tgl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR );\n\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase MultiplyBlending:\n\n\t\t\t\t\t\t\tif ( premultipliedAlpha ) {\n\n\t\t\t\t\t\t\t\tgl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );\n\t\t\t\t\t\t\t\tgl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tgl.blendEquation( gl.FUNC_ADD );\n\t\t\t\t\t\t\t\tgl.blendFunc( gl.ZERO, gl.SRC_COLOR );\n\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\n\t\t\t\t\t\t\tif ( premultipliedAlpha ) {\n\n\t\t\t\t\t\t\t\tgl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );\n\t\t\t\t\t\t\t\tgl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tgl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );\n\t\t\t\t\t\t\t\tgl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tcurrentBlendEquation = null;\n\t\t\t\tcurrentBlendSrc = null;\n\t\t\t\tcurrentBlendDst = null;\n\t\t\t\tcurrentBlendEquationAlpha = null;\n\t\t\t\tcurrentBlendSrcAlpha = null;\n\t\t\t\tcurrentBlendDstAlpha = null;\n\n\t\t\t} else {\n\n\t\t\t\tblendEquationAlpha = blendEquationAlpha || blendEquation;\n\t\t\t\tblendSrcAlpha = blendSrcAlpha || blendSrc;\n\t\t\t\tblendDstAlpha = blendDstAlpha || blendDst;\n\n\t\t\t\tif ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {\n\n\t\t\t\t\tgl.blendEquationSeparate( utils.convert( blendEquation ), utils.convert( blendEquationAlpha ) );\n\n\t\t\t\t\tcurrentBlendEquation = blendEquation;\n\t\t\t\t\tcurrentBlendEquationAlpha = blendEquationAlpha;\n\n\t\t\t\t}\n\n\t\t\t\tif ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {\n\n\t\t\t\t\tgl.blendFuncSeparate( utils.convert( blendSrc ), utils.convert( blendDst ), utils.convert( blendSrcAlpha ), utils.convert( blendDstAlpha ) );\n\n\t\t\t\t\tcurrentBlendSrc = blendSrc;\n\t\t\t\t\tcurrentBlendDst = blendDst;\n\t\t\t\t\tcurrentBlendSrcAlpha = blendSrcAlpha;\n\t\t\t\t\tcurrentBlendDstAlpha = blendDstAlpha;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tcurrentBlending = blending;\n\t\t\tcurrentPremultipledAlpha = premultipliedAlpha;\n\n\t\t}\n\n\t\tfunction setMaterial( material ) {\n\n\t\t\tmaterial.side === DoubleSide\n\t\t\t\t? disable( gl.CULL_FACE )\n\t\t\t\t: enable( gl.CULL_FACE );\n\n\t\t\tsetFlipSided( material.side === BackSide );\n\n\t\t\tmaterial.transparent === true\n\t\t\t\t? setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha )\n\t\t\t\t: setBlending( NoBlending );\n\n\t\t\tdepthBuffer.setFunc( material.depthFunc );\n\t\t\tdepthBuffer.setTest( material.depthTest );\n\t\t\tdepthBuffer.setMask( material.depthWrite );\n\t\t\tcolorBuffer.setMask( material.colorWrite );\n\n\t\t\tsetPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );\n\n\t\t}\n\n\t\t//\n\n\t\tfunction setFlipSided( flipSided ) {\n\n\t\t\tif ( currentFlipSided !== flipSided ) {\n\n\t\t\t\tif ( flipSided ) {\n\n\t\t\t\t\tgl.frontFace( gl.CW );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tgl.frontFace( gl.CCW );\n\n\t\t\t\t}\n\n\t\t\t\tcurrentFlipSided = flipSided;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction setCullFace( cullFace ) {\n\n\t\t\tif ( cullFace !== CullFaceNone ) {\n\n\t\t\t\tenable( gl.CULL_FACE );\n\n\t\t\t\tif ( cullFace !== currentCullFace ) {\n\n\t\t\t\t\tif ( cullFace === CullFaceBack ) {\n\n\t\t\t\t\t\tgl.cullFace( gl.BACK );\n\n\t\t\t\t\t} else if ( cullFace === CullFaceFront ) {\n\n\t\t\t\t\t\tgl.cullFace( gl.FRONT );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tgl.cullFace( gl.FRONT_AND_BACK );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tdisable( gl.CULL_FACE );\n\n\t\t\t}\n\n\t\t\tcurrentCullFace = cullFace;\n\n\t\t}\n\n\t\tfunction setLineWidth( width ) {\n\n\t\t\tif ( width !== currentLineWidth ) {\n\n\t\t\t\tif ( lineWidthAvailable ) gl.lineWidth( width );\n\n\t\t\t\tcurrentLineWidth = width;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction setPolygonOffset( polygonOffset, factor, units ) {\n\n\t\t\tif ( polygonOffset ) {\n\n\t\t\t\tenable( gl.POLYGON_OFFSET_FILL );\n\n\t\t\t\tif ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {\n\n\t\t\t\t\tgl.polygonOffset( factor, units );\n\n\t\t\t\t\tcurrentPolygonOffsetFactor = factor;\n\t\t\t\t\tcurrentPolygonOffsetUnits = units;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tdisable( gl.POLYGON_OFFSET_FILL );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction setScissorTest( scissorTest ) {\n\n\t\t\tif ( scissorTest ) {\n\n\t\t\t\tenable( gl.SCISSOR_TEST );\n\n\t\t\t} else {\n\n\t\t\t\tdisable( gl.SCISSOR_TEST );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// texture\n\n\t\tfunction activeTexture( webglSlot ) {\n\n\t\t\tif ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1;\n\n\t\t\tif ( currentTextureSlot !== webglSlot ) {\n\n\t\t\t\tgl.activeTexture( webglSlot );\n\t\t\t\tcurrentTextureSlot = webglSlot;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction bindTexture( webglType, webglTexture ) {\n\n\t\t\tif ( currentTextureSlot === null ) {\n\n\t\t\t\tactiveTexture();\n\n\t\t\t}\n\n\t\t\tvar boundTexture = currentBoundTextures[ currentTextureSlot ];\n\n\t\t\tif ( boundTexture === undefined ) {\n\n\t\t\t\tboundTexture = { type: undefined, texture: undefined };\n\t\t\t\tcurrentBoundTextures[ currentTextureSlot ] = boundTexture;\n\n\t\t\t}\n\n\t\t\tif ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {\n\n\t\t\t\tgl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );\n\n\t\t\t\tboundTexture.type = webglType;\n\t\t\t\tboundTexture.texture = webglTexture;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction compressedTexImage2D() {\n\n\t\t\ttry {\n\n\t\t\t\tgl.compressedTexImage2D.apply( gl, arguments );\n\n\t\t\t} catch ( error ) {\n\n\t\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction texImage2D() {\n\n\t\t\ttry {\n\n\t\t\t\tgl.texImage2D.apply( gl, arguments );\n\n\t\t\t} catch ( error ) {\n\n\t\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t\t}\n\n\t\t}\n\n\t\t//\n\n\t\tfunction scissor( scissor ) {\n\n\t\t\tif ( currentScissor.equals( scissor ) === false ) {\n\n\t\t\t\tgl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );\n\t\t\t\tcurrentScissor.copy( scissor );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction viewport( viewport ) {\n\n\t\t\tif ( currentViewport.equals( viewport ) === false ) {\n\n\t\t\t\tgl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );\n\t\t\t\tcurrentViewport.copy( viewport );\n\n\t\t\t}\n\n\t\t}\n\n\t\t//\n\n\t\tfunction reset() {\n\n\t\t\tfor ( var i = 0; i < enabledAttributes.length; i ++ ) {\n\n\t\t\t\tif ( enabledAttributes[ i ] === 1 ) {\n\n\t\t\t\t\tgl.disableVertexAttribArray( i );\n\t\t\t\t\tenabledAttributes[ i ] = 0;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tcapabilities = {};\n\n\t\t\tcompressedTextureFormats = null;\n\n\t\t\tcurrentTextureSlot = null;\n\t\t\tcurrentBoundTextures = {};\n\n\t\t\tcurrentProgram = null;\n\n\t\t\tcurrentBlending = null;\n\n\t\t\tcurrentFlipSided = null;\n\t\t\tcurrentCullFace = null;\n\n\t\t\tcolorBuffer.reset();\n\t\t\tdepthBuffer.reset();\n\t\t\tstencilBuffer.reset();\n\n\t\t}\n\n\t\treturn {\n\n\t\t\tbuffers: {\n\t\t\t\tcolor: colorBuffer,\n\t\t\t\tdepth: depthBuffer,\n\t\t\t\tstencil: stencilBuffer\n\t\t\t},\n\n\t\t\tinitAttributes: initAttributes,\n\t\t\tenableAttribute: enableAttribute,\n\t\t\tenableAttributeAndDivisor: enableAttributeAndDivisor,\n\t\t\tdisableUnusedAttributes: disableUnusedAttributes,\n\t\t\tenable: enable,\n\t\t\tdisable: disable,\n\t\t\tgetCompressedTextureFormats: getCompressedTextureFormats,\n\n\t\t\tuseProgram: useProgram,\n\n\t\t\tsetBlending: setBlending,\n\t\t\tsetMaterial: setMaterial,\n\n\t\t\tsetFlipSided: setFlipSided,\n\t\t\tsetCullFace: setCullFace,\n\n\t\t\tsetLineWidth: setLineWidth,\n\t\t\tsetPolygonOffset: setPolygonOffset,\n\n\t\t\tsetScissorTest: setScissorTest,\n\n\t\t\tactiveTexture: activeTexture,\n\t\t\tbindTexture: bindTexture,\n\t\t\tcompressedTexImage2D: compressedTexImage2D,\n\t\t\ttexImage2D: texImage2D,\n\n\t\t\tscissor: scissor,\n\t\t\tviewport: viewport,\n\n\t\t\treset: reset\n\n\t\t};\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction WebGLCapabilities( gl, extensions, parameters ) {\n\n\t\tvar maxAnisotropy;\n\n\t\tfunction getMaxAnisotropy() {\n\n\t\t\tif ( maxAnisotropy !== undefined ) return maxAnisotropy;\n\n\t\t\tvar extension = extensions.get( 'EXT_texture_filter_anisotropic' );\n\n\t\t\tif ( extension !== null ) {\n\n\t\t\t\tmaxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );\n\n\t\t\t} else {\n\n\t\t\t\tmaxAnisotropy = 0;\n\n\t\t\t}\n\n\t\t\treturn maxAnisotropy;\n\n\t\t}\n\n\t\tfunction getMaxPrecision( precision ) {\n\n\t\t\tif ( precision === 'highp' ) {\n\n\t\t\t\tif ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 &&\n\t\t\t\t     gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) {\n\n\t\t\t\t\treturn 'highp';\n\n\t\t\t\t}\n\n\t\t\t\tprecision = 'mediump';\n\n\t\t\t}\n\n\t\t\tif ( precision === 'mediump' ) {\n\n\t\t\t\tif ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 &&\n\t\t\t\t     gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) {\n\n\t\t\t\t\treturn 'mediump';\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn 'lowp';\n\n\t\t}\n\n\t\tvar precision = parameters.precision !== undefined ? parameters.precision : 'highp';\n\t\tvar maxPrecision = getMaxPrecision( precision );\n\n\t\tif ( maxPrecision !== precision ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' );\n\t\t\tprecision = maxPrecision;\n\n\t\t}\n\n\t\tvar logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true && !! extensions.get( 'EXT_frag_depth' );\n\n\t\tvar maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS );\n\t\tvar maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );\n\t\tvar maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE );\n\t\tvar maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE );\n\n\t\tvar maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );\n\t\tvar maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS );\n\t\tvar maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS );\n\t\tvar maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS );\n\n\t\tvar vertexTextures = maxVertexTextures > 0;\n\t\tvar floatFragmentTextures = !! extensions.get( 'OES_texture_float' );\n\t\tvar floatVertexTextures = vertexTextures && floatFragmentTextures;\n\n\t\treturn {\n\n\t\t\tgetMaxAnisotropy: getMaxAnisotropy,\n\t\t\tgetMaxPrecision: getMaxPrecision,\n\n\t\t\tprecision: precision,\n\t\t\tlogarithmicDepthBuffer: logarithmicDepthBuffer,\n\n\t\t\tmaxTextures: maxTextures,\n\t\t\tmaxVertexTextures: maxVertexTextures,\n\t\t\tmaxTextureSize: maxTextureSize,\n\t\t\tmaxCubemapSize: maxCubemapSize,\n\n\t\t\tmaxAttributes: maxAttributes,\n\t\t\tmaxVertexUniforms: maxVertexUniforms,\n\t\t\tmaxVaryings: maxVaryings,\n\t\t\tmaxFragmentUniforms: maxFragmentUniforms,\n\n\t\t\tvertexTextures: vertexTextures,\n\t\t\tfloatFragmentTextures: floatFragmentTextures,\n\t\t\tfloatVertexTextures: floatVertexTextures\n\n\t\t};\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction ArrayCamera( array ) {\n\n\t\tPerspectiveCamera.call( this );\n\n\t\tthis.cameras = array || [];\n\n\t}\n\n\tArrayCamera.prototype = Object.assign( Object.create( PerspectiveCamera.prototype ), {\n\n\t\tconstructor: ArrayCamera,\n\n\t\tisArrayCamera: true\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction WebVRManager( renderer ) {\n\n\t\tvar scope = this;\n\n\t\tvar device = null;\n\t\tvar frameData = null;\n\n\t\tif ( 'VRFrameData' in window ) {\n\n\t\t\tframeData = new window.VRFrameData();\n\n\t\t}\n\n\t\tvar matrixWorldInverse = new Matrix4();\n\n\t\tvar standingMatrix = new Matrix4();\n\t\tvar standingMatrixInverse = new Matrix4();\n\n\t\tvar cameraL = new PerspectiveCamera();\n\t\tcameraL.bounds = new Vector4( 0.0, 0.0, 0.5, 1.0 );\n\t\tcameraL.layers.enable( 1 );\n\n\t\tvar cameraR = new PerspectiveCamera();\n\t\tcameraR.bounds = new Vector4( 0.5, 0.0, 0.5, 1.0 );\n\t\tcameraR.layers.enable( 2 );\n\n\t\tvar cameraVR = new ArrayCamera( [ cameraL, cameraR ] );\n\t\tcameraVR.layers.enable( 1 );\n\t\tcameraVR.layers.enable( 2 );\n\n\t\t//\n\n\t\tvar currentSize, currentPixelRatio;\n\n\t\tfunction onVRDisplayPresentChange() {\n\n\t\t\tif ( device !== null && device.isPresenting ) {\n\n\t\t\t\tvar eyeParameters = device.getEyeParameters( 'left' );\n\t\t\t\tvar renderWidth = eyeParameters.renderWidth;\n\t\t\t\tvar renderHeight = eyeParameters.renderHeight;\n\n\t\t\t\tcurrentPixelRatio = renderer.getPixelRatio();\n\t\t\t\tcurrentSize = renderer.getSize();\n\n\t\t\t\trenderer.setDrawingBufferSize( renderWidth * 2, renderHeight, 1 );\n\n\t\t\t} else if ( scope.enabled ) {\n\n\t\t\t\trenderer.setDrawingBufferSize( currentSize.width, currentSize.height, currentPixelRatio );\n\n\t\t\t}\n\n\t\t}\n\n\t\twindow.addEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false );\n\n\t\t//\n\n\t\tthis.enabled = false;\n\t\tthis.standing = false;\n\n\t\tthis.getDevice = function () {\n\n\t\t\treturn device;\n\n\t\t};\n\n\t\tthis.setDevice = function ( value ) {\n\n\t\t\tif ( value !== undefined ) device = value;\n\n\t\t};\n\n\t\tthis.getCamera = function ( camera ) {\n\n\t\t\tif ( device === null ) return camera;\n\n\t\t\tdevice.depthNear = camera.near;\n\t\t\tdevice.depthFar = camera.far;\n\n\t\t\tdevice.getFrameData( frameData );\n\n\t\t\t//\n\n\t\t\tvar pose = frameData.pose;\n\n\t\t\tif ( pose.position !== null ) {\n\t\t\t\tcamera.position.fromArray( pose.position );\n\n\t\t\t} else {\n\n\t\t\t\tcamera.position.set( 0, 0, 0 );\n\n\t\t\t}\n\n\t\t\tif ( pose.orientation !== null ) {\n\n\t\t\t\tcamera.quaternion.fromArray( pose.orientation );\n\n\t\t\t}\n\n\t\t\tcamera.updateMatrixWorld();\n\n\t\t\tvar stageParameters = device.stageParameters;\n\n\t\t\tif ( this.standing && stageParameters ) {\n\n\t\t\t\tstandingMatrix.fromArray( stageParameters.sittingToStandingTransform );\n\t\t\t\tstandingMatrixInverse.getInverse( standingMatrix );\n\n\t\t\t\tcamera.matrixWorld.multiply( standingMatrix );\n\t\t\t\tcamera.matrixWorldInverse.multiply( standingMatrixInverse );\n\n\t\t\t}\n\n\t\t\tif ( device.isPresenting === false ) return camera;\n\n\t\t\t//\n\n\t\t\tcameraL.near = camera.near;\n\t\t\tcameraR.near = camera.near;\n\n\t\t\tcameraL.far = camera.far;\n\t\t\tcameraR.far = camera.far;\n\t\t\t\n\t\t\tcameraVR.matrixWorld.copy( camera.matrixWorld );\n\t\t\tcameraVR.matrixWorldInverse.copy( camera.matrixWorldInverse );\n\n\t\t\tcameraL.matrixWorldInverse.fromArray( frameData.leftViewMatrix );\n\t\t\tcameraR.matrixWorldInverse.fromArray( frameData.rightViewMatrix );\n\n\t\t\tif ( this.standing && stageParameters ) {\n\n\t\t\t\tcameraL.matrixWorldInverse.multiply( standingMatrixInverse );\n\t\t\t\tcameraR.matrixWorldInverse.multiply( standingMatrixInverse );\n\n\t\t\t}\n\n\t\t\tvar parent = camera.parent;\n\n\t\t\tif ( parent !== null ) {\n\n\t\t\t\tmatrixWorldInverse.getInverse( parent.matrixWorld );\n\n\t\t\t\tcameraL.matrixWorldInverse.multiply( matrixWorldInverse );\n\t\t\t\tcameraR.matrixWorldInverse.multiply( matrixWorldInverse );\n\n\t\t\t}\n\n\t\t\t// envMap and Mirror needs camera.matrixWorld\n\n\t\t\tcameraL.matrixWorld.getInverse( cameraL.matrixWorldInverse );\n\t\t\tcameraR.matrixWorld.getInverse( cameraR.matrixWorldInverse );\n\n\t\t\tcameraL.projectionMatrix.fromArray( frameData.leftProjectionMatrix );\n\t\t\tcameraR.projectionMatrix.fromArray( frameData.rightProjectionMatrix );\n\n\t\t\t// HACK @mrdoob\n\t\t\t// https://github.com/w3c/webvr/issues/203\n\n\t\t\tcameraVR.projectionMatrix.copy( cameraL.projectionMatrix );\n\n\t\t\t//\n\n\t\t\tvar layers = device.getLayers();\n\n\t\t\tif ( layers.length ) {\n\n\t\t\t\tvar layer = layers[ 0 ];\n\n\t\t\t\tif ( layer.leftBounds !== null && layer.leftBounds.length === 4 ) {\n\n\t\t\t\t\tcameraL.bounds.fromArray( layer.leftBounds );\n\n\t\t\t\t}\n\n\t\t\t\tif ( layer.rightBounds !== null && layer.rightBounds.length === 4 ) {\n\n\t\t\t\t\tcameraR.bounds.fromArray( layer.rightBounds );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn cameraVR;\n\n\t\t};\n\n\t\tthis.getStandingMatrix = function () {\n\n\t\t\treturn standingMatrix;\n\n\t\t};\n\n\t\tthis.submitFrame = function () {\n\n\t\t\tif ( device && device.isPresenting ) device.submitFrame();\n\n\t\t};\n\n\t\tthis.dispose = function() {\n\n\t\t\twindow.removeEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange );\n\n\t\t};\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction WebGLExtensions( gl ) {\n\n\t\tvar extensions = {};\n\n\t\treturn {\n\n\t\t\tget: function ( name ) {\n\n\t\t\t\tif ( extensions[ name ] !== undefined ) {\n\n\t\t\t\t\treturn extensions[ name ];\n\n\t\t\t\t}\n\n\t\t\t\tvar extension;\n\n\t\t\t\tswitch ( name ) {\n\n\t\t\t\t\tcase 'WEBGL_depth_texture':\n\t\t\t\t\t\textension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'EXT_texture_filter_anisotropic':\n\t\t\t\t\t\textension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'WEBGL_compressed_texture_s3tc':\n\t\t\t\t\t\textension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'WEBGL_compressed_texture_pvrtc':\n\t\t\t\t\t\textension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'WEBGL_compressed_texture_etc1':\n\t\t\t\t\t\textension = gl.getExtension( 'WEBGL_compressed_texture_etc1' );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\textension = gl.getExtension( name );\n\n\t\t\t\t}\n\n\t\t\t\tif ( extension === null ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );\n\n\t\t\t\t}\n\n\t\t\t\textensions[ name ] = extension;\n\n\t\t\t\treturn extension;\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\t/**\n\t * @author tschw\n\t */\n\n\tfunction WebGLClipping() {\n\n\t\tvar scope = this,\n\n\t\t\tglobalState = null,\n\t\t\tnumGlobalPlanes = 0,\n\t\t\tlocalClippingEnabled = false,\n\t\t\trenderingShadows = false,\n\n\t\t\tplane = new Plane(),\n\t\t\tviewNormalMatrix = new Matrix3(),\n\n\t\t\tuniform = { value: null, needsUpdate: false };\n\n\t\tthis.uniform = uniform;\n\t\tthis.numPlanes = 0;\n\t\tthis.numIntersection = 0;\n\n\t\tthis.init = function( planes, enableLocalClipping, camera ) {\n\n\t\t\tvar enabled =\n\t\t\t\tplanes.length !== 0 ||\n\t\t\t\tenableLocalClipping ||\n\t\t\t\t// enable state of previous frame - the clipping code has to\n\t\t\t\t// run another frame in order to reset the state:\n\t\t\t\tnumGlobalPlanes !== 0 ||\n\t\t\t\tlocalClippingEnabled;\n\n\t\t\tlocalClippingEnabled = enableLocalClipping;\n\n\t\t\tglobalState = projectPlanes( planes, camera, 0 );\n\t\t\tnumGlobalPlanes = planes.length;\n\n\t\t\treturn enabled;\n\n\t\t};\n\n\t\tthis.beginShadows = function() {\n\n\t\t\trenderingShadows = true;\n\t\t\tprojectPlanes( null );\n\n\t\t};\n\n\t\tthis.endShadows = function() {\n\n\t\t\trenderingShadows = false;\n\t\t\tresetGlobalState();\n\n\t\t};\n\n\t\tthis.setState = function( planes, clipIntersection, clipShadows, camera, cache, fromCache ) {\n\n\t\t\tif ( ! localClippingEnabled ||\n\t\t\t\t\tplanes === null || planes.length === 0 ||\n\t\t\t\t\trenderingShadows && ! clipShadows ) {\n\t\t\t\t// there's no local clipping\n\n\t\t\t\tif ( renderingShadows ) {\n\t\t\t\t\t// there's no global clipping\n\n\t\t\t\t\tprojectPlanes( null );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tresetGlobalState();\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tvar nGlobal = renderingShadows ? 0 : numGlobalPlanes,\n\t\t\t\t\tlGlobal = nGlobal * 4,\n\n\t\t\t\t\tdstArray = cache.clippingState || null;\n\n\t\t\t\tuniform.value = dstArray; // ensure unique state\n\n\t\t\t\tdstArray = projectPlanes( planes, camera, lGlobal, fromCache );\n\n\t\t\t\tfor ( var i = 0; i !== lGlobal; ++ i ) {\n\n\t\t\t\t\tdstArray[ i ] = globalState[ i ];\n\n\t\t\t\t}\n\n\t\t\t\tcache.clippingState = dstArray;\n\t\t\t\tthis.numIntersection = clipIntersection ? this.numPlanes : 0;\n\t\t\t\tthis.numPlanes += nGlobal;\n\n\t\t\t}\n\n\n\t\t};\n\n\t\tfunction resetGlobalState() {\n\n\t\t\tif ( uniform.value !== globalState ) {\n\n\t\t\t\tuniform.value = globalState;\n\t\t\t\tuniform.needsUpdate = numGlobalPlanes > 0;\n\n\t\t\t}\n\n\t\t\tscope.numPlanes = numGlobalPlanes;\n\t\t\tscope.numIntersection = 0;\n\n\t\t}\n\n\t\tfunction projectPlanes( planes, camera, dstOffset, skipTransform ) {\n\n\t\t\tvar nPlanes = planes !== null ? planes.length : 0,\n\t\t\t\tdstArray = null;\n\n\t\t\tif ( nPlanes !== 0 ) {\n\n\t\t\t\tdstArray = uniform.value;\n\n\t\t\t\tif ( skipTransform !== true || dstArray === null ) {\n\n\t\t\t\t\tvar flatSize = dstOffset + nPlanes * 4,\n\t\t\t\t\t\tviewMatrix = camera.matrixWorldInverse;\n\n\t\t\t\t\tviewNormalMatrix.getNormalMatrix( viewMatrix );\n\n\t\t\t\t\tif ( dstArray === null || dstArray.length < flatSize ) {\n\n\t\t\t\t\t\tdstArray = new Float32Array( flatSize );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfor ( var i = 0, i4 = dstOffset;\n\t\t\t\t\t\t\t\t\t\ti !== nPlanes; ++ i, i4 += 4 ) {\n\n\t\t\t\t\t\tplane.copy( planes[ i ] ).\n\t\t\t\t\t\t\t\tapplyMatrix4( viewMatrix, viewNormalMatrix );\n\n\t\t\t\t\t\tplane.normal.toArray( dstArray, i4 );\n\t\t\t\t\t\tdstArray[ i4 + 3 ] = plane.constant;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tuniform.value = dstArray;\n\t\t\t\tuniform.needsUpdate = true;\n\n\t\t\t}\n\n\t\t\tscope.numPlanes = nPlanes;\n\t\t\t\n\t\t\treturn dstArray;\n\n\t\t}\n\n\t}\n\n\t/**\n\t * @author thespite / http://www.twitter.com/thespite\n\t */\n\n\tfunction WebGLUtils ( gl, extensions ) {\n\n\t\tfunction convert ( p ) {\n\n\t\t\tvar extension;\n\n\t\t\tif ( p === RepeatWrapping ) return gl.REPEAT;\n\t\t\tif ( p === ClampToEdgeWrapping ) return gl.CLAMP_TO_EDGE;\n\t\t\tif ( p === MirroredRepeatWrapping ) return gl.MIRRORED_REPEAT;\n\n\t\t\tif ( p === NearestFilter ) return gl.NEAREST;\n\t\t\tif ( p === NearestMipMapNearestFilter ) return gl.NEAREST_MIPMAP_NEAREST;\n\t\t\tif ( p === NearestMipMapLinearFilter ) return gl.NEAREST_MIPMAP_LINEAR;\n\n\t\t\tif ( p === LinearFilter ) return gl.LINEAR;\n\t\t\tif ( p === LinearMipMapNearestFilter ) return gl.LINEAR_MIPMAP_NEAREST;\n\t\t\tif ( p === LinearMipMapLinearFilter ) return gl.LINEAR_MIPMAP_LINEAR;\n\n\t\t\tif ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE;\n\t\t\tif ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4;\n\t\t\tif ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1;\n\t\t\tif ( p === UnsignedShort565Type ) return gl.UNSIGNED_SHORT_5_6_5;\n\n\t\t\tif ( p === ByteType ) return gl.BYTE;\n\t\t\tif ( p === ShortType ) return gl.SHORT;\n\t\t\tif ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT;\n\t\t\tif ( p === IntType ) return gl.INT;\n\t\t\tif ( p === UnsignedIntType ) return gl.UNSIGNED_INT;\n\t\t\tif ( p === FloatType ) return gl.FLOAT;\n\n\t\t\tif ( p === HalfFloatType ) {\n\n\t\t\t\textension = extensions.get( 'OES_texture_half_float' );\n\n\t\t\t\tif ( extension !== null ) return extension.HALF_FLOAT_OES;\n\n\t\t\t}\n\n\t\t\tif ( p === AlphaFormat ) return gl.ALPHA;\n\t\t\tif ( p === RGBFormat ) return gl.RGB;\n\t\t\tif ( p === RGBAFormat ) return gl.RGBA;\n\t\t\tif ( p === LuminanceFormat ) return gl.LUMINANCE;\n\t\t\tif ( p === LuminanceAlphaFormat ) return gl.LUMINANCE_ALPHA;\n\t\t\tif ( p === DepthFormat ) return gl.DEPTH_COMPONENT;\n\t\t\tif ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL;\n\n\t\t\tif ( p === AddEquation ) return gl.FUNC_ADD;\n\t\t\tif ( p === SubtractEquation ) return gl.FUNC_SUBTRACT;\n\t\t\tif ( p === ReverseSubtractEquation ) return gl.FUNC_REVERSE_SUBTRACT;\n\n\t\t\tif ( p === ZeroFactor ) return gl.ZERO;\n\t\t\tif ( p === OneFactor ) return gl.ONE;\n\t\t\tif ( p === SrcColorFactor ) return gl.SRC_COLOR;\n\t\t\tif ( p === OneMinusSrcColorFactor ) return gl.ONE_MINUS_SRC_COLOR;\n\t\t\tif ( p === SrcAlphaFactor ) return gl.SRC_ALPHA;\n\t\t\tif ( p === OneMinusSrcAlphaFactor ) return gl.ONE_MINUS_SRC_ALPHA;\n\t\t\tif ( p === DstAlphaFactor ) return gl.DST_ALPHA;\n\t\t\tif ( p === OneMinusDstAlphaFactor ) return gl.ONE_MINUS_DST_ALPHA;\n\n\t\t\tif ( p === DstColorFactor ) return gl.DST_COLOR;\n\t\t\tif ( p === OneMinusDstColorFactor ) return gl.ONE_MINUS_DST_COLOR;\n\t\t\tif ( p === SrcAlphaSaturateFactor ) return gl.SRC_ALPHA_SATURATE;\n\n\t\t\tif ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format ||\n\t\t\t\tp === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {\n\n\t\t\t\textension = extensions.get( 'WEBGL_compressed_texture_s3tc' );\n\n\t\t\t\tif ( extension !== null ) {\n\n\t\t\t\t\tif ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;\n\t\t\t\t\tif ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;\n\t\t\t\t\tif ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;\n\t\t\t\t\tif ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format ||\n\t\t\t\tp === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {\n\n\t\t\t\textension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );\n\n\t\t\t\tif ( extension !== null ) {\n\n\t\t\t\t\tif ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;\n\t\t\t\t\tif ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;\n\t\t\t\t\tif ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;\n\t\t\t\t\tif ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( p === RGB_ETC1_Format ) {\n\n\t\t\t\textension = extensions.get( 'WEBGL_compressed_texture_etc1' );\n\n\t\t\t\tif ( extension !== null ) return extension.COMPRESSED_RGB_ETC1_WEBGL;\n\n\t\t\t}\n\n\t\t\tif ( p === MinEquation || p === MaxEquation ) {\n\n\t\t\t\textension = extensions.get( 'EXT_blend_minmax' );\n\n\t\t\t\tif ( extension !== null ) {\n\n\t\t\t\t\tif ( p === MinEquation ) return extension.MIN_EXT;\n\t\t\t\t\tif ( p === MaxEquation ) return extension.MAX_EXT;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( p === UnsignedInt248Type ) {\n\n\t\t\t\textension = extensions.get( 'WEBGL_depth_texture' );\n\n\t\t\t\tif ( extension !== null ) return extension.UNSIGNED_INT_24_8_WEBGL;\n\n\t\t\t}\n\n\t\t\treturn 0;\n\n\t\t}\n\n\t\treturn { convert: convert }\n\n\t}\n\n\t// import { Sphere } from '../math/Sphere';\n\t/**\n\t * @author supereggbert / http://www.paulbrunt.co.uk/\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author szimek / https://github.com/szimek/\n\t * @author tschw\n\t */\n\n\tfunction WebGLRenderer( parameters ) {\n\n\t\tconsole.log( 'THREE.WebGLRenderer', REVISION );\n\n\t\tparameters = parameters || {};\n\n\t\tvar _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ),\n\t\t\t_context = parameters.context !== undefined ? parameters.context : null,\n\n\t\t\t_alpha = parameters.alpha !== undefined ? parameters.alpha : false,\n\t\t\t_depth = parameters.depth !== undefined ? parameters.depth : true,\n\t\t\t_stencil = parameters.stencil !== undefined ? parameters.stencil : true,\n\t\t\t_antialias = parameters.antialias !== undefined ? parameters.antialias : false,\n\t\t\t_premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,\n\t\t\t_preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false;\n\n\t\tvar lightsArray = [];\n\t\tvar shadowsArray = [];\n\n\t\tvar currentRenderList = null;\n\n\t\tvar spritesArray = [];\n\t\tvar flaresArray = [];\n\n\t\t// public properties\n\n\t\tthis.domElement = _canvas;\n\t\tthis.context = null;\n\n\t\t// clearing\n\n\t\tthis.autoClear = true;\n\t\tthis.autoClearColor = true;\n\t\tthis.autoClearDepth = true;\n\t\tthis.autoClearStencil = true;\n\n\t\t// scene graph\n\n\t\tthis.sortObjects = true;\n\n\t\t// user-defined clipping\n\n\t\tthis.clippingPlanes = [];\n\t\tthis.localClippingEnabled = false;\n\n\t\t// physically based shading\n\n\t\tthis.gammaFactor = 2.0;\t// for backwards compatibility\n\t\tthis.gammaInput = false;\n\t\tthis.gammaOutput = false;\n\n\t\t// physical lights\n\n\t\tthis.physicallyCorrectLights = false;\n\n\t\t// tone mapping\n\n\t\tthis.toneMapping = LinearToneMapping;\n\t\tthis.toneMappingExposure = 1.0;\n\t\tthis.toneMappingWhitePoint = 1.0;\n\n\t\t// morphs\n\n\t\tthis.maxMorphTargets = 8;\n\t\tthis.maxMorphNormals = 4;\n\n\t\t// internal properties\n\n\t\tvar _this = this,\n\n\t\t\t_isContextLost = false,\n\n\t\t\t// internal state cache\n\n\t\t\t_currentRenderTarget = null,\n\t\t\t_currentFramebuffer = null,\n\t\t\t_currentMaterialId = - 1,\n\t\t\t_currentGeometryProgram = '',\n\n\t\t\t_currentCamera = null,\n\t\t\t_currentArrayCamera = null,\n\n\t\t\t_currentViewport = new Vector4(),\n\t\t\t_currentScissor = new Vector4(),\n\t\t\t_currentScissorTest = null,\n\n\t\t\t//\n\n\t\t\t_usedTextureUnits = 0,\n\n\t\t\t//\n\n\t\t\t_width = _canvas.width,\n\t\t\t_height = _canvas.height,\n\n\t\t\t_pixelRatio = 1,\n\n\t\t\t_viewport = new Vector4( 0, 0, _width, _height ),\n\t\t\t_scissor = new Vector4( 0, 0, _width, _height ),\n\t\t\t_scissorTest = false,\n\n\t\t\t// frustum\n\n\t\t\t_frustum = new Frustum(),\n\n\t\t\t// clipping\n\n\t\t\t_clipping = new WebGLClipping(),\n\t\t\t_clippingEnabled = false,\n\t\t\t_localClippingEnabled = false,\n\n\t\t\t// camera matrices cache\n\n\t\t\t_projScreenMatrix = new Matrix4(),\n\n\t\t\t_vector3 = new Vector3(),\n\n\t\t\t// info\n\n\t\t\t_infoMemory = {\n\t\t\t\tgeometries: 0,\n\t\t\t\ttextures: 0\n\t\t\t},\n\n\t\t\t_infoRender = {\n\n\t\t\t\tframe: 0,\n\t\t\t\tcalls: 0,\n\t\t\t\tvertices: 0,\n\t\t\t\tfaces: 0,\n\t\t\t\tpoints: 0\n\n\t\t\t};\n\n\t\tthis.info = {\n\n\t\t\trender: _infoRender,\n\t\t\tmemory: _infoMemory,\n\t\t\tprograms: null\n\n\t\t};\n\n\t\tfunction getTargetPixelRatio() {\n\n\t\t\treturn _currentRenderTarget === null ? _pixelRatio : 1;\n\n\t\t}\n\n\t\t// initialize\n\n\t\tvar _gl;\n\n\t\ttry {\n\n\t\t\tvar contextAttributes = {\n\t\t\t\talpha: _alpha,\n\t\t\t\tdepth: _depth,\n\t\t\t\tstencil: _stencil,\n\t\t\t\tantialias: _antialias,\n\t\t\t\tpremultipliedAlpha: _premultipliedAlpha,\n\t\t\t\tpreserveDrawingBuffer: _preserveDrawingBuffer\n\t\t\t};\n\n\t\t\t_gl = _context || _canvas.getContext( 'webgl', contextAttributes ) || _canvas.getContext( 'experimental-webgl', contextAttributes );\n\n\t\t\tif ( _gl === null ) {\n\n\t\t\t\tif ( _canvas.getContext( 'webgl' ) !== null ) {\n\n\t\t\t\t\tthrow 'Error creating WebGL context with your selected attributes.';\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthrow 'Error creating WebGL context.';\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// Some experimental-webgl implementations do not have getShaderPrecisionFormat\n\n\t\t\tif ( _gl.getShaderPrecisionFormat === undefined ) {\n\n\t\t\t\t_gl.getShaderPrecisionFormat = function () {\n\n\t\t\t\t\treturn { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 };\n\n\t\t\t\t};\n\n\t\t\t}\n\n\t\t\t_canvas.addEventListener( 'webglcontextlost', onContextLost, false );\n\t\t\t_canvas.addEventListener( 'webglcontextrestored', onContextRestore, false );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLRenderer: ' + error );\n\n\t\t}\n\n\t\tvar extensions, capabilities, state;\n\t\tvar properties, textures, attributes, geometries, objects, lights;\n\t\tvar programCache, renderLists;\n\n\t\tvar background, morphtargets, bufferRenderer, indexedBufferRenderer;\n\t\tvar flareRenderer, spriteRenderer;\n\n\t\tvar utils;\n\n\t\tfunction initGLContext() {\n\n\t\t\textensions = new WebGLExtensions( _gl );\n\t\t\textensions.get( 'WEBGL_depth_texture' );\n\t\t\textensions.get( 'OES_texture_float' );\n\t\t\textensions.get( 'OES_texture_float_linear' );\n\t\t\textensions.get( 'OES_texture_half_float' );\n\t\t\textensions.get( 'OES_texture_half_float_linear' );\n\t\t\textensions.get( 'OES_standard_derivatives' );\n\t\t\textensions.get( 'ANGLE_instanced_arrays' );\n\n\t\t\tif ( extensions.get( 'OES_element_index_uint' ) ) {\n\n\t\t\t\tBufferGeometry.MaxIndex = 4294967296;\n\n\t\t\t}\n\n\t\t\tutils = new WebGLUtils( _gl, extensions );\n\n\t\t\tcapabilities = new WebGLCapabilities( _gl, extensions, parameters );\n\n\t\t\tstate = new WebGLState( _gl, extensions, utils );\n\t\t\tstate.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) );\n\t\t\tstate.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) );\n\n\t\t\tproperties = new WebGLProperties();\n\t\t\ttextures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, _infoMemory );\n\t\t\tattributes = new WebGLAttributes( _gl );\n\t\t\tgeometries = new WebGLGeometries( _gl, attributes, _infoMemory );\n\t\t\tobjects = new WebGLObjects( geometries, _infoRender );\n\t\t\tmorphtargets = new WebGLMorphtargets( _gl );\n\t\t\tprogramCache = new WebGLPrograms( _this, extensions, capabilities );\n\t\t\tlights = new WebGLLights();\n\t\t\trenderLists = new WebGLRenderLists();\n\n\t\t\tbackground = new WebGLBackground( _this, state, geometries, _premultipliedAlpha );\n\n\t\t\tbufferRenderer = new WebGLBufferRenderer( _gl, extensions, _infoRender );\n\t\t\tindexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, _infoRender );\n\n\t\t\tflareRenderer = new WebGLFlareRenderer( _this, _gl, state, textures, capabilities );\n\t\t\tspriteRenderer = new WebGLSpriteRenderer( _this, _gl, state, textures, capabilities );\n\n\t\t\t_this.info.programs = programCache.programs;\n\n\t\t\t_this.context = _gl;\n\t\t\t_this.capabilities = capabilities;\n\t\t\t_this.extensions = extensions;\n\t\t\t_this.properties = properties;\n\t\t\t_this.renderLists = renderLists;\n\t\t\t_this.state = state;\n\n\t\t}\n\n\t\tinitGLContext();\n\n\t\t// vr\n\n\t\tvar vr = new WebVRManager( _this );\n\n\t\tthis.vr = vr;\n\n\t\t// shadow map\n\n\t\tvar shadowMap = new WebGLShadowMap( _this, objects, capabilities.maxTextureSize );\n\n\t\tthis.shadowMap = shadowMap;\n\n\t\t// API\n\n\t\tthis.getContext = function () {\n\n\t\t\treturn _gl;\n\n\t\t};\n\n\t\tthis.getContextAttributes = function () {\n\n\t\t\treturn _gl.getContextAttributes();\n\n\t\t};\n\n\t\tthis.forceContextLoss = function () {\n\n\t\t\tvar extension = extensions.get( 'WEBGL_lose_context' );\n\t\t\tif ( extension ) extension.loseContext();\n\n\t\t};\n\n\t\tthis.forceContextRestore = function () {\n\n\t\t\tvar extension = extensions.get( 'WEBGL_lose_context' );\n\t\t\tif ( extension ) extension.restoreContext();\n\n\t\t};\n\n\t\tthis.getPixelRatio = function () {\n\n\t\t\treturn _pixelRatio;\n\n\t\t};\n\n\t\tthis.setPixelRatio = function ( value ) {\n\n\t\t\tif ( value === undefined ) return;\n\n\t\t\t_pixelRatio = value;\n\n\t\t\tthis.setSize( _width, _height, false );\n\n\t\t};\n\n\t\tthis.getSize = function () {\n\n\t\t\treturn {\n\t\t\t\twidth: _width,\n\t\t\t\theight: _height\n\t\t\t};\n\n\t\t};\n\n\t\tthis.setSize = function ( width, height, updateStyle ) {\n\n\t\t\tvar device = vr.getDevice();\n\n\t\t\tif ( device && device.isPresenting ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Can\\'t change size while VR device is presenting.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\t_width = width;\n\t\t\t_height = height;\n\n\t\t\t_canvas.width = width * _pixelRatio;\n\t\t\t_canvas.height = height * _pixelRatio;\n\n\t\t\tif ( updateStyle !== false ) {\n\n\t\t\t\t_canvas.style.width = width + 'px';\n\t\t\t\t_canvas.style.height = height + 'px';\n\n\t\t\t}\n\n\t\t\tthis.setViewport( 0, 0, width, height );\n\n\t\t};\n\n\t\tthis.getDrawingBufferSize = function () {\n\n\t\t\treturn {\n\t\t\t\twidth: _width * _pixelRatio,\n\t\t\t\theight: _height * _pixelRatio\n\t\t\t};\n\n\t\t};\n\n\t\tthis.setDrawingBufferSize = function ( width, height, pixelRatio ) {\n\n\t\t\t_width = width;\n\t\t\t_height = height;\n\n\t\t\t_pixelRatio = pixelRatio;\n\n\t\t\t_canvas.width = width * pixelRatio;\n\t\t\t_canvas.height = height * pixelRatio;\n\n\t\t\tthis.setViewport( 0, 0, width, height );\n\n\t\t};\n\n\t\tthis.setViewport = function ( x, y, width, height ) {\n\n\t\t\t_viewport.set( x, _height - y - height, width, height );\n\t\t\tstate.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) );\n\n\t\t};\n\n\t\tthis.setScissor = function ( x, y, width, height ) {\n\n\t\t\t_scissor.set( x, _height - y - height, width, height );\n\t\t\tstate.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) );\n\n\t\t};\n\n\t\tthis.setScissorTest = function ( boolean ) {\n\n\t\t\tstate.setScissorTest( _scissorTest = boolean );\n\n\t\t};\n\n\t\t// Clearing\n\n\t\tthis.getClearColor = background.getClearColor;\n\t\tthis.setClearColor = background.setClearColor;\n\t\tthis.getClearAlpha = background.getClearAlpha;\n\t\tthis.setClearAlpha = background.setClearAlpha;\n\n\t\tthis.clear = function ( color, depth, stencil ) {\n\n\t\t\tvar bits = 0;\n\n\t\t\tif ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT;\n\t\t\tif ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT;\n\t\t\tif ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT;\n\n\t\t\t_gl.clear( bits );\n\n\t\t};\n\n\t\tthis.clearColor = function () {\n\n\t\t\tthis.clear( true, false, false );\n\n\t\t};\n\n\t\tthis.clearDepth = function () {\n\n\t\t\tthis.clear( false, true, false );\n\n\t\t};\n\n\t\tthis.clearStencil = function () {\n\n\t\t\tthis.clear( false, false, true );\n\n\t\t};\n\n\t\tthis.clearTarget = function ( renderTarget, color, depth, stencil ) {\n\n\t\t\tthis.setRenderTarget( renderTarget );\n\t\t\tthis.clear( color, depth, stencil );\n\n\t\t};\n\n\t\t//\n\n\t\tthis.dispose = function () {\n\n\t\t\t_canvas.removeEventListener( 'webglcontextlost', onContextLost, false );\n\t\t\t_canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false );\n\n\t\t\trenderLists.dispose();\n\n\t\t\tvr.dispose();\n\n\t\t};\n\n\t\t// Events\n\n\t\tfunction onContextLost( event ) {\n\n\t\t\tevent.preventDefault();\n\n\t\t\tconsole.log( 'THREE.WebGLRenderer: Context Lost.' );\n\n\t\t\t_isContextLost = true;\n\n\t\t}\n\n\t\tfunction onContextRestore( event ) {\n\n\t\t\tconsole.log( 'THREE.WebGLRenderer: Context Restored.' );\n\n\t\t\t_isContextLost = false;\n\n\t\t\tinitGLContext();\n\n\t\t}\n\n\t\tfunction onMaterialDispose( event ) {\n\n\t\t\tvar material = event.target;\n\n\t\t\tmaterial.removeEventListener( 'dispose', onMaterialDispose );\n\n\t\t\tdeallocateMaterial( material );\n\n\t\t}\n\n\t\t// Buffer deallocation\n\n\t\tfunction deallocateMaterial( material ) {\n\n\t\t\treleaseMaterialProgramReference( material );\n\n\t\t\tproperties.remove( material );\n\n\t\t}\n\n\n\t\tfunction releaseMaterialProgramReference( material ) {\n\n\t\t\tvar programInfo = properties.get( material ).program;\n\n\t\t\tmaterial.program = undefined;\n\n\t\t\tif ( programInfo !== undefined ) {\n\n\t\t\t\tprogramCache.releaseProgram( programInfo );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// Buffer rendering\n\n\t\tfunction renderObjectImmediate( object, program, material ) {\n\n\t\t\tobject.render( function ( object ) {\n\n\t\t\t\t_this.renderBufferImmediate( object, program, material );\n\n\t\t\t} );\n\n\t\t}\n\n\t\tthis.renderBufferImmediate = function ( object, program, material ) {\n\n\t\t\tstate.initAttributes();\n\n\t\t\tvar buffers = properties.get( object );\n\n\t\t\tif ( object.hasPositions && ! buffers.position ) buffers.position = _gl.createBuffer();\n\t\t\tif ( object.hasNormals && ! buffers.normal ) buffers.normal = _gl.createBuffer();\n\t\t\tif ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer();\n\t\t\tif ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer();\n\n\t\t\tvar programAttributes = program.getAttributes();\n\n\t\t\tif ( object.hasPositions ) {\n\n\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.position );\n\t\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );\n\n\t\t\t\tstate.enableAttribute( programAttributes.position );\n\t\t\t\t_gl.vertexAttribPointer( programAttributes.position, 3, _gl.FLOAT, false, 0, 0 );\n\n\t\t\t}\n\n\t\t\tif ( object.hasNormals ) {\n\n\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.normal );\n\n\t\t\t\tif ( ! material.isMeshPhongMaterial &&\n\t\t\t\t\t! material.isMeshStandardMaterial &&\n\t\t\t\t\t! material.isMeshNormalMaterial &&\n\t\t\t\t\tmaterial.flatShading === true ) {\n\n\t\t\t\t\tfor ( var i = 0, l = object.count * 3; i < l; i += 9 ) {\n\n\t\t\t\t\t\tvar array = object.normalArray;\n\n\t\t\t\t\t\tvar nx = ( array[ i + 0 ] + array[ i + 3 ] + array[ i + 6 ] ) / 3;\n\t\t\t\t\t\tvar ny = ( array[ i + 1 ] + array[ i + 4 ] + array[ i + 7 ] ) / 3;\n\t\t\t\t\t\tvar nz = ( array[ i + 2 ] + array[ i + 5 ] + array[ i + 8 ] ) / 3;\n\n\t\t\t\t\t\tarray[ i + 0 ] = nx;\n\t\t\t\t\t\tarray[ i + 1 ] = ny;\n\t\t\t\t\t\tarray[ i + 2 ] = nz;\n\n\t\t\t\t\t\tarray[ i + 3 ] = nx;\n\t\t\t\t\t\tarray[ i + 4 ] = ny;\n\t\t\t\t\t\tarray[ i + 5 ] = nz;\n\n\t\t\t\t\t\tarray[ i + 6 ] = nx;\n\t\t\t\t\t\tarray[ i + 7 ] = ny;\n\t\t\t\t\t\tarray[ i + 8 ] = nz;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );\n\n\t\t\t\tstate.enableAttribute( programAttributes.normal );\n\n\t\t\t\t_gl.vertexAttribPointer( programAttributes.normal, 3, _gl.FLOAT, false, 0, 0 );\n\n\t\t\t}\n\n\t\t\tif ( object.hasUvs && material.map ) {\n\n\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.uv );\n\t\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );\n\n\t\t\t\tstate.enableAttribute( programAttributes.uv );\n\n\t\t\t\t_gl.vertexAttribPointer( programAttributes.uv, 2, _gl.FLOAT, false, 0, 0 );\n\n\t\t\t}\n\n\t\t\tif ( object.hasColors && material.vertexColors !== NoColors ) {\n\n\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.color );\n\t\t\t\t_gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );\n\n\t\t\t\tstate.enableAttribute( programAttributes.color );\n\n\t\t\t\t_gl.vertexAttribPointer( programAttributes.color, 3, _gl.FLOAT, false, 0, 0 );\n\n\t\t\t}\n\n\t\t\tstate.disableUnusedAttributes();\n\n\t\t\t_gl.drawArrays( _gl.TRIANGLES, 0, object.count );\n\n\t\t\tobject.count = 0;\n\n\t\t};\n\n\t\tthis.renderBufferDirect = function ( camera, fog, geometry, material, object, group ) {\n\n\t\t\tstate.setMaterial( material );\n\n\t\t\tvar program = setProgram( camera, fog, material, object );\n\t\t\tvar geometryProgram = geometry.id + '_' + program.id + '_' + ( material.wireframe === true );\n\n\t\t\tvar updateBuffers = false;\n\n\t\t\tif ( geometryProgram !== _currentGeometryProgram ) {\n\n\t\t\t\t_currentGeometryProgram = geometryProgram;\n\t\t\t\tupdateBuffers = true;\n\n\t\t\t}\n\n\t\t\tif ( object.morphTargetInfluences ) {\n\n\t\t\t\tmorphtargets.update( object, geometry, material, program );\n\n\t\t\t\tupdateBuffers = true;\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tvar index = geometry.index;\n\t\t\tvar position = geometry.attributes.position;\n\t\t\tvar rangeFactor = 1;\n\n\t\t\tif ( material.wireframe === true ) {\n\n\t\t\t\tindex = geometries.getWireframeAttribute( geometry );\n\t\t\t\trangeFactor = 2;\n\n\t\t\t}\n\n\t\t\tvar attribute;\n\t\t\tvar renderer = bufferRenderer;\n\n\t\t\tif ( index !== null ) {\n\n\t\t\t\tattribute = attributes.get( index );\n\n\t\t\t\trenderer = indexedBufferRenderer;\n\t\t\t\trenderer.setIndex( attribute );\n\n\t\t\t}\n\n\t\t\tif ( updateBuffers ) {\n\n\t\t\t\tsetupVertexAttributes( material, program, geometry );\n\n\t\t\t\tif ( index !== null ) {\n\n\t\t\t\t\t_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attribute.buffer );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tvar dataCount = 0;\n\n\t\t\tif ( index !== null ) {\n\n\t\t\t\tdataCount = index.count;\n\n\t\t\t} else if ( position !== undefined ) {\n\n\t\t\t\tdataCount = position.count;\n\n\t\t\t}\n\n\t\t\tvar rangeStart = geometry.drawRange.start * rangeFactor;\n\t\t\tvar rangeCount = geometry.drawRange.count * rangeFactor;\n\n\t\t\tvar groupStart = group !== null ? group.start * rangeFactor : 0;\n\t\t\tvar groupCount = group !== null ? group.count * rangeFactor : Infinity;\n\n\t\t\tvar drawStart = Math.max( rangeStart, groupStart );\n\t\t\tvar drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1;\n\n\t\t\tvar drawCount = Math.max( 0, drawEnd - drawStart + 1 );\n\n\t\t\tif ( drawCount === 0 ) return;\n\n\t\t\t//\n\n\t\t\tif ( object.isMesh ) {\n\n\t\t\t\tif ( material.wireframe === true ) {\n\n\t\t\t\t\tstate.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() );\n\t\t\t\t\trenderer.setMode( _gl.LINES );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tswitch ( object.drawMode ) {\n\n\t\t\t\t\t\tcase TrianglesDrawMode:\n\t\t\t\t\t\t\trenderer.setMode( _gl.TRIANGLES );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase TriangleStripDrawMode:\n\t\t\t\t\t\t\trenderer.setMode( _gl.TRIANGLE_STRIP );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase TriangleFanDrawMode:\n\t\t\t\t\t\t\trenderer.setMode( _gl.TRIANGLE_FAN );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\n\t\t\t} else if ( object.isLine ) {\n\n\t\t\t\tvar lineWidth = material.linewidth;\n\n\t\t\t\tif ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material\n\n\t\t\t\tstate.setLineWidth( lineWidth * getTargetPixelRatio() );\n\n\t\t\t\tif ( object.isLineSegments ) {\n\n\t\t\t\t\trenderer.setMode( _gl.LINES );\n\n\t\t\t\t} else if ( object.isLineLoop ) {\n\n\t\t\t\t\trenderer.setMode( _gl.LINE_LOOP );\n\n\t\t\t\t} else {\n\n\t\t\t\t\trenderer.setMode( _gl.LINE_STRIP );\n\n\t\t\t\t}\n\n\t\t\t} else if ( object.isPoints ) {\n\n\t\t\t\trenderer.setMode( _gl.POINTS );\n\n\t\t\t}\n\n\t\t\tif ( geometry && geometry.isInstancedBufferGeometry ) {\n\n\t\t\t\tif ( geometry.maxInstancedCount > 0 ) {\n\n\t\t\t\t\trenderer.renderInstances( geometry, drawStart, drawCount );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\trenderer.render( drawStart, drawCount );\n\n\t\t\t}\n\n\t\t};\n\n\t\tfunction setupVertexAttributes( material, program, geometry, startIndex ) {\n\n\t\t\tif ( geometry && geometry.isInstancedBufferGeometry ) {\n\n\t\t\t\tif ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) {\n\n\t\t\t\t\tconsole.error( 'THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( startIndex === undefined ) startIndex = 0;\n\n\t\t\tstate.initAttributes();\n\n\t\t\tvar geometryAttributes = geometry.attributes;\n\n\t\t\tvar programAttributes = program.getAttributes();\n\n\t\t\tvar materialDefaultAttributeValues = material.defaultAttributeValues;\n\n\t\t\tfor ( var name in programAttributes ) {\n\n\t\t\t\tvar programAttribute = programAttributes[ name ];\n\n\t\t\t\tif ( programAttribute >= 0 ) {\n\n\t\t\t\t\tvar geometryAttribute = geometryAttributes[ name ];\n\n\t\t\t\t\tif ( geometryAttribute !== undefined ) {\n\n\t\t\t\t\t\tvar normalized = geometryAttribute.normalized;\n\t\t\t\t\t\tvar size = geometryAttribute.itemSize;\n\n\t\t\t\t\t\tvar attribute = attributes.get( geometryAttribute );\n\n\t\t\t\t\t\t// TODO Attribute may not be available on context restore\n\n\t\t\t\t\t\tif ( attribute === undefined ) continue;\n\n\t\t\t\t\t\tvar buffer = attribute.buffer;\n\t\t\t\t\t\tvar type = attribute.type;\n\t\t\t\t\t\tvar bytesPerElement = attribute.bytesPerElement;\n\n\t\t\t\t\t\tif ( geometryAttribute.isInterleavedBufferAttribute ) {\n\n\t\t\t\t\t\t\tvar data = geometryAttribute.data;\n\t\t\t\t\t\t\tvar stride = data.stride;\n\t\t\t\t\t\t\tvar offset = geometryAttribute.offset;\n\n\t\t\t\t\t\t\tif ( data && data.isInstancedInterleavedBuffer ) {\n\n\t\t\t\t\t\t\t\tstate.enableAttributeAndDivisor( programAttribute, data.meshPerAttribute );\n\n\t\t\t\t\t\t\t\tif ( geometry.maxInstancedCount === undefined ) {\n\n\t\t\t\t\t\t\t\t\tgeometry.maxInstancedCount = data.meshPerAttribute * data.count;\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tstate.enableAttribute( programAttribute );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );\n\t\t\t\t\t\t\t_gl.vertexAttribPointer( programAttribute, size, type, normalized, stride * bytesPerElement, ( startIndex * stride + offset ) * bytesPerElement );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tif ( geometryAttribute.isInstancedBufferAttribute ) {\n\n\t\t\t\t\t\t\t\tstate.enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute );\n\n\t\t\t\t\t\t\t\tif ( geometry.maxInstancedCount === undefined ) {\n\n\t\t\t\t\t\t\t\t\tgeometry.maxInstancedCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tstate.enableAttribute( programAttribute );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );\n\t\t\t\t\t\t\t_gl.vertexAttribPointer( programAttribute, size, type, normalized, 0, startIndex * size * bytesPerElement );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else if ( materialDefaultAttributeValues !== undefined ) {\n\n\t\t\t\t\t\tvar value = materialDefaultAttributeValues[ name ];\n\n\t\t\t\t\t\tif ( value !== undefined ) {\n\n\t\t\t\t\t\t\tswitch ( value.length ) {\n\n\t\t\t\t\t\t\t\tcase 2:\n\t\t\t\t\t\t\t\t\t_gl.vertexAttrib2fv( programAttribute, value );\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase 3:\n\t\t\t\t\t\t\t\t\t_gl.vertexAttrib3fv( programAttribute, value );\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase 4:\n\t\t\t\t\t\t\t\t\t_gl.vertexAttrib4fv( programAttribute, value );\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\t_gl.vertexAttrib1fv( programAttribute, value );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tstate.disableUnusedAttributes();\n\n\t\t}\n\n\t\t// Compile\n\n\t\tthis.compile = function ( scene, camera ) {\n\n\t\t\tlightsArray.length = 0;\n\t\t\tshadowsArray.length = 0;\n\n\t\t\tscene.traverse( function ( object ) {\n\n\t\t\t\tif ( object.isLight ) {\n\n\t\t\t\t\tlightsArray.push( object );\n\n\t\t\t\t\tif ( object.castShadow ) {\n\n\t\t\t\t\t\tshadowsArray.push( object );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t\tlights.setup( lightsArray, shadowsArray, camera );\n\n\t\t\tscene.traverse( function ( object ) {\n\n\t\t\t\tif ( object.material ) {\n\n\t\t\t\t\tif ( Array.isArray( object.material ) ) {\n\n\t\t\t\t\t\tfor ( var i = 0; i < object.material.length; i ++ ) {\n\n\t\t\t\t\t\t\tinitMaterial( object.material[ i ], scene.fog, object );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tinitMaterial( object.material, scene.fog, object );\n\t\t\t\t\t\tsetProgram( camera, scene.fog, object.material, object );\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t};\n\n\t\t// Animation Loop\n\n\t\tvar isAnimating = false;\n\t\tvar onAnimationFrame = null;\n\n\t\tfunction start() {\n\n\t\t\tif ( isAnimating ) return;\n\t\t\t( vr.getDevice() || window ).requestAnimationFrame( loop );\n\t\t\tisAnimating = true;\n\n\t\t}\n\n\t\tfunction loop( time ) {\n\n\t\t\tif ( onAnimationFrame !== null ) onAnimationFrame( time );\n\t\t\t( vr.getDevice() || window ).requestAnimationFrame( loop );\n\n\t\t}\n\n\t\tthis.animate = function ( callback ) {\n\n\t\t\tonAnimationFrame = callback;\n\t\t\tstart();\n\n\t\t};\n\n\t\t// Rendering\n\n\t\tthis.render = function ( scene, camera, renderTarget, forceClear ) {\n\n\t\t\tif ( ! ( camera && camera.isCamera ) ) {\n\n\t\t\t\tconsole.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tif ( _isContextLost ) return;\n\n\t\t\t// reset caching for this frame\n\n\t\t\t_currentGeometryProgram = '';\n\t\t\t_currentMaterialId = - 1;\n\t\t\t_currentCamera = null;\n\n\t\t\t// update scene graph\n\n\t\t\tif ( scene.autoUpdate === true ) scene.updateMatrixWorld();\n\n\t\t\t// update camera matrices and frustum\n\n\t\t\tif ( camera.parent === null ) camera.updateMatrixWorld();\n\n\t\t\tif ( vr.enabled ) {\n\t\t\t\tcamera = vr.getCamera( camera );\n\t\t\t}\n\n\t\t\t_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );\n\t\t\t_frustum.setFromMatrix( _projScreenMatrix );\n\n\t\t\tlightsArray.length = 0;\n\t\t\tshadowsArray.length = 0;\n\n\t\t\tspritesArray.length = 0;\n\t\t\tflaresArray.length = 0;\n\n\t\t\t_localClippingEnabled = this.localClippingEnabled;\n\t\t\t_clippingEnabled = _clipping.init( this.clippingPlanes, _localClippingEnabled, camera );\n\n\t\t\tcurrentRenderList = renderLists.get( scene, camera );\n\t\t\tcurrentRenderList.init();\n\n\t\t\tprojectObject( scene, camera, _this.sortObjects );\n\n\t\t\tif ( _this.sortObjects === true ) {\n\n\t\t\t\tcurrentRenderList.sort();\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tif ( _clippingEnabled ) _clipping.beginShadows();\n\n\t\t\tshadowMap.render( shadowsArray, scene, camera );\n\n\t\t\tlights.setup( lightsArray, shadowsArray, camera );\n\n\t\t\tif ( _clippingEnabled ) _clipping.endShadows();\n\n\t\t\t//\n\n\t\t\t_infoRender.frame ++;\n\t\t\t_infoRender.calls = 0;\n\t\t\t_infoRender.vertices = 0;\n\t\t\t_infoRender.faces = 0;\n\t\t\t_infoRender.points = 0;\n\n\t\t\tif ( renderTarget === undefined ) {\n\n\t\t\t\trenderTarget = null;\n\n\t\t\t}\n\n\t\t\tthis.setRenderTarget( renderTarget );\n\n\t\t\t//\n\n\t\t\tbackground.render( currentRenderList, scene, camera, forceClear );\n\n\t\t\t// render scene\n\n\t\t\tvar opaqueObjects = currentRenderList.opaque;\n\t\t\tvar transparentObjects = currentRenderList.transparent;\n\n\t\t\tif ( scene.overrideMaterial ) {\n\n\t\t\t\tvar overrideMaterial = scene.overrideMaterial;\n\n\t\t\t\tif ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera, overrideMaterial );\n\t\t\t\tif ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera, overrideMaterial );\n\n\t\t\t} else {\n\n\t\t\t\t// opaque pass (front-to-back order)\n\n\t\t\t\tif ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera );\n\n\t\t\t\t// transparent pass (back-to-front order)\n\n\t\t\t\tif ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera );\n\n\t\t\t}\n\n\t\t\t// custom renderers\n\n\t\t\tspriteRenderer.render( spritesArray, scene, camera );\n\t\t\tflareRenderer.render( flaresArray, scene, camera, _currentViewport );\n\n\t\t\t// Generate mipmap if we're using any kind of mipmap filtering\n\n\t\t\tif ( renderTarget ) {\n\n\t\t\t\ttextures.updateRenderTargetMipmap( renderTarget );\n\n\t\t\t}\n\n\t\t\t// Ensure depth buffer writing is enabled so it can be cleared on next render\n\n\t\t\tstate.buffers.depth.setTest( true );\n\t\t\tstate.buffers.depth.setMask( true );\n\t\t\tstate.buffers.color.setMask( true );\n\n\t\t\tstate.setPolygonOffset( false );\n\n\t\t\tif ( vr.enabled ) {\n\t\t\t\t\n\t\t\t\tvr.submitFrame();\n\n\t\t\t}\n\n\t\t\t// _gl.finish();\n\n\t\t};\n\n\t\t/*\n\t\t// TODO Duplicated code (Frustum)\n\n\t\tvar _sphere = new Sphere();\n\n\t\tfunction isObjectViewable( object ) {\n\n\t\t\tvar geometry = object.geometry;\n\n\t\t\tif ( geometry.boundingSphere === null )\n\t\t\t\tgeometry.computeBoundingSphere();\n\n\t\t\t_sphere.copy( geometry.boundingSphere ).\n\t\t\tapplyMatrix4( object.matrixWorld );\n\n\t\t\treturn isSphereViewable( _sphere );\n\n\t\t}\n\n\t\tfunction isSpriteViewable( sprite ) {\n\n\t\t\t_sphere.center.set( 0, 0, 0 );\n\t\t\t_sphere.radius = 0.7071067811865476;\n\t\t\t_sphere.applyMatrix4( sprite.matrixWorld );\n\n\t\t\treturn isSphereViewable( _sphere );\n\n\t\t}\n\n\t\tfunction isSphereViewable( sphere ) {\n\n\t\t\tif ( ! _frustum.intersectsSphere( sphere ) ) return false;\n\n\t\t\tvar numPlanes = _clipping.numPlanes;\n\n\t\t\tif ( numPlanes === 0 ) return true;\n\n\t\t\tvar planes = _this.clippingPlanes,\n\n\t\t\t\tcenter = sphere.center,\n\t\t\t\tnegRad = - sphere.radius,\n\t\t\t\ti = 0;\n\n\t\t\tdo {\n\n\t\t\t\t// out when deeper than radius in the negative halfspace\n\t\t\t\tif ( planes[ i ].distanceToPoint( center ) < negRad ) return false;\n\n\t\t\t} while ( ++ i !== numPlanes );\n\n\t\t\treturn true;\n\n\t\t}\n\t\t*/\n\n\t\tfunction projectObject( object, camera, sortObjects ) {\n\n\t\t\tif ( ! object.visible ) return;\n\n\t\t\tvar visible = object.layers.test( camera.layers );\n\n\t\t\tif ( visible ) {\n\n\t\t\t\tif ( object.isLight ) {\n\n\t\t\t\t\tlightsArray.push( object );\n\n\t\t\t\t\tif ( object.castShadow ) {\n\n\t\t\t\t\t\tshadowsArray.push( object );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( object.isSprite ) {\n\n\t\t\t\t\tif ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {\n\n\t\t\t\t\t\tspritesArray.push( object );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( object.isLensFlare ) {\n\n\t\t\t\t\tflaresArray.push( object );\n\n\t\t\t\t} else if ( object.isImmediateRenderObject ) {\n\n\t\t\t\t\tif ( sortObjects ) {\n\n\t\t\t\t\t\t_vector3.setFromMatrixPosition( object.matrixWorld )\n\t\t\t\t\t\t\t.applyMatrix4( _projScreenMatrix );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tcurrentRenderList.push( object, null, object.material, _vector3.z, null );\n\n\t\t\t\t} else if ( object.isMesh || object.isLine || object.isPoints ) {\n\n\t\t\t\t\tif ( object.isSkinnedMesh ) {\n\n\t\t\t\t\t\tobject.skeleton.update();\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {\n\n\t\t\t\t\t\tif ( sortObjects ) {\n\n\t\t\t\t\t\t\t_vector3.setFromMatrixPosition( object.matrixWorld )\n\t\t\t\t\t\t\t\t.applyMatrix4( _projScreenMatrix );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar geometry = objects.update( object );\n\t\t\t\t\t\tvar material = object.material;\n\n\t\t\t\t\t\tif ( Array.isArray( material ) ) {\n\n\t\t\t\t\t\t\tvar groups = geometry.groups;\n\n\t\t\t\t\t\t\tfor ( var i = 0, l = groups.length; i < l; i ++ ) {\n\n\t\t\t\t\t\t\t\tvar group = groups[ i ];\n\t\t\t\t\t\t\t\tvar groupMaterial = material[ group.materialIndex ];\n\n\t\t\t\t\t\t\t\tif ( groupMaterial && groupMaterial.visible ) {\n\n\t\t\t\t\t\t\t\t\tcurrentRenderList.push( object, geometry, groupMaterial, _vector3.z, group );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else if ( material.visible ) {\n\n\t\t\t\t\t\t\tcurrentRenderList.push( object, geometry, material, _vector3.z, null );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tvar children = object.children;\n\n\t\t\tfor ( var i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\t\tprojectObject( children[ i ], camera, sortObjects );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction renderObjects( renderList, scene, camera, overrideMaterial ) {\n\n\t\t\tfor ( var i = 0, l = renderList.length; i < l; i ++ ) {\n\n\t\t\t\tvar renderItem = renderList[ i ];\n\n\t\t\t\tvar object = renderItem.object;\n\t\t\t\tvar geometry = renderItem.geometry;\n\t\t\t\tvar material = overrideMaterial === undefined ? renderItem.material : overrideMaterial;\n\t\t\t\tvar group = renderItem.group;\n\n\t\t\t\tif ( camera.isArrayCamera ) {\n\n\t\t\t\t\t_currentArrayCamera = camera;\n\n\t\t\t\t\tvar cameras = camera.cameras;\n\n\t\t\t\t\tfor ( var j = 0, jl = cameras.length; j < jl; j ++ ) {\n\n\t\t\t\t\t\tvar camera2 = cameras[ j ];\n\n\t\t\t\t\t\tif ( object.layers.test( camera2.layers ) ) {\n\n\t\t\t\t\t\t\tvar bounds = camera2.bounds;\n\n\t\t\t\t\t\t\tvar x = bounds.x * _width;\n\t\t\t\t\t\t\tvar y = bounds.y * _height;\n\t\t\t\t\t\t\tvar width = bounds.z * _width;\n\t\t\t\t\t\t\tvar height = bounds.w * _height;\n\n\t\t\t\t\t\t\tstate.viewport( _currentViewport.set( x, y, width, height ).multiplyScalar( _pixelRatio ) );\n\n\t\t\t\t\t\t\trenderObject( object, scene, camera2, geometry, material, group );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t_currentArrayCamera = null;\n\n\t\t\t\t\trenderObject( object, scene, camera, geometry, material, group );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction renderObject( object, scene, camera, geometry, material, group ) {\n\t\t\tobject.onBeforeRender( _this, scene, camera, geometry, material, group );\n\n\t\t\tobject.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );\n\t\t\tobject.normalMatrix.getNormalMatrix( object.modelViewMatrix );\n\n\t\t\tif ( object.isImmediateRenderObject ) {\n\n\t\t\t\tstate.setMaterial( material );\n\n\t\t\t\tvar program = setProgram( camera, scene.fog, material, object );\n\n\t\t\t\t_currentGeometryProgram = '';\n\n\t\t\t\trenderObjectImmediate( object, program, material );\n\n\t\t\t} else {\n\n\t\t\t\t_this.renderBufferDirect( camera, scene.fog, geometry, material, object, group );\n\n\t\t\t}\n\n\t\t\tobject.onAfterRender( _this, scene, camera, geometry, material, group );\n\n\t\t}\n\n\t\tfunction initMaterial( material, fog, object ) {\n\n\t\t\tvar materialProperties = properties.get( material );\n\n\t\t\tvar parameters = programCache.getParameters(\n\t\t\t\tmaterial, lights.state, shadowsArray, fog, _clipping.numPlanes, _clipping.numIntersection, object );\n\n\t\t\tvar code = programCache.getProgramCode( material, parameters );\n\n\t\t\tvar program = materialProperties.program;\n\t\t\tvar programChange = true;\n\n\t\t\tif ( program === undefined ) {\n\n\t\t\t\t// new material\n\t\t\t\tmaterial.addEventListener( 'dispose', onMaterialDispose );\n\n\t\t\t} else if ( program.code !== code ) {\n\n\t\t\t\t// changed glsl or parameters\n\t\t\t\treleaseMaterialProgramReference( material );\n\n\t\t\t} else if ( parameters.shaderID !== undefined ) {\n\n\t\t\t\t// same glsl and uniform list\n\t\t\t\treturn;\n\n\t\t\t} else {\n\n\t\t\t\t// only rebuild uniform list\n\t\t\t\tprogramChange = false;\n\n\t\t\t}\n\n\t\t\tif ( programChange ) {\n\n\t\t\t\tif ( parameters.shaderID ) {\n\n\t\t\t\t\tvar shader = ShaderLib[ parameters.shaderID ];\n\n\t\t\t\t\tmaterialProperties.shader = {\n\t\t\t\t\t\tname: material.type,\n\t\t\t\t\t\tuniforms: UniformsUtils.clone( shader.uniforms ),\n\t\t\t\t\t\tvertexShader: shader.vertexShader,\n\t\t\t\t\t\tfragmentShader: shader.fragmentShader\n\t\t\t\t\t};\n\n\t\t\t\t} else {\n\n\t\t\t\t\tmaterialProperties.shader = {\n\t\t\t\t\t\tname: material.type,\n\t\t\t\t\t\tuniforms: material.uniforms,\n\t\t\t\t\t\tvertexShader: material.vertexShader,\n\t\t\t\t\t\tfragmentShader: material.fragmentShader\n\t\t\t\t\t};\n\n\t\t\t\t}\n\n\t\t\t\tmaterial.onBeforeCompile( materialProperties.shader );\n\n\t\t\t\tprogram = programCache.acquireProgram( material, materialProperties.shader, parameters, code );\n\t\t\t\tmaterialProperties.program = program;\n\t\t\t\tmaterial.program = program;\n\n\t\t\t}\n\n\t\t\tvar programAttributes = program.getAttributes();\n\n\t\t\tif ( material.morphTargets ) {\n\n\t\t\t\tmaterial.numSupportedMorphTargets = 0;\n\n\t\t\t\tfor ( var i = 0; i < _this.maxMorphTargets; i ++ ) {\n\n\t\t\t\t\tif ( programAttributes[ 'morphTarget' + i ] >= 0 ) {\n\n\t\t\t\t\t\tmaterial.numSupportedMorphTargets ++;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( material.morphNormals ) {\n\n\t\t\t\tmaterial.numSupportedMorphNormals = 0;\n\n\t\t\t\tfor ( var i = 0; i < _this.maxMorphNormals; i ++ ) {\n\n\t\t\t\t\tif ( programAttributes[ 'morphNormal' + i ] >= 0 ) {\n\n\t\t\t\t\t\tmaterial.numSupportedMorphNormals ++;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tvar uniforms = materialProperties.shader.uniforms;\n\n\t\t\tif ( ! material.isShaderMaterial &&\n\t\t\t\t! material.isRawShaderMaterial ||\n\t\t\t\tmaterial.clipping === true ) {\n\n\t\t\t\tmaterialProperties.numClippingPlanes = _clipping.numPlanes;\n\t\t\t\tmaterialProperties.numIntersection = _clipping.numIntersection;\n\t\t\t\tuniforms.clippingPlanes = _clipping.uniform;\n\n\t\t\t}\n\n\t\t\tmaterialProperties.fog = fog;\n\n\t\t\t// store the light setup it was created for\n\n\t\t\tmaterialProperties.lightsHash = lights.state.hash;\n\n\t\t\tif ( material.lights ) {\n\n\t\t\t\t// wire up the material to this renderer's lighting state\n\n\t\t\t\tuniforms.ambientLightColor.value = lights.state.ambient;\n\t\t\t\tuniforms.directionalLights.value = lights.state.directional;\n\t\t\t\tuniforms.spotLights.value = lights.state.spot;\n\t\t\t\tuniforms.rectAreaLights.value = lights.state.rectArea;\n\t\t\t\tuniforms.pointLights.value = lights.state.point;\n\t\t\t\tuniforms.hemisphereLights.value = lights.state.hemi;\n\n\t\t\t\tuniforms.directionalShadowMap.value = lights.state.directionalShadowMap;\n\t\t\t\tuniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;\n\t\t\t\tuniforms.spotShadowMap.value = lights.state.spotShadowMap;\n\t\t\t\tuniforms.spotShadowMatrix.value = lights.state.spotShadowMatrix;\n\t\t\t\tuniforms.pointShadowMap.value = lights.state.pointShadowMap;\n\t\t\t\tuniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;\n\t\t\t\t// TODO (abelnation): add area lights shadow info to uniforms\n\n\t\t\t}\n\n\t\t\tvar progUniforms = materialProperties.program.getUniforms(),\n\t\t\t\tuniformsList =\n\t\t\t\t\tWebGLUniforms.seqWithValue( progUniforms.seq, uniforms );\n\n\t\t\tmaterialProperties.uniformsList = uniformsList;\n\n\t\t}\n\n\t\tfunction setProgram( camera, fog, material, object ) {\n\n\t\t\t_usedTextureUnits = 0;\n\n\t\t\tvar materialProperties = properties.get( material );\n\n\t\t\tif ( _clippingEnabled ) {\n\n\t\t\t\tif ( _localClippingEnabled || camera !== _currentCamera ) {\n\n\t\t\t\t\tvar useCache =\n\t\t\t\t\t\tcamera === _currentCamera &&\n\t\t\t\t\t\tmaterial.id === _currentMaterialId;\n\n\t\t\t\t\t// we might want to call this function with some ClippingGroup\n\t\t\t\t\t// object instead of the material, once it becomes feasible\n\t\t\t\t\t// (#8465, #8379)\n\t\t\t\t\t_clipping.setState(\n\t\t\t\t\t\tmaterial.clippingPlanes, material.clipIntersection, material.clipShadows,\n\t\t\t\t\t\tcamera, materialProperties, useCache );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( material.needsUpdate === false ) {\n\n\t\t\t\tif ( materialProperties.program === undefined ) {\n\n\t\t\t\t\tmaterial.needsUpdate = true;\n\n\t\t\t\t} else if ( material.fog && materialProperties.fog !== fog ) {\n\n\t\t\t\t\tmaterial.needsUpdate = true;\n\n\t\t\t\t} else if ( material.lights && materialProperties.lightsHash !== lights.state.hash ) {\n\n\t\t\t\t\tmaterial.needsUpdate = true;\n\n\t\t\t\t} else if ( materialProperties.numClippingPlanes !== undefined &&\n\t\t\t\t\t( materialProperties.numClippingPlanes !== _clipping.numPlanes ||\n\t\t\t\t\tmaterialProperties.numIntersection !== _clipping.numIntersection ) ) {\n\n\t\t\t\t\tmaterial.needsUpdate = true;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( material.needsUpdate ) {\n\n\t\t\t\tinitMaterial( material, fog, object );\n\t\t\t\tmaterial.needsUpdate = false;\n\n\t\t\t}\n\n\t\t\tvar refreshProgram = false;\n\t\t\tvar refreshMaterial = false;\n\t\t\tvar refreshLights = false;\n\n\t\t\tvar program = materialProperties.program,\n\t\t\t\tp_uniforms = program.getUniforms(),\n\t\t\t\tm_uniforms = materialProperties.shader.uniforms;\n\n\t\t\tif ( state.useProgram( program.program ) ) {\n\n\t\t\t\trefreshProgram = true;\n\t\t\t\trefreshMaterial = true;\n\t\t\t\trefreshLights = true;\n\n\t\t\t}\n\n\t\t\tif ( material.id !== _currentMaterialId ) {\n\n\t\t\t\t_currentMaterialId = material.id;\n\n\t\t\t\trefreshMaterial = true;\n\n\t\t\t}\n\n\t\t\tif ( refreshProgram || camera !== _currentCamera ) {\n\n\t\t\t\tp_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );\n\n\t\t\t\tif ( capabilities.logarithmicDepthBuffer ) {\n\n\t\t\t\t\tp_uniforms.setValue( _gl, 'logDepthBufFC',\n\t\t\t\t\t\t2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );\n\n\t\t\t\t}\n\n\t\t\t\t// Avoid unneeded uniform updates per ArrayCamera's sub-camera\n\n\t\t\t\tif ( _currentCamera !== ( _currentArrayCamera || camera ) ) {\n\n\t\t\t\t\t_currentCamera = ( _currentArrayCamera || camera );\n\n\t\t\t\t\t// lighting uniforms depend on the camera so enforce an update\n\t\t\t\t\t// now, in case this material supports lights - or later, when\n\t\t\t\t\t// the next material that does gets activated:\n\n\t\t\t\t\trefreshMaterial = true;\t\t// set to true on material change\n\t\t\t\t\trefreshLights = true;\t\t// remains set until update done\n\n\t\t\t\t}\n\n\t\t\t\t// load material specific uniforms\n\t\t\t\t// (shader material also gets them for the sake of genericity)\n\n\t\t\t\tif ( material.isShaderMaterial ||\n\t\t\t\t\tmaterial.isMeshPhongMaterial ||\n\t\t\t\t\tmaterial.isMeshStandardMaterial ||\n\t\t\t\t\tmaterial.envMap ) {\n\n\t\t\t\t\tvar uCamPos = p_uniforms.map.cameraPosition;\n\n\t\t\t\t\tif ( uCamPos !== undefined ) {\n\n\t\t\t\t\t\tuCamPos.setValue( _gl,\n\t\t\t\t\t\t\t_vector3.setFromMatrixPosition( camera.matrixWorld ) );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( material.isMeshPhongMaterial ||\n\t\t\t\t\tmaterial.isMeshLambertMaterial ||\n\t\t\t\t\tmaterial.isMeshBasicMaterial ||\n\t\t\t\t\tmaterial.isMeshStandardMaterial ||\n\t\t\t\t\tmaterial.isShaderMaterial ||\n\t\t\t\t\tmaterial.skinning ) {\n\n\t\t\t\t\tp_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// skinning uniforms must be set even if material didn't change\n\t\t\t// auto-setting of texture unit for bone texture must go before other textures\n\t\t\t// not sure why, but otherwise weird things happen\n\n\t\t\tif ( material.skinning ) {\n\n\t\t\t\tp_uniforms.setOptional( _gl, object, 'bindMatrix' );\n\t\t\t\tp_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );\n\n\t\t\t\tvar skeleton = object.skeleton;\n\n\t\t\t\tif ( skeleton ) {\n\n\t\t\t\t\tvar bones = skeleton.bones;\n\n\t\t\t\t\tif ( capabilities.floatVertexTextures ) {\n\n\t\t\t\t\t\tif ( skeleton.boneTexture === undefined ) {\n\n\t\t\t\t\t\t\t// layout (1 matrix = 4 pixels)\n\t\t\t\t\t\t\t//      RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)\n\t\t\t\t\t\t\t//  with  8x8  pixel texture max   16 bones * 4 pixels =  (8 * 8)\n\t\t\t\t\t\t\t//       16x16 pixel texture max   64 bones * 4 pixels = (16 * 16)\n\t\t\t\t\t\t\t//       32x32 pixel texture max  256 bones * 4 pixels = (32 * 32)\n\t\t\t\t\t\t\t//       64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)\n\n\n\t\t\t\t\t\t\tvar size = Math.sqrt( bones.length * 4 ); // 4 pixels needed for 1 matrix\n\t\t\t\t\t\t\tsize = _Math.nextPowerOfTwo( Math.ceil( size ) );\n\t\t\t\t\t\t\tsize = Math.max( size, 4 );\n\n\t\t\t\t\t\t\tvar boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel\n\t\t\t\t\t\t\tboneMatrices.set( skeleton.boneMatrices ); // copy current values\n\n\t\t\t\t\t\t\tvar boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType );\n\n\t\t\t\t\t\t\tskeleton.boneMatrices = boneMatrices;\n\t\t\t\t\t\t\tskeleton.boneTexture = boneTexture;\n\t\t\t\t\t\t\tskeleton.boneTextureSize = size;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tp_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture );\n\t\t\t\t\t\tp_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tp_uniforms.setOptional( _gl, skeleton, 'boneMatrices' );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( refreshMaterial ) {\n\n\t\t\t\tp_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );\n\t\t\t\tp_uniforms.setValue( _gl, 'toneMappingWhitePoint', _this.toneMappingWhitePoint );\n\n\t\t\t\tif ( material.lights ) {\n\n\t\t\t\t\t// the current material requires lighting info\n\n\t\t\t\t\t// note: all lighting uniforms are always set correctly\n\t\t\t\t\t// they simply reference the renderer's state for their\n\t\t\t\t\t// values\n\t\t\t\t\t//\n\t\t\t\t\t// use the current material's .needsUpdate flags to set\n\t\t\t\t\t// the GL state when required\n\n\t\t\t\t\tmarkUniformsLightsNeedsUpdate( m_uniforms, refreshLights );\n\n\t\t\t\t}\n\n\t\t\t\t// refresh uniforms common to several materials\n\n\t\t\t\tif ( fog && material.fog ) {\n\n\t\t\t\t\trefreshUniformsFog( m_uniforms, fog );\n\n\t\t\t\t}\n\n\t\t\t\tif ( material.isMeshBasicMaterial ) {\n\n\t\t\t\t\trefreshUniformsCommon( m_uniforms, material );\n\n\t\t\t\t} else if ( material.isMeshLambertMaterial ) {\n\n\t\t\t\t\trefreshUniformsCommon( m_uniforms, material );\n\t\t\t\t\trefreshUniformsLambert( m_uniforms, material );\n\n\t\t\t\t} else if ( material.isMeshPhongMaterial ) {\n\n\t\t\t\t\trefreshUniformsCommon( m_uniforms, material );\n\n\t\t\t\t\tif ( material.isMeshToonMaterial ) {\n\n\t\t\t\t\t\trefreshUniformsToon( m_uniforms, material );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\trefreshUniformsPhong( m_uniforms, material );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( material.isMeshStandardMaterial ) {\n\n\t\t\t\t\trefreshUniformsCommon( m_uniforms, material );\n\n\t\t\t\t\tif ( material.isMeshPhysicalMaterial ) {\n\n\t\t\t\t\t\trefreshUniformsPhysical( m_uniforms, material );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\trefreshUniformsStandard( m_uniforms, material );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( material.isMeshDepthMaterial ) {\n\n\t\t\t\t\trefreshUniformsCommon( m_uniforms, material );\n\t\t\t\t\trefreshUniformsDepth( m_uniforms, material );\n\n\t\t\t\t} else if ( material.isMeshDistanceMaterial ) {\n\n\t\t\t\t\trefreshUniformsCommon( m_uniforms, material );\n\t\t\t\t\trefreshUniformsDistance( m_uniforms, material );\n\n\t\t\t\t} else if ( material.isMeshNormalMaterial ) {\n\n\t\t\t\t\trefreshUniformsCommon( m_uniforms, material );\n\t\t\t\t\trefreshUniformsNormal( m_uniforms, material );\n\n\t\t\t\t} else if ( material.isLineBasicMaterial ) {\n\n\t\t\t\t\trefreshUniformsLine( m_uniforms, material );\n\n\t\t\t\t\tif ( material.isLineDashedMaterial ) {\n\n\t\t\t\t\t\trefreshUniformsDash( m_uniforms, material );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( material.isPointsMaterial ) {\n\n\t\t\t\t\trefreshUniformsPoints( m_uniforms, material );\n\n\t\t\t\t} else if ( material.isShadowMaterial ) {\n\n\t\t\t\t\tm_uniforms.color.value = material.color;\n\t\t\t\t\tm_uniforms.opacity.value = material.opacity;\n\n\t\t\t\t}\n\n\t\t\t\t// RectAreaLight Texture\n\t\t\t\t// TODO (mrdoob): Find a nicer implementation\n\n\t\t\t\tif ( m_uniforms.ltcMat !== undefined ) m_uniforms.ltcMat.value = UniformsLib.LTC_MAT_TEXTURE;\n\t\t\t\tif ( m_uniforms.ltcMag !== undefined ) m_uniforms.ltcMag.value = UniformsLib.LTC_MAG_TEXTURE;\n\n\t\t\t\tWebGLUniforms.upload(\n\t\t\t\t\t_gl, materialProperties.uniformsList, m_uniforms, _this );\n\n\t\t\t}\n\n\n\t\t\t// common matrices\n\n\t\t\tp_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );\n\t\t\tp_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );\n\t\t\tp_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );\n\n\t\t\treturn program;\n\n\t\t}\n\n\t\t// Uniforms (refresh uniforms objects)\n\n\t\tfunction refreshUniformsCommon( uniforms, material ) {\n\n\t\t\tuniforms.opacity.value = material.opacity;\n\n\t\t\tif ( material.color ) {\n\n\t\t\t\tuniforms.diffuse.value = material.color;\n\n\t\t\t}\n\n\t\t\tif ( material.emissive ) {\n\n\t\t\t\tuniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );\n\n\t\t\t}\n\n\t\t\tif ( material.map ) {\n\n\t\t\t\tuniforms.map.value = material.map;\n\n\t\t\t}\n\n\t\t\tif ( material.alphaMap ) {\n\n\t\t\t\tuniforms.alphaMap.value = material.alphaMap;\n\n\t\t\t}\n\n\t\t\tif ( material.specularMap ) {\n\n\t\t\t\tuniforms.specularMap.value = material.specularMap;\n\n\t\t\t}\n\n\t\t\tif ( material.envMap ) {\n\n\t\t\t\tuniforms.envMap.value = material.envMap;\n\n\t\t\t\t// don't flip CubeTexture envMaps, flip everything else:\n\t\t\t\t//  WebGLRenderTargetCube will be flipped for backwards compatibility\n\t\t\t\t//  WebGLRenderTargetCube.texture will be flipped because it's a Texture and NOT a CubeTexture\n\t\t\t\t// this check must be handled differently, or removed entirely, if WebGLRenderTargetCube uses a CubeTexture in the future\n\t\t\t\tuniforms.flipEnvMap.value = ( ! ( material.envMap && material.envMap.isCubeTexture ) ) ? 1 : - 1;\n\n\t\t\t\tuniforms.reflectivity.value = material.reflectivity;\n\t\t\t\tuniforms.refractionRatio.value = material.refractionRatio;\n\n\t\t\t}\n\n\t\t\tif ( material.lightMap ) {\n\n\t\t\t\tuniforms.lightMap.value = material.lightMap;\n\t\t\t\tuniforms.lightMapIntensity.value = material.lightMapIntensity;\n\n\t\t\t}\n\n\t\t\tif ( material.aoMap ) {\n\n\t\t\t\tuniforms.aoMap.value = material.aoMap;\n\t\t\t\tuniforms.aoMapIntensity.value = material.aoMapIntensity;\n\n\t\t\t}\n\n\t\t\t// uv repeat and offset setting priorities\n\t\t\t// 1. color map\n\t\t\t// 2. specular map\n\t\t\t// 3. normal map\n\t\t\t// 4. bump map\n\t\t\t// 5. alpha map\n\t\t\t// 6. emissive map\n\n\t\t\tvar uvScaleMap;\n\n\t\t\tif ( material.map ) {\n\n\t\t\t\tuvScaleMap = material.map;\n\n\t\t\t} else if ( material.specularMap ) {\n\n\t\t\t\tuvScaleMap = material.specularMap;\n\n\t\t\t} else if ( material.displacementMap ) {\n\n\t\t\t\tuvScaleMap = material.displacementMap;\n\n\t\t\t} else if ( material.normalMap ) {\n\n\t\t\t\tuvScaleMap = material.normalMap;\n\n\t\t\t} else if ( material.bumpMap ) {\n\n\t\t\t\tuvScaleMap = material.bumpMap;\n\n\t\t\t} else if ( material.roughnessMap ) {\n\n\t\t\t\tuvScaleMap = material.roughnessMap;\n\n\t\t\t} else if ( material.metalnessMap ) {\n\n\t\t\t\tuvScaleMap = material.metalnessMap;\n\n\t\t\t} else if ( material.alphaMap ) {\n\n\t\t\t\tuvScaleMap = material.alphaMap;\n\n\t\t\t} else if ( material.emissiveMap ) {\n\n\t\t\t\tuvScaleMap = material.emissiveMap;\n\n\t\t\t}\n\n\t\t\tif ( uvScaleMap !== undefined ) {\n\n\t\t\t\t// backwards compatibility\n\t\t\t\tif ( uvScaleMap.isWebGLRenderTarget ) {\n\n\t\t\t\t\tuvScaleMap = uvScaleMap.texture;\n\n\t\t\t\t}\n\n\t\t\t\tvar offset = uvScaleMap.offset;\n\t\t\t\tvar repeat = uvScaleMap.repeat;\n\n\t\t\t\tuniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction refreshUniformsLine( uniforms, material ) {\n\n\t\t\tuniforms.diffuse.value = material.color;\n\t\t\tuniforms.opacity.value = material.opacity;\n\n\t\t}\n\n\t\tfunction refreshUniformsDash( uniforms, material ) {\n\n\t\t\tuniforms.dashSize.value = material.dashSize;\n\t\t\tuniforms.totalSize.value = material.dashSize + material.gapSize;\n\t\t\tuniforms.scale.value = material.scale;\n\n\t\t}\n\n\t\tfunction refreshUniformsPoints( uniforms, material ) {\n\n\t\t\tuniforms.diffuse.value = material.color;\n\t\t\tuniforms.opacity.value = material.opacity;\n\t\t\tuniforms.size.value = material.size * _pixelRatio;\n\t\t\tuniforms.scale.value = _height * 0.5;\n\n\t\t\tuniforms.map.value = material.map;\n\n\t\t\tif ( material.map !== null ) {\n\n\t\t\t\tvar offset = material.map.offset;\n\t\t\t\tvar repeat = material.map.repeat;\n\n\t\t\t\tuniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction refreshUniformsFog( uniforms, fog ) {\n\n\t\t\tuniforms.fogColor.value = fog.color;\n\n\t\t\tif ( fog.isFog ) {\n\n\t\t\t\tuniforms.fogNear.value = fog.near;\n\t\t\t\tuniforms.fogFar.value = fog.far;\n\n\t\t\t} else if ( fog.isFogExp2 ) {\n\n\t\t\t\tuniforms.fogDensity.value = fog.density;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction refreshUniformsLambert( uniforms, material ) {\n\n\t\t\tif ( material.emissiveMap ) {\n\n\t\t\t\tuniforms.emissiveMap.value = material.emissiveMap;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction refreshUniformsPhong( uniforms, material ) {\n\n\t\t\tuniforms.specular.value = material.specular;\n\t\t\tuniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )\n\n\t\t\tif ( material.emissiveMap ) {\n\n\t\t\t\tuniforms.emissiveMap.value = material.emissiveMap;\n\n\t\t\t}\n\n\t\t\tif ( material.bumpMap ) {\n\n\t\t\t\tuniforms.bumpMap.value = material.bumpMap;\n\t\t\t\tuniforms.bumpScale.value = material.bumpScale;\n\n\t\t\t}\n\n\t\t\tif ( material.normalMap ) {\n\n\t\t\t\tuniforms.normalMap.value = material.normalMap;\n\t\t\t\tuniforms.normalScale.value.copy( material.normalScale );\n\n\t\t\t}\n\n\t\t\tif ( material.displacementMap ) {\n\n\t\t\t\tuniforms.displacementMap.value = material.displacementMap;\n\t\t\t\tuniforms.displacementScale.value = material.displacementScale;\n\t\t\t\tuniforms.displacementBias.value = material.displacementBias;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction refreshUniformsToon( uniforms, material ) {\n\n\t\t\trefreshUniformsPhong( uniforms, material );\n\n\t\t\tif ( material.gradientMap ) {\n\n\t\t\t\tuniforms.gradientMap.value = material.gradientMap;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction refreshUniformsStandard( uniforms, material ) {\n\n\t\t\tuniforms.roughness.value = material.roughness;\n\t\t\tuniforms.metalness.value = material.metalness;\n\n\t\t\tif ( material.roughnessMap ) {\n\n\t\t\t\tuniforms.roughnessMap.value = material.roughnessMap;\n\n\t\t\t}\n\n\t\t\tif ( material.metalnessMap ) {\n\n\t\t\t\tuniforms.metalnessMap.value = material.metalnessMap;\n\n\t\t\t}\n\n\t\t\tif ( material.emissiveMap ) {\n\n\t\t\t\tuniforms.emissiveMap.value = material.emissiveMap;\n\n\t\t\t}\n\n\t\t\tif ( material.bumpMap ) {\n\n\t\t\t\tuniforms.bumpMap.value = material.bumpMap;\n\t\t\t\tuniforms.bumpScale.value = material.bumpScale;\n\n\t\t\t}\n\n\t\t\tif ( material.normalMap ) {\n\n\t\t\t\tuniforms.normalMap.value = material.normalMap;\n\t\t\t\tuniforms.normalScale.value.copy( material.normalScale );\n\n\t\t\t}\n\n\t\t\tif ( material.displacementMap ) {\n\n\t\t\t\tuniforms.displacementMap.value = material.displacementMap;\n\t\t\t\tuniforms.displacementScale.value = material.displacementScale;\n\t\t\t\tuniforms.displacementBias.value = material.displacementBias;\n\n\t\t\t}\n\n\t\t\tif ( material.envMap ) {\n\n\t\t\t\t//uniforms.envMap.value = material.envMap; // part of uniforms common\n\t\t\t\tuniforms.envMapIntensity.value = material.envMapIntensity;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction refreshUniformsPhysical( uniforms, material ) {\n\n\t\t\tuniforms.clearCoat.value = material.clearCoat;\n\t\t\tuniforms.clearCoatRoughness.value = material.clearCoatRoughness;\n\n\t\t\trefreshUniformsStandard( uniforms, material );\n\n\t\t}\n\n\t\tfunction refreshUniformsDepth( uniforms, material ) {\n\n\t\t\tif ( material.displacementMap ) {\n\n\t\t\t\tuniforms.displacementMap.value = material.displacementMap;\n\t\t\t\tuniforms.displacementScale.value = material.displacementScale;\n\t\t\t\tuniforms.displacementBias.value = material.displacementBias;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction refreshUniformsDistance( uniforms, material ) {\n\n\t\t\tif ( material.displacementMap ) {\n\n\t\t\t\tuniforms.displacementMap.value = material.displacementMap;\n\t\t\t\tuniforms.displacementScale.value = material.displacementScale;\n\t\t\t\tuniforms.displacementBias.value = material.displacementBias;\n\n\t\t\t}\n\n\t\t\tuniforms.referencePosition.value.copy( material.referencePosition );\n\t\t\tuniforms.nearDistance.value = material.nearDistance;\n\t\t\tuniforms.farDistance.value = material.farDistance;\n\n\t\t}\n\n\t\tfunction refreshUniformsNormal( uniforms, material ) {\n\n\t\t\tif ( material.bumpMap ) {\n\n\t\t\t\tuniforms.bumpMap.value = material.bumpMap;\n\t\t\t\tuniforms.bumpScale.value = material.bumpScale;\n\n\t\t\t}\n\n\t\t\tif ( material.normalMap ) {\n\n\t\t\t\tuniforms.normalMap.value = material.normalMap;\n\t\t\t\tuniforms.normalScale.value.copy( material.normalScale );\n\n\t\t\t}\n\n\t\t\tif ( material.displacementMap ) {\n\n\t\t\t\tuniforms.displacementMap.value = material.displacementMap;\n\t\t\t\tuniforms.displacementScale.value = material.displacementScale;\n\t\t\t\tuniforms.displacementBias.value = material.displacementBias;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// If uniforms are marked as clean, they don't need to be loaded to the GPU.\n\n\t\tfunction markUniformsLightsNeedsUpdate( uniforms, value ) {\n\n\t\t\tuniforms.ambientLightColor.needsUpdate = value;\n\n\t\t\tuniforms.directionalLights.needsUpdate = value;\n\t\t\tuniforms.pointLights.needsUpdate = value;\n\t\t\tuniforms.spotLights.needsUpdate = value;\n\t\t\tuniforms.rectAreaLights.needsUpdate = value;\n\t\t\tuniforms.hemisphereLights.needsUpdate = value;\n\n\t\t}\n\n\t\t// GL state setting\n\n\t\tthis.setFaceCulling = function ( cullFace, frontFaceDirection ) {\n\n\t\t\tstate.setCullFace( cullFace );\n\t\t\tstate.setFlipSided( frontFaceDirection === FrontFaceDirectionCW );\n\n\t\t};\n\n\t\t// Textures\n\n\t\tfunction allocTextureUnit() {\n\n\t\t\tvar textureUnit = _usedTextureUnits;\n\n\t\t\tif ( textureUnit >= capabilities.maxTextures ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures );\n\n\t\t\t}\n\n\t\t\t_usedTextureUnits += 1;\n\n\t\t\treturn textureUnit;\n\n\t\t}\n\n\t\tthis.allocTextureUnit = allocTextureUnit;\n\n\t\t// this.setTexture2D = setTexture2D;\n\t\tthis.setTexture2D = ( function () {\n\n\t\t\tvar warned = false;\n\n\t\t\t// backwards compatibility: peel texture.texture\n\t\t\treturn function setTexture2D( texture, slot ) {\n\n\t\t\t\tif ( texture && texture.isWebGLRenderTarget ) {\n\n\t\t\t\t\tif ( ! warned ) {\n\n\t\t\t\t\t\tconsole.warn( \"THREE.WebGLRenderer.setTexture2D: don't use render targets as textures. Use their .texture property instead.\" );\n\t\t\t\t\t\twarned = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttexture = texture.texture;\n\n\t\t\t\t}\n\n\t\t\t\ttextures.setTexture2D( texture, slot );\n\n\t\t\t};\n\n\t\t}() );\n\n\t\tthis.setTexture = ( function () {\n\n\t\t\tvar warned = false;\n\n\t\t\treturn function setTexture( texture, slot ) {\n\n\t\t\t\tif ( ! warned ) {\n\n\t\t\t\t\tconsole.warn( \"THREE.WebGLRenderer: .setTexture is deprecated, use setTexture2D instead.\" );\n\t\t\t\t\twarned = true;\n\n\t\t\t\t}\n\n\t\t\t\ttextures.setTexture2D( texture, slot );\n\n\t\t\t};\n\n\t\t}() );\n\n\t\tthis.setTextureCube = ( function () {\n\n\t\t\tvar warned = false;\n\n\t\t\treturn function setTextureCube( texture, slot ) {\n\n\t\t\t\t// backwards compatibility: peel texture.texture\n\t\t\t\tif ( texture && texture.isWebGLRenderTargetCube ) {\n\n\t\t\t\t\tif ( ! warned ) {\n\n\t\t\t\t\t\tconsole.warn( \"THREE.WebGLRenderer.setTextureCube: don't use cube render targets as textures. Use their .texture property instead.\" );\n\t\t\t\t\t\twarned = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttexture = texture.texture;\n\n\t\t\t\t}\n\n\t\t\t\t// currently relying on the fact that WebGLRenderTargetCube.texture is a Texture and NOT a CubeTexture\n\t\t\t\t// TODO: unify these code paths\n\t\t\t\tif ( ( texture && texture.isCubeTexture ) ||\n\t\t\t\t\t( Array.isArray( texture.image ) && texture.image.length === 6 ) ) {\n\n\t\t\t\t\t// CompressedTexture can have Array in image :/\n\n\t\t\t\t\t// this function alone should take care of cube textures\n\t\t\t\t\ttextures.setTextureCube( texture, slot );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// assumed: texture property of THREE.WebGLRenderTargetCube\n\n\t\t\t\t\ttextures.setTextureCubeDynamic( texture, slot );\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t}() );\n\n\t\tthis.getRenderTarget = function () {\n\n\t\t\treturn _currentRenderTarget;\n\n\t\t};\n\n\t\tthis.setRenderTarget = function ( renderTarget ) {\n\n\t\t\t_currentRenderTarget = renderTarget;\n\n\t\t\tif ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) {\n\n\t\t\t\ttextures.setupRenderTarget( renderTarget );\n\n\t\t\t}\n\n\t\t\tvar framebuffer = null;\n\t\t\tvar isCube = false;\n\n\t\t\tif ( renderTarget ) {\n\n\t\t\t\tvar __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer;\n\n\t\t\t\tif ( renderTarget.isWebGLRenderTargetCube ) {\n\n\t\t\t\t\tframebuffer = __webglFramebuffer[ renderTarget.activeCubeFace ];\n\t\t\t\t\tisCube = true;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tframebuffer = __webglFramebuffer;\n\n\t\t\t\t}\n\n\t\t\t\t_currentViewport.copy( renderTarget.viewport );\n\t\t\t\t_currentScissor.copy( renderTarget.scissor );\n\t\t\t\t_currentScissorTest = renderTarget.scissorTest;\n\n\t\t\t} else {\n\n\t\t\t\t_currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio );\n\t\t\t\t_currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio );\n\t\t\t\t_currentScissorTest = _scissorTest;\n\n\t\t\t}\n\n\t\t\tif ( _currentFramebuffer !== framebuffer ) {\n\n\t\t\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\t\t\t\t_currentFramebuffer = framebuffer;\n\n\t\t\t}\n\n\t\t\tstate.viewport( _currentViewport );\n\t\t\tstate.scissor( _currentScissor );\n\t\t\tstate.setScissorTest( _currentScissorTest );\n\n\t\t\tif ( isCube ) {\n\n\t\t\t\tvar textureProperties = properties.get( renderTarget.texture );\n\t\t\t\t_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + renderTarget.activeCubeFace, textureProperties.__webglTexture, renderTarget.activeMipMapLevel );\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer ) {\n\n\t\t\tif ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {\n\n\t\t\t\tconsole.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tvar framebuffer = properties.get( renderTarget ).__webglFramebuffer;\n\n\t\t\tif ( framebuffer ) {\n\n\t\t\t\tvar restore = false;\n\n\t\t\t\tif ( framebuffer !== _currentFramebuffer ) {\n\n\t\t\t\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\n\t\t\t\t\trestore = true;\n\n\t\t\t\t}\n\n\t\t\t\ttry {\n\n\t\t\t\t\tvar texture = renderTarget.texture;\n\t\t\t\t\tvar textureFormat = texture.format;\n\t\t\t\t\tvar textureType = texture.type;\n\n\t\t\t\t\tif ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // IE11, Edge and Chrome Mac < 52 (#9513)\n\t\t\t\t\t\t! ( textureType === FloatType && ( extensions.get( 'OES_texture_float' ) || extensions.get( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox\n\t\t\t\t\t\t! ( textureType === HalfFloatType && extensions.get( 'EXT_color_buffer_half_float' ) ) ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) {\n\n\t\t\t\t\t\t// the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)\n\n\t\t\t\t\t\tif ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {\n\n\t\t\t\t\t\t\t_gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tconsole.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' );\n\n\t\t\t\t\t}\n\n\t\t\t\t} finally {\n\n\t\t\t\t\tif ( restore ) {\n\n\t\t\t\t\t\t_gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tfunction FogExp2 ( color, density ) {\n\n\t\tthis.name = '';\n\n\t\tthis.color = new Color( color );\n\t\tthis.density = ( density !== undefined ) ? density : 0.00025;\n\n\t}\n\n\tFogExp2.prototype.isFogExp2 = true;\n\n\tFogExp2.prototype.clone = function () {\n\n\t\treturn new FogExp2( this.color.getHex(), this.density );\n\n\t};\n\n\tFogExp2.prototype.toJSON = function ( meta ) {\n\n\t\treturn {\n\t\t\ttype: 'FogExp2',\n\t\t\tcolor: this.color.getHex(),\n\t\t\tdensity: this.density\n\t\t};\n\n\t};\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tfunction Fog ( color, near, far ) {\n\n\t\tthis.name = '';\n\n\t\tthis.color = new Color( color );\n\n\t\tthis.near = ( near !== undefined ) ? near : 1;\n\t\tthis.far = ( far !== undefined ) ? far : 1000;\n\n\t}\n\n\tFog.prototype.isFog = true;\n\n\tFog.prototype.clone = function () {\n\n\t\treturn new Fog( this.color.getHex(), this.near, this.far );\n\n\t};\n\n\tFog.prototype.toJSON = function ( meta ) {\n\n\t\treturn {\n\t\t\ttype: 'Fog',\n\t\t\tcolor: this.color.getHex(),\n\t\t\tnear: this.near,\n\t\t\tfar: this.far\n\t\t};\n\n\t};\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction Scene () {\n\n\t\tObject3D.call( this );\n\n\t\tthis.type = 'Scene';\n\n\t\tthis.background = null;\n\t\tthis.fog = null;\n\t\tthis.overrideMaterial = null;\n\n\t\tthis.autoUpdate = true; // checked by the renderer\n\n\t}\n\n\tScene.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\t\tconstructor: Scene,\n\n\t\tcopy: function ( source, recursive ) {\n\n\t\t\tObject3D.prototype.copy.call( this, source, recursive );\n\n\t\t\tif ( source.background !== null ) this.background = source.background.clone();\n\t\t\tif ( source.fog !== null ) this.fog = source.fog.clone();\n\t\t\tif ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone();\n\n\t\t\tthis.autoUpdate = source.autoUpdate;\n\t\t\tthis.matrixAutoUpdate = source.matrixAutoUpdate;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\ttoJSON: function ( meta ) {\n\n\t\t\tvar data = Object3D.prototype.toJSON.call( this, meta );\n\n\t\t\tif ( this.background !== null ) data.object.background = this.background.toJSON( meta );\n\t\t\tif ( this.fog !== null ) data.object.fog = this.fog.toJSON();\n\n\t\t\treturn data;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mikael emtinger / http://gomo.se/\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tfunction LensFlare( texture, size, distance, blending, color ) {\n\n\t\tObject3D.call( this );\n\n\t\tthis.lensFlares = [];\n\n\t\tthis.positionScreen = new Vector3();\n\t\tthis.customUpdateCallback = undefined;\n\n\t\tif ( texture !== undefined ) {\n\n\t\t\tthis.add( texture, size, distance, blending, color );\n\n\t\t}\n\n\t}\n\n\tLensFlare.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\t\tconstructor: LensFlare,\n\n\t\tisLensFlare: true,\n\n\t\tcopy: function ( source ) {\n\n\t\t\tObject3D.prototype.copy.call( this, source );\n\n\t\t\tthis.positionScreen.copy( source.positionScreen );\n\t\t\tthis.customUpdateCallback = source.customUpdateCallback;\n\n\t\t\tfor ( var i = 0, l = source.lensFlares.length; i < l; i ++ ) {\n\n\t\t\t\tthis.lensFlares.push( source.lensFlares[ i ] );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tadd: function ( texture, size, distance, blending, color, opacity ) {\n\n\t\t\tif ( size === undefined ) size = - 1;\n\t\t\tif ( distance === undefined ) distance = 0;\n\t\t\tif ( opacity === undefined ) opacity = 1;\n\t\t\tif ( color === undefined ) color = new Color( 0xffffff );\n\t\t\tif ( blending === undefined ) blending = NormalBlending;\n\n\t\t\tdistance = Math.min( distance, Math.max( 0, distance ) );\n\n\t\t\tthis.lensFlares.push( {\n\t\t\t\ttexture: texture,\t// THREE.Texture\n\t\t\t\tsize: size, \t\t// size in pixels (-1 = use texture.width)\n\t\t\t\tdistance: distance, \t// distance (0-1) from light source (0=at light source)\n\t\t\t\tx: 0, y: 0, z: 0,\t// screen position (-1 => 1) z = 0 is in front z = 1 is back\n\t\t\t\tscale: 1, \t\t// scale\n\t\t\t\trotation: 0, \t\t// rotation\n\t\t\t\topacity: opacity,\t// opacity\n\t\t\t\tcolor: color,\t\t// color\n\t\t\t\tblending: blending\t// blending\n\t\t\t} );\n\n\t\t},\n\n\t\t/*\n\t\t * Update lens flares update positions on all flares based on the screen position\n\t\t * Set myLensFlare.customUpdateCallback to alter the flares in your project specific way.\n\t\t */\n\n\t\tupdateLensFlares: function () {\n\n\t\t\tvar f, fl = this.lensFlares.length;\n\t\t\tvar flare;\n\t\t\tvar vecX = - this.positionScreen.x * 2;\n\t\t\tvar vecY = - this.positionScreen.y * 2;\n\n\t\t\tfor ( f = 0; f < fl; f ++ ) {\n\n\t\t\t\tflare = this.lensFlares[ f ];\n\n\t\t\t\tflare.x = this.positionScreen.x + vecX * flare.distance;\n\t\t\t\tflare.y = this.positionScreen.y + vecY * flare.distance;\n\n\t\t\t\tflare.wantedRotation = flare.x * Math.PI * 0.25;\n\t\t\t\tflare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25;\n\n\t\t\t}\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t *\n\t * parameters = {\n\t *  color: <hex>,\n\t *  opacity: <float>,\n\t *  map: new THREE.Texture( <Image> ),\n\t *\n\t *\tuvOffset: new THREE.Vector2(),\n\t *\tuvScale: new THREE.Vector2()\n\t * }\n\t */\n\n\tfunction SpriteMaterial( parameters ) {\n\n\t\tMaterial.call( this );\n\n\t\tthis.type = 'SpriteMaterial';\n\n\t\tthis.color = new Color( 0xffffff );\n\t\tthis.map = null;\n\n\t\tthis.rotation = 0;\n\n\t\tthis.fog = false;\n\t\tthis.lights = false;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tSpriteMaterial.prototype = Object.create( Material.prototype );\n\tSpriteMaterial.prototype.constructor = SpriteMaterial;\n\tSpriteMaterial.prototype.isSpriteMaterial = true;\n\n\tSpriteMaterial.prototype.copy = function ( source ) {\n\n\t\tMaterial.prototype.copy.call( this, source );\n\n\t\tthis.color.copy( source.color );\n\t\tthis.map = source.map;\n\n\t\tthis.rotation = source.rotation;\n\n\t\treturn this;\n\n\t};\n\n\t/**\n\t * @author mikael emtinger / http://gomo.se/\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tfunction Sprite( material ) {\n\n\t\tObject3D.call( this );\n\n\t\tthis.type = 'Sprite';\n\n\t\tthis.material = ( material !== undefined ) ? material : new SpriteMaterial();\n\n\t}\n\n\tSprite.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\t\tconstructor: Sprite,\n\n\t\tisSprite: true,\n\n\t\traycast: ( function () {\n\n\t\t\tvar intersectPoint = new Vector3();\n\t\t\tvar worldPosition = new Vector3();\n\t\t\tvar worldScale = new Vector3();\n\n\t\t\treturn function raycast( raycaster, intersects ) {\n\n\t\t\t\tworldPosition.setFromMatrixPosition( this.matrixWorld );\n\t\t\t\traycaster.ray.closestPointToPoint( worldPosition, intersectPoint );\n\n\t\t\t\tworldScale.setFromMatrixScale( this.matrixWorld );\n\t\t\t\tvar guessSizeSq = worldScale.x * worldScale.y / 4;\n\n\t\t\t\tif ( worldPosition.distanceToSquared( intersectPoint ) > guessSizeSq ) return;\n\n\t\t\t\tvar distance = raycaster.ray.origin.distanceTo( intersectPoint );\n\n\t\t\t\tif ( distance < raycaster.near || distance > raycaster.far ) return;\n\n\t\t\t\tintersects.push( {\n\n\t\t\t\t\tdistance: distance,\n\t\t\t\t\tpoint: intersectPoint.clone(),\n\t\t\t\t\tface: null,\n\t\t\t\t\tobject: this\n\n\t\t\t\t} );\n\n\t\t\t};\n\n\t\t}() ),\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor( this.material ).copy( this );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mikael emtinger / http://gomo.se/\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction LOD() {\n\n\t\tObject3D.call( this );\n\n\t\tthis.type = 'LOD';\n\n\t\tObject.defineProperties( this, {\n\t\t\tlevels: {\n\t\t\t\tenumerable: true,\n\t\t\t\tvalue: []\n\t\t\t}\n\t\t} );\n\n\t}\n\n\tLOD.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\t\tconstructor: LOD,\n\n\t\tcopy: function ( source ) {\n\n\t\t\tObject3D.prototype.copy.call( this, source, false );\n\n\t\t\tvar levels = source.levels;\n\n\t\t\tfor ( var i = 0, l = levels.length; i < l; i ++ ) {\n\n\t\t\t\tvar level = levels[ i ];\n\n\t\t\t\tthis.addLevel( level.object.clone(), level.distance );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\taddLevel: function ( object, distance ) {\n\n\t\t\tif ( distance === undefined ) distance = 0;\n\n\t\t\tdistance = Math.abs( distance );\n\n\t\t\tvar levels = this.levels;\n\n\t\t\tfor ( var l = 0; l < levels.length; l ++ ) {\n\n\t\t\t\tif ( distance < levels[ l ].distance ) {\n\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tlevels.splice( l, 0, { distance: distance, object: object } );\n\n\t\t\tthis.add( object );\n\n\t\t},\n\n\t\tgetObjectForDistance: function ( distance ) {\n\n\t\t\tvar levels = this.levels;\n\n\t\t\tfor ( var i = 1, l = levels.length; i < l; i ++ ) {\n\n\t\t\t\tif ( distance < levels[ i ].distance ) {\n\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn levels[ i - 1 ].object;\n\n\t\t},\n\n\t\traycast: ( function () {\n\n\t\t\tvar matrixPosition = new Vector3();\n\n\t\t\treturn function raycast( raycaster, intersects ) {\n\n\t\t\t\tmatrixPosition.setFromMatrixPosition( this.matrixWorld );\n\n\t\t\t\tvar distance = raycaster.ray.origin.distanceTo( matrixPosition );\n\n\t\t\t\tthis.getObjectForDistance( distance ).raycast( raycaster, intersects );\n\n\t\t\t};\n\n\t\t}() ),\n\n\t\tupdate: function () {\n\n\t\t\tvar v1 = new Vector3();\n\t\t\tvar v2 = new Vector3();\n\n\t\t\treturn function update( camera ) {\n\n\t\t\t\tvar levels = this.levels;\n\n\t\t\t\tif ( levels.length > 1 ) {\n\n\t\t\t\t\tv1.setFromMatrixPosition( camera.matrixWorld );\n\t\t\t\t\tv2.setFromMatrixPosition( this.matrixWorld );\n\n\t\t\t\t\tvar distance = v1.distanceTo( v2 );\n\n\t\t\t\t\tlevels[ 0 ].object.visible = true;\n\n\t\t\t\t\tfor ( var i = 1, l = levels.length; i < l; i ++ ) {\n\n\t\t\t\t\t\tif ( distance >= levels[ i ].distance ) {\n\n\t\t\t\t\t\t\tlevels[ i - 1 ].object.visible = false;\n\t\t\t\t\t\t\tlevels[ i ].object.visible = true;\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfor ( ; i < l; i ++ ) {\n\n\t\t\t\t\t\tlevels[ i ].object.visible = false;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t}(),\n\n\t\ttoJSON: function ( meta ) {\n\n\t\t\tvar data = Object3D.prototype.toJSON.call( this, meta );\n\n\t\t\tdata.object.levels = [];\n\n\t\t\tvar levels = this.levels;\n\n\t\t\tfor ( var i = 0, l = levels.length; i < l; i ++ ) {\n\n\t\t\t\tvar level = levels[ i ];\n\n\t\t\t\tdata.object.levels.push( {\n\t\t\t\t\tobject: level.object.uuid,\n\t\t\t\t\tdistance: level.distance\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mikael emtinger / http://gomo.se/\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author michael guerrero / http://realitymeltdown.com\n\t * @author ikerr / http://verold.com\n\t */\n\n\tfunction Skeleton( bones, boneInverses ) {\n\n\t\t// copy the bone array\n\n\t\tbones = bones || [];\n\n\t\tthis.bones = bones.slice( 0 );\n\t\tthis.boneMatrices = new Float32Array( this.bones.length * 16 );\n\n\t\t// use the supplied bone inverses or calculate the inverses\n\n\t\tif ( boneInverses === undefined ) {\n\n\t\t\tthis.calculateInverses();\n\n\t\t} else {\n\n\t\t\tif ( this.bones.length === boneInverses.length ) {\n\n\t\t\t\tthis.boneInverses = boneInverses.slice( 0 );\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( 'THREE.Skeleton boneInverses is the wrong length.' );\n\n\t\t\t\tthis.boneInverses = [];\n\n\t\t\t\tfor ( var i = 0, il = this.bones.length; i < il; i ++ ) {\n\n\t\t\t\t\tthis.boneInverses.push( new Matrix4() );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tObject.assign( Skeleton.prototype, {\n\n\t\tcalculateInverses: function () {\n\n\t\t\tthis.boneInverses = [];\n\n\t\t\tfor ( var i = 0, il = this.bones.length; i < il; i ++ ) {\n\n\t\t\t\tvar inverse = new Matrix4();\n\n\t\t\t\tif ( this.bones[ i ] ) {\n\n\t\t\t\t\tinverse.getInverse( this.bones[ i ].matrixWorld );\n\n\t\t\t\t}\n\n\t\t\t\tthis.boneInverses.push( inverse );\n\n\t\t\t}\n\n\t\t},\n\n\t\tpose: function () {\n\n\t\t\tvar bone, i, il;\n\n\t\t\t// recover the bind-time world matrices\n\n\t\t\tfor ( i = 0, il = this.bones.length; i < il; i ++ ) {\n\n\t\t\t\tbone = this.bones[ i ];\n\n\t\t\t\tif ( bone ) {\n\n\t\t\t\t\tbone.matrixWorld.getInverse( this.boneInverses[ i ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// compute the local matrices, positions, rotations and scales\n\n\t\t\tfor ( i = 0, il = this.bones.length; i < il; i ++ ) {\n\n\t\t\t\tbone = this.bones[ i ];\n\n\t\t\t\tif ( bone ) {\n\n\t\t\t\t\tif ( bone.parent && bone.parent.isBone ) {\n\n\t\t\t\t\t\tbone.matrix.getInverse( bone.parent.matrixWorld );\n\t\t\t\t\t\tbone.matrix.multiply( bone.matrixWorld );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tbone.matrix.copy( bone.matrixWorld );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbone.matrix.decompose( bone.position, bone.quaternion, bone.scale );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t},\n\n\t\tupdate: ( function () {\n\n\t\t\tvar offsetMatrix = new Matrix4();\n\t\t\tvar identityMatrix = new Matrix4();\n\n\t\t\treturn function update() {\n\n\t\t\t\tvar bones = this.bones;\n\t\t\t\tvar boneInverses = this.boneInverses;\n\t\t\t\tvar boneMatrices = this.boneMatrices;\n\t\t\t\tvar boneTexture = this.boneTexture;\n\n\t\t\t\t// flatten bone matrices to array\n\n\t\t\t\tfor ( var i = 0, il = bones.length; i < il; i ++ ) {\n\n\t\t\t\t\t// compute the offset between the current and the original transform\n\n\t\t\t\t\tvar matrix = bones[ i ] ? bones[ i ].matrixWorld : identityMatrix;\n\n\t\t\t\t\toffsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] );\n\t\t\t\t\toffsetMatrix.toArray( boneMatrices, i * 16 );\n\n\t\t\t\t}\n\n\t\t\t\tif ( boneTexture !== undefined ) {\n\n\t\t\t\t\tboneTexture.needsUpdate = true;\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t} )(),\n\n\t\tclone: function () {\n\n\t\t\treturn new Skeleton( this.bones, this.boneInverses );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mikael emtinger / http://gomo.se/\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author ikerr / http://verold.com\n\t */\n\n\tfunction Bone() {\n\n\t\tObject3D.call( this );\n\n\t\tthis.type = 'Bone';\n\n\t}\n\n\tBone.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\t\tconstructor: Bone,\n\n\t\tisBone: true\n\n\t} );\n\n\t/**\n\t * @author mikael emtinger / http://gomo.se/\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author ikerr / http://verold.com\n\t */\n\n\tfunction SkinnedMesh( geometry, material ) {\n\n\t\tMesh.call( this, geometry, material );\n\n\t\tthis.type = 'SkinnedMesh';\n\n\t\tthis.bindMode = 'attached';\n\t\tthis.bindMatrix = new Matrix4();\n\t\tthis.bindMatrixInverse = new Matrix4();\n\n\t\tvar bones = this.initBones();\n\t\tvar skeleton = new Skeleton( bones );\n\n\t\tthis.bind( skeleton, this.matrixWorld );\n\n\t\tthis.normalizeSkinWeights();\n\n\t}\n\n\tSkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {\n\n\t\tconstructor: SkinnedMesh,\n\n\t\tisSkinnedMesh: true,\n\n\t\tinitBones: function () {\n\n\t\t\tvar bones = [], bone, gbone;\n\t\t\tvar i, il;\n\n\t\t\tif ( this.geometry && this.geometry.bones !== undefined ) {\n\n\t\t\t\t// first, create array of 'Bone' objects from geometry data\n\n\t\t\t\tfor ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) {\n\n\t\t\t\t\tgbone = this.geometry.bones[ i ];\n\n\t\t\t\t\t// create new 'Bone' object\n\n\t\t\t\t\tbone = new Bone();\n\t\t\t\t\tbones.push( bone );\n\n\t\t\t\t\t// apply values\n\n\t\t\t\t\tbone.name = gbone.name;\n\t\t\t\t\tbone.position.fromArray( gbone.pos );\n\t\t\t\t\tbone.quaternion.fromArray( gbone.rotq );\n\t\t\t\t\tif ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl );\n\n\t\t\t\t}\n\n\t\t\t\t// second, create bone hierarchy\n\n\t\t\t\tfor ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) {\n\n\t\t\t\t\tgbone = this.geometry.bones[ i ];\n\n\t\t\t\t\tif ( ( gbone.parent !== - 1 ) && ( gbone.parent !== null ) && ( bones[ gbone.parent ] !== undefined ) ) {\n\n\t\t\t\t\t\t// subsequent bones in the hierarchy\n\n\t\t\t\t\t\tbones[ gbone.parent ].add( bones[ i ] );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// topmost bone, immediate child of the skinned mesh\n\n\t\t\t\t\t\tthis.add( bones[ i ] );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// now the bones are part of the scene graph and children of the skinned mesh.\n\t\t\t// let's update the corresponding matrices\n\n\t\t\tthis.updateMatrixWorld( true );\n\n\t\t\treturn bones;\n\n\t\t},\n\n\t\tbind: function ( skeleton, bindMatrix ) {\n\n\t\t\tthis.skeleton = skeleton;\n\n\t\t\tif ( bindMatrix === undefined ) {\n\n\t\t\t\tthis.updateMatrixWorld( true );\n\n\t\t\t\tthis.skeleton.calculateInverses();\n\n\t\t\t\tbindMatrix = this.matrixWorld;\n\n\t\t\t}\n\n\t\t\tthis.bindMatrix.copy( bindMatrix );\n\t\t\tthis.bindMatrixInverse.getInverse( bindMatrix );\n\n\t\t},\n\n\t\tpose: function () {\n\n\t\t\tthis.skeleton.pose();\n\n\t\t},\n\n\t\tnormalizeSkinWeights: function () {\n\n\t\t\tvar scale, i;\n\n\t\t\tif ( this.geometry && this.geometry.isGeometry ) {\n\n\t\t\t\tfor ( i = 0; i < this.geometry.skinWeights.length; i ++ ) {\n\n\t\t\t\t\tvar sw = this.geometry.skinWeights[ i ];\n\n\t\t\t\t\tscale = 1.0 / sw.lengthManhattan();\n\n\t\t\t\t\tif ( scale !== Infinity ) {\n\n\t\t\t\t\t\tsw.multiplyScalar( scale );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tsw.set( 1, 0, 0, 0 ); // do something reasonable\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else if ( this.geometry && this.geometry.isBufferGeometry ) {\n\n\t\t\t\tvar vec = new Vector4();\n\n\t\t\t\tvar skinWeight = this.geometry.attributes.skinWeight;\n\n\t\t\t\tfor ( i = 0; i < skinWeight.count; i ++ ) {\n\n\t\t\t\t\tvec.x = skinWeight.getX( i );\n\t\t\t\t\tvec.y = skinWeight.getY( i );\n\t\t\t\t\tvec.z = skinWeight.getZ( i );\n\t\t\t\t\tvec.w = skinWeight.getW( i );\n\n\t\t\t\t\tscale = 1.0 / vec.lengthManhattan();\n\n\t\t\t\t\tif ( scale !== Infinity ) {\n\n\t\t\t\t\t\tvec.multiplyScalar( scale );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tvec.set( 1, 0, 0, 0 ); // do something reasonable\n\n\t\t\t\t\t}\n\n\t\t\t\t\tskinWeight.setXYZW( i, vec.x, vec.y, vec.z, vec.w );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t},\n\n\t\tupdateMatrixWorld: function ( force ) {\n\n\t\t\tMesh.prototype.updateMatrixWorld.call( this, force );\n\n\t\t\tif ( this.bindMode === 'attached' ) {\n\n\t\t\t\tthis.bindMatrixInverse.getInverse( this.matrixWorld );\n\n\t\t\t} else if ( this.bindMode === 'detached' ) {\n\n\t\t\t\tthis.bindMatrixInverse.getInverse( this.bindMatrix );\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode );\n\n\t\t\t}\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor( this.geometry, this.material ).copy( this );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author alteredq / http://alteredqualia.com/\n\t *\n\t * parameters = {\n\t *  color: <hex>,\n\t *  opacity: <float>,\n\t *\n\t *  linewidth: <float>,\n\t *  linecap: \"round\",\n\t *  linejoin: \"round\"\n\t * }\n\t */\n\n\tfunction LineBasicMaterial( parameters ) {\n\n\t\tMaterial.call( this );\n\n\t\tthis.type = 'LineBasicMaterial';\n\n\t\tthis.color = new Color( 0xffffff );\n\n\t\tthis.linewidth = 1;\n\t\tthis.linecap = 'round';\n\t\tthis.linejoin = 'round';\n\n\t\tthis.lights = false;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tLineBasicMaterial.prototype = Object.create( Material.prototype );\n\tLineBasicMaterial.prototype.constructor = LineBasicMaterial;\n\n\tLineBasicMaterial.prototype.isLineBasicMaterial = true;\n\n\tLineBasicMaterial.prototype.copy = function ( source ) {\n\n\t\tMaterial.prototype.copy.call( this, source );\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.linewidth = source.linewidth;\n\t\tthis.linecap = source.linecap;\n\t\tthis.linejoin = source.linejoin;\n\n\t\treturn this;\n\n\t};\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction Line( geometry, material, mode ) {\n\n\t\tif ( mode === 1 ) {\n\n\t\t\tconsole.warn( 'THREE.Line: parameter THREE.LinePieces no longer supported. Created THREE.LineSegments instead.' );\n\t\t\treturn new LineSegments( geometry, material );\n\n\t\t}\n\n\t\tObject3D.call( this );\n\n\t\tthis.type = 'Line';\n\n\t\tthis.geometry = geometry !== undefined ? geometry : new BufferGeometry();\n\t\tthis.material = material !== undefined ? material : new LineBasicMaterial( { color: Math.random() * 0xffffff } );\n\n\t}\n\n\tLine.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\t\tconstructor: Line,\n\n\t\tisLine: true,\n\n\t\traycast: ( function () {\n\n\t\t\tvar inverseMatrix = new Matrix4();\n\t\t\tvar ray = new Ray();\n\t\t\tvar sphere = new Sphere();\n\n\t\t\treturn function raycast( raycaster, intersects ) {\n\n\t\t\t\tvar precision = raycaster.linePrecision;\n\t\t\t\tvar precisionSq = precision * precision;\n\n\t\t\t\tvar geometry = this.geometry;\n\t\t\t\tvar matrixWorld = this.matrixWorld;\n\n\t\t\t\t// Checking boundingSphere distance to ray\n\n\t\t\t\tif ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();\n\n\t\t\t\tsphere.copy( geometry.boundingSphere );\n\t\t\t\tsphere.applyMatrix4( matrixWorld );\n\n\t\t\t\tif ( raycaster.ray.intersectsSphere( sphere ) === false ) return;\n\n\t\t\t\t//\n\n\t\t\t\tinverseMatrix.getInverse( matrixWorld );\n\t\t\t\tray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );\n\n\t\t\t\tvar vStart = new Vector3();\n\t\t\t\tvar vEnd = new Vector3();\n\t\t\t\tvar interSegment = new Vector3();\n\t\t\t\tvar interRay = new Vector3();\n\t\t\t\tvar step = (this && this.isLineSegments) ? 2 : 1;\n\n\t\t\t\tif ( geometry.isBufferGeometry ) {\n\n\t\t\t\t\tvar index = geometry.index;\n\t\t\t\t\tvar attributes = geometry.attributes;\n\t\t\t\t\tvar positions = attributes.position.array;\n\n\t\t\t\t\tif ( index !== null ) {\n\n\t\t\t\t\t\tvar indices = index.array;\n\n\t\t\t\t\t\tfor ( var i = 0, l = indices.length - 1; i < l; i += step ) {\n\n\t\t\t\t\t\t\tvar a = indices[ i ];\n\t\t\t\t\t\t\tvar b = indices[ i + 1 ];\n\n\t\t\t\t\t\t\tvStart.fromArray( positions, a * 3 );\n\t\t\t\t\t\t\tvEnd.fromArray( positions, b * 3 );\n\n\t\t\t\t\t\t\tvar distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment );\n\n\t\t\t\t\t\t\tif ( distSq > precisionSq ) continue;\n\n\t\t\t\t\t\t\tinterRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation\n\n\t\t\t\t\t\t\tvar distance = raycaster.ray.origin.distanceTo( interRay );\n\n\t\t\t\t\t\t\tif ( distance < raycaster.near || distance > raycaster.far ) continue;\n\n\t\t\t\t\t\t\tintersects.push( {\n\n\t\t\t\t\t\t\t\tdistance: distance,\n\t\t\t\t\t\t\t\t// What do we want? intersection point on the ray or on the segment??\n\t\t\t\t\t\t\t\t// point: raycaster.ray.at( distance ),\n\t\t\t\t\t\t\t\tpoint: interSegment.clone().applyMatrix4( this.matrixWorld ),\n\t\t\t\t\t\t\t\tindex: i,\n\t\t\t\t\t\t\t\tface: null,\n\t\t\t\t\t\t\t\tfaceIndex: null,\n\t\t\t\t\t\t\t\tobject: this\n\n\t\t\t\t\t\t\t} );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tfor ( var i = 0, l = positions.length / 3 - 1; i < l; i += step ) {\n\n\t\t\t\t\t\t\tvStart.fromArray( positions, 3 * i );\n\t\t\t\t\t\t\tvEnd.fromArray( positions, 3 * i + 3 );\n\n\t\t\t\t\t\t\tvar distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment );\n\n\t\t\t\t\t\t\tif ( distSq > precisionSq ) continue;\n\n\t\t\t\t\t\t\tinterRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation\n\n\t\t\t\t\t\t\tvar distance = raycaster.ray.origin.distanceTo( interRay );\n\n\t\t\t\t\t\t\tif ( distance < raycaster.near || distance > raycaster.far ) continue;\n\n\t\t\t\t\t\t\tintersects.push( {\n\n\t\t\t\t\t\t\t\tdistance: distance,\n\t\t\t\t\t\t\t\t// What do we want? intersection point on the ray or on the segment??\n\t\t\t\t\t\t\t\t// point: raycaster.ray.at( distance ),\n\t\t\t\t\t\t\t\tpoint: interSegment.clone().applyMatrix4( this.matrixWorld ),\n\t\t\t\t\t\t\t\tindex: i,\n\t\t\t\t\t\t\t\tface: null,\n\t\t\t\t\t\t\t\tfaceIndex: null,\n\t\t\t\t\t\t\t\tobject: this\n\n\t\t\t\t\t\t\t} );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( geometry.isGeometry ) {\n\n\t\t\t\t\tvar vertices = geometry.vertices;\n\t\t\t\t\tvar nbVertices = vertices.length;\n\n\t\t\t\t\tfor ( var i = 0; i < nbVertices - 1; i += step ) {\n\n\t\t\t\t\t\tvar distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment );\n\n\t\t\t\t\t\tif ( distSq > precisionSq ) continue;\n\n\t\t\t\t\t\tinterRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation\n\n\t\t\t\t\t\tvar distance = raycaster.ray.origin.distanceTo( interRay );\n\n\t\t\t\t\t\tif ( distance < raycaster.near || distance > raycaster.far ) continue;\n\n\t\t\t\t\t\tintersects.push( {\n\n\t\t\t\t\t\t\tdistance: distance,\n\t\t\t\t\t\t\t// What do we want? intersection point on the ray or on the segment??\n\t\t\t\t\t\t\t// point: raycaster.ray.at( distance ),\n\t\t\t\t\t\t\tpoint: interSegment.clone().applyMatrix4( this.matrixWorld ),\n\t\t\t\t\t\t\tindex: i,\n\t\t\t\t\t\t\tface: null,\n\t\t\t\t\t\t\tfaceIndex: null,\n\t\t\t\t\t\t\tobject: this\n\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t}() ),\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor( this.geometry, this.material ).copy( this );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction LineSegments( geometry, material ) {\n\n\t\tLine.call( this, geometry, material );\n\n\t\tthis.type = 'LineSegments';\n\n\t}\n\n\tLineSegments.prototype = Object.assign( Object.create( Line.prototype ), {\n\n\t\tconstructor: LineSegments,\n\n\t\tisLineSegments: true\n\n\t} );\n\n\t/**\n\t * @author mgreter / http://github.com/mgreter\n\t */\n\n\tfunction LineLoop( geometry, material ) {\n\n\t\tLine.call( this, geometry, material );\n\n\t\tthis.type = 'LineLoop';\n\n\t}\n\n\tLineLoop.prototype = Object.assign( Object.create( Line.prototype ), {\n\n\t\tconstructor: LineLoop,\n\n\t\tisLineLoop: true,\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author alteredq / http://alteredqualia.com/\n\t *\n\t * parameters = {\n\t *  color: <hex>,\n\t *  opacity: <float>,\n\t *  map: new THREE.Texture( <Image> ),\n\t *\n\t *  size: <float>,\n\t *  sizeAttenuation: <bool>\n\t * }\n\t */\n\n\tfunction PointsMaterial( parameters ) {\n\n\t\tMaterial.call( this );\n\n\t\tthis.type = 'PointsMaterial';\n\n\t\tthis.color = new Color( 0xffffff );\n\n\t\tthis.map = null;\n\n\t\tthis.size = 1;\n\t\tthis.sizeAttenuation = true;\n\n\t\tthis.lights = false;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tPointsMaterial.prototype = Object.create( Material.prototype );\n\tPointsMaterial.prototype.constructor = PointsMaterial;\n\n\tPointsMaterial.prototype.isPointsMaterial = true;\n\n\tPointsMaterial.prototype.copy = function ( source ) {\n\n\t\tMaterial.prototype.copy.call( this, source );\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.map = source.map;\n\n\t\tthis.size = source.size;\n\t\tthis.sizeAttenuation = source.sizeAttenuation;\n\n\t\treturn this;\n\n\t};\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tfunction Points( geometry, material ) {\n\n\t\tObject3D.call( this );\n\n\t\tthis.type = 'Points';\n\n\t\tthis.geometry = geometry !== undefined ? geometry : new BufferGeometry();\n\t\tthis.material = material !== undefined ? material : new PointsMaterial( { color: Math.random() * 0xffffff } );\n\n\t}\n\n\tPoints.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\t\tconstructor: Points,\n\n\t\tisPoints: true,\n\n\t\traycast: ( function () {\n\n\t\t\tvar inverseMatrix = new Matrix4();\n\t\t\tvar ray = new Ray();\n\t\t\tvar sphere = new Sphere();\n\n\t\t\treturn function raycast( raycaster, intersects ) {\n\n\t\t\t\tvar object = this;\n\t\t\t\tvar geometry = this.geometry;\n\t\t\t\tvar matrixWorld = this.matrixWorld;\n\t\t\t\tvar threshold = raycaster.params.Points.threshold;\n\n\t\t\t\t// Checking boundingSphere distance to ray\n\n\t\t\t\tif ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();\n\n\t\t\t\tsphere.copy( geometry.boundingSphere );\n\t\t\t\tsphere.applyMatrix4( matrixWorld );\n\t\t\t\tsphere.radius += threshold;\n\n\t\t\t\tif ( raycaster.ray.intersectsSphere( sphere ) === false ) return;\n\n\t\t\t\t//\n\n\t\t\t\tinverseMatrix.getInverse( matrixWorld );\n\t\t\t\tray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );\n\n\t\t\t\tvar localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );\n\t\t\t\tvar localThresholdSq = localThreshold * localThreshold;\n\t\t\t\tvar position = new Vector3();\n\n\t\t\t\tfunction testPoint( point, index ) {\n\n\t\t\t\t\tvar rayPointDistanceSq = ray.distanceSqToPoint( point );\n\n\t\t\t\t\tif ( rayPointDistanceSq < localThresholdSq ) {\n\n\t\t\t\t\t\tvar intersectPoint = ray.closestPointToPoint( point );\n\t\t\t\t\t\tintersectPoint.applyMatrix4( matrixWorld );\n\n\t\t\t\t\t\tvar distance = raycaster.ray.origin.distanceTo( intersectPoint );\n\n\t\t\t\t\t\tif ( distance < raycaster.near || distance > raycaster.far ) return;\n\n\t\t\t\t\t\tintersects.push( {\n\n\t\t\t\t\t\t\tdistance: distance,\n\t\t\t\t\t\t\tdistanceToRay: Math.sqrt( rayPointDistanceSq ),\n\t\t\t\t\t\t\tpoint: intersectPoint.clone(),\n\t\t\t\t\t\t\tindex: index,\n\t\t\t\t\t\t\tface: null,\n\t\t\t\t\t\t\tobject: object\n\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( geometry.isBufferGeometry ) {\n\n\t\t\t\t\tvar index = geometry.index;\n\t\t\t\t\tvar attributes = geometry.attributes;\n\t\t\t\t\tvar positions = attributes.position.array;\n\n\t\t\t\t\tif ( index !== null ) {\n\n\t\t\t\t\t\tvar indices = index.array;\n\n\t\t\t\t\t\tfor ( var i = 0, il = indices.length; i < il; i ++ ) {\n\n\t\t\t\t\t\t\tvar a = indices[ i ];\n\n\t\t\t\t\t\t\tposition.fromArray( positions, a * 3 );\n\n\t\t\t\t\t\t\ttestPoint( position, a );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tfor ( var i = 0, l = positions.length / 3; i < l; i ++ ) {\n\n\t\t\t\t\t\t\tposition.fromArray( positions, i * 3 );\n\n\t\t\t\t\t\t\ttestPoint( position, i );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tvar vertices = geometry.vertices;\n\n\t\t\t\t\tfor ( var i = 0, l = vertices.length; i < l; i ++ ) {\n\n\t\t\t\t\t\ttestPoint( vertices[ i ], i );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t}() ),\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor( this.geometry, this.material ).copy( this );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction Group() {\n\n\t\tObject3D.call( this );\n\n\t\tthis.type = 'Group';\n\n\t}\n\n\tGroup.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\t\tconstructor: Group\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction VideoTexture( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {\n\n\t\tTexture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );\n\n\t\tthis.generateMipmaps = false;\n\n\t\tvar scope = this;\n\n\t\tfunction update() {\n\n\t\t\trequestAnimationFrame( update );\n\n\t\t\tif ( video.readyState >= video.HAVE_CURRENT_DATA ) {\n\n\t\t\t\tscope.needsUpdate = true;\n\n\t\t\t}\n\n\t\t}\n\n\t\tupdate();\n\n\t}\n\n\tVideoTexture.prototype = Object.create( Texture.prototype );\n\tVideoTexture.prototype.constructor = VideoTexture;\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tfunction CompressedTexture( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {\n\n\t\tTexture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );\n\n\t\tthis.image = { width: width, height: height };\n\t\tthis.mipmaps = mipmaps;\n\n\t\t// no flipping for cube textures\n\t\t// (also flipping doesn't work for compressed textures )\n\n\t\tthis.flipY = false;\n\n\t\t// can't generate mipmaps for compressed textures\n\t\t// mips must be embedded in DDS files\n\n\t\tthis.generateMipmaps = false;\n\n\t}\n\n\tCompressedTexture.prototype = Object.create( Texture.prototype );\n\tCompressedTexture.prototype.constructor = CompressedTexture;\n\n\tCompressedTexture.prototype.isCompressedTexture = true;\n\n\t/**\n\t * @author Matt DesLauriers / @mattdesl\n\t * @author atix / arthursilber.de\n\t */\n\n\tfunction DepthTexture( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) {\n\n\t\tformat = format !== undefined ? format : DepthFormat;\n\n\t\tif ( format !== DepthFormat && format !== DepthStencilFormat ) {\n\n\t\t\tthrow new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' );\n\n\t\t}\n\n\t\tif ( type === undefined && format === DepthFormat ) type = UnsignedShortType;\n\t\tif ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type;\n\n\t\tTexture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );\n\n\t\tthis.image = { width: width, height: height };\n\n\t\tthis.magFilter = magFilter !== undefined ? magFilter : NearestFilter;\n\t\tthis.minFilter = minFilter !== undefined ? minFilter : NearestFilter;\n\n\t\tthis.flipY = false;\n\t\tthis.generateMipmaps\t= false;\n\n\t}\n\n\tDepthTexture.prototype = Object.create( Texture.prototype );\n\tDepthTexture.prototype.constructor = DepthTexture;\n\tDepthTexture.prototype.isDepthTexture = true;\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author Mugen87 / https://github.com/Mugen87\n\t */\n\n\tfunction WireframeGeometry( geometry ) {\n\n\t\tBufferGeometry.call( this );\n\n\t\tthis.type = 'WireframeGeometry';\n\n\t\t// buffer\n\n\t\tvar vertices = [];\n\n\t\t// helper variables\n\n\t\tvar i, j, l, o, ol;\n\t\tvar edge = [ 0, 0 ], edges = {}, e, edge1, edge2;\n\t\tvar key, keys = [ 'a', 'b', 'c' ];\n\t\tvar vertex;\n\n\t\t// different logic for Geometry and BufferGeometry\n\n\t\tif ( geometry && geometry.isGeometry ) {\n\n\t\t\t// create a data structure that contains all edges without duplicates\n\n\t\t\tvar faces = geometry.faces;\n\n\t\t\tfor ( i = 0, l = faces.length; i < l; i ++ ) {\n\n\t\t\t\tvar face = faces[ i ];\n\n\t\t\t\tfor ( j = 0; j < 3; j ++ ) {\n\n\t\t\t\t\tedge1 = face[ keys[ j ] ];\n\t\t\t\t\tedge2 = face[ keys[ ( j + 1 ) % 3 ] ];\n\t\t\t\t\tedge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates\n\t\t\t\t\tedge[ 1 ] = Math.max( edge1, edge2 );\n\n\t\t\t\t\tkey = edge[ 0 ] + ',' + edge[ 1 ];\n\n\t\t\t\t\tif ( edges[ key ] === undefined ) {\n\n\t\t\t\t\t\tedges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// generate vertices\n\n\t\t\tfor ( key in edges ) {\n\n\t\t\t\te = edges[ key ];\n\n\t\t\t\tvertex = geometry.vertices[ e.index1 ];\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\tvertex = geometry.vertices[ e.index2 ];\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t}\n\n\t\t} else if ( geometry && geometry.isBufferGeometry ) {\n\n\t\t\tvar position, indices, groups;\n\t\t\tvar group, start, count;\n\t\t\tvar index1, index2;\n\n\t\t\tvertex = new Vector3();\n\n\t\t\tif ( geometry.index !== null ) {\n\n\t\t\t\t// indexed BufferGeometry\n\n\t\t\t\tposition = geometry.attributes.position;\n\t\t\t\tindices = geometry.index;\n\t\t\t\tgroups = geometry.groups;\n\n\t\t\t\tif ( groups.length === 0 ) {\n\n\t\t\t\t\tgroups = [ { start: 0, count: indices.count, materialIndex: 0 } ];\n\n\t\t\t\t}\n\n\t\t\t\t// create a data structure that contains all eges without duplicates\n\n\t\t\t\tfor ( o = 0, ol = groups.length; o < ol; ++ o ) {\n\n\t\t\t\t\tgroup = groups[ o ];\n\n\t\t\t\t\tstart = group.start;\n\t\t\t\t\tcount = group.count;\n\n\t\t\t\t\tfor ( i = start, l = ( start + count ); i < l; i += 3 ) {\n\n\t\t\t\t\t\tfor ( j = 0; j < 3; j ++ ) {\n\n\t\t\t\t\t\t\tedge1 = indices.getX( i + j );\n\t\t\t\t\t\t\tedge2 = indices.getX( i + ( j + 1 ) % 3 );\n\t\t\t\t\t\t\tedge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates\n\t\t\t\t\t\t\tedge[ 1 ] = Math.max( edge1, edge2 );\n\n\t\t\t\t\t\t\tkey = edge[ 0 ] + ',' + edge[ 1 ];\n\n\t\t\t\t\t\t\tif ( edges[ key ] === undefined ) {\n\n\t\t\t\t\t\t\t\tedges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t// generate vertices\n\n\t\t\t\tfor ( key in edges ) {\n\n\t\t\t\t\te = edges[ key ];\n\n\t\t\t\t\tvertex.fromBufferAttribute( position, e.index1 );\n\t\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t\tvertex.fromBufferAttribute( position, e.index2 );\n\t\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// non-indexed BufferGeometry\n\n\t\t\t\tposition = geometry.attributes.position;\n\n\t\t\t\tfor ( i = 0, l = ( position.count / 3 ); i < l; i ++ ) {\n\n\t\t\t\t\tfor ( j = 0; j < 3; j ++ ) {\n\n\t\t\t\t\t\t// three edges per triangle, an edge is represented as (index1, index2)\n\t\t\t\t\t\t// e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)\n\n\t\t\t\t\t\tindex1 = 3 * i + j;\n\t\t\t\t\t\tvertex.fromBufferAttribute( position, index1 );\n\t\t\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t\t\tindex2 = 3 * i + ( ( j + 1 ) % 3 );\n\t\t\t\t\t\tvertex.fromBufferAttribute( position, index2 );\n\t\t\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\n\t}\n\n\tWireframeGeometry.prototype = Object.create( BufferGeometry.prototype );\n\tWireframeGeometry.prototype.constructor = WireframeGeometry;\n\n\t/**\n\t * @author zz85 / https://github.com/zz85\n\t * @author Mugen87 / https://github.com/Mugen87\n\t *\n\t * Parametric Surfaces Geometry\n\t * based on the brilliant article by @prideout http://prideout.net/blog/?p=44\n\t */\n\n\t// ParametricGeometry\n\n\tfunction ParametricGeometry( func, slices, stacks ) {\n\n\t\tGeometry.call( this );\n\n\t\tthis.type = 'ParametricGeometry';\n\n\t\tthis.parameters = {\n\t\t\tfunc: func,\n\t\t\tslices: slices,\n\t\t\tstacks: stacks\n\t\t};\n\n\t\tthis.fromBufferGeometry( new ParametricBufferGeometry( func, slices, stacks ) );\n\t\tthis.mergeVertices();\n\n\t}\n\n\tParametricGeometry.prototype = Object.create( Geometry.prototype );\n\tParametricGeometry.prototype.constructor = ParametricGeometry;\n\n\t// ParametricBufferGeometry\n\n\tfunction ParametricBufferGeometry( func, slices, stacks ) {\n\n\t\tBufferGeometry.call( this );\n\n\t\tthis.type = 'ParametricBufferGeometry';\n\n\t\tthis.parameters = {\n\t\t\tfunc: func,\n\t\t\tslices: slices,\n\t\t\tstacks: stacks\n\t\t};\n\n\t\t// buffers\n\n\t\tvar indices = [];\n\t\tvar vertices = [];\n\t\tvar normals = [];\n\t\tvar uvs = [];\n\n\t\tvar EPS = 0.00001;\n\n\t\tvar normal = new Vector3();\n\n\t\tvar p0 = new Vector3(), p1 = new Vector3();\n\t\tvar pu = new Vector3(), pv = new Vector3();\n\n\t\tvar i, j;\n\n\t\t// generate vertices, normals and uvs\n\n\t\tvar sliceCount = slices + 1;\n\n\t\tfor ( i = 0; i <= stacks; i ++ ) {\n\n\t\t\tvar v = i / stacks;\n\n\t\t\tfor ( j = 0; j <= slices; j ++ ) {\n\n\t\t\t\tvar u = j / slices;\n\n\t\t\t\t// vertex\n\n\t\t\t\tp0 = func( u, v, p0 );\n\t\t\t\tvertices.push( p0.x, p0.y, p0.z );\n\n\t\t\t\t// normal\n\n\t\t\t\t// approximate tangent vectors via finite differences\n\n\t\t\t\tif ( u - EPS >= 0 ) {\n\n\t\t\t\t\tp1 = func( u - EPS, v, p1 );\n\t\t\t\t\tpu.subVectors( p0, p1 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tp1 = func( u + EPS, v, p1 );\n\t\t\t\t\tpu.subVectors( p1, p0 );\n\n\t\t\t\t}\n\n\t\t\t\tif ( v - EPS >= 0 ) {\n\n\t\t\t\t\tp1 = func( u, v - EPS, p1 );\n\t\t\t\t\tpv.subVectors( p0, p1 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tp1 = func( u, v + EPS, p1 );\n\t\t\t\t\tpv.subVectors( p1, p0 );\n\n\t\t\t\t}\n\n\t\t\t\t// cross product of tangent vectors returns surface normal\n\n\t\t\t\tnormal.crossVectors( pu, pv ).normalize();\n\t\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t// uv\n\n\t\t\t\tuvs.push( u, v );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// generate indices\n\n\t\tfor ( i = 0; i < stacks; i ++ ) {\n\n\t\t\tfor ( j = 0; j < slices; j ++ ) {\n\n\t\t\t\tvar a = i * sliceCount + j;\n\t\t\t\tvar b = i * sliceCount + j + 1;\n\t\t\t\tvar c = ( i + 1 ) * sliceCount + j + 1;\n\t\t\t\tvar d = ( i + 1 ) * sliceCount + j;\n\n\t\t\t\t// faces one and two\n\n\t\t\t\tindices.push( a, b, d );\n\t\t\t\tindices.push( b, c, d );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t}\n\n\tParametricBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\n\tParametricBufferGeometry.prototype.constructor = ParametricBufferGeometry;\n\n\t/**\n\t * @author clockworkgeek / https://github.com/clockworkgeek\n\t * @author timothypratley / https://github.com/timothypratley\n\t * @author WestLangley / http://github.com/WestLangley\n\t * @author Mugen87 / https://github.com/Mugen87\n\t */\n\n\t// PolyhedronGeometry\n\n\tfunction PolyhedronGeometry( vertices, indices, radius, detail ) {\n\n\t\tGeometry.call( this );\n\n\t\tthis.type = 'PolyhedronGeometry';\n\n\t\tthis.parameters = {\n\t\t\tvertices: vertices,\n\t\t\tindices: indices,\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t\tthis.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) );\n\t\tthis.mergeVertices();\n\n\t}\n\n\tPolyhedronGeometry.prototype = Object.create( Geometry.prototype );\n\tPolyhedronGeometry.prototype.constructor = PolyhedronGeometry;\n\n\t// PolyhedronBufferGeometry\n\n\tfunction PolyhedronBufferGeometry( vertices, indices, radius, detail ) {\n\n\t\tBufferGeometry.call( this );\n\n\t\tthis.type = 'PolyhedronBufferGeometry';\n\n\t\tthis.parameters = {\n\t\t\tvertices: vertices,\n\t\t\tindices: indices,\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t\tradius = radius || 1;\n\t\tdetail = detail || 0;\n\n\t\t// default buffer data\n\n\t\tvar vertexBuffer = [];\n\t\tvar uvBuffer = [];\n\n\t\t// the subdivision creates the vertex buffer data\n\n\t\tsubdivide( detail );\n\n\t\t// all vertices should lie on a conceptual sphere with a given radius\n\n\t\tappplyRadius( radius );\n\n\t\t// finally, create the uv data\n\n\t\tgenerateUVs();\n\n\t\t// build non-indexed geometry\n\n\t\tthis.addAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );\n\t\tthis.addAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );\n\t\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );\n\n\t\tif ( detail === 0 ) {\n\n\t\t\tthis.computeVertexNormals(); // flat normals\n\n\t\t} else {\n\n\t\t\tthis.normalizeNormals(); // smooth normals\n\n\t\t}\n\n\t\t// helper functions\n\n\t\tfunction subdivide( detail ) {\n\n\t\t\tvar a = new Vector3();\n\t\t\tvar b = new Vector3();\n\t\t\tvar c = new Vector3();\n\n\t\t\t// iterate over all faces and apply a subdivison with the given detail value\n\n\t\t\tfor ( var i = 0; i < indices.length; i += 3 ) {\n\n\t\t\t\t// get the vertices of the face\n\n\t\t\t\tgetVertexByIndex( indices[ i + 0 ], a );\n\t\t\t\tgetVertexByIndex( indices[ i + 1 ], b );\n\t\t\t\tgetVertexByIndex( indices[ i + 2 ], c );\n\n\t\t\t\t// perform subdivision\n\n\t\t\t\tsubdivideFace( a, b, c, detail );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction subdivideFace( a, b, c, detail ) {\n\n\t\t\tvar cols = Math.pow( 2, detail );\n\n\t\t\t// we use this multidimensional array as a data structure for creating the subdivision\n\n\t\t\tvar v = [];\n\n\t\t\tvar i, j;\n\n\t\t\t// construct all of the vertices for this subdivision\n\n\t\t\tfor ( i = 0; i <= cols; i ++ ) {\n\n\t\t\t\tv[ i ] = [];\n\n\t\t\t\tvar aj = a.clone().lerp( c, i / cols );\n\t\t\t\tvar bj = b.clone().lerp( c, i / cols );\n\n\t\t\t\tvar rows = cols - i;\n\n\t\t\t\tfor ( j = 0; j <= rows; j ++ ) {\n\n\t\t\t\t\tif ( j === 0 && i === cols ) {\n\n\t\t\t\t\t\tv[ i ][ j ] = aj;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tv[ i ][ j ] = aj.clone().lerp( bj, j / rows );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// construct all of the faces\n\n\t\t\tfor ( i = 0; i < cols; i ++ ) {\n\n\t\t\t\tfor ( j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {\n\n\t\t\t\t\tvar k = Math.floor( j / 2 );\n\n\t\t\t\t\tif ( j % 2 === 0 ) {\n\n\t\t\t\t\t\tpushVertex( v[ i ][ k + 1 ] );\n\t\t\t\t\t\tpushVertex( v[ i + 1 ][ k ] );\n\t\t\t\t\t\tpushVertex( v[ i ][ k ] );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tpushVertex( v[ i ][ k + 1 ] );\n\t\t\t\t\t\tpushVertex( v[ i + 1 ][ k + 1 ] );\n\t\t\t\t\t\tpushVertex( v[ i + 1 ][ k ] );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction appplyRadius( radius ) {\n\n\t\t\tvar vertex = new Vector3();\n\n\t\t\t// iterate over the entire buffer and apply the radius to each vertex\n\n\t\t\tfor ( var i = 0; i < vertexBuffer.length; i += 3 ) {\n\n\t\t\t\tvertex.x = vertexBuffer[ i + 0 ];\n\t\t\t\tvertex.y = vertexBuffer[ i + 1 ];\n\t\t\t\tvertex.z = vertexBuffer[ i + 2 ];\n\n\t\t\t\tvertex.normalize().multiplyScalar( radius );\n\n\t\t\t\tvertexBuffer[ i + 0 ] = vertex.x;\n\t\t\t\tvertexBuffer[ i + 1 ] = vertex.y;\n\t\t\t\tvertexBuffer[ i + 2 ] = vertex.z;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction generateUVs() {\n\n\t\t\tvar vertex = new Vector3();\n\n\t\t\tfor ( var i = 0; i < vertexBuffer.length; i += 3 ) {\n\n\t\t\t\tvertex.x = vertexBuffer[ i + 0 ];\n\t\t\t\tvertex.y = vertexBuffer[ i + 1 ];\n\t\t\t\tvertex.z = vertexBuffer[ i + 2 ];\n\n\t\t\t\tvar u = azimuth( vertex ) / 2 / Math.PI + 0.5;\n\t\t\t\tvar v = inclination( vertex ) / Math.PI + 0.5;\n\t\t\t\tuvBuffer.push( u, 1 - v );\n\n\t\t\t}\n\n\t\t\tcorrectUVs();\n\n\t\t\tcorrectSeam();\n\n\t\t}\n\n\t\tfunction correctSeam() {\n\n\t\t\t// handle case when face straddles the seam, see #3269\n\n\t\t\tfor ( var i = 0; i < uvBuffer.length; i += 6 ) {\n\n\t\t\t\t// uv data of a single face\n\n\t\t\t\tvar x0 = uvBuffer[ i + 0 ];\n\t\t\t\tvar x1 = uvBuffer[ i + 2 ];\n\t\t\t\tvar x2 = uvBuffer[ i + 4 ];\n\n\t\t\t\tvar max = Math.max( x0, x1, x2 );\n\t\t\t\tvar min = Math.min( x0, x1, x2 );\n\n\t\t\t\t// 0.9 is somewhat arbitrary\n\n\t\t\t\tif ( max > 0.9 && min < 0.1 ) {\n\n\t\t\t\t\tif ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;\n\t\t\t\t\tif ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;\n\t\t\t\t\tif ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction pushVertex( vertex ) {\n\n\t\t\tvertexBuffer.push( vertex.x, vertex.y, vertex.z );\n\n\t\t}\n\n\t\tfunction getVertexByIndex( index, vertex ) {\n\n\t\t\tvar stride = index * 3;\n\n\t\t\tvertex.x = vertices[ stride + 0 ];\n\t\t\tvertex.y = vertices[ stride + 1 ];\n\t\t\tvertex.z = vertices[ stride + 2 ];\n\n\t\t}\n\n\t\tfunction correctUVs() {\n\n\t\t\tvar a = new Vector3();\n\t\t\tvar b = new Vector3();\n\t\t\tvar c = new Vector3();\n\n\t\t\tvar centroid = new Vector3();\n\n\t\t\tvar uvA = new Vector2();\n\t\t\tvar uvB = new Vector2();\n\t\t\tvar uvC = new Vector2();\n\n\t\t\tfor ( var i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {\n\n\t\t\t\ta.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );\n\t\t\t\tb.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );\n\t\t\t\tc.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );\n\n\t\t\t\tuvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );\n\t\t\t\tuvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );\n\t\t\t\tuvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );\n\n\t\t\t\tcentroid.copy( a ).add( b ).add( c ).divideScalar( 3 );\n\n\t\t\t\tvar azi = azimuth( centroid );\n\n\t\t\t\tcorrectUV( uvA, j + 0, a, azi );\n\t\t\t\tcorrectUV( uvB, j + 2, b, azi );\n\t\t\t\tcorrectUV( uvC, j + 4, c, azi );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction correctUV( uv, stride, vector, azimuth ) {\n\n\t\t\tif ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {\n\n\t\t\t\tuvBuffer[ stride ] = uv.x - 1;\n\n\t\t\t}\n\n\t\t\tif ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {\n\n\t\t\t\tuvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// Angle around the Y axis, counter-clockwise when looking from above.\n\n\t\tfunction azimuth( vector ) {\n\n\t\t\treturn Math.atan2( vector.z, - vector.x );\n\n\t\t}\n\n\n\t\t// Angle above the XZ plane.\n\n\t\tfunction inclination( vector ) {\n\n\t\t\treturn Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );\n\n\t\t}\n\n\t}\n\n\tPolyhedronBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\n\tPolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry;\n\n\t/**\n\t * @author timothypratley / https://github.com/timothypratley\n\t * @author Mugen87 / https://github.com/Mugen87\n\t */\n\n\t// TetrahedronGeometry\n\n\tfunction TetrahedronGeometry( radius, detail ) {\n\n\t\tGeometry.call( this );\n\n\t\tthis.type = 'TetrahedronGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t\tthis.fromBufferGeometry( new TetrahedronBufferGeometry( radius, detail ) );\n\t\tthis.mergeVertices();\n\n\t}\n\n\tTetrahedronGeometry.prototype = Object.create( Geometry.prototype );\n\tTetrahedronGeometry.prototype.constructor = TetrahedronGeometry;\n\n\t// TetrahedronBufferGeometry\n\n\tfunction TetrahedronBufferGeometry( radius, detail ) {\n\n\t\tvar vertices = [\n\t\t\t1,  1,  1,   - 1, - 1,  1,   - 1,  1, - 1,    1, - 1, - 1\n\t\t];\n\n\t\tvar indices = [\n\t\t\t2,  1,  0,    0,  3,  2,    1,  3,  0,    2,  3,  1\n\t\t];\n\n\t\tPolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );\n\n\t\tthis.type = 'TetrahedronBufferGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t}\n\n\tTetrahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );\n\tTetrahedronBufferGeometry.prototype.constructor = TetrahedronBufferGeometry;\n\n\t/**\n\t * @author timothypratley / https://github.com/timothypratley\n\t * @author Mugen87 / https://github.com/Mugen87\n\t */\n\n\t// OctahedronGeometry\n\n\tfunction OctahedronGeometry( radius, detail ) {\n\n\t\tGeometry.call( this );\n\n\t\tthis.type = 'OctahedronGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t\tthis.fromBufferGeometry( new OctahedronBufferGeometry( radius, detail ) );\n\t\tthis.mergeVertices();\n\n\t}\n\n\tOctahedronGeometry.prototype = Object.create( Geometry.prototype );\n\tOctahedronGeometry.prototype.constructor = OctahedronGeometry;\n\n\t// OctahedronBufferGeometry\n\n\tfunction OctahedronBufferGeometry( radius, detail ) {\n\n\t\tvar vertices = [\n\t\t\t1, 0, 0,   - 1, 0, 0,    0, 1, 0,    0, - 1, 0,    0, 0, 1,    0, 0, - 1\n\t\t];\n\n\t\tvar indices = [\n\t\t\t0, 2, 4,    0, 4, 3,    0, 3, 5,    0, 5, 2,    1, 2, 5,    1, 5, 3,    1, 3, 4,    1, 4, 2\n\t\t];\n\n\t\tPolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );\n\n\t\tthis.type = 'OctahedronBufferGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t}\n\n\tOctahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );\n\tOctahedronBufferGeometry.prototype.constructor = OctahedronBufferGeometry;\n\n\t/**\n\t * @author timothypratley / https://github.com/timothypratley\n\t * @author Mugen87 / https://github.com/Mugen87\n\t */\n\n\t// IcosahedronGeometry\n\n\tfunction IcosahedronGeometry( radius, detail ) {\n\n\t \tGeometry.call( this );\n\n\t\tthis.type = 'IcosahedronGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t\tthis.fromBufferGeometry( new IcosahedronBufferGeometry( radius, detail ) );\n\t\tthis.mergeVertices();\n\n\t}\n\n\tIcosahedronGeometry.prototype = Object.create( Geometry.prototype );\n\tIcosahedronGeometry.prototype.constructor = IcosahedronGeometry;\n\n\t// IcosahedronBufferGeometry\n\n\tfunction IcosahedronBufferGeometry( radius, detail ) {\n\n\t\tvar t = ( 1 + Math.sqrt( 5 ) ) / 2;\n\n\t\tvar vertices = [\n\t\t\t- 1,  t,  0,    1,  t,  0,   - 1, - t,  0,    1, - t,  0,\n\t\t\t 0, - 1,  t,    0,  1,  t,    0, - 1, - t,    0,  1, - t,\n\t\t\t t,  0, - 1,    t,  0,  1,   - t,  0, - 1,   - t,  0,  1\n\t\t];\n\n\t\tvar indices = [\n\t\t\t 0, 11,  5,    0,  5,  1,    0,  1,  7,    0,  7, 10,    0, 10, 11,\n\t\t\t 1,  5,  9,    5, 11,  4,   11, 10,  2,   10,  7,  6,    7,  1,  8,\n\t\t\t 3,  9,  4,    3,  4,  2,    3,  2,  6,    3,  6,  8,    3,  8,  9,\n\t\t\t 4,  9,  5,    2,  4, 11,    6,  2, 10,    8,  6,  7,    9,  8,  1\n\t\t];\n\n\t\tPolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );\n\n\t\tthis.type = 'IcosahedronBufferGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t}\n\n\tIcosahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );\n\tIcosahedronBufferGeometry.prototype.constructor = IcosahedronBufferGeometry;\n\n\t/**\n\t * @author Abe Pazos / https://hamoid.com\n\t * @author Mugen87 / https://github.com/Mugen87\n\t */\n\n\t// DodecahedronGeometry\n\n\tfunction DodecahedronGeometry( radius, detail ) {\n\n\t\tGeometry.call( this );\n\n\t\tthis.type = 'DodecahedronGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t\tthis.fromBufferGeometry( new DodecahedronBufferGeometry( radius, detail ) );\n\t\tthis.mergeVertices();\n\n\t}\n\n\tDodecahedronGeometry.prototype = Object.create( Geometry.prototype );\n\tDodecahedronGeometry.prototype.constructor = DodecahedronGeometry;\n\n\t// DodecahedronBufferGeometry\n\n\tfunction DodecahedronBufferGeometry( radius, detail ) {\n\n\t\tvar t = ( 1 + Math.sqrt( 5 ) ) / 2;\n\t\tvar r = 1 / t;\n\n\t\tvar vertices = [\n\n\t\t\t// (±1, ±1, ±1)\n\t\t\t- 1, - 1, - 1,    - 1, - 1,  1,\n\t\t\t- 1,  1, - 1,    - 1,  1,  1,\n\t\t\t  1, - 1, - 1,     1, - 1,  1,\n\t\t\t  1,  1, - 1,     1,  1,  1,\n\n\t\t\t// (0, ±1/φ, ±φ)\n\t\t\t 0, - r, - t,     0, - r,  t,\n\t\t\t 0,  r, - t,     0,  r,  t,\n\n\t\t\t// (±1/φ, ±φ, 0)\n\t\t\t- r, - t,  0,    - r,  t,  0,\n\t\t\t r, - t,  0,     r,  t,  0,\n\n\t\t\t// (±φ, 0, ±1/φ)\n\t\t\t- t,  0, - r,     t,  0, - r,\n\t\t\t- t,  0,  r,     t,  0,  r\n\t\t];\n\n\t\tvar indices = [\n\t\t\t 3, 11,  7,      3,  7, 15,      3, 15, 13,\n\t\t\t 7, 19, 17,      7, 17,  6,      7,  6, 15,\n\t\t\t17,  4,  8,     17,  8, 10,     17, 10,  6,\n\t\t\t 8,  0, 16,      8, 16,  2,      8,  2, 10,\n\t\t\t 0, 12,  1,      0,  1, 18,      0, 18, 16,\n\t\t\t 6, 10,  2,      6,  2, 13,      6, 13, 15,\n\t\t\t 2, 16, 18,      2, 18,  3,      2,  3, 13,\n\t\t\t18,  1,  9,     18,  9, 11,     18, 11,  3,\n\t\t\t 4, 14, 12,      4, 12,  0,      4,  0,  8,\n\t\t\t11,  9,  5,     11,  5, 19,     11, 19,  7,\n\t\t\t19,  5, 14,     19, 14,  4,     19,  4, 17,\n\t\t\t 1, 12, 14,      1, 14,  5,      1,  5,  9\n\t\t];\n\n\t\tPolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );\n\n\t\tthis.type = 'DodecahedronBufferGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t}\n\n\tDodecahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );\n\tDodecahedronBufferGeometry.prototype.constructor = DodecahedronBufferGeometry;\n\n\t/**\n\t * @author oosmoxiecode / https://github.com/oosmoxiecode\n\t * @author WestLangley / https://github.com/WestLangley\n\t * @author zz85 / https://github.com/zz85\n\t * @author miningold / https://github.com/miningold\n\t * @author jonobr1 / https://github.com/jonobr1\n\t * @author Mugen87 / https://github.com/Mugen87\n\t *\n\t */\n\n\t// TubeGeometry\n\n\tfunction TubeGeometry( path, tubularSegments, radius, radialSegments, closed, taper ) {\n\n\t\tGeometry.call( this );\n\n\t\tthis.type = 'TubeGeometry';\n\n\t\tthis.parameters = {\n\t\t\tpath: path,\n\t\t\ttubularSegments: tubularSegments,\n\t\t\tradius: radius,\n\t\t\tradialSegments: radialSegments,\n\t\t\tclosed: closed\n\t\t};\n\n\t\tif ( taper !== undefined ) console.warn( 'THREE.TubeGeometry: taper has been removed.' );\n\n\t\tvar bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed );\n\n\t\t// expose internals\n\n\t\tthis.tangents = bufferGeometry.tangents;\n\t\tthis.normals = bufferGeometry.normals;\n\t\tthis.binormals = bufferGeometry.binormals;\n\n\t\t// create geometry\n\n\t\tthis.fromBufferGeometry( bufferGeometry );\n\t\tthis.mergeVertices();\n\n\t}\n\n\tTubeGeometry.prototype = Object.create( Geometry.prototype );\n\tTubeGeometry.prototype.constructor = TubeGeometry;\n\n\t// TubeBufferGeometry\n\n\tfunction TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ) {\n\n\t\tBufferGeometry.call( this );\n\n\t\tthis.type = 'TubeBufferGeometry';\n\n\t\tthis.parameters = {\n\t\t\tpath: path,\n\t\t\ttubularSegments: tubularSegments,\n\t\t\tradius: radius,\n\t\t\tradialSegments: radialSegments,\n\t\t\tclosed: closed\n\t\t};\n\n\t\ttubularSegments = tubularSegments || 64;\n\t\tradius = radius || 1;\n\t\tradialSegments = radialSegments || 8;\n\t\tclosed = closed || false;\n\n\t\tvar frames = path.computeFrenetFrames( tubularSegments, closed );\n\n\t\t// expose internals\n\n\t\tthis.tangents = frames.tangents;\n\t\tthis.normals = frames.normals;\n\t\tthis.binormals = frames.binormals;\n\n\t\t// helper variables\n\n\t\tvar vertex = new Vector3();\n\t\tvar normal = new Vector3();\n\t\tvar uv = new Vector2();\n\n\t\tvar i, j;\n\n\t\t// buffer\n\n\t\tvar vertices = [];\n\t\tvar normals = [];\n\t\tvar uvs = [];\n\t\tvar indices = [];\n\n\t\t// create buffer data\n\n\t\tgenerateBufferData();\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t\t// functions\n\n\t\tfunction generateBufferData() {\n\n\t\t\tfor ( i = 0; i < tubularSegments; i ++ ) {\n\n\t\t\t\tgenerateSegment( i );\n\n\t\t\t}\n\n\t\t\t// if the geometry is not closed, generate the last row of vertices and normals\n\t\t\t// at the regular position on the given path\n\t\t\t//\n\t\t\t// if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)\n\n\t\t\tgenerateSegment( ( closed === false ) ? tubularSegments : 0 );\n\n\t\t\t// uvs are generated in a separate function.\n\t\t\t// this makes it easy compute correct values for closed geometries\n\n\t\t\tgenerateUVs();\n\n\t\t\t// finally create faces\n\n\t\t\tgenerateIndices();\n\n\t\t}\n\n\t\tfunction generateSegment( i ) {\n\n\t\t\t// we use getPointAt to sample evenly distributed points from the given path\n\n\t\t\tvar P = path.getPointAt( i / tubularSegments );\n\n\t\t\t// retrieve corresponding normal and binormal\n\n\t\t\tvar N = frames.normals[ i ];\n\t\t\tvar B = frames.binormals[ i ];\n\n\t\t\t// generate normals and vertices for the current segment\n\n\t\t\tfor ( j = 0; j <= radialSegments; j ++ ) {\n\n\t\t\t\tvar v = j / radialSegments * Math.PI * 2;\n\n\t\t\t\tvar sin =   Math.sin( v );\n\t\t\t\tvar cos = - Math.cos( v );\n\n\t\t\t\t// normal\n\n\t\t\t\tnormal.x = ( cos * N.x + sin * B.x );\n\t\t\t\tnormal.y = ( cos * N.y + sin * B.y );\n\t\t\t\tnormal.z = ( cos * N.z + sin * B.z );\n\t\t\t\tnormal.normalize();\n\n\t\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertex.x = P.x + radius * normal.x;\n\t\t\t\tvertex.y = P.y + radius * normal.y;\n\t\t\t\tvertex.z = P.z + radius * normal.z;\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction generateIndices() {\n\n\t\t\tfor ( j = 1; j <= tubularSegments; j ++ ) {\n\n\t\t\t\tfor ( i = 1; i <= radialSegments; i ++ ) {\n\n\t\t\t\t\tvar a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );\n\t\t\t\t\tvar b = ( radialSegments + 1 ) * j + ( i - 1 );\n\t\t\t\t\tvar c = ( radialSegments + 1 ) * j + i;\n\t\t\t\t\tvar d = ( radialSegments + 1 ) * ( j - 1 ) + i;\n\n\t\t\t\t\t// faces\n\n\t\t\t\t\tindices.push( a, b, d );\n\t\t\t\t\tindices.push( b, c, d );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction generateUVs() {\n\n\t\t\tfor ( i = 0; i <= tubularSegments; i ++ ) {\n\n\t\t\t\tfor ( j = 0; j <= radialSegments; j ++ ) {\n\n\t\t\t\t\tuv.x = i / tubularSegments;\n\t\t\t\t\tuv.y = j / radialSegments;\n\n\t\t\t\t\tuvs.push( uv.x, uv.y );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tTubeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\n\tTubeBufferGeometry.prototype.constructor = TubeBufferGeometry;\n\n\t/**\n\t * @author oosmoxiecode\n\t * @author Mugen87 / https://github.com/Mugen87\n\t *\n\t * based on http://www.blackpawn.com/texts/pqtorus/\n\t */\n\n\t// TorusKnotGeometry\n\n\tfunction TorusKnotGeometry( radius, tube, tubularSegments, radialSegments, p, q, heightScale ) {\n\n\t\tGeometry.call( this );\n\n\t\tthis.type = 'TorusKnotGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\ttube: tube,\n\t\t\ttubularSegments: tubularSegments,\n\t\t\tradialSegments: radialSegments,\n\t\t\tp: p,\n\t\t\tq: q\n\t\t};\n\n\t\tif ( heightScale !== undefined ) console.warn( 'THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.' );\n\n\t\tthis.fromBufferGeometry( new TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) );\n\t\tthis.mergeVertices();\n\n\t}\n\n\tTorusKnotGeometry.prototype = Object.create( Geometry.prototype );\n\tTorusKnotGeometry.prototype.constructor = TorusKnotGeometry;\n\n\t// TorusKnotBufferGeometry\n\n\tfunction TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) {\n\n\t\tBufferGeometry.call( this );\n\n\t\tthis.type = 'TorusKnotBufferGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\ttube: tube,\n\t\t\ttubularSegments: tubularSegments,\n\t\t\tradialSegments: radialSegments,\n\t\t\tp: p,\n\t\t\tq: q\n\t\t};\n\n\t\tradius = radius || 100;\n\t\ttube = tube || 40;\n\t\ttubularSegments = Math.floor( tubularSegments ) || 64;\n\t\tradialSegments = Math.floor( radialSegments ) || 8;\n\t\tp = p || 2;\n\t\tq = q || 3;\n\n\t\t// buffers\n\n\t\tvar indices = [];\n\t\tvar vertices = [];\n\t\tvar normals = [];\n\t\tvar uvs = [];\n\n\t\t// helper variables\n\n\t\tvar i, j;\n\n\t\tvar vertex = new Vector3();\n\t\tvar normal = new Vector3();\n\n\t\tvar P1 = new Vector3();\n\t\tvar P2 = new Vector3();\n\n\t\tvar B = new Vector3();\n\t\tvar T = new Vector3();\n\t\tvar N = new Vector3();\n\n\t\t// generate vertices, normals and uvs\n\n\t\tfor ( i = 0; i <= tubularSegments; ++ i ) {\n\n\t\t\t// the radian \"u\" is used to calculate the position on the torus curve of the current tubular segement\n\n\t\t\tvar u = i / tubularSegments * p * Math.PI * 2;\n\n\t\t\t// now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.\n\t\t\t// these points are used to create a special \"coordinate space\", which is necessary to calculate the correct vertex positions\n\n\t\t\tcalculatePositionOnCurve( u, p, q, radius, P1 );\n\t\t\tcalculatePositionOnCurve( u + 0.01, p, q, radius, P2 );\n\n\t\t\t// calculate orthonormal basis\n\n\t\t\tT.subVectors( P2, P1 );\n\t\t\tN.addVectors( P2, P1 );\n\t\t\tB.crossVectors( T, N );\n\t\t\tN.crossVectors( B, T );\n\n\t\t\t// normalize B, N. T can be ignored, we don't use it\n\n\t\t\tB.normalize();\n\t\t\tN.normalize();\n\n\t\t\tfor ( j = 0; j <= radialSegments; ++ j ) {\n\n\t\t\t\t// now calculate the vertices. they are nothing more than an extrusion of the torus curve.\n\t\t\t\t// because we extrude a shape in the xy-plane, there is no need to calculate a z-value.\n\n\t\t\t\tvar v = j / radialSegments * Math.PI * 2;\n\t\t\t\tvar cx = - tube * Math.cos( v );\n\t\t\t\tvar cy = tube * Math.sin( v );\n\n\t\t\t\t// now calculate the final vertex position.\n\t\t\t\t// first we orient the extrusion with our basis vectos, then we add it to the current position on the curve\n\n\t\t\t\tvertex.x = P1.x + ( cx * N.x + cy * B.x );\n\t\t\t\tvertex.y = P1.y + ( cx * N.y + cy * B.y );\n\t\t\t\tvertex.z = P1.z + ( cx * N.z + cy * B.z );\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t// normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)\n\n\t\t\t\tnormal.subVectors( vertex, P1 ).normalize();\n\n\t\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t// uv\n\n\t\t\t\tuvs.push( i / tubularSegments );\n\t\t\t\tuvs.push( j / radialSegments );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// generate indices\n\n\t\tfor ( j = 1; j <= tubularSegments; j ++ ) {\n\n\t\t\tfor ( i = 1; i <= radialSegments; i ++ ) {\n\n\t\t\t\t// indices\n\n\t\t\t\tvar a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );\n\t\t\t\tvar b = ( radialSegments + 1 ) * j + ( i - 1 );\n\t\t\t\tvar c = ( radialSegments + 1 ) * j + i;\n\t\t\t\tvar d = ( radialSegments + 1 ) * ( j - 1 ) + i;\n\n\t\t\t\t// faces\n\n\t\t\t\tindices.push( a, b, d );\n\t\t\t\tindices.push( b, c, d );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t\t// this function calculates the current position on the torus curve\n\n\t\tfunction calculatePositionOnCurve( u, p, q, radius, position ) {\n\n\t\t\tvar cu = Math.cos( u );\n\t\t\tvar su = Math.sin( u );\n\t\t\tvar quOverP = q / p * u;\n\t\t\tvar cs = Math.cos( quOverP );\n\n\t\t\tposition.x = radius * ( 2 + cs ) * 0.5 * cu;\n\t\t\tposition.y = radius * ( 2 + cs ) * su * 0.5;\n\t\t\tposition.z = radius * Math.sin( quOverP ) * 0.5;\n\n\t\t}\n\n\t}\n\n\tTorusKnotBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\n\tTorusKnotBufferGeometry.prototype.constructor = TorusKnotBufferGeometry;\n\n\t/**\n\t * @author oosmoxiecode\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author Mugen87 / https://github.com/Mugen87\n\t */\n\n\t// TorusGeometry\n\n\tfunction TorusGeometry( radius, tube, radialSegments, tubularSegments, arc ) {\n\n\t\tGeometry.call( this );\n\n\t\tthis.type = 'TorusGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\ttube: tube,\n\t\t\tradialSegments: radialSegments,\n\t\t\ttubularSegments: tubularSegments,\n\t\t\tarc: arc\n\t\t};\n\n\t\tthis.fromBufferGeometry( new TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) );\n\t\tthis.mergeVertices();\n\n\t}\n\n\tTorusGeometry.prototype = Object.create( Geometry.prototype );\n\tTorusGeometry.prototype.constructor = TorusGeometry;\n\n\t// TorusBufferGeometry\n\n\tfunction TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) {\n\n\t\tBufferGeometry.call( this );\n\n\t\tthis.type = 'TorusBufferGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\ttube: tube,\n\t\t\tradialSegments: radialSegments,\n\t\t\ttubularSegments: tubularSegments,\n\t\t\tarc: arc\n\t\t};\n\n\t\tradius = radius || 100;\n\t\ttube = tube || 40;\n\t\tradialSegments = Math.floor( radialSegments ) || 8;\n\t\ttubularSegments = Math.floor( tubularSegments ) || 6;\n\t\tarc = arc || Math.PI * 2;\n\n\t\t// buffers\n\n\t\tvar indices = [];\n\t\tvar vertices = [];\n\t\tvar normals = [];\n\t\tvar uvs = [];\n\n\t\t// helper variables\n\n\t\tvar center = new Vector3();\n\t\tvar vertex = new Vector3();\n\t\tvar normal = new Vector3();\n\n\t\tvar j, i;\n\n\t\t// generate vertices, normals and uvs\n\n\t\tfor ( j = 0; j <= radialSegments; j ++ ) {\n\n\t\t\tfor ( i = 0; i <= tubularSegments; i ++ ) {\n\n\t\t\t\tvar u = i / tubularSegments * arc;\n\t\t\t\tvar v = j / radialSegments * Math.PI * 2;\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );\n\t\t\t\tvertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );\n\t\t\t\tvertex.z = tube * Math.sin( v );\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t// normal\n\n\t\t\t\tcenter.x = radius * Math.cos( u );\n\t\t\t\tcenter.y = radius * Math.sin( u );\n\t\t\t\tnormal.subVectors( vertex, center ).normalize();\n\n\t\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t// uv\n\n\t\t\t\tuvs.push( i / tubularSegments );\n\t\t\t\tuvs.push( j / radialSegments );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// generate indices\n\n\t\tfor ( j = 1; j <= radialSegments; j ++ ) {\n\n\t\t\tfor ( i = 1; i <= tubularSegments; i ++ ) {\n\n\t\t\t\t// indices\n\n\t\t\t\tvar a = ( tubularSegments + 1 ) * j + i - 1;\n\t\t\t\tvar b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;\n\t\t\t\tvar c = ( tubularSegments + 1 ) * ( j - 1 ) + i;\n\t\t\t\tvar d = ( tubularSegments + 1 ) * j + i;\n\n\t\t\t\t// faces\n\n\t\t\t\tindices.push( a, b, d );\n\t\t\t\tindices.push( b, c, d );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t}\n\n\tTorusBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\n\tTorusBufferGeometry.prototype.constructor = TorusBufferGeometry;\n\n\t/**\n\t * @author zz85 / http://www.lab4games.net/zz85/blog\n\t */\n\n\tvar ShapeUtils = {\n\n\t\t// calculate area of the contour polygon\n\n\t\tarea: function ( contour ) {\n\n\t\t\tvar n = contour.length;\n\t\t\tvar a = 0.0;\n\n\t\t\tfor ( var p = n - 1, q = 0; q < n; p = q ++ ) {\n\n\t\t\t\ta += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;\n\n\t\t\t}\n\n\t\t\treturn a * 0.5;\n\n\t\t},\n\n\t\ttriangulate: ( function () {\n\n\t\t\t/**\n\t\t\t * This code is a quick port of code written in C++ which was submitted to\n\t\t\t * flipcode.com by John W. Ratcliff  // July 22, 2000\n\t\t\t * See original code and more information here:\n\t\t\t * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml\n\t\t\t *\n\t\t\t * ported to actionscript by Zevan Rosser\n\t\t\t * www.actionsnippet.com\n\t\t\t *\n\t\t\t * ported to javascript by Joshua Koo\n\t\t\t * http://www.lab4games.net/zz85/blog\n\t\t\t *\n\t\t\t */\n\n\t\t\tfunction snip( contour, u, v, w, n, verts ) {\n\n\t\t\t\tvar p;\n\t\t\t\tvar ax, ay, bx, by;\n\t\t\t\tvar cx, cy, px, py;\n\n\t\t\t\tax = contour[ verts[ u ] ].x;\n\t\t\t\tay = contour[ verts[ u ] ].y;\n\n\t\t\t\tbx = contour[ verts[ v ] ].x;\n\t\t\t\tby = contour[ verts[ v ] ].y;\n\n\t\t\t\tcx = contour[ verts[ w ] ].x;\n\t\t\t\tcy = contour[ verts[ w ] ].y;\n\n\t\t\t\tif ( ( bx - ax ) * ( cy - ay ) - ( by - ay ) * ( cx - ax ) <= 0 ) return false;\n\n\t\t\t\tvar aX, aY, bX, bY, cX, cY;\n\t\t\t\tvar apx, apy, bpx, bpy, cpx, cpy;\n\t\t\t\tvar cCROSSap, bCROSScp, aCROSSbp;\n\n\t\t\t\taX = cx - bx;  aY = cy - by;\n\t\t\t\tbX = ax - cx;  bY = ay - cy;\n\t\t\t\tcX = bx - ax;  cY = by - ay;\n\n\t\t\t\tfor ( p = 0; p < n; p ++ ) {\n\n\t\t\t\t\tpx = contour[ verts[ p ] ].x;\n\t\t\t\t\tpy = contour[ verts[ p ] ].y;\n\n\t\t\t\t\tif ( ( ( px === ax ) && ( py === ay ) ) ||\n\t\t\t\t\t\t ( ( px === bx ) && ( py === by ) ) ||\n\t\t\t\t\t\t ( ( px === cx ) && ( py === cy ) ) )\tcontinue;\n\n\t\t\t\t\tapx = px - ax;  apy = py - ay;\n\t\t\t\t\tbpx = px - bx;  bpy = py - by;\n\t\t\t\t\tcpx = px - cx;  cpy = py - cy;\n\n\t\t\t\t\t// see if p is inside triangle abc\n\n\t\t\t\t\taCROSSbp = aX * bpy - aY * bpx;\n\t\t\t\t\tcCROSSap = cX * apy - cY * apx;\n\t\t\t\t\tbCROSScp = bX * cpy - bY * cpx;\n\n\t\t\t\t\tif ( ( aCROSSbp >= - Number.EPSILON ) && ( bCROSScp >= - Number.EPSILON ) && ( cCROSSap >= - Number.EPSILON ) ) return false;\n\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\n\t\t\t}\n\n\t\t\t// takes in an contour array and returns\n\n\t\t\treturn function triangulate( contour, indices ) {\n\n\t\t\t\tvar n = contour.length;\n\n\t\t\t\tif ( n < 3 ) return null;\n\n\t\t\t\tvar result = [],\n\t\t\t\t\tverts = [],\n\t\t\t\t\tvertIndices = [];\n\n\t\t\t\t/* we want a counter-clockwise polygon in verts */\n\n\t\t\t\tvar u, v, w;\n\n\t\t\t\tif ( ShapeUtils.area( contour ) > 0.0 ) {\n\n\t\t\t\t\tfor ( v = 0; v < n; v ++ ) verts[ v ] = v;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tfor ( v = 0; v < n; v ++ ) verts[ v ] = ( n - 1 ) - v;\n\n\t\t\t\t}\n\n\t\t\t\tvar nv = n;\n\n\t\t\t\t/*  remove nv - 2 vertices, creating 1 triangle every time */\n\n\t\t\t\tvar count = 2 * nv;   /* error detection */\n\n\t\t\t\tfor ( v = nv - 1; nv > 2; ) {\n\n\t\t\t\t\t/* if we loop, it is probably a non-simple polygon */\n\n\t\t\t\t\tif ( ( count -- ) <= 0 ) {\n\n\t\t\t\t\t\t//** Triangulate: ERROR - probable bad polygon!\n\n\t\t\t\t\t\t//throw ( \"Warning, unable to triangulate polygon!\" );\n\t\t\t\t\t\t//return null;\n\t\t\t\t\t\t// Sometimes warning is fine, especially polygons are triangulated in reverse.\n\t\t\t\t\t\tconsole.warn( 'THREE.ShapeUtils: Unable to triangulate polygon! in triangulate()' );\n\n\t\t\t\t\t\tif ( indices ) return vertIndices;\n\t\t\t\t\t\treturn result;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t/* three consecutive vertices in current polygon, <u,v,w> */\n\n\t\t\t\t\tu = v; \t \tif ( nv <= u ) u = 0;     /* previous */\n\t\t\t\t\tv = u + 1;  if ( nv <= v ) v = 0;     /* new v    */\n\t\t\t\t\tw = v + 1;  if ( nv <= w ) w = 0;     /* next     */\n\n\t\t\t\t\tif ( snip( contour, u, v, w, nv, verts ) ) {\n\n\t\t\t\t\t\tvar a, b, c, s, t;\n\n\t\t\t\t\t\t/* true names of the vertices */\n\n\t\t\t\t\t\ta = verts[ u ];\n\t\t\t\t\t\tb = verts[ v ];\n\t\t\t\t\t\tc = verts[ w ];\n\n\t\t\t\t\t\t/* output Triangle */\n\n\t\t\t\t\t\tresult.push( [ contour[ a ],\n\t\t\t\t\t\t\tcontour[ b ],\n\t\t\t\t\t\t\tcontour[ c ] ] );\n\n\n\t\t\t\t\t\tvertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] );\n\n\t\t\t\t\t\t/* remove v from the remaining polygon */\n\n\t\t\t\t\t\tfor ( s = v, t = v + 1; t < nv; s ++, t ++ ) {\n\n\t\t\t\t\t\t\tverts[ s ] = verts[ t ];\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tnv --;\n\n\t\t\t\t\t\t/* reset error detection counter */\n\n\t\t\t\t\t\tcount = 2 * nv;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( indices ) return vertIndices;\n\t\t\t\treturn result;\n\n\t\t\t};\n\n\t\t} )(),\n\n\t\ttriangulateShape: function ( contour, holes ) {\n\n\t\t\tfunction removeDupEndPts(points) {\n\n\t\t\t\tvar l = points.length;\n\n\t\t\t\tif ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) {\n\n\t\t\t\t\tpoints.pop();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tremoveDupEndPts( contour );\n\t\t\tholes.forEach( removeDupEndPts );\n\n\t\t\tfunction point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) {\n\n\t\t\t\t// inOtherPt needs to be collinear to the inSegment\n\t\t\t\tif ( inSegPt1.x !== inSegPt2.x ) {\n\n\t\t\t\t\tif ( inSegPt1.x < inSegPt2.x ) {\n\n\t\t\t\t\t\treturn\t( ( inSegPt1.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt2.x ) );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\treturn\t( ( inSegPt2.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt1.x ) );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( inSegPt1.y < inSegPt2.y ) {\n\n\t\t\t\t\t\treturn\t( ( inSegPt1.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt2.y ) );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\treturn\t( ( inSegPt2.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt1.y ) );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tfunction intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs ) {\n\n\t\t\t\tvar seg1dx = inSeg1Pt2.x - inSeg1Pt1.x,   seg1dy = inSeg1Pt2.y - inSeg1Pt1.y;\n\t\t\t\tvar seg2dx = inSeg2Pt2.x - inSeg2Pt1.x,   seg2dy = inSeg2Pt2.y - inSeg2Pt1.y;\n\n\t\t\t\tvar seg1seg2dx = inSeg1Pt1.x - inSeg2Pt1.x;\n\t\t\t\tvar seg1seg2dy = inSeg1Pt1.y - inSeg2Pt1.y;\n\n\t\t\t\tvar limit\t\t= seg1dy * seg2dx - seg1dx * seg2dy;\n\t\t\t\tvar perpSeg1\t= seg1dy * seg1seg2dx - seg1dx * seg1seg2dy;\n\n\t\t\t\tif ( Math.abs( limit ) > Number.EPSILON ) {\n\n\t\t\t\t\t// not parallel\n\n\t\t\t\t\tvar perpSeg2;\n\t\t\t\t\tif ( limit > 0 ) {\n\n\t\t\t\t\t\tif ( ( perpSeg1 < 0 ) || ( perpSeg1 > limit ) ) \t\treturn [];\n\t\t\t\t\t\tperpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy;\n\t\t\t\t\t\tif ( ( perpSeg2 < 0 ) || ( perpSeg2 > limit ) ) \t\treturn [];\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( ( perpSeg1 > 0 ) || ( perpSeg1 < limit ) ) \t\treturn [];\n\t\t\t\t\t\tperpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy;\n\t\t\t\t\t\tif ( ( perpSeg2 > 0 ) || ( perpSeg2 < limit ) ) \t\treturn [];\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// i.e. to reduce rounding errors\n\t\t\t\t\t// intersection at endpoint of segment#1?\n\t\t\t\t\tif ( perpSeg2 === 0 ) {\n\n\t\t\t\t\t\tif ( ( inExcludeAdjacentSegs ) &&\n\t\t\t\t\t\t\t ( ( perpSeg1 === 0 ) || ( perpSeg1 === limit ) ) )\t\treturn [];\n\t\t\t\t\t\treturn [ inSeg1Pt1 ];\n\n\t\t\t\t\t}\n\t\t\t\t\tif ( perpSeg2 === limit ) {\n\n\t\t\t\t\t\tif ( ( inExcludeAdjacentSegs ) &&\n\t\t\t\t\t\t\t ( ( perpSeg1 === 0 ) || ( perpSeg1 === limit ) ) )\t\treturn [];\n\t\t\t\t\t\treturn [ inSeg1Pt2 ];\n\n\t\t\t\t\t}\n\t\t\t\t\t// intersection at endpoint of segment#2?\n\t\t\t\t\tif ( perpSeg1 === 0 )\t\treturn [ inSeg2Pt1 ];\n\t\t\t\t\tif ( perpSeg1 === limit )\treturn [ inSeg2Pt2 ];\n\n\t\t\t\t\t// return real intersection point\n\t\t\t\t\tvar factorSeg1 = perpSeg2 / limit;\n\t\t\t\t\treturn\t[ { x: inSeg1Pt1.x + factorSeg1 * seg1dx,\n\t\t\t\t\t\t\t\ty: inSeg1Pt1.y + factorSeg1 * seg1dy } ];\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// parallel or collinear\n\t\t\t\t\tif ( ( perpSeg1 !== 0 ) ||\n\t\t\t\t\t\t ( seg2dy * seg1seg2dx !== seg2dx * seg1seg2dy ) ) \t\t\treturn [];\n\n\t\t\t\t\t// they are collinear or degenerate\n\t\t\t\t\tvar seg1Pt = ( ( seg1dx === 0 ) && ( seg1dy === 0 ) );\t// segment1 is just a point?\n\t\t\t\t\tvar seg2Pt = ( ( seg2dx === 0 ) && ( seg2dy === 0 ) );\t// segment2 is just a point?\n\t\t\t\t\t// both segments are points\n\t\t\t\t\tif ( seg1Pt && seg2Pt ) {\n\n\t\t\t\t\t\tif ( ( inSeg1Pt1.x !== inSeg2Pt1.x ) ||\n\t\t\t\t\t\t\t ( inSeg1Pt1.y !== inSeg2Pt1.y ) )\t\treturn [];\t// they are distinct  points\n\t\t\t\t\t\treturn [ inSeg1Pt1 ];                 \t\t\t\t\t\t// they are the same point\n\n\t\t\t\t\t}\n\t\t\t\t\t// segment#1  is a single point\n\t\t\t\t\tif ( seg1Pt ) {\n\n\t\t\t\t\t\tif ( ! point_in_segment_2D_colin( inSeg2Pt1, inSeg2Pt2, inSeg1Pt1 ) )\t\treturn [];\t\t// but not in segment#2\n\t\t\t\t\t\treturn [ inSeg1Pt1 ];\n\n\t\t\t\t\t}\n\t\t\t\t\t// segment#2  is a single point\n\t\t\t\t\tif ( seg2Pt ) {\n\n\t\t\t\t\t\tif ( ! point_in_segment_2D_colin( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1 ) )\t\treturn [];\t\t// but not in segment#1\n\t\t\t\t\t\treturn [ inSeg2Pt1 ];\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// they are collinear segments, which might overlap\n\t\t\t\t\tvar seg1min, seg1max, seg1minVal, seg1maxVal;\n\t\t\t\t\tvar seg2min, seg2max, seg2minVal, seg2maxVal;\n\t\t\t\t\tif ( seg1dx !== 0 ) {\n\n\t\t\t\t\t\t// the segments are NOT on a vertical line\n\t\t\t\t\t\tif ( inSeg1Pt1.x < inSeg1Pt2.x ) {\n\n\t\t\t\t\t\t\tseg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.x;\n\t\t\t\t\t\t\tseg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.x;\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tseg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.x;\n\t\t\t\t\t\t\tseg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.x;\n\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( inSeg2Pt1.x < inSeg2Pt2.x ) {\n\n\t\t\t\t\t\t\tseg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.x;\n\t\t\t\t\t\t\tseg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.x;\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tseg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.x;\n\t\t\t\t\t\t\tseg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.x;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// the segments are on a vertical line\n\t\t\t\t\t\tif ( inSeg1Pt1.y < inSeg1Pt2.y ) {\n\n\t\t\t\t\t\t\tseg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.y;\n\t\t\t\t\t\t\tseg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.y;\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tseg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.y;\n\t\t\t\t\t\t\tseg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.y;\n\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( inSeg2Pt1.y < inSeg2Pt2.y ) {\n\n\t\t\t\t\t\t\tseg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.y;\n\t\t\t\t\t\t\tseg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.y;\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tseg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.y;\n\t\t\t\t\t\t\tseg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.y;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\t\t\t\t\tif ( seg1minVal <= seg2minVal ) {\n\n\t\t\t\t\t\tif ( seg1maxVal <  seg2minVal )\treturn [];\n\t\t\t\t\t\tif ( seg1maxVal === seg2minVal )\t{\n\n\t\t\t\t\t\t\tif ( inExcludeAdjacentSegs )\t\treturn [];\n\t\t\t\t\t\t\treturn [ seg2min ];\n\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( seg1maxVal <= seg2maxVal )\treturn [ seg2min, seg1max ];\n\t\t\t\t\t\treturn\t[ seg2min, seg2max ];\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( seg1minVal >  seg2maxVal )\treturn [];\n\t\t\t\t\t\tif ( seg1minVal === seg2maxVal )\t{\n\n\t\t\t\t\t\t\tif ( inExcludeAdjacentSegs )\t\treturn [];\n\t\t\t\t\t\t\treturn [ seg1min ];\n\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( seg1maxVal <= seg2maxVal )\treturn [ seg1min, seg1max ];\n\t\t\t\t\t\treturn\t[ seg1min, seg2max ];\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tfunction isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt ) {\n\n\t\t\t\t// The order of legs is important\n\n\t\t\t\t// translation of all points, so that Vertex is at (0,0)\n\t\t\t\tvar legFromPtX\t= inLegFromPt.x - inVertex.x,  legFromPtY\t= inLegFromPt.y - inVertex.y;\n\t\t\t\tvar legToPtX\t= inLegToPt.x\t- inVertex.x,  legToPtY\t\t= inLegToPt.y\t- inVertex.y;\n\t\t\t\tvar otherPtX\t= inOtherPt.x\t- inVertex.x,  otherPtY\t\t= inOtherPt.y\t- inVertex.y;\n\n\t\t\t\t// main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg.\n\t\t\t\tvar from2toAngle\t= legFromPtX * legToPtY - legFromPtY * legToPtX;\n\t\t\t\tvar from2otherAngle\t= legFromPtX * otherPtY - legFromPtY * otherPtX;\n\n\t\t\t\tif ( Math.abs( from2toAngle ) > Number.EPSILON ) {\n\n\t\t\t\t\t// angle != 180 deg.\n\n\t\t\t\t\tvar other2toAngle\t\t= otherPtX * legToPtY - otherPtY * legToPtX;\n\t\t\t\t\t// console.log( \"from2to: \" + from2toAngle + \", from2other: \" + from2otherAngle + \", other2to: \" + other2toAngle );\n\n\t\t\t\t\tif ( from2toAngle > 0 ) {\n\n\t\t\t\t\t\t// main angle < 180 deg.\n\t\t\t\t\t\treturn\t( ( from2otherAngle >= 0 ) && ( other2toAngle >= 0 ) );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// main angle > 180 deg.\n\t\t\t\t\t\treturn\t( ( from2otherAngle >= 0 ) || ( other2toAngle >= 0 ) );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// angle == 180 deg.\n\t\t\t\t\t// console.log( \"from2to: 180 deg., from2other: \" + from2otherAngle  );\n\t\t\t\t\treturn\t( from2otherAngle > 0 );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\n\t\t\tfunction removeHoles( contour, holes ) {\n\n\t\t\t\tvar shape = contour.concat(); // work on this shape\n\t\t\t\tvar hole;\n\n\t\t\t\tfunction isCutLineInsideAngles( inShapeIdx, inHoleIdx ) {\n\n\t\t\t\t\t// Check if hole point lies within angle around shape point\n\t\t\t\t\tvar lastShapeIdx = shape.length - 1;\n\n\t\t\t\t\tvar prevShapeIdx = inShapeIdx - 1;\n\t\t\t\t\tif ( prevShapeIdx < 0 )\t\t\tprevShapeIdx = lastShapeIdx;\n\n\t\t\t\t\tvar nextShapeIdx = inShapeIdx + 1;\n\t\t\t\t\tif ( nextShapeIdx > lastShapeIdx )\tnextShapeIdx = 0;\n\n\t\t\t\t\tvar insideAngle = isPointInsideAngle( shape[ inShapeIdx ], shape[ prevShapeIdx ], shape[ nextShapeIdx ], hole[ inHoleIdx ] );\n\t\t\t\t\tif ( ! insideAngle ) {\n\n\t\t\t\t\t\t// console.log( \"Vertex (Shape): \" + inShapeIdx + \", Point: \" + hole[inHoleIdx].x + \"/\" + hole[inHoleIdx].y );\n\t\t\t\t\t\treturn\tfalse;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check if shape point lies within angle around hole point\n\t\t\t\t\tvar lastHoleIdx = hole.length - 1;\n\n\t\t\t\t\tvar prevHoleIdx = inHoleIdx - 1;\n\t\t\t\t\tif ( prevHoleIdx < 0 )\t\t\tprevHoleIdx = lastHoleIdx;\n\n\t\t\t\t\tvar nextHoleIdx = inHoleIdx + 1;\n\t\t\t\t\tif ( nextHoleIdx > lastHoleIdx )\tnextHoleIdx = 0;\n\n\t\t\t\t\tinsideAngle = isPointInsideAngle( hole[ inHoleIdx ], hole[ prevHoleIdx ], hole[ nextHoleIdx ], shape[ inShapeIdx ] );\n\t\t\t\t\tif ( ! insideAngle ) {\n\n\t\t\t\t\t\t// console.log( \"Vertex (Hole): \" + inHoleIdx + \", Point: \" + shape[inShapeIdx].x + \"/\" + shape[inShapeIdx].y );\n\t\t\t\t\t\treturn\tfalse;\n\n\t\t\t\t\t}\n\n\t\t\t\t\treturn\ttrue;\n\n\t\t\t\t}\n\n\t\t\t\tfunction intersectsShapeEdge( inShapePt, inHolePt ) {\n\n\t\t\t\t\t// checks for intersections with shape edges\n\t\t\t\t\tvar sIdx, nextIdx, intersection;\n\t\t\t\t\tfor ( sIdx = 0; sIdx < shape.length; sIdx ++ ) {\n\n\t\t\t\t\t\tnextIdx = sIdx + 1; nextIdx %= shape.length;\n\t\t\t\t\t\tintersection = intersect_segments_2D( inShapePt, inHolePt, shape[ sIdx ], shape[ nextIdx ], true );\n\t\t\t\t\t\tif ( intersection.length > 0 )\t\treturn\ttrue;\n\n\t\t\t\t\t}\n\n\t\t\t\t\treturn\tfalse;\n\n\t\t\t\t}\n\n\t\t\t\tvar indepHoles = [];\n\n\t\t\t\tfunction intersectsHoleEdge( inShapePt, inHolePt ) {\n\n\t\t\t\t\t// checks for intersections with hole edges\n\t\t\t\t\tvar ihIdx, chkHole,\n\t\t\t\t\t\thIdx, nextIdx, intersection;\n\t\t\t\t\tfor ( ihIdx = 0; ihIdx < indepHoles.length; ihIdx ++ ) {\n\n\t\t\t\t\t\tchkHole = holes[ indepHoles[ ihIdx ] ];\n\t\t\t\t\t\tfor ( hIdx = 0; hIdx < chkHole.length; hIdx ++ ) {\n\n\t\t\t\t\t\t\tnextIdx = hIdx + 1; nextIdx %= chkHole.length;\n\t\t\t\t\t\t\tintersection = intersect_segments_2D( inShapePt, inHolePt, chkHole[ hIdx ], chkHole[ nextIdx ], true );\n\t\t\t\t\t\t\tif ( intersection.length > 0 )\t\treturn\ttrue;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\t\t\t\t\treturn\tfalse;\n\n\t\t\t\t}\n\n\t\t\t\tvar holeIndex, shapeIndex,\n\t\t\t\t\tshapePt, holePt,\n\t\t\t\t\tholeIdx, cutKey, failedCuts = [],\n\t\t\t\t\ttmpShape1, tmpShape2,\n\t\t\t\t\ttmpHole1, tmpHole2;\n\n\t\t\t\tfor ( var h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\t\t\tindepHoles.push( h );\n\n\t\t\t\t}\n\n\t\t\t\tvar minShapeIndex = 0;\n\t\t\t\tvar counter = indepHoles.length * 2;\n\t\t\t\twhile ( indepHoles.length > 0 ) {\n\n\t\t\t\t\tcounter --;\n\t\t\t\t\tif ( counter < 0 ) {\n\n\t\t\t\t\t\tconsole.log( 'THREE.ShapeUtils: Infinite Loop! Holes left:\" + indepHoles.length + \", Probably Hole outside Shape!' );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// search for shape-vertex and hole-vertex,\n\t\t\t\t\t// which can be connected without intersections\n\t\t\t\t\tfor ( shapeIndex = minShapeIndex; shapeIndex < shape.length; shapeIndex ++ ) {\n\n\t\t\t\t\t\tshapePt = shape[ shapeIndex ];\n\t\t\t\t\t\tholeIndex\t= - 1;\n\n\t\t\t\t\t\t// search for hole which can be reached without intersections\n\t\t\t\t\t\tfor ( var h = 0; h < indepHoles.length; h ++ ) {\n\n\t\t\t\t\t\t\tholeIdx = indepHoles[ h ];\n\n\t\t\t\t\t\t\t// prevent multiple checks\n\t\t\t\t\t\t\tcutKey = shapePt.x + ':' + shapePt.y + ':' + holeIdx;\n\t\t\t\t\t\t\tif ( failedCuts[ cutKey ] !== undefined )\t\t\tcontinue;\n\n\t\t\t\t\t\t\thole = holes[ holeIdx ];\n\t\t\t\t\t\t\tfor ( var h2 = 0; h2 < hole.length; h2 ++ ) {\n\n\t\t\t\t\t\t\t\tholePt = hole[ h2 ];\n\t\t\t\t\t\t\t\tif ( ! isCutLineInsideAngles( shapeIndex, h2 ) )\t\tcontinue;\n\t\t\t\t\t\t\t\tif ( intersectsShapeEdge( shapePt, holePt ) )\t\tcontinue;\n\t\t\t\t\t\t\t\tif ( intersectsHoleEdge( shapePt, holePt ) )\t\tcontinue;\n\n\t\t\t\t\t\t\t\tholeIndex = h2;\n\t\t\t\t\t\t\t\tindepHoles.splice( h, 1 );\n\n\t\t\t\t\t\t\t\ttmpShape1 = shape.slice( 0, shapeIndex + 1 );\n\t\t\t\t\t\t\t\ttmpShape2 = shape.slice( shapeIndex );\n\t\t\t\t\t\t\t\ttmpHole1 = hole.slice( holeIndex );\n\t\t\t\t\t\t\t\ttmpHole2 = hole.slice( 0, holeIndex + 1 );\n\n\t\t\t\t\t\t\t\tshape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 );\n\n\t\t\t\t\t\t\t\tminShapeIndex = shapeIndex;\n\n\t\t\t\t\t\t\t\t// Debug only, to show the selected cuts\n\t\t\t\t\t\t\t\t// glob_CutLines.push( [ shapePt, holePt ] );\n\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif ( holeIndex >= 0 )\tbreak;\t\t// hole-vertex found\n\n\t\t\t\t\t\t\tfailedCuts[ cutKey ] = true;\t\t\t// remember failure\n\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( holeIndex >= 0 )\tbreak;\t\t// hole-vertex found\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\treturn shape; \t\t\t/* shape with no holes */\n\n\t\t\t}\n\n\n\t\t\tvar i, il, f, face,\n\t\t\t\tkey, index,\n\t\t\t\tallPointsMap = {};\n\n\t\t\t// To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first.\n\n\t\t\tvar allpoints = contour.concat();\n\n\t\t\tfor ( var h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\t\tArray.prototype.push.apply( allpoints, holes[ h ] );\n\n\t\t\t}\n\n\t\t\t//console.log( \"allpoints\",allpoints, allpoints.length );\n\n\t\t\t// prepare all points map\n\n\t\t\tfor ( i = 0, il = allpoints.length; i < il; i ++ ) {\n\n\t\t\t\tkey = allpoints[ i ].x + ':' + allpoints[ i ].y;\n\n\t\t\t\tif ( allPointsMap[ key ] !== undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.ShapeUtils: Duplicate point', key, i );\n\n\t\t\t\t}\n\n\t\t\t\tallPointsMap[ key ] = i;\n\n\t\t\t}\n\n\t\t\t// remove holes by cutting paths to holes and adding them to the shape\n\t\t\tvar shapeWithoutHoles = removeHoles( contour, holes );\n\n\t\t\tvar triangles = ShapeUtils.triangulate( shapeWithoutHoles, false ); // True returns indices for points of spooled shape\n\t\t\t//console.log( \"triangles\",triangles, triangles.length );\n\n\t\t\t// check all face vertices against all points map\n\n\t\t\tfor ( i = 0, il = triangles.length; i < il; i ++ ) {\n\n\t\t\t\tface = triangles[ i ];\n\n\t\t\t\tfor ( f = 0; f < 3; f ++ ) {\n\n\t\t\t\t\tkey = face[ f ].x + ':' + face[ f ].y;\n\n\t\t\t\t\tindex = allPointsMap[ key ];\n\n\t\t\t\t\tif ( index !== undefined ) {\n\n\t\t\t\t\t\tface[ f ] = index;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn triangles.concat();\n\n\t\t},\n\n\t\tisClockWise: function ( pts ) {\n\n\t\t\treturn ShapeUtils.area( pts ) < 0;\n\n\t\t}\n\n\t};\n\n\t/**\n\t * @author zz85 / http://www.lab4games.net/zz85/blog\n\t *\n\t * Creates extruded geometry from a path shape.\n\t *\n\t * parameters = {\n\t *\n\t *  curveSegments: <int>, // number of points on the curves\n\t *  steps: <int>, // number of points for z-side extrusions / used for subdividing segments of extrude spline too\n\t *  amount: <int>, // Depth to extrude the shape\n\t *\n\t *  bevelEnabled: <bool>, // turn on bevel\n\t *  bevelThickness: <float>, // how deep into the original shape bevel goes\n\t *  bevelSize: <float>, // how far from shape outline is bevel\n\t *  bevelSegments: <int>, // number of bevel layers\n\t *\n\t *  extrudePath: <THREE.Curve> // curve to extrude shape along\n\t *  frames: <Object> // containing arrays of tangents, normals, binormals\n\t *\n\t *  UVGenerator: <Object> // object that provides UV generator functions\n\t *\n\t * }\n\t */\n\n\t// ExtrudeGeometry\n\n\tfunction ExtrudeGeometry( shapes, options ) {\n\n\t\tGeometry.call( this );\n\n\t\tthis.type = 'ExtrudeGeometry';\n\n\t\tthis.parameters = {\n\t\t\tshapes: shapes,\n\t\t\toptions: options\n\t\t};\n\n\t\tthis.fromBufferGeometry( new ExtrudeBufferGeometry( shapes, options ) );\n\t\tthis.mergeVertices();\n\n\t}\n\n\tExtrudeGeometry.prototype = Object.create( Geometry.prototype );\n\tExtrudeGeometry.prototype.constructor = ExtrudeGeometry;\n\n\t// ExtrudeBufferGeometry\n\n\tfunction ExtrudeBufferGeometry( shapes, options ) {\n\n\t\tif ( typeof ( shapes ) === \"undefined\" ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tBufferGeometry.call( this );\n\n\t\tthis.type = 'ExtrudeBufferGeometry';\n\n\t\tshapes = Array.isArray( shapes ) ? shapes : [ shapes ];\n\n\t\tthis.addShapeList( shapes, options );\n\n\t\tthis.computeVertexNormals();\n\n\t\t// can't really use automatic vertex normals\n\t\t// as then front and back sides get smoothed too\n\t\t// should do separate smoothing just for sides\n\n\t\t//this.computeVertexNormals();\n\n\t\t//console.log( \"took\", ( Date.now() - startTime ) );\n\n\t}\n\n\tExtrudeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\n\tExtrudeBufferGeometry.prototype.constructor = ExtrudeBufferGeometry;\n\n\tExtrudeBufferGeometry.prototype.getArrays = function () {\n\n\t\tvar positionAttribute = this.getAttribute( \"position\" );\n\t\tvar verticesArray = positionAttribute ? Array.prototype.slice.call( positionAttribute.array ) : [];\n\n\t\tvar uvAttribute = this.getAttribute( \"uv\" );\n\t\tvar uvArray = uvAttribute ? Array.prototype.slice.call( uvAttribute.array ) : [];\n\n\t\tvar IndexAttribute = this.index;\n\t\tvar indicesArray = IndexAttribute ? Array.prototype.slice.call( IndexAttribute.array ) : [];\n\n\t\treturn {\n\t\t\tposition: verticesArray,\n\t\t\tuv: uvArray,\n\t\t\tindex: indicesArray\n\t\t};\n\n\t};\n\n\tExtrudeBufferGeometry.prototype.addShapeList = function ( shapes, options ) {\n\n\t\tvar sl = shapes.length;\n\t\toptions.arrays = this.getArrays();\n\n\t\tfor ( var s = 0; s < sl; s ++ ) {\n\n\t\t\tvar shape = shapes[ s ];\n\t\t\tthis.addShape( shape, options );\n\n\t\t}\n\n\t\tthis.setIndex( options.arrays.index );\n\t\tthis.addAttribute( 'position', new Float32BufferAttribute( options.arrays.position, 3 ) );\n\t\tthis.addAttribute( 'uv', new Float32BufferAttribute( options.arrays.uv, 2 ) );\n\n\t};\n\n\tExtrudeBufferGeometry.prototype.addShape = function ( shape, options ) {\n\n\t\tvar arrays = options.arrays ? options.arrays : this.getArrays();\n\t\tvar verticesArray = arrays.position;\n\t\tvar indicesArray = arrays.index;\n\t\tvar uvArray = arrays.uv;\n\n\t\tvar placeholder = [];\n\n\n\t\tvar amount = options.amount !== undefined ? options.amount : 100;\n\n\t\tvar bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; // 10\n\t\tvar bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; // 8\n\t\tvar bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;\n\n\t\tvar bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false\n\n\t\tvar curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;\n\n\t\tvar steps = options.steps !== undefined ? options.steps : 1;\n\n\t\tvar extrudePath = options.extrudePath;\n\t\tvar extrudePts, extrudeByPath = false;\n\n\t\t// Use default WorldUVGenerator if no UV generators are specified.\n\t\tvar uvgen = options.UVGenerator !== undefined ? options.UVGenerator : ExtrudeGeometry.WorldUVGenerator;\n\n\t\tvar splineTube, binormal, normal, position2;\n\t\tif ( extrudePath ) {\n\n\t\t\textrudePts = extrudePath.getSpacedPoints( steps );\n\n\t\t\textrudeByPath = true;\n\t\t\tbevelEnabled = false; // bevels not supported for path extrusion\n\n\t\t\t// SETUP TNB variables\n\n\t\t\t// TODO1 - have a .isClosed in spline?\n\n\t\t\tsplineTube = options.frames !== undefined ? options.frames : extrudePath.computeFrenetFrames( steps, false );\n\n\t\t\t// console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);\n\n\t\t\tbinormal = new Vector3();\n\t\t\tnormal = new Vector3();\n\t\t\tposition2 = new Vector3();\n\n\t\t}\n\n\t\t// Safeguards if bevels are not enabled\n\n\t\tif ( ! bevelEnabled ) {\n\n\t\t\tbevelSegments = 0;\n\t\t\tbevelThickness = 0;\n\t\t\tbevelSize = 0;\n\n\t\t}\n\n\t\t// Variables initialization\n\n\t\tvar ahole, h, hl; // looping of holes\n\t\tvar scope = this;\n\n\t\tvar shapePoints = shape.extractPoints( curveSegments );\n\n\t\tvar vertices = shapePoints.shape;\n\t\tvar holes = shapePoints.holes;\n\n\t\tvar reverse = ! ShapeUtils.isClockWise( vertices );\n\n\t\tif ( reverse ) {\n\n\t\t\tvertices = vertices.reverse();\n\n\t\t\t// Maybe we should also check if holes are in the opposite direction, just to be safe ...\n\n\t\t\tfor ( h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\t\tahole = holes[ h ];\n\n\t\t\t\tif ( ShapeUtils.isClockWise( ahole ) ) {\n\n\t\t\t\t\tholes[ h ] = ahole.reverse();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\n\t\tvar faces = ShapeUtils.triangulateShape( vertices, holes );\n\n\t\t/* Vertices */\n\n\t\tvar contour = vertices; // vertices has all points but contour has only points of circumference\n\n\t\tfor ( h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\tahole = holes[ h ];\n\n\t\t\tvertices = vertices.concat( ahole );\n\n\t\t}\n\n\n\t\tfunction scalePt2( pt, vec, size ) {\n\n\t\t\tif ( ! vec ) console.error( \"THREE.ExtrudeGeometry: vec does not exist\" );\n\n\t\t\treturn vec.clone().multiplyScalar( size ).add( pt );\n\n\t\t}\n\n\t\tvar b, bs, t, z,\n\t\t\tvert, vlen = vertices.length,\n\t\t\tface, flen = faces.length;\n\n\n\t\t// Find directions for point movement\n\n\n\t\tfunction getBevelVec( inPt, inPrev, inNext ) {\n\n\t\t\t// computes for inPt the corresponding point inPt' on a new contour\n\t\t\t//   shifted by 1 unit (length of normalized vector) to the left\n\t\t\t// if we walk along contour clockwise, this new contour is outside the old one\n\t\t\t//\n\t\t\t// inPt' is the intersection of the two lines parallel to the two\n\t\t\t//  adjacent edges of inPt at a distance of 1 unit on the left side.\n\n\t\t\tvar v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt\n\n\t\t\t// good reading for geometry algorithms (here: line-line intersection)\n\t\t\t// http://geomalgorithms.com/a05-_intersect-1.html\n\n\t\t\tvar v_prev_x = inPt.x - inPrev.x,\n\t\t\t\tv_prev_y = inPt.y - inPrev.y;\n\t\t\tvar v_next_x = inNext.x - inPt.x,\n\t\t\t\tv_next_y = inNext.y - inPt.y;\n\n\t\t\tvar v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y );\n\n\t\t\t// check for collinear edges\n\t\t\tvar collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x );\n\n\t\t\tif ( Math.abs( collinear0 ) > Number.EPSILON ) {\n\n\t\t\t\t// not collinear\n\n\t\t\t\t// length of vectors for normalizing\n\n\t\t\t\tvar v_prev_len = Math.sqrt( v_prev_lensq );\n\t\t\t\tvar v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y );\n\n\t\t\t\t// shift adjacent points by unit vectors to the left\n\n\t\t\t\tvar ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len );\n\t\t\t\tvar ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len );\n\n\t\t\t\tvar ptNextShift_x = ( inNext.x - v_next_y / v_next_len );\n\t\t\t\tvar ptNextShift_y = ( inNext.y + v_next_x / v_next_len );\n\n\t\t\t\t// scaling factor for v_prev to intersection point\n\n\t\t\t\tvar sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y -\n\t\t\t\t\t\t( ptNextShift_y - ptPrevShift_y ) * v_next_x ) /\n\t\t\t\t\t( v_prev_x * v_next_y - v_prev_y * v_next_x );\n\n\t\t\t\t// vector from inPt to intersection point\n\n\t\t\t\tv_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x );\n\t\t\t\tv_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y );\n\n\t\t\t\t// Don't normalize!, otherwise sharp corners become ugly\n\t\t\t\t//  but prevent crazy spikes\n\t\t\t\tvar v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y );\n\t\t\t\tif ( v_trans_lensq <= 2 ) {\n\n\t\t\t\t\treturn new Vector2( v_trans_x, v_trans_y );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tshrink_by = Math.sqrt( v_trans_lensq / 2 );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// handle special case of collinear edges\n\n\t\t\t\tvar direction_eq = false; // assumes: opposite\n\t\t\t\tif ( v_prev_x > Number.EPSILON ) {\n\n\t\t\t\t\tif ( v_next_x > Number.EPSILON ) {\n\n\t\t\t\t\t\tdirection_eq = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( v_prev_x < - Number.EPSILON ) {\n\n\t\t\t\t\t\tif ( v_next_x < - Number.EPSILON ) {\n\n\t\t\t\t\t\t\tdirection_eq = true;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) {\n\n\t\t\t\t\t\t\tdirection_eq = true;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( direction_eq ) {\n\n\t\t\t\t\t// console.log(\"Warning: lines are a straight sequence\");\n\t\t\t\t\tv_trans_x = - v_prev_y;\n\t\t\t\t\tv_trans_y = v_prev_x;\n\t\t\t\t\tshrink_by = Math.sqrt( v_prev_lensq );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// console.log(\"Warning: lines are a straight spike\");\n\t\t\t\t\tv_trans_x = v_prev_x;\n\t\t\t\t\tv_trans_y = v_prev_y;\n\t\t\t\t\tshrink_by = Math.sqrt( v_prev_lensq / 2 );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by );\n\n\t\t}\n\n\n\t\tvar contourMovements = [];\n\n\t\tfor ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {\n\n\t\t\tif ( j === il ) j = 0;\n\t\t\tif ( k === il ) k = 0;\n\n\t\t\t//  (j)---(i)---(k)\n\t\t\t// console.log('i,j,k', i, j , k)\n\n\t\t\tcontourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] );\n\n\t\t}\n\n\t\tvar holesMovements = [],\n\t\t\toneHoleMovements, verticesMovements = contourMovements.concat();\n\n\t\tfor ( h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\tahole = holes[ h ];\n\n\t\t\toneHoleMovements = [];\n\n\t\t\tfor ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {\n\n\t\t\t\tif ( j === il ) j = 0;\n\t\t\t\tif ( k === il ) k = 0;\n\n\t\t\t\t//  (j)---(i)---(k)\n\t\t\t\toneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );\n\n\t\t\t}\n\n\t\t\tholesMovements.push( oneHoleMovements );\n\t\t\tverticesMovements = verticesMovements.concat( oneHoleMovements );\n\n\t\t}\n\n\n\t\t// Loop bevelSegments, 1 for the front, 1 for the back\n\n\t\tfor ( b = 0; b < bevelSegments; b ++ ) {\n\n\t\t\t//for ( b = bevelSegments; b > 0; b -- ) {\n\n\t\t\tt = b / bevelSegments;\n\t\t\tz = bevelThickness * Math.cos( t * Math.PI / 2 );\n\t\t\tbs = bevelSize * Math.sin( t * Math.PI / 2 );\n\n\t\t\t// contract shape\n\n\t\t\tfor ( i = 0, il = contour.length; i < il; i ++ ) {\n\n\t\t\t\tvert = scalePt2( contour[ i ], contourMovements[ i ], bs );\n\n\t\t\t\tv( vert.x, vert.y, - z );\n\n\t\t\t}\n\n\t\t\t// expand holes\n\n\t\t\tfor ( h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\t\tahole = holes[ h ];\n\t\t\t\toneHoleMovements = holesMovements[ h ];\n\n\t\t\t\tfor ( i = 0, il = ahole.length; i < il; i ++ ) {\n\n\t\t\t\t\tvert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );\n\n\t\t\t\t\tv( vert.x, vert.y, - z );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tbs = bevelSize;\n\n\t\t// Back facing vertices\n\n\t\tfor ( i = 0; i < vlen; i ++ ) {\n\n\t\t\tvert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];\n\n\t\t\tif ( ! extrudeByPath ) {\n\n\t\t\t\tv( vert.x, vert.y, 0 );\n\n\t\t\t} else {\n\n\t\t\t\t// v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );\n\n\t\t\t\tnormal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x );\n\t\t\t\tbinormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y );\n\n\t\t\t\tposition2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal );\n\n\t\t\t\tv( position2.x, position2.y, position2.z );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// Add stepped vertices...\n\t\t// Including front facing vertices\n\n\t\tvar s;\n\n\t\tfor ( s = 1; s <= steps; s ++ ) {\n\n\t\t\tfor ( i = 0; i < vlen; i ++ ) {\n\n\t\t\t\tvert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];\n\n\t\t\t\tif ( ! extrudeByPath ) {\n\n\t\t\t\t\tv( vert.x, vert.y, amount / steps * s );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );\n\n\t\t\t\t\tnormal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x );\n\t\t\t\t\tbinormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y );\n\n\t\t\t\t\tposition2.copy( extrudePts[ s ] ).add( normal ).add( binormal );\n\n\t\t\t\t\tv( position2.x, position2.y, position2.z );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\n\t\t// Add bevel segments planes\n\n\t\t//for ( b = 1; b <= bevelSegments; b ++ ) {\n\t\tfor ( b = bevelSegments - 1; b >= 0; b -- ) {\n\n\t\t\tt = b / bevelSegments;\n\t\t\tz = bevelThickness * Math.cos( t * Math.PI / 2 );\n\t\t\tbs = bevelSize * Math.sin( t * Math.PI / 2 );\n\n\t\t\t// contract shape\n\n\t\t\tfor ( i = 0, il = contour.length; i < il; i ++ ) {\n\n\t\t\t\tvert = scalePt2( contour[ i ], contourMovements[ i ], bs );\n\t\t\t\tv( vert.x, vert.y, amount + z );\n\n\t\t\t}\n\n\t\t\t// expand holes\n\n\t\t\tfor ( h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\t\tahole = holes[ h ];\n\t\t\t\toneHoleMovements = holesMovements[ h ];\n\n\t\t\t\tfor ( i = 0, il = ahole.length; i < il; i ++ ) {\n\n\t\t\t\t\tvert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );\n\n\t\t\t\t\tif ( ! extrudeByPath ) {\n\n\t\t\t\t\t\tv( vert.x, vert.y, amount + z );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tv( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t/* Faces */\n\n\t\t// Top and bottom faces\n\n\t\tbuildLidFaces();\n\n\t\t// Sides faces\n\n\t\tbuildSideFaces();\n\n\n\t\t/////  Internal functions\n\n\t\tfunction buildLidFaces() {\n\n\t\t\tvar start = verticesArray.length/3;\n\n\t\t\tif ( bevelEnabled ) {\n\n\t\t\t\tvar layer = 0; // steps + 1\n\t\t\t\tvar offset = vlen * layer;\n\n\t\t\t\t// Bottom faces\n\n\t\t\t\tfor ( i = 0; i < flen; i ++ ) {\n\n\t\t\t\t\tface = faces[ i ];\n\t\t\t\t\tf3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset );\n\n\t\t\t\t}\n\n\t\t\t\tlayer = steps + bevelSegments * 2;\n\t\t\t\toffset = vlen * layer;\n\n\t\t\t\t// Top faces\n\n\t\t\t\tfor ( i = 0; i < flen; i ++ ) {\n\n\t\t\t\t\tface = faces[ i ];\n\t\t\t\t\tf3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// Bottom faces\n\n\t\t\t\tfor ( i = 0; i < flen; i ++ ) {\n\n\t\t\t\t\tface = faces[ i ];\n\t\t\t\t\tf3( face[ 2 ], face[ 1 ], face[ 0 ] );\n\n\t\t\t\t}\n\n\t\t\t\t// Top faces\n\n\t\t\t\tfor ( i = 0; i < flen; i ++ ) {\n\n\t\t\t\t\tface = faces[ i ];\n\t\t\t\t\tf3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tscope.addGroup( start, verticesArray.length/3 -start, options.material !== undefined ? options.material : 0);\n\n\t\t}\n\n\t\t// Create faces for the z-sides of the shape\n\n\t\tfunction buildSideFaces() {\n\n\t\t\tvar start = verticesArray.length/3;\n\t\t\tvar layeroffset = 0;\n\t\t\tsidewalls( contour, layeroffset );\n\t\t\tlayeroffset += contour.length;\n\n\t\t\tfor ( h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\t\tahole = holes[ h ];\n\t\t\t\tsidewalls( ahole, layeroffset );\n\n\t\t\t\t//, true\n\t\t\t\tlayeroffset += ahole.length;\n\n\t\t\t}\n\n\n\t\t\tscope.addGroup( start, verticesArray.length/3 -start, options.extrudeMaterial !== undefined ? options.extrudeMaterial : 1);\n\n\n\t\t}\n\n\t\tfunction sidewalls( contour, layeroffset ) {\n\n\t\t\tvar j, k;\n\t\t\ti = contour.length;\n\n\t\t\twhile ( -- i >= 0 ) {\n\n\t\t\t\tj = i;\n\t\t\t\tk = i - 1;\n\t\t\t\tif ( k < 0 ) k = contour.length - 1;\n\n\t\t\t\t//console.log('b', i,j, i-1, k,vertices.length);\n\n\t\t\t\tvar s = 0,\n\t\t\t\t\tsl = steps + bevelSegments * 2;\n\n\t\t\t\tfor ( s = 0; s < sl; s ++ ) {\n\n\t\t\t\t\tvar slen1 = vlen * s;\n\t\t\t\t\tvar slen2 = vlen * ( s + 1 );\n\n\t\t\t\t\tvar a = layeroffset + j + slen1,\n\t\t\t\t\t\tb = layeroffset + k + slen1,\n\t\t\t\t\t\tc = layeroffset + k + slen2,\n\t\t\t\t\t\td = layeroffset + j + slen2;\n\n\t\t\t\t\tf4( a, b, c, d, contour, s, sl, j, k );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction v( x, y, z ) {\n\n\t\t\tplaceholder.push( x );\n\t\t\tplaceholder.push( y );\n\t\t\tplaceholder.push( z );\n\n\t\t}\n\n\n\t\tfunction f3( a, b, c ) {\n\n\t\t\taddVertex( a );\n\t\t\taddVertex( b );\n\t\t\taddVertex( c );\n\n\t\t\tvar nextIndex = verticesArray.length / 3;\n\t\t\tvar uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 );\n\n\t\t\taddUV( uvs[ 0 ] );\n\t\t\taddUV( uvs[ 1 ] );\n\t\t\taddUV( uvs[ 2 ] );\n\n\t\t}\n\n\t\tfunction f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) {\n\n\t\t\taddVertex( a );\n\t\t\taddVertex( b );\n\t\t\taddVertex( d );\n\n\t\t\taddVertex( b );\n\t\t\taddVertex( c );\n\t\t\taddVertex( d );\n\n\n\t\t\tvar nextIndex = verticesArray.length / 3;\n\t\t\tvar uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 );\n\n\t\t\taddUV( uvs[ 0 ] );\n\t\t\taddUV( uvs[ 1 ] );\n\t\t\taddUV( uvs[ 3 ] );\n\n\t\t\taddUV( uvs[ 1 ] );\n\t\t\taddUV( uvs[ 2 ] );\n\t\t\taddUV( uvs[ 3 ] );\n\n\t\t}\n\n\t\tfunction addVertex( index ) {\n\n\t\t\tindicesArray.push( verticesArray.length / 3 );\n\t\t\tverticesArray.push( placeholder[ index * 3 + 0 ] );\n\t\t\tverticesArray.push( placeholder[ index * 3 + 1 ] );\n\t\t\tverticesArray.push( placeholder[ index * 3 + 2 ] );\n\n\t\t}\n\n\n\t\tfunction addUV( vector2 ) {\n\n\t\t\tuvArray.push( vector2.x );\n\t\t\tuvArray.push( vector2.y );\n\n\t\t}\n\n\t\tif ( ! options.arrays ) {\n\n\t\t\tthis.setIndex( indicesArray );\n\t\t\tthis.addAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) );\n\t\t\tthis.addAttribute( 'uv', new Float32BufferAttribute( options.arrays.uv, 2 ) );\n\n\t\t}\n\n\t};\n\n\tExtrudeGeometry.WorldUVGenerator = {\n\n\t\tgenerateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) {\n\n\t\t\tvar a_x = vertices[ indexA * 3 ];\n\t\t\tvar a_y = vertices[ indexA * 3 + 1 ];\n\t\t\tvar b_x = vertices[ indexB * 3 ];\n\t\t\tvar b_y = vertices[ indexB * 3 + 1 ];\n\t\t\tvar c_x = vertices[ indexC * 3 ];\n\t\t\tvar c_y = vertices[ indexC * 3 + 1 ];\n\n\t\t\treturn [\n\t\t\t\tnew Vector2( a_x, a_y ),\n\t\t\t\tnew Vector2( b_x, b_y ),\n\t\t\t\tnew Vector2( c_x, c_y )\n\t\t\t];\n\n\t\t},\n\n\t\tgenerateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) {\n\n\t\t\tvar a_x = vertices[ indexA * 3 ];\n\t\t\tvar a_y = vertices[ indexA * 3 + 1 ];\n\t\t\tvar a_z = vertices[ indexA * 3 + 2 ];\n\t\t\tvar b_x = vertices[ indexB * 3 ];\n\t\t\tvar b_y = vertices[ indexB * 3 + 1 ];\n\t\t\tvar b_z = vertices[ indexB * 3 + 2 ];\n\t\t\tvar c_x = vertices[ indexC * 3 ];\n\t\t\tvar c_y = vertices[ indexC * 3 + 1 ];\n\t\t\tvar c_z = vertices[ indexC * 3 + 2 ];\n\t\t\tvar d_x = vertices[ indexD * 3 ];\n\t\t\tvar d_y = vertices[ indexD * 3 + 1 ];\n\t\t\tvar d_z = vertices[ indexD * 3 + 2 ];\n\n\t\t\tif ( Math.abs( a_y - b_y ) < 0.01 ) {\n\n\t\t\t\treturn [\n\t\t\t\t\tnew Vector2( a_x, 1 - a_z ),\n\t\t\t\t\tnew Vector2( b_x, 1 - b_z ),\n\t\t\t\t\tnew Vector2( c_x, 1 - c_z ),\n\t\t\t\t\tnew Vector2( d_x, 1 - d_z )\n\t\t\t\t];\n\n\t\t\t} else {\n\n\t\t\t\treturn [\n\t\t\t\t\tnew Vector2( a_y, 1 - a_z ),\n\t\t\t\t\tnew Vector2( b_y, 1 - b_z ),\n\t\t\t\t\tnew Vector2( c_y, 1 - c_z ),\n\t\t\t\t\tnew Vector2( d_y, 1 - d_z )\n\t\t\t\t];\n\n\t\t\t}\n\n\t\t}\n\t};\n\n\t/**\n\t * @author zz85 / http://www.lab4games.net/zz85/blog\n\t * @author alteredq / http://alteredqualia.com/\n\t *\n\t * Text = 3D Text\n\t *\n\t * parameters = {\n\t *  font: <THREE.Font>, // font\n\t *\n\t *  size: <float>, // size of the text\n\t *  height: <float>, // thickness to extrude text\n\t *  curveSegments: <int>, // number of points on the curves\n\t *\n\t *  bevelEnabled: <bool>, // turn on bevel\n\t *  bevelThickness: <float>, // how deep into text bevel goes\n\t *  bevelSize: <float> // how far from text outline is bevel\n\t * }\n\t */\n\n\t// TextGeometry\n\n\tfunction TextGeometry(  text, parameters ) {\n\n\t\tGeometry.call( this );\n\n\t\tthis.type = 'TextGeometry';\n\n\t\tthis.parameters = {\n\t\t\ttext: text,\n\t\t\tparameters: parameters\n\t\t};\n\n\t\tthis.fromBufferGeometry( new TextBufferGeometry( text, parameters ) );\n\t\tthis.mergeVertices();\n\n\t}\n\n\tTextGeometry.prototype = Object.create( Geometry.prototype );\n\tTextGeometry.prototype.constructor = TextGeometry;\n\n\t// TextBufferGeometry\n\n\tfunction TextBufferGeometry( text, parameters ) {\n\n\t\tparameters = parameters || {};\n\n\t\tvar font = parameters.font;\n\n\t\tif ( ! ( font && font.isFont ) ) {\n\n\t\t\tconsole.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' );\n\t\t\treturn new Geometry();\n\n\t\t}\n\n\t\tvar shapes = font.generateShapes( text, parameters.size, parameters.curveSegments );\n\n\t\t// translate parameters to ExtrudeGeometry API\n\n\t\tparameters.amount = parameters.height !== undefined ? parameters.height : 50;\n\n\t\t// defaults\n\n\t\tif ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10;\n\t\tif ( parameters.bevelSize === undefined ) parameters.bevelSize = 8;\n\t\tif ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false;\n\n\t\tExtrudeBufferGeometry.call( this, shapes, parameters );\n\n\t\tthis.type = 'TextBufferGeometry';\n\n\t}\n\n\tTextBufferGeometry.prototype = Object.create( ExtrudeBufferGeometry.prototype );\n\tTextBufferGeometry.prototype.constructor = TextBufferGeometry;\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author benaadams / https://twitter.com/ben_a_adams\n\t * @author Mugen87 / https://github.com/Mugen87\n\t */\n\n\t// SphereGeometry\n\n\tfunction SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {\n\n\t\tGeometry.call( this );\n\n\t\tthis.type = 'SphereGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\twidthSegments: widthSegments,\n\t\t\theightSegments: heightSegments,\n\t\t\tphiStart: phiStart,\n\t\t\tphiLength: phiLength,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t\tthis.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) );\n\t\tthis.mergeVertices();\n\n\t}\n\n\tSphereGeometry.prototype = Object.create( Geometry.prototype );\n\tSphereGeometry.prototype.constructor = SphereGeometry;\n\n\t// SphereBufferGeometry\n\n\tfunction SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {\n\n\t\tBufferGeometry.call( this );\n\n\t\tthis.type = 'SphereBufferGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\twidthSegments: widthSegments,\n\t\t\theightSegments: heightSegments,\n\t\t\tphiStart: phiStart,\n\t\t\tphiLength: phiLength,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t\tradius = radius || 50;\n\n\t\twidthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 );\n\t\theightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 );\n\n\t\tphiStart = phiStart !== undefined ? phiStart : 0;\n\t\tphiLength = phiLength !== undefined ? phiLength : Math.PI * 2;\n\n\t\tthetaStart = thetaStart !== undefined ? thetaStart : 0;\n\t\tthetaLength = thetaLength !== undefined ? thetaLength : Math.PI;\n\n\t\tvar thetaEnd = thetaStart + thetaLength;\n\n\t\tvar ix, iy;\n\n\t\tvar index = 0;\n\t\tvar grid = [];\n\n\t\tvar vertex = new Vector3();\n\t\tvar normal = new Vector3();\n\n\t\t// buffers\n\n\t\tvar indices = [];\n\t\tvar vertices = [];\n\t\tvar normals = [];\n\t\tvar uvs = [];\n\n\t\t// generate vertices, normals and uvs\n\n\t\tfor ( iy = 0; iy <= heightSegments; iy ++ ) {\n\n\t\t\tvar verticesRow = [];\n\n\t\t\tvar v = iy / heightSegments;\n\n\t\t\tfor ( ix = 0; ix <= widthSegments; ix ++ ) {\n\n\t\t\t\tvar u = ix / widthSegments;\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );\n\t\t\t\tvertex.y = radius * Math.cos( thetaStart + v * thetaLength );\n\t\t\t\tvertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t// normal\n\n\t\t\t\tnormal.set( vertex.x, vertex.y, vertex.z ).normalize();\n\t\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t// uv\n\n\t\t\t\tuvs.push( u, 1 - v );\n\n\t\t\t\tverticesRow.push( index ++ );\n\n\t\t\t}\n\n\t\t\tgrid.push( verticesRow );\n\n\t\t}\n\n\t\t// indices\n\n\t\tfor ( iy = 0; iy < heightSegments; iy ++ ) {\n\n\t\t\tfor ( ix = 0; ix < widthSegments; ix ++ ) {\n\n\t\t\t\tvar a = grid[ iy ][ ix + 1 ];\n\t\t\t\tvar b = grid[ iy ][ ix ];\n\t\t\t\tvar c = grid[ iy + 1 ][ ix ];\n\t\t\t\tvar d = grid[ iy + 1 ][ ix + 1 ];\n\n\t\t\t\tif ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );\n\t\t\t\tif ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t}\n\n\tSphereBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\n\tSphereBufferGeometry.prototype.constructor = SphereBufferGeometry;\n\n\t/**\n\t * @author Kaleb Murphy\n\t * @author Mugen87 / https://github.com/Mugen87\n\t */\n\n\t// RingGeometry\n\n\tfunction RingGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {\n\n\t\tGeometry.call( this );\n\n\t\tthis.type = 'RingGeometry';\n\n\t\tthis.parameters = {\n\t\t\tinnerRadius: innerRadius,\n\t\t\touterRadius: outerRadius,\n\t\t\tthetaSegments: thetaSegments,\n\t\t\tphiSegments: phiSegments,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t\tthis.fromBufferGeometry( new RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) );\n\t\tthis.mergeVertices();\n\n\t}\n\n\tRingGeometry.prototype = Object.create( Geometry.prototype );\n\tRingGeometry.prototype.constructor = RingGeometry;\n\n\t// RingBufferGeometry\n\n\tfunction RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {\n\n\t\tBufferGeometry.call( this );\n\n\t\tthis.type = 'RingBufferGeometry';\n\n\t\tthis.parameters = {\n\t\t\tinnerRadius: innerRadius,\n\t\t\touterRadius: outerRadius,\n\t\t\tthetaSegments: thetaSegments,\n\t\t\tphiSegments: phiSegments,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t\tinnerRadius = innerRadius || 20;\n\t\touterRadius = outerRadius || 50;\n\n\t\tthetaStart = thetaStart !== undefined ? thetaStart : 0;\n\t\tthetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;\n\n\t\tthetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8;\n\t\tphiSegments = phiSegments !== undefined ? Math.max( 1, phiSegments ) : 1;\n\n\t\t// buffers\n\n\t\tvar indices = [];\n\t\tvar vertices = [];\n\t\tvar normals = [];\n\t\tvar uvs = [];\n\n\t\t// some helper variables\n\n\t\tvar segment;\n\t\tvar radius = innerRadius;\n\t\tvar radiusStep = ( ( outerRadius - innerRadius ) / phiSegments );\n\t\tvar vertex = new Vector3();\n\t\tvar uv = new Vector2();\n\t\tvar j, i;\n\n\t\t// generate vertices, normals and uvs\n\n\t\tfor ( j = 0; j <= phiSegments; j ++ ) {\n\n\t\t\tfor ( i = 0; i <= thetaSegments; i ++ ) {\n\n\t\t\t\t// values are generate from the inside of the ring to the outside\n\n\t\t\t\tsegment = thetaStart + i / thetaSegments * thetaLength;\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertex.x = radius * Math.cos( segment );\n\t\t\t\tvertex.y = radius * Math.sin( segment );\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t// normal\n\n\t\t\t\tnormals.push( 0, 0, 1 );\n\n\t\t\t\t// uv\n\n\t\t\t\tuv.x = ( vertex.x / outerRadius + 1 ) / 2;\n\t\t\t\tuv.y = ( vertex.y / outerRadius + 1 ) / 2;\n\n\t\t\t\tuvs.push( uv.x, uv.y );\n\n\t\t\t}\n\n\t\t\t// increase the radius for next row of vertices\n\n\t\t\tradius += radiusStep;\n\n\t\t}\n\n\t\t// indices\n\n\t\tfor ( j = 0; j < phiSegments; j ++ ) {\n\n\t\t\tvar thetaSegmentLevel = j * ( thetaSegments + 1 );\n\n\t\t\tfor ( i = 0; i < thetaSegments; i ++ ) {\n\n\t\t\t\tsegment = i + thetaSegmentLevel;\n\n\t\t\t\tvar a = segment;\n\t\t\t\tvar b = segment + thetaSegments + 1;\n\t\t\t\tvar c = segment + thetaSegments + 2;\n\t\t\t\tvar d = segment + 1;\n\n\t\t\t\t// faces\n\n\t\t\t\tindices.push( a, b, d );\n\t\t\t\tindices.push( b, c, d );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t}\n\n\tRingBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\n\tRingBufferGeometry.prototype.constructor = RingBufferGeometry;\n\n\t/**\n\t * @author astrodud / http://astrodud.isgreat.org/\n\t * @author zz85 / https://github.com/zz85\n\t * @author bhouston / http://clara.io\n\t * @author Mugen87 / https://github.com/Mugen87\n\t */\n\n\t// LatheGeometry\n\n\tfunction LatheGeometry( points, segments, phiStart, phiLength ) {\n\n\t\tGeometry.call( this );\n\n\t\tthis.type = 'LatheGeometry';\n\n\t\tthis.parameters = {\n\t\t\tpoints: points,\n\t\t\tsegments: segments,\n\t\t\tphiStart: phiStart,\n\t\t\tphiLength: phiLength\n\t\t};\n\n\t\tthis.fromBufferGeometry( new LatheBufferGeometry( points, segments, phiStart, phiLength ) );\n\t\tthis.mergeVertices();\n\n\t}\n\n\tLatheGeometry.prototype = Object.create( Geometry.prototype );\n\tLatheGeometry.prototype.constructor = LatheGeometry;\n\n\t// LatheBufferGeometry\n\n\tfunction LatheBufferGeometry( points, segments, phiStart, phiLength ) {\n\n\t\tBufferGeometry.call( this );\n\n\t\tthis.type = 'LatheBufferGeometry';\n\n\t\tthis.parameters = {\n\t\t\tpoints: points,\n\t\t\tsegments: segments,\n\t\t\tphiStart: phiStart,\n\t\t\tphiLength: phiLength\n\t\t};\n\n\t\tsegments = Math.floor( segments ) || 12;\n\t\tphiStart = phiStart || 0;\n\t\tphiLength = phiLength || Math.PI * 2;\n\n\t\t// clamp phiLength so it's in range of [ 0, 2PI ]\n\n\t\tphiLength = _Math.clamp( phiLength, 0, Math.PI * 2 );\n\n\n\t\t// buffers\n\n\t\tvar indices = [];\n\t\tvar vertices = [];\n\t\tvar uvs = [];\n\n\t\t// helper variables\n\n\t\tvar base;\n\t\tvar inverseSegments = 1.0 / segments;\n\t\tvar vertex = new Vector3();\n\t\tvar uv = new Vector2();\n\t\tvar i, j;\n\n\t\t// generate vertices and uvs\n\n\t\tfor ( i = 0; i <= segments; i ++ ) {\n\n\t\t\tvar phi = phiStart + i * inverseSegments * phiLength;\n\n\t\t\tvar sin = Math.sin( phi );\n\t\t\tvar cos = Math.cos( phi );\n\n\t\t\tfor ( j = 0; j <= ( points.length - 1 ); j ++ ) {\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertex.x = points[ j ].x * sin;\n\t\t\t\tvertex.y = points[ j ].y;\n\t\t\t\tvertex.z = points[ j ].x * cos;\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t// uv\n\n\t\t\t\tuv.x = i / segments;\n\t\t\t\tuv.y = j / ( points.length - 1 );\n\n\t\t\t\tuvs.push( uv.x, uv.y );\n\n\n\t\t\t}\n\n\t\t}\n\n\t\t// indices\n\n\t\tfor ( i = 0; i < segments; i ++ ) {\n\n\t\t\tfor ( j = 0; j < ( points.length - 1 ); j ++ ) {\n\n\t\t\t\tbase = j + i * points.length;\n\n\t\t\t\tvar a = base;\n\t\t\t\tvar b = base + points.length;\n\t\t\t\tvar c = base + points.length + 1;\n\t\t\t\tvar d = base + 1;\n\n\t\t\t\t// faces\n\n\t\t\t\tindices.push( a, b, d );\n\t\t\t\tindices.push( b, c, d );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t\t// generate normals\n\n\t\tthis.computeVertexNormals();\n\n\t\t// if the geometry is closed, we need to average the normals along the seam.\n\t\t// because the corresponding vertices are identical (but still have different UVs).\n\n\t\tif ( phiLength === Math.PI * 2 ) {\n\n\t\t\tvar normals = this.attributes.normal.array;\n\t\t\tvar n1 = new Vector3();\n\t\t\tvar n2 = new Vector3();\n\t\t\tvar n = new Vector3();\n\n\t\t\t// this is the buffer offset for the last line of vertices\n\n\t\t\tbase = segments * points.length * 3;\n\n\t\t\tfor ( i = 0, j = 0; i < points.length; i ++, j += 3 ) {\n\n\t\t\t\t// select the normal of the vertex in the first line\n\n\t\t\t\tn1.x = normals[ j + 0 ];\n\t\t\t\tn1.y = normals[ j + 1 ];\n\t\t\t\tn1.z = normals[ j + 2 ];\n\n\t\t\t\t// select the normal of the vertex in the last line\n\n\t\t\t\tn2.x = normals[ base + j + 0 ];\n\t\t\t\tn2.y = normals[ base + j + 1 ];\n\t\t\t\tn2.z = normals[ base + j + 2 ];\n\n\t\t\t\t// average normals\n\n\t\t\t\tn.addVectors( n1, n2 ).normalize();\n\n\t\t\t\t// assign the new values to both normals\n\n\t\t\t\tnormals[ j + 0 ] = normals[ base + j + 0 ] = n.x;\n\t\t\t\tnormals[ j + 1 ] = normals[ base + j + 1 ] = n.y;\n\t\t\t\tnormals[ j + 2 ] = normals[ base + j + 2 ] = n.z;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tLatheBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\n\tLatheBufferGeometry.prototype.constructor = LatheBufferGeometry;\n\n\t/**\n\t * @author jonobr1 / http://jonobr1.com\n\t * @author Mugen87 / https://github.com/Mugen87\n\t */\n\n\t// ShapeGeometry\n\n\tfunction ShapeGeometry( shapes, curveSegments ) {\n\n\t\tGeometry.call( this );\n\n\t\tthis.type = 'ShapeGeometry';\n\n\t\tif ( typeof curveSegments === 'object' ) {\n\n\t\t\tconsole.warn( 'THREE.ShapeGeometry: Options parameter has been removed.' );\n\n\t\t\tcurveSegments = curveSegments.curveSegments;\n\n\t\t}\n\n\t\tthis.parameters = {\n\t\t\tshapes: shapes,\n\t\t\tcurveSegments: curveSegments\n\t\t};\n\n\t\tthis.fromBufferGeometry( new ShapeBufferGeometry( shapes, curveSegments ) );\n\t\tthis.mergeVertices();\n\n\t}\n\n\tShapeGeometry.prototype = Object.create( Geometry.prototype );\n\tShapeGeometry.prototype.constructor = ShapeGeometry;\n\n\t// ShapeBufferGeometry\n\n\tfunction ShapeBufferGeometry( shapes, curveSegments ) {\n\n\t\tBufferGeometry.call( this );\n\n\t\tthis.type = 'ShapeBufferGeometry';\n\n\t\tthis.parameters = {\n\t\t\tshapes: shapes,\n\t\t\tcurveSegments: curveSegments\n\t\t};\n\n\t\tcurveSegments = curveSegments || 12;\n\n\t\t// buffers\n\n\t\tvar indices = [];\n\t\tvar vertices = [];\n\t\tvar normals = [];\n\t\tvar uvs = [];\n\n\t\t// helper variables\n\n\t\tvar groupStart = 0;\n\t\tvar groupCount = 0;\n\n\t\t// allow single and array values for \"shapes\" parameter\n\n\t\tif ( Array.isArray( shapes ) === false ) {\n\n\t\t\taddShape( shapes );\n\n\t\t} else {\n\n\t\t\tfor ( var i = 0; i < shapes.length; i ++ ) {\n\n\t\t\t\taddShape( shapes[ i ] );\n\n\t\t\t\tthis.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support\n\n\t\t\t\tgroupStart += groupCount;\n\t\t\t\tgroupCount = 0;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\n\t\t// helper functions\n\n\t\tfunction addShape( shape ) {\n\n\t\t\tvar i, l, shapeHole;\n\n\t\t\tvar indexOffset = vertices.length / 3;\n\t\t\tvar points = shape.extractPoints( curveSegments );\n\n\t\t\tvar shapeVertices = points.shape;\n\t\t\tvar shapeHoles = points.holes;\n\n\t\t\t// check direction of vertices\n\n\t\t\tif ( ShapeUtils.isClockWise( shapeVertices ) === false ) {\n\n\t\t\t\tshapeVertices = shapeVertices.reverse();\n\n\t\t\t\t// also check if holes are in the opposite direction\n\n\t\t\t\tfor ( i = 0, l = shapeHoles.length; i < l; i ++ ) {\n\n\t\t\t\t\tshapeHole = shapeHoles[ i ];\n\n\t\t\t\t\tif ( ShapeUtils.isClockWise( shapeHole ) === true ) {\n\n\t\t\t\t\t\tshapeHoles[ i ] = shapeHole.reverse();\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tvar faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );\n\n\t\t\t// join vertices of inner and outer paths to a single array\n\n\t\t\tfor ( i = 0, l = shapeHoles.length; i < l; i ++ ) {\n\n\t\t\t\tshapeHole = shapeHoles[ i ];\n\t\t\t\tshapeVertices = shapeVertices.concat( shapeHole );\n\n\t\t\t}\n\n\t\t\t// vertices, normals, uvs\n\n\t\t\tfor ( i = 0, l = shapeVertices.length; i < l; i ++ ) {\n\n\t\t\t\tvar vertex = shapeVertices[ i ];\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, 0 );\n\t\t\t\tnormals.push( 0, 0, 1 );\n\t\t\t\tuvs.push( vertex.x, vertex.y ); // world uvs\n\n\t\t\t}\n\n\t\t\t// incides\n\n\t\t\tfor ( i = 0, l = faces.length; i < l; i ++ ) {\n\n\t\t\t\tvar face = faces[ i ];\n\n\t\t\t\tvar a = face[ 0 ] + indexOffset;\n\t\t\t\tvar b = face[ 1 ] + indexOffset;\n\t\t\t\tvar c = face[ 2 ] + indexOffset;\n\n\t\t\t\tindices.push( a, b, c );\n\t\t\t\tgroupCount += 3;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tShapeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\n\tShapeBufferGeometry.prototype.constructor = ShapeBufferGeometry;\n\n\t/**\n\t * @author WestLangley / http://github.com/WestLangley\n\t * @author Mugen87 / https://github.com/Mugen87\n\t */\n\n\tfunction EdgesGeometry( geometry, thresholdAngle ) {\n\n\t\tBufferGeometry.call( this );\n\n\t\tthis.type = 'EdgesGeometry';\n\n\t\tthis.parameters = {\n\t\t\tthresholdAngle: thresholdAngle\n\t\t};\n\n\t\tthresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1;\n\n\t\t// buffer\n\n\t\tvar vertices = [];\n\n\t\t// helper variables\n\n\t\tvar thresholdDot = Math.cos( _Math.DEG2RAD * thresholdAngle );\n\t\tvar edge = [ 0, 0 ], edges = {}, edge1, edge2;\n\t\tvar key, keys = [ 'a', 'b', 'c' ];\n\n\t\t// prepare source geometry\n\n\t\tvar geometry2;\n\n\t\tif ( geometry.isBufferGeometry ) {\n\n\t\t\tgeometry2 = new Geometry();\n\t\t\tgeometry2.fromBufferGeometry( geometry );\n\n\t\t} else {\n\n\t\t\tgeometry2 = geometry.clone();\n\n\t\t}\n\n\t\tgeometry2.mergeVertices();\n\t\tgeometry2.computeFaceNormals();\n\n\t\tvar sourceVertices = geometry2.vertices;\n\t\tvar faces = geometry2.faces;\n\n\t\t// now create a data structure where each entry represents an edge with its adjoining faces\n\n\t\tfor ( var i = 0, l = faces.length; i < l; i ++ ) {\n\n\t\t\tvar face = faces[ i ];\n\n\t\t\tfor ( var j = 0; j < 3; j ++ ) {\n\n\t\t\t\tedge1 = face[ keys[ j ] ];\n\t\t\t\tedge2 = face[ keys[ ( j + 1 ) % 3 ] ];\n\t\t\t\tedge[ 0 ] = Math.min( edge1, edge2 );\n\t\t\t\tedge[ 1 ] = Math.max( edge1, edge2 );\n\n\t\t\t\tkey = edge[ 0 ] + ',' + edge[ 1 ];\n\n\t\t\t\tif ( edges[ key ] === undefined ) {\n\n\t\t\t\t\tedges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ], face1: i, face2: undefined };\n\n\t\t\t\t} else {\n\n\t\t\t\t\tedges[ key ].face2 = i;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t// generate vertices\n\n\t\tfor ( key in edges ) {\n\n\t\t\tvar e = edges[ key ];\n\n\t\t\t// an edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value. default = 1 degree.\n\n\t\t\tif ( e.face2 === undefined || faces[ e.face1 ].normal.dot( faces[ e.face2 ].normal ) <= thresholdDot ) {\n\n\t\t\t\tvar vertex = sourceVertices[ e.index1 ];\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\tvertex = sourceVertices[ e.index2 ];\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\n\t}\n\n\tEdgesGeometry.prototype = Object.create( BufferGeometry.prototype );\n\tEdgesGeometry.prototype.constructor = EdgesGeometry;\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author Mugen87 / https://github.com/Mugen87\n\t */\n\n\t// CylinderGeometry\n\n\tfunction CylinderGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {\n\n\t\tGeometry.call( this );\n\n\t\tthis.type = 'CylinderGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradiusTop: radiusTop,\n\t\t\tradiusBottom: radiusBottom,\n\t\t\theight: height,\n\t\t\tradialSegments: radialSegments,\n\t\t\theightSegments: heightSegments,\n\t\t\topenEnded: openEnded,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t\tthis.fromBufferGeometry( new CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) );\n\t\tthis.mergeVertices();\n\n\t}\n\n\tCylinderGeometry.prototype = Object.create( Geometry.prototype );\n\tCylinderGeometry.prototype.constructor = CylinderGeometry;\n\n\t// CylinderBufferGeometry\n\n\tfunction CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {\n\n\t\tBufferGeometry.call( this );\n\n\t\tthis.type = 'CylinderBufferGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradiusTop: radiusTop,\n\t\t\tradiusBottom: radiusBottom,\n\t\t\theight: height,\n\t\t\tradialSegments: radialSegments,\n\t\t\theightSegments: heightSegments,\n\t\t\topenEnded: openEnded,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t\tvar scope = this;\n\n\t\tradiusTop = radiusTop !== undefined ? radiusTop : 20;\n\t\tradiusBottom = radiusBottom !== undefined ? radiusBottom : 20;\n\t\theight = height !== undefined ? height : 100;\n\n\t\tradialSegments = Math.floor( radialSegments ) || 8;\n\t\theightSegments = Math.floor( heightSegments ) || 1;\n\n\t\topenEnded = openEnded !== undefined ? openEnded : false;\n\t\tthetaStart = thetaStart !== undefined ? thetaStart : 0.0;\n\t\tthetaLength = thetaLength !== undefined ? thetaLength : 2.0 * Math.PI;\n\n\t\t// buffers\n\n\t\tvar indices = [];\n\t\tvar vertices = [];\n\t\tvar normals = [];\n\t\tvar uvs = [];\n\n\t\t// helper variables\n\n\t\tvar index = 0;\n\t\tvar indexArray = [];\n\t\tvar halfHeight = height / 2;\n\t\tvar groupStart = 0;\n\n\t\t// generate geometry\n\n\t\tgenerateTorso();\n\n\t\tif ( openEnded === false ) {\n\n\t\t\tif ( radiusTop > 0 ) generateCap( true );\n\t\t\tif ( radiusBottom > 0 ) generateCap( false );\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t\tfunction generateTorso() {\n\n\t\t\tvar x, y;\n\t\t\tvar normal = new Vector3();\n\t\t\tvar vertex = new Vector3();\n\n\t\t\tvar groupCount = 0;\n\n\t\t\t// this will be used to calculate the normal\n\t\t\tvar slope = ( radiusBottom - radiusTop ) / height;\n\n\t\t\t// generate vertices, normals and uvs\n\n\t\t\tfor ( y = 0; y <= heightSegments; y ++ ) {\n\n\t\t\t\tvar indexRow = [];\n\n\t\t\t\tvar v = y / heightSegments;\n\n\t\t\t\t// calculate the radius of the current row\n\n\t\t\t\tvar radius = v * ( radiusBottom - radiusTop ) + radiusTop;\n\n\t\t\t\tfor ( x = 0; x <= radialSegments; x ++ ) {\n\n\t\t\t\t\tvar u = x / radialSegments;\n\n\t\t\t\t\tvar theta = u * thetaLength + thetaStart;\n\n\t\t\t\t\tvar sinTheta = Math.sin( theta );\n\t\t\t\t\tvar cosTheta = Math.cos( theta );\n\n\t\t\t\t\t// vertex\n\n\t\t\t\t\tvertex.x = radius * sinTheta;\n\t\t\t\t\tvertex.y = - v * height + halfHeight;\n\t\t\t\t\tvertex.z = radius * cosTheta;\n\t\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t\t// normal\n\n\t\t\t\t\tnormal.set( sinTheta, slope, cosTheta ).normalize();\n\t\t\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t\t// uv\n\n\t\t\t\t\tuvs.push( u, 1 - v );\n\n\t\t\t\t\t// save index of vertex in respective row\n\n\t\t\t\t\tindexRow.push( index ++ );\n\n\t\t\t\t}\n\n\t\t\t\t// now save vertices of the row in our index array\n\n\t\t\t\tindexArray.push( indexRow );\n\n\t\t\t}\n\n\t\t\t// generate indices\n\n\t\t\tfor ( x = 0; x < radialSegments; x ++ ) {\n\n\t\t\t\tfor ( y = 0; y < heightSegments; y ++ ) {\n\n\t\t\t\t\t// we use the index array to access the correct indices\n\n\t\t\t\t\tvar a = indexArray[ y ][ x ];\n\t\t\t\t\tvar b = indexArray[ y + 1 ][ x ];\n\t\t\t\t\tvar c = indexArray[ y + 1 ][ x + 1 ];\n\t\t\t\t\tvar d = indexArray[ y ][ x + 1 ];\n\n\t\t\t\t\t// faces\n\n\t\t\t\t\tindices.push( a, b, d );\n\t\t\t\t\tindices.push( b, c, d );\n\n\t\t\t\t\t// update group counter\n\n\t\t\t\t\tgroupCount += 6;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// add a group to the geometry. this will ensure multi material support\n\n\t\t\tscope.addGroup( groupStart, groupCount, 0 );\n\n\t\t\t// calculate new start value for groups\n\n\t\t\tgroupStart += groupCount;\n\n\t\t}\n\n\t\tfunction generateCap( top ) {\n\n\t\t\tvar x, centerIndexStart, centerIndexEnd;\n\n\t\t\tvar uv = new Vector2();\n\t\t\tvar vertex = new Vector3();\n\n\t\t\tvar groupCount = 0;\n\n\t\t\tvar radius = ( top === true ) ? radiusTop : radiusBottom;\n\t\t\tvar sign = ( top === true ) ? 1 : - 1;\n\n\t\t\t// save the index of the first center vertex\n\t\t\tcenterIndexStart = index;\n\n\t\t\t// first we generate the center vertex data of the cap.\n\t\t\t// because the geometry needs one set of uvs per face,\n\t\t\t// we must generate a center vertex per face/segment\n\n\t\t\tfor ( x = 1; x <= radialSegments; x ++ ) {\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertices.push( 0, halfHeight * sign, 0 );\n\n\t\t\t\t// normal\n\n\t\t\t\tnormals.push( 0, sign, 0 );\n\n\t\t\t\t// uv\n\n\t\t\t\tuvs.push( 0.5, 0.5 );\n\n\t\t\t\t// increase index\n\n\t\t\t\tindex ++;\n\n\t\t\t}\n\n\t\t\t// save the index of the last center vertex\n\n\t\t\tcenterIndexEnd = index;\n\n\t\t\t// now we generate the surrounding vertices, normals and uvs\n\n\t\t\tfor ( x = 0; x <= radialSegments; x ++ ) {\n\n\t\t\t\tvar u = x / radialSegments;\n\t\t\t\tvar theta = u * thetaLength + thetaStart;\n\n\t\t\t\tvar cosTheta = Math.cos( theta );\n\t\t\t\tvar sinTheta = Math.sin( theta );\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertex.x = radius * sinTheta;\n\t\t\t\tvertex.y = halfHeight * sign;\n\t\t\t\tvertex.z = radius * cosTheta;\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t// normal\n\n\t\t\t\tnormals.push( 0, sign, 0 );\n\n\t\t\t\t// uv\n\n\t\t\t\tuv.x = ( cosTheta * 0.5 ) + 0.5;\n\t\t\t\tuv.y = ( sinTheta * 0.5 * sign ) + 0.5;\n\t\t\t\tuvs.push( uv.x, uv.y );\n\n\t\t\t\t// increase index\n\n\t\t\t\tindex ++;\n\n\t\t\t}\n\n\t\t\t// generate indices\n\n\t\t\tfor ( x = 0; x < radialSegments; x ++ ) {\n\n\t\t\t\tvar c = centerIndexStart + x;\n\t\t\t\tvar i = centerIndexEnd + x;\n\n\t\t\t\tif ( top === true ) {\n\n\t\t\t\t\t// face top\n\n\t\t\t\t\tindices.push( i, i + 1, c );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// face bottom\n\n\t\t\t\t\tindices.push( i + 1, i, c );\n\n\t\t\t\t}\n\n\t\t\t\tgroupCount += 3;\n\n\t\t\t}\n\n\t\t\t// add a group to the geometry. this will ensure multi material support\n\n\t\t\tscope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );\n\n\t\t\t// calculate new start value for groups\n\n\t\t\tgroupStart += groupCount;\n\n\t\t}\n\n\t}\n\n\tCylinderBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\n\tCylinderBufferGeometry.prototype.constructor = CylinderBufferGeometry;\n\n\t/**\n\t * @author abelnation / http://github.com/abelnation\n\t */\n\n\t// ConeGeometry\n\n\tfunction ConeGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {\n\n\t\tCylinderGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );\n\n\t\tthis.type = 'ConeGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\theight: height,\n\t\t\tradialSegments: radialSegments,\n\t\t\theightSegments: heightSegments,\n\t\t\topenEnded: openEnded,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t}\n\n\tConeGeometry.prototype = Object.create( CylinderGeometry.prototype );\n\tConeGeometry.prototype.constructor = ConeGeometry;\n\n\t// ConeBufferGeometry\n\n\tfunction ConeBufferGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {\n\n\t\tCylinderBufferGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );\n\n\t\tthis.type = 'ConeBufferGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\theight: height,\n\t\t\tradialSegments: radialSegments,\n\t\t\theightSegments: heightSegments,\n\t\t\topenEnded: openEnded,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t}\n\n\tConeBufferGeometry.prototype = Object.create( CylinderBufferGeometry.prototype );\n\tConeBufferGeometry.prototype.constructor = ConeBufferGeometry;\n\n\t/**\n\t * @author benaadams / https://twitter.com/ben_a_adams\n\t * @author Mugen87 / https://github.com/Mugen87\n\t * @author hughes\n\t */\n\n\t// CircleGeometry\n\n\tfunction CircleGeometry( radius, segments, thetaStart, thetaLength ) {\n\n\t\tGeometry.call( this );\n\n\t\tthis.type = 'CircleGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tsegments: segments,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t\tthis.fromBufferGeometry( new CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) );\n\t\tthis.mergeVertices();\n\n\t}\n\n\tCircleGeometry.prototype = Object.create( Geometry.prototype );\n\tCircleGeometry.prototype.constructor = CircleGeometry;\n\n\t// CircleBufferGeometry\n\n\tfunction CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) {\n\n\t\tBufferGeometry.call( this );\n\n\t\tthis.type = 'CircleBufferGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tsegments: segments,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t\tradius = radius || 50;\n\t\tsegments = segments !== undefined ? Math.max( 3, segments ) : 8;\n\n\t\tthetaStart = thetaStart !== undefined ? thetaStart : 0;\n\t\tthetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;\n\n\t\t// buffers\n\n\t\tvar indices = [];\n\t\tvar vertices = [];\n\t\tvar normals = [];\n\t\tvar uvs = [];\n\n\t\t// helper variables\n\n\t\tvar i, s;\n\t\tvar vertex = new Vector3();\n\t\tvar uv = new Vector2();\n\n\t\t// center point\n\n\t\tvertices.push( 0, 0, 0 );\n\t\tnormals.push( 0, 0, 1 );\n\t\tuvs.push( 0.5, 0.5 );\n\n\t\tfor ( s = 0, i = 3; s <= segments; s ++, i += 3 ) {\n\n\t\t\tvar segment = thetaStart + s / segments * thetaLength;\n\n\t\t\t// vertex\n\n\t\t\tvertex.x = radius * Math.cos( segment );\n\t\t\tvertex.y = radius * Math.sin( segment );\n\n\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t// normal\n\n\t\t\tnormals.push( 0, 0, 1 );\n\n\t\t\t// uvs\n\n\t\t\tuv.x = ( vertices[ i ] / radius + 1 ) / 2;\n\t\t\tuv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;\n\n\t\t\tuvs.push( uv.x, uv.y );\n\n\t\t}\n\n\t\t// indices\n\n\t\tfor ( i = 1; i <= segments; i ++ ) {\n\n\t\t\tindices.push( i, i + 1, 0 );\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t}\n\n\tCircleBufferGeometry.prototype = Object.create( BufferGeometry.prototype );\n\tCircleBufferGeometry.prototype.constructor = CircleBufferGeometry;\n\n\n\n\tvar Geometries = Object.freeze({\n\t\tWireframeGeometry: WireframeGeometry,\n\t\tParametricGeometry: ParametricGeometry,\n\t\tParametricBufferGeometry: ParametricBufferGeometry,\n\t\tTetrahedronGeometry: TetrahedronGeometry,\n\t\tTetrahedronBufferGeometry: TetrahedronBufferGeometry,\n\t\tOctahedronGeometry: OctahedronGeometry,\n\t\tOctahedronBufferGeometry: OctahedronBufferGeometry,\n\t\tIcosahedronGeometry: IcosahedronGeometry,\n\t\tIcosahedronBufferGeometry: IcosahedronBufferGeometry,\n\t\tDodecahedronGeometry: DodecahedronGeometry,\n\t\tDodecahedronBufferGeometry: DodecahedronBufferGeometry,\n\t\tPolyhedronGeometry: PolyhedronGeometry,\n\t\tPolyhedronBufferGeometry: PolyhedronBufferGeometry,\n\t\tTubeGeometry: TubeGeometry,\n\t\tTubeBufferGeometry: TubeBufferGeometry,\n\t\tTorusKnotGeometry: TorusKnotGeometry,\n\t\tTorusKnotBufferGeometry: TorusKnotBufferGeometry,\n\t\tTorusGeometry: TorusGeometry,\n\t\tTorusBufferGeometry: TorusBufferGeometry,\n\t\tTextGeometry: TextGeometry,\n\t\tTextBufferGeometry: TextBufferGeometry,\n\t\tSphereGeometry: SphereGeometry,\n\t\tSphereBufferGeometry: SphereBufferGeometry,\n\t\tRingGeometry: RingGeometry,\n\t\tRingBufferGeometry: RingBufferGeometry,\n\t\tPlaneGeometry: PlaneGeometry,\n\t\tPlaneBufferGeometry: PlaneBufferGeometry,\n\t\tLatheGeometry: LatheGeometry,\n\t\tLatheBufferGeometry: LatheBufferGeometry,\n\t\tShapeGeometry: ShapeGeometry,\n\t\tShapeBufferGeometry: ShapeBufferGeometry,\n\t\tExtrudeGeometry: ExtrudeGeometry,\n\t\tExtrudeBufferGeometry: ExtrudeBufferGeometry,\n\t\tEdgesGeometry: EdgesGeometry,\n\t\tConeGeometry: ConeGeometry,\n\t\tConeBufferGeometry: ConeBufferGeometry,\n\t\tCylinderGeometry: CylinderGeometry,\n\t\tCylinderBufferGeometry: CylinderBufferGeometry,\n\t\tCircleGeometry: CircleGeometry,\n\t\tCircleBufferGeometry: CircleBufferGeometry,\n\t\tBoxGeometry: BoxGeometry,\n\t\tBoxBufferGeometry: BoxBufferGeometry\n\t});\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t *\n\t * parameters = {\n\t *  color: <THREE.Color>,\n\t *  opacity: <float>\n\t * }\n\t */\n\n\tfunction ShadowMaterial( parameters ) {\n\n\t\tMaterial.call( this );\n\n\t\tthis.type = 'ShadowMaterial';\n\n\t\tthis.color = new Color( 0x000000 );\n\t\tthis.opacity = 1.0;\n\n\t\tthis.lights = true;\n\t\tthis.transparent = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tShadowMaterial.prototype = Object.create( Material.prototype );\n\tShadowMaterial.prototype.constructor = ShadowMaterial;\n\n\tShadowMaterial.prototype.isShadowMaterial = true;\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction RawShaderMaterial( parameters ) {\n\n\t\tShaderMaterial.call( this, parameters );\n\n\t\tthis.type = 'RawShaderMaterial';\n\n\t}\n\n\tRawShaderMaterial.prototype = Object.create( ShaderMaterial.prototype );\n\tRawShaderMaterial.prototype.constructor = RawShaderMaterial;\n\n\tRawShaderMaterial.prototype.isRawShaderMaterial = true;\n\n\t/**\n\t * @author WestLangley / http://github.com/WestLangley\n\t *\n\t * parameters = {\n\t *  color: <hex>,\n\t *  roughness: <float>,\n\t *  metalness: <float>,\n\t *  opacity: <float>,\n\t *\n\t *  map: new THREE.Texture( <Image> ),\n\t *\n\t *  lightMap: new THREE.Texture( <Image> ),\n\t *  lightMapIntensity: <float>\n\t *\n\t *  aoMap: new THREE.Texture( <Image> ),\n\t *  aoMapIntensity: <float>\n\t *\n\t *  emissive: <hex>,\n\t *  emissiveIntensity: <float>\n\t *  emissiveMap: new THREE.Texture( <Image> ),\n\t *\n\t *  bumpMap: new THREE.Texture( <Image> ),\n\t *  bumpScale: <float>,\n\t *\n\t *  normalMap: new THREE.Texture( <Image> ),\n\t *  normalScale: <Vector2>,\n\t *\n\t *  displacementMap: new THREE.Texture( <Image> ),\n\t *  displacementScale: <float>,\n\t *  displacementBias: <float>,\n\t *\n\t *  roughnessMap: new THREE.Texture( <Image> ),\n\t *\n\t *  metalnessMap: new THREE.Texture( <Image> ),\n\t *\n\t *  alphaMap: new THREE.Texture( <Image> ),\n\t *\n\t *  envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),\n\t *  envMapIntensity: <float>\n\t *\n\t *  refractionRatio: <float>,\n\t *\n\t *  wireframe: <boolean>,\n\t *  wireframeLinewidth: <float>,\n\t *\n\t *  skinning: <bool>,\n\t *  morphTargets: <bool>,\n\t *  morphNormals: <bool>\n\t * }\n\t */\n\n\tfunction MeshStandardMaterial( parameters ) {\n\n\t\tMaterial.call( this );\n\n\t\tthis.defines = { 'STANDARD': '' };\n\n\t\tthis.type = 'MeshStandardMaterial';\n\n\t\tthis.color = new Color( 0xffffff ); // diffuse\n\t\tthis.roughness = 0.5;\n\t\tthis.metalness = 0.5;\n\n\t\tthis.map = null;\n\n\t\tthis.lightMap = null;\n\t\tthis.lightMapIntensity = 1.0;\n\n\t\tthis.aoMap = null;\n\t\tthis.aoMapIntensity = 1.0;\n\n\t\tthis.emissive = new Color( 0x000000 );\n\t\tthis.emissiveIntensity = 1.0;\n\t\tthis.emissiveMap = null;\n\n\t\tthis.bumpMap = null;\n\t\tthis.bumpScale = 1;\n\n\t\tthis.normalMap = null;\n\t\tthis.normalScale = new Vector2( 1, 1 );\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.roughnessMap = null;\n\n\t\tthis.metalnessMap = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.envMap = null;\n\t\tthis.envMapIntensity = 1.0;\n\n\t\tthis.refractionRatio = 0.98;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\t\tthis.wireframeLinecap = 'round';\n\t\tthis.wireframeLinejoin = 'round';\n\n\t\tthis.skinning = false;\n\t\tthis.morphTargets = false;\n\t\tthis.morphNormals = false;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tMeshStandardMaterial.prototype = Object.create( Material.prototype );\n\tMeshStandardMaterial.prototype.constructor = MeshStandardMaterial;\n\n\tMeshStandardMaterial.prototype.isMeshStandardMaterial = true;\n\n\tMeshStandardMaterial.prototype.copy = function ( source ) {\n\n\t\tMaterial.prototype.copy.call( this, source );\n\n\t\tthis.defines = { 'STANDARD': '' };\n\n\t\tthis.color.copy( source.color );\n\t\tthis.roughness = source.roughness;\n\t\tthis.metalness = source.metalness;\n\n\t\tthis.map = source.map;\n\n\t\tthis.lightMap = source.lightMap;\n\t\tthis.lightMapIntensity = source.lightMapIntensity;\n\n\t\tthis.aoMap = source.aoMap;\n\t\tthis.aoMapIntensity = source.aoMapIntensity;\n\n\t\tthis.emissive.copy( source.emissive );\n\t\tthis.emissiveMap = source.emissiveMap;\n\t\tthis.emissiveIntensity = source.emissiveIntensity;\n\n\t\tthis.bumpMap = source.bumpMap;\n\t\tthis.bumpScale = source.bumpScale;\n\n\t\tthis.normalMap = source.normalMap;\n\t\tthis.normalScale.copy( source.normalScale );\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\tthis.roughnessMap = source.roughnessMap;\n\n\t\tthis.metalnessMap = source.metalnessMap;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.envMap = source.envMap;\n\t\tthis.envMapIntensity = source.envMapIntensity;\n\n\t\tthis.refractionRatio = source.refractionRatio;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\t\tthis.wireframeLinecap = source.wireframeLinecap;\n\t\tthis.wireframeLinejoin = source.wireframeLinejoin;\n\n\t\tthis.skinning = source.skinning;\n\t\tthis.morphTargets = source.morphTargets;\n\t\tthis.morphNormals = source.morphNormals;\n\n\t\treturn this;\n\n\t};\n\n\t/**\n\t * @author WestLangley / http://github.com/WestLangley\n\t *\n\t * parameters = {\n\t *  reflectivity: <float>\n\t * }\n\t */\n\n\tfunction MeshPhysicalMaterial( parameters ) {\n\n\t\tMeshStandardMaterial.call( this );\n\n\t\tthis.defines = { 'PHYSICAL': '' };\n\n\t\tthis.type = 'MeshPhysicalMaterial';\n\n\t\tthis.reflectivity = 0.5; // maps to F0 = 0.04\n\n\t\tthis.clearCoat = 0.0;\n\t\tthis.clearCoatRoughness = 0.0;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tMeshPhysicalMaterial.prototype = Object.create( MeshStandardMaterial.prototype );\n\tMeshPhysicalMaterial.prototype.constructor = MeshPhysicalMaterial;\n\n\tMeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true;\n\n\tMeshPhysicalMaterial.prototype.copy = function ( source ) {\n\n\t\tMeshStandardMaterial.prototype.copy.call( this, source );\n\n\t\tthis.defines = { 'PHYSICAL': '' };\n\n\t\tthis.reflectivity = source.reflectivity;\n\n\t\tthis.clearCoat = source.clearCoat;\n\t\tthis.clearCoatRoughness = source.clearCoatRoughness;\n\n\t\treturn this;\n\n\t};\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author alteredq / http://alteredqualia.com/\n\t *\n\t * parameters = {\n\t *  color: <hex>,\n\t *  specular: <hex>,\n\t *  shininess: <float>,\n\t *  opacity: <float>,\n\t *\n\t *  map: new THREE.Texture( <Image> ),\n\t *\n\t *  lightMap: new THREE.Texture( <Image> ),\n\t *  lightMapIntensity: <float>\n\t *\n\t *  aoMap: new THREE.Texture( <Image> ),\n\t *  aoMapIntensity: <float>\n\t *\n\t *  emissive: <hex>,\n\t *  emissiveIntensity: <float>\n\t *  emissiveMap: new THREE.Texture( <Image> ),\n\t *\n\t *  bumpMap: new THREE.Texture( <Image> ),\n\t *  bumpScale: <float>,\n\t *\n\t *  normalMap: new THREE.Texture( <Image> ),\n\t *  normalScale: <Vector2>,\n\t *\n\t *  displacementMap: new THREE.Texture( <Image> ),\n\t *  displacementScale: <float>,\n\t *  displacementBias: <float>,\n\t *\n\t *  specularMap: new THREE.Texture( <Image> ),\n\t *\n\t *  alphaMap: new THREE.Texture( <Image> ),\n\t *\n\t *  envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),\n\t *  combine: THREE.Multiply,\n\t *  reflectivity: <float>,\n\t *  refractionRatio: <float>,\n\t *\n\t *  wireframe: <boolean>,\n\t *  wireframeLinewidth: <float>,\n\t *\n\t *  skinning: <bool>,\n\t *  morphTargets: <bool>,\n\t *  morphNormals: <bool>\n\t * }\n\t */\n\n\tfunction MeshPhongMaterial( parameters ) {\n\n\t\tMaterial.call( this );\n\n\t\tthis.type = 'MeshPhongMaterial';\n\n\t\tthis.color = new Color( 0xffffff ); // diffuse\n\t\tthis.specular = new Color( 0x111111 );\n\t\tthis.shininess = 30;\n\n\t\tthis.map = null;\n\n\t\tthis.lightMap = null;\n\t\tthis.lightMapIntensity = 1.0;\n\n\t\tthis.aoMap = null;\n\t\tthis.aoMapIntensity = 1.0;\n\n\t\tthis.emissive = new Color( 0x000000 );\n\t\tthis.emissiveIntensity = 1.0;\n\t\tthis.emissiveMap = null;\n\n\t\tthis.bumpMap = null;\n\t\tthis.bumpScale = 1;\n\n\t\tthis.normalMap = null;\n\t\tthis.normalScale = new Vector2( 1, 1 );\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.specularMap = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.envMap = null;\n\t\tthis.combine = MultiplyOperation;\n\t\tthis.reflectivity = 1;\n\t\tthis.refractionRatio = 0.98;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\t\tthis.wireframeLinecap = 'round';\n\t\tthis.wireframeLinejoin = 'round';\n\n\t\tthis.skinning = false;\n\t\tthis.morphTargets = false;\n\t\tthis.morphNormals = false;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tMeshPhongMaterial.prototype = Object.create( Material.prototype );\n\tMeshPhongMaterial.prototype.constructor = MeshPhongMaterial;\n\n\tMeshPhongMaterial.prototype.isMeshPhongMaterial = true;\n\n\tMeshPhongMaterial.prototype.copy = function ( source ) {\n\n\t\tMaterial.prototype.copy.call( this, source );\n\n\t\tthis.color.copy( source.color );\n\t\tthis.specular.copy( source.specular );\n\t\tthis.shininess = source.shininess;\n\n\t\tthis.map = source.map;\n\n\t\tthis.lightMap = source.lightMap;\n\t\tthis.lightMapIntensity = source.lightMapIntensity;\n\n\t\tthis.aoMap = source.aoMap;\n\t\tthis.aoMapIntensity = source.aoMapIntensity;\n\n\t\tthis.emissive.copy( source.emissive );\n\t\tthis.emissiveMap = source.emissiveMap;\n\t\tthis.emissiveIntensity = source.emissiveIntensity;\n\n\t\tthis.bumpMap = source.bumpMap;\n\t\tthis.bumpScale = source.bumpScale;\n\n\t\tthis.normalMap = source.normalMap;\n\t\tthis.normalScale.copy( source.normalScale );\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\tthis.specularMap = source.specularMap;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.envMap = source.envMap;\n\t\tthis.combine = source.combine;\n\t\tthis.reflectivity = source.reflectivity;\n\t\tthis.refractionRatio = source.refractionRatio;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\t\tthis.wireframeLinecap = source.wireframeLinecap;\n\t\tthis.wireframeLinejoin = source.wireframeLinejoin;\n\n\t\tthis.skinning = source.skinning;\n\t\tthis.morphTargets = source.morphTargets;\n\t\tthis.morphNormals = source.morphNormals;\n\n\t\treturn this;\n\n\t};\n\n\t/**\n\t * @author takahirox / http://github.com/takahirox\n\t *\n\t * parameters = {\n\t *  gradientMap: new THREE.Texture( <Image> )\n\t * }\n\t */\n\n\tfunction MeshToonMaterial( parameters ) {\n\n\t\tMeshPhongMaterial.call( this );\n\n\t\tthis.defines = { 'TOON': '' };\n\n\t\tthis.type = 'MeshToonMaterial';\n\n\t\tthis.gradientMap = null;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tMeshToonMaterial.prototype = Object.create( MeshPhongMaterial.prototype );\n\tMeshToonMaterial.prototype.constructor = MeshToonMaterial;\n\n\tMeshToonMaterial.prototype.isMeshToonMaterial = true;\n\n\tMeshToonMaterial.prototype.copy = function ( source ) {\n\n\t\tMeshPhongMaterial.prototype.copy.call( this, source );\n\n\t\tthis.gradientMap = source.gradientMap;\n\n\t\treturn this;\n\n\t};\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author WestLangley / http://github.com/WestLangley\n\t *\n\t * parameters = {\n\t *  opacity: <float>,\n\t *\n\t *  bumpMap: new THREE.Texture( <Image> ),\n\t *  bumpScale: <float>,\n\t *\n\t *  normalMap: new THREE.Texture( <Image> ),\n\t *  normalScale: <Vector2>,\n\t *\n\t *  displacementMap: new THREE.Texture( <Image> ),\n\t *  displacementScale: <float>,\n\t *  displacementBias: <float>,\n\t *\n\t *  wireframe: <boolean>,\n\t *  wireframeLinewidth: <float>\n\t *\n\t *  skinning: <bool>,\n\t *  morphTargets: <bool>,\n\t *  morphNormals: <bool>\n\t * }\n\t */\n\n\tfunction MeshNormalMaterial( parameters ) {\n\n\t\tMaterial.call( this );\n\n\t\tthis.type = 'MeshNormalMaterial';\n\n\t\tthis.bumpMap = null;\n\t\tthis.bumpScale = 1;\n\n\t\tthis.normalMap = null;\n\t\tthis.normalScale = new Vector2( 1, 1 );\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\n\t\tthis.fog = false;\n\t\tthis.lights = false;\n\n\t\tthis.skinning = false;\n\t\tthis.morphTargets = false;\n\t\tthis.morphNormals = false;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tMeshNormalMaterial.prototype = Object.create( Material.prototype );\n\tMeshNormalMaterial.prototype.constructor = MeshNormalMaterial;\n\n\tMeshNormalMaterial.prototype.isMeshNormalMaterial = true;\n\n\tMeshNormalMaterial.prototype.copy = function ( source ) {\n\n\t\tMaterial.prototype.copy.call( this, source );\n\n\t\tthis.bumpMap = source.bumpMap;\n\t\tthis.bumpScale = source.bumpScale;\n\n\t\tthis.normalMap = source.normalMap;\n\t\tthis.normalScale.copy( source.normalScale );\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\n\t\tthis.skinning = source.skinning;\n\t\tthis.morphTargets = source.morphTargets;\n\t\tthis.morphNormals = source.morphNormals;\n\n\t\treturn this;\n\n\t};\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author alteredq / http://alteredqualia.com/\n\t *\n\t * parameters = {\n\t *  color: <hex>,\n\t *  opacity: <float>,\n\t *\n\t *  map: new THREE.Texture( <Image> ),\n\t *\n\t *  lightMap: new THREE.Texture( <Image> ),\n\t *  lightMapIntensity: <float>\n\t *\n\t *  aoMap: new THREE.Texture( <Image> ),\n\t *  aoMapIntensity: <float>\n\t *\n\t *  emissive: <hex>,\n\t *  emissiveIntensity: <float>\n\t *  emissiveMap: new THREE.Texture( <Image> ),\n\t *\n\t *  specularMap: new THREE.Texture( <Image> ),\n\t *\n\t *  alphaMap: new THREE.Texture( <Image> ),\n\t *\n\t *  envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),\n\t *  combine: THREE.Multiply,\n\t *  reflectivity: <float>,\n\t *  refractionRatio: <float>,\n\t *\n\t *  wireframe: <boolean>,\n\t *  wireframeLinewidth: <float>,\n\t *\n\t *  skinning: <bool>,\n\t *  morphTargets: <bool>,\n\t *  morphNormals: <bool>\n\t * }\n\t */\n\n\tfunction MeshLambertMaterial( parameters ) {\n\n\t\tMaterial.call( this );\n\n\t\tthis.type = 'MeshLambertMaterial';\n\n\t\tthis.color = new Color( 0xffffff ); // diffuse\n\n\t\tthis.map = null;\n\n\t\tthis.lightMap = null;\n\t\tthis.lightMapIntensity = 1.0;\n\n\t\tthis.aoMap = null;\n\t\tthis.aoMapIntensity = 1.0;\n\n\t\tthis.emissive = new Color( 0x000000 );\n\t\tthis.emissiveIntensity = 1.0;\n\t\tthis.emissiveMap = null;\n\n\t\tthis.specularMap = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.envMap = null;\n\t\tthis.combine = MultiplyOperation;\n\t\tthis.reflectivity = 1;\n\t\tthis.refractionRatio = 0.98;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\t\tthis.wireframeLinecap = 'round';\n\t\tthis.wireframeLinejoin = 'round';\n\n\t\tthis.skinning = false;\n\t\tthis.morphTargets = false;\n\t\tthis.morphNormals = false;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tMeshLambertMaterial.prototype = Object.create( Material.prototype );\n\tMeshLambertMaterial.prototype.constructor = MeshLambertMaterial;\n\n\tMeshLambertMaterial.prototype.isMeshLambertMaterial = true;\n\n\tMeshLambertMaterial.prototype.copy = function ( source ) {\n\n\t\tMaterial.prototype.copy.call( this, source );\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.map = source.map;\n\n\t\tthis.lightMap = source.lightMap;\n\t\tthis.lightMapIntensity = source.lightMapIntensity;\n\n\t\tthis.aoMap = source.aoMap;\n\t\tthis.aoMapIntensity = source.aoMapIntensity;\n\n\t\tthis.emissive.copy( source.emissive );\n\t\tthis.emissiveMap = source.emissiveMap;\n\t\tthis.emissiveIntensity = source.emissiveIntensity;\n\n\t\tthis.specularMap = source.specularMap;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.envMap = source.envMap;\n\t\tthis.combine = source.combine;\n\t\tthis.reflectivity = source.reflectivity;\n\t\tthis.refractionRatio = source.refractionRatio;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\t\tthis.wireframeLinecap = source.wireframeLinecap;\n\t\tthis.wireframeLinejoin = source.wireframeLinejoin;\n\n\t\tthis.skinning = source.skinning;\n\t\tthis.morphTargets = source.morphTargets;\n\t\tthis.morphNormals = source.morphNormals;\n\n\t\treturn this;\n\n\t};\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t *\n\t * parameters = {\n\t *  color: <hex>,\n\t *  opacity: <float>,\n\t *\n\t *  linewidth: <float>,\n\t *\n\t *  scale: <float>,\n\t *  dashSize: <float>,\n\t *  gapSize: <float>\n\t * }\n\t */\n\n\tfunction LineDashedMaterial( parameters ) {\n\n\t\tLineBasicMaterial.call( this );\n\n\t\tthis.type = 'LineDashedMaterial';\n\n\t\tthis.scale = 1;\n\t\tthis.dashSize = 3;\n\t\tthis.gapSize = 1;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tLineDashedMaterial.prototype = Object.create( LineBasicMaterial.prototype );\n\tLineDashedMaterial.prototype.constructor = LineDashedMaterial;\n\n\tLineDashedMaterial.prototype.isLineDashedMaterial = true;\n\n\tLineDashedMaterial.prototype.copy = function ( source ) {\n\n\t\tLineBasicMaterial.prototype.copy.call( this, source );\n\n\t\tthis.scale = source.scale;\n\t\tthis.dashSize = source.dashSize;\n\t\tthis.gapSize = source.gapSize;\n\n\t\treturn this;\n\n\t};\n\n\n\n\tvar Materials = Object.freeze({\n\t\tShadowMaterial: ShadowMaterial,\n\t\tSpriteMaterial: SpriteMaterial,\n\t\tRawShaderMaterial: RawShaderMaterial,\n\t\tShaderMaterial: ShaderMaterial,\n\t\tPointsMaterial: PointsMaterial,\n\t\tMeshPhysicalMaterial: MeshPhysicalMaterial,\n\t\tMeshStandardMaterial: MeshStandardMaterial,\n\t\tMeshPhongMaterial: MeshPhongMaterial,\n\t\tMeshToonMaterial: MeshToonMaterial,\n\t\tMeshNormalMaterial: MeshNormalMaterial,\n\t\tMeshLambertMaterial: MeshLambertMaterial,\n\t\tMeshDepthMaterial: MeshDepthMaterial,\n\t\tMeshDistanceMaterial: MeshDistanceMaterial,\n\t\tMeshBasicMaterial: MeshBasicMaterial,\n\t\tLineDashedMaterial: LineDashedMaterial,\n\t\tLineBasicMaterial: LineBasicMaterial,\n\t\tMaterial: Material\n\t});\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tvar Cache = {\n\n\t\tenabled: false,\n\n\t\tfiles: {},\n\n\t\tadd: function ( key, file ) {\n\n\t\t\tif ( this.enabled === false ) return;\n\n\t\t\t// console.log( 'THREE.Cache', 'Adding key:', key );\n\n\t\t\tthis.files[ key ] = file;\n\n\t\t},\n\n\t\tget: function ( key ) {\n\n\t\t\tif ( this.enabled === false ) return;\n\n\t\t\t// console.log( 'THREE.Cache', 'Checking key:', key );\n\n\t\t\treturn this.files[ key ];\n\n\t\t},\n\n\t\tremove: function ( key ) {\n\n\t\t\tdelete this.files[ key ];\n\n\t\t},\n\n\t\tclear: function () {\n\n\t\t\tthis.files = {};\n\n\t\t}\n\n\t};\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction LoadingManager( onLoad, onProgress, onError ) {\n\n\t\tvar scope = this;\n\n\t\tvar isLoading = false, itemsLoaded = 0, itemsTotal = 0;\n\n\t\tthis.onStart = undefined;\n\t\tthis.onLoad = onLoad;\n\t\tthis.onProgress = onProgress;\n\t\tthis.onError = onError;\n\n\t\tthis.itemStart = function ( url ) {\n\n\t\t\titemsTotal ++;\n\n\t\t\tif ( isLoading === false ) {\n\n\t\t\t\tif ( scope.onStart !== undefined ) {\n\n\t\t\t\t\tscope.onStart( url, itemsLoaded, itemsTotal );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tisLoading = true;\n\n\t\t};\n\n\t\tthis.itemEnd = function ( url ) {\n\n\t\t\titemsLoaded ++;\n\n\t\t\tif ( scope.onProgress !== undefined ) {\n\n\t\t\t\tscope.onProgress( url, itemsLoaded, itemsTotal );\n\n\t\t\t}\n\n\t\t\tif ( itemsLoaded === itemsTotal ) {\n\n\t\t\t\tisLoading = false;\n\n\t\t\t\tif ( scope.onLoad !== undefined ) {\n\n\t\t\t\t\tscope.onLoad();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.itemError = function ( url ) {\n\n\t\t\tif ( scope.onError !== undefined ) {\n\n\t\t\t\tscope.onError( url );\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\tvar DefaultLoadingManager = new LoadingManager();\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction FileLoader( manager ) {\n\n\t\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n\t}\n\n\tObject.assign( FileLoader.prototype, {\n\n\t\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\t\tif ( url === undefined ) url = '';\n\n\t\t\tif ( this.path !== undefined ) url = this.path + url;\n\n\t\t\tvar scope = this;\n\n\t\t\tvar cached = Cache.get( url );\n\n\t\t\tif ( cached !== undefined ) {\n\n\t\t\t\tscope.manager.itemStart( url );\n\n\t\t\t\tsetTimeout( function () {\n\n\t\t\t\t\tif ( onLoad ) onLoad( cached );\n\n\t\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t\t}, 0 );\n\n\t\t\t\treturn cached;\n\n\t\t\t}\n\n\t\t\t// Check for data: URI\n\t\t\tvar dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;\n\t\t\tvar dataUriRegexResult = url.match( dataUriRegex );\n\n\t\t\t// Safari can not handle Data URIs through XMLHttpRequest so process manually\n\t\t\tif ( dataUriRegexResult ) {\n\n\t\t\t\tvar mimeType = dataUriRegexResult[ 1 ];\n\t\t\t\tvar isBase64 = !! dataUriRegexResult[ 2 ];\n\t\t\t\tvar data = dataUriRegexResult[ 3 ];\n\n\t\t\t\tdata = window.decodeURIComponent( data );\n\n\t\t\t\tif ( isBase64 ) data = window.atob( data );\n\n\t\t\t\ttry {\n\n\t\t\t\t\tvar response;\n\t\t\t\t\tvar responseType = ( this.responseType || '' ).toLowerCase();\n\n\t\t\t\t\tswitch ( responseType ) {\n\n\t\t\t\t\t\tcase 'arraybuffer':\n\t\t\t\t\t\tcase 'blob':\n\n\t\t\t\t\t\t \tresponse = new ArrayBuffer( data.length );\n\n\t\t\t\t\t\t\tvar view = new Uint8Array( response );\n\n\t\t\t\t\t\t\tfor ( var i = 0; i < data.length; i ++ ) {\n\n\t\t\t\t\t\t\t\tview[ i ] = data.charCodeAt( i );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif ( responseType === 'blob' ) {\n\n\t\t\t\t\t\t\t\tresponse = new Blob( [ response ], { type: mimeType } );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'document':\n\n\t\t\t\t\t\t\tvar parser = new DOMParser();\n\t\t\t\t\t\t\tresponse = parser.parseFromString( data, mimeType );\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'json':\n\n\t\t\t\t\t\t\tresponse = JSON.parse( data );\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault: // 'text' or other\n\n\t\t\t\t\t\t\tresponse = data;\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// Wait for next browser tick\n\t\t\t\t\twindow.setTimeout( function () {\n\n\t\t\t\t\t\tif ( onLoad ) onLoad( response );\n\n\t\t\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t\t\t}, 0 );\n\n\t\t\t\t} catch ( error ) {\n\n\t\t\t\t\t// Wait for next browser tick\n\t\t\t\t\twindow.setTimeout( function () {\n\n\t\t\t\t\t\tif ( onError ) onError( error );\n\n\t\t\t\t\t\tscope.manager.itemEnd( url );\n\t\t\t\t\t\tscope.manager.itemError( url );\n\n\t\t\t\t\t}, 0 );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tvar request = new XMLHttpRequest();\n\t\t\t\trequest.open( 'GET', url, true );\n\n\t\t\t\trequest.addEventListener( 'load', function ( event ) {\n\n\t\t\t\t\tvar response = event.target.response;\n\n\t\t\t\t\tCache.add( url, response );\n\n\t\t\t\t\tif ( this.status === 200 ) {\n\n\t\t\t\t\t\tif ( onLoad ) onLoad( response );\n\n\t\t\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t\t\t} else if ( this.status === 0 ) {\n\n\t\t\t\t\t\t// Some browsers return HTTP Status 0 when using non-http protocol\n\t\t\t\t\t\t// e.g. 'file://' or 'data://'. Handle as success.\n\n\t\t\t\t\t\tconsole.warn( 'THREE.FileLoader: HTTP Status 0 received.' );\n\n\t\t\t\t\t\tif ( onLoad ) onLoad( response );\n\n\t\t\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( onError ) onError( event );\n\n\t\t\t\t\t\tscope.manager.itemEnd( url );\n\t\t\t\t\t\tscope.manager.itemError( url );\n\n\t\t\t\t\t}\n\n\t\t\t\t}, false );\n\n\t\t\t\tif ( onProgress !== undefined ) {\n\n\t\t\t\t\trequest.addEventListener( 'progress', function ( event ) {\n\n\t\t\t\t\t\tonProgress( event );\n\n\t\t\t\t\t}, false );\n\n\t\t\t\t}\n\n\t\t\t\trequest.addEventListener( 'error', function ( event ) {\n\n\t\t\t\t\tif ( onError ) onError( event );\n\n\t\t\t\t\tscope.manager.itemEnd( url );\n\t\t\t\t\tscope.manager.itemError( url );\n\n\t\t\t\t}, false );\n\n\t\t\t\tif ( this.responseType !== undefined ) request.responseType = this.responseType;\n\t\t\t\tif ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;\n\n\t\t\t\tif ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' );\n\n\t\t\t\tfor ( var header in this.requestHeader ) {\n\n\t\t\t\t\trequest.setRequestHeader( header, this.requestHeader[ header ] );\n\n\t\t\t\t}\n\n\t\t\t\trequest.send( null );\n\n\t\t\t}\n\n\t\t\tscope.manager.itemStart( url );\n\n\t\t\treturn request;\n\n\t\t},\n\n\t\tsetPath: function ( value ) {\n\n\t\t\tthis.path = value;\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetResponseType: function ( value ) {\n\n\t\t\tthis.responseType = value;\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetWithCredentials: function ( value ) {\n\n\t\t\tthis.withCredentials = value;\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetMimeType: function ( value ) {\n\n\t\t\tthis.mimeType = value;\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetRequestHeader: function ( value ) {\n\n\t\t\tthis.requestHeader = value;\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t *\n\t * Abstract Base class to block based textures loader (dds, pvr, ...)\n\t */\n\n\tfunction CompressedTextureLoader( manager ) {\n\n\t\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n\t\t// override in sub classes\n\t\tthis._parser = null;\n\n\t}\n\n\tObject.assign( CompressedTextureLoader.prototype, {\n\n\t\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\t\tvar scope = this;\n\n\t\t\tvar images = [];\n\n\t\t\tvar texture = new CompressedTexture();\n\t\t\ttexture.image = images;\n\n\t\t\tvar loader = new FileLoader( this.manager );\n\t\t\tloader.setPath( this.path );\n\t\t\tloader.setResponseType( 'arraybuffer' );\n\n\t\t\tfunction loadTexture( i ) {\n\n\t\t\t\tloader.load( url[ i ], function ( buffer ) {\n\n\t\t\t\t\tvar texDatas = scope._parser( buffer, true );\n\n\t\t\t\t\timages[ i ] = {\n\t\t\t\t\t\twidth: texDatas.width,\n\t\t\t\t\t\theight: texDatas.height,\n\t\t\t\t\t\tformat: texDatas.format,\n\t\t\t\t\t\tmipmaps: texDatas.mipmaps\n\t\t\t\t\t};\n\n\t\t\t\t\tloaded += 1;\n\n\t\t\t\t\tif ( loaded === 6 ) {\n\n\t\t\t\t\t\tif ( texDatas.mipmapCount === 1 )\n\t\t\t\t\t\t\ttexture.minFilter = LinearFilter;\n\n\t\t\t\t\t\ttexture.format = texDatas.format;\n\t\t\t\t\t\ttexture.needsUpdate = true;\n\n\t\t\t\t\t\tif ( onLoad ) onLoad( texture );\n\n\t\t\t\t\t}\n\n\t\t\t\t}, onProgress, onError );\n\n\t\t\t}\n\n\t\t\tif ( Array.isArray( url ) ) {\n\n\t\t\t\tvar loaded = 0;\n\n\t\t\t\tfor ( var i = 0, il = url.length; i < il; ++ i ) {\n\n\t\t\t\t\tloadTexture( i );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// compressed cubemap texture stored in a single DDS file\n\n\t\t\t\tloader.load( url, function ( buffer ) {\n\n\t\t\t\t\tvar texDatas = scope._parser( buffer, true );\n\n\t\t\t\t\tif ( texDatas.isCubemap ) {\n\n\t\t\t\t\t\tvar faces = texDatas.mipmaps.length / texDatas.mipmapCount;\n\n\t\t\t\t\t\tfor ( var f = 0; f < faces; f ++ ) {\n\n\t\t\t\t\t\t\timages[ f ] = { mipmaps : [] };\n\n\t\t\t\t\t\t\tfor ( var i = 0; i < texDatas.mipmapCount; i ++ ) {\n\n\t\t\t\t\t\t\t\timages[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] );\n\t\t\t\t\t\t\t\timages[ f ].format = texDatas.format;\n\t\t\t\t\t\t\t\timages[ f ].width = texDatas.width;\n\t\t\t\t\t\t\t\timages[ f ].height = texDatas.height;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\ttexture.image.width = texDatas.width;\n\t\t\t\t\t\ttexture.image.height = texDatas.height;\n\t\t\t\t\t\ttexture.mipmaps = texDatas.mipmaps;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( texDatas.mipmapCount === 1 ) {\n\n\t\t\t\t\t\ttexture.minFilter = LinearFilter;\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttexture.format = texDatas.format;\n\t\t\t\t\ttexture.needsUpdate = true;\n\n\t\t\t\t\tif ( onLoad ) onLoad( texture );\n\n\t\t\t\t}, onProgress, onError );\n\n\t\t\t}\n\n\t\t\treturn texture;\n\n\t\t},\n\n\t\tsetPath: function ( value ) {\n\n\t\t\tthis.path = value;\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author Nikos M. / https://github.com/foo123/\n\t *\n\t * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...)\n\t */\n\n\tfunction DataTextureLoader( manager ) {\n\n\t\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n\t\t// override in sub classes\n\t\tthis._parser = null;\n\n\t}\n\n\tObject.assign( DataTextureLoader.prototype, {\n\n\t\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\t\tvar scope = this;\n\n\t\t\tvar texture = new DataTexture();\n\n\t\t\tvar loader = new FileLoader( this.manager );\n\t\t\tloader.setResponseType( 'arraybuffer' );\n\n\t\t\tloader.load( url, function ( buffer ) {\n\n\t\t\t\tvar texData = scope._parser( buffer );\n\n\t\t\t\tif ( ! texData ) return;\n\n\t\t\t\tif ( undefined !== texData.image ) {\n\n\t\t\t\t\ttexture.image = texData.image;\n\n\t\t\t\t} else if ( undefined !== texData.data ) {\n\n\t\t\t\t\ttexture.image.width = texData.width;\n\t\t\t\t\ttexture.image.height = texData.height;\n\t\t\t\t\ttexture.image.data = texData.data;\n\n\t\t\t\t}\n\n\t\t\t\ttexture.wrapS = undefined !== texData.wrapS ? texData.wrapS : ClampToEdgeWrapping;\n\t\t\t\ttexture.wrapT = undefined !== texData.wrapT ? texData.wrapT : ClampToEdgeWrapping;\n\n\t\t\t\ttexture.magFilter = undefined !== texData.magFilter ? texData.magFilter : LinearFilter;\n\t\t\t\ttexture.minFilter = undefined !== texData.minFilter ? texData.minFilter : LinearMipMapLinearFilter;\n\n\t\t\t\ttexture.anisotropy = undefined !== texData.anisotropy ? texData.anisotropy : 1;\n\n\t\t\t\tif ( undefined !== texData.format ) {\n\n\t\t\t\t\ttexture.format = texData.format;\n\n\t\t\t\t}\n\t\t\t\tif ( undefined !== texData.type ) {\n\n\t\t\t\t\ttexture.type = texData.type;\n\n\t\t\t\t}\n\n\t\t\t\tif ( undefined !== texData.mipmaps ) {\n\n\t\t\t\t\ttexture.mipmaps = texData.mipmaps;\n\n\t\t\t\t}\n\n\t\t\t\tif ( 1 === texData.mipmapCount ) {\n\n\t\t\t\t\ttexture.minFilter = LinearFilter;\n\n\t\t\t\t}\n\n\t\t\t\ttexture.needsUpdate = true;\n\n\t\t\t\tif ( onLoad ) onLoad( texture, texData );\n\n\t\t\t}, onProgress, onError );\n\n\n\t\t\treturn texture;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction ImageLoader( manager ) {\n\n\t\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n\t}\n\n\tObject.assign( ImageLoader.prototype, {\n\n\t\tcrossOrigin: 'Anonymous',\n\n\t\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\t\tif ( url === undefined ) url = '';\n\n\t\t\tif ( this.path !== undefined ) url = this.path + url;\n\n\t\t\tvar scope = this;\n\n\t\t\tvar cached = Cache.get( url );\n\n\t\t\tif ( cached !== undefined ) {\n\n\t\t\t\tscope.manager.itemStart( url );\n\n\t\t\t\tsetTimeout( function () {\n\n\t\t\t\t\tif ( onLoad ) onLoad( cached );\n\n\t\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t\t}, 0 );\n\n\t\t\t\treturn cached;\n\n\t\t\t}\n\n\t\t\tvar image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' );\n\n\t\t\timage.addEventListener( 'load', function () {\n\n\t\t\t\tCache.add( url, this );\n\n\t\t\t\tif ( onLoad ) onLoad( this );\n\n\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t}, false );\n\n\t\t\t/*\n\t\t\timage.addEventListener( 'progress', function ( event ) {\n\n\t\t\t\tif ( onProgress ) onProgress( event );\n\n\t\t\t}, false );\n\t\t\t*/\n\n\t\t\timage.addEventListener( 'error', function ( event ) {\n\n\t\t\t\tif ( onError ) onError( event );\n\n\t\t\t\tscope.manager.itemEnd( url );\n\t\t\t\tscope.manager.itemError( url );\n\n\t\t\t}, false );\n\n\t\t\tif ( url.substr( 0, 5 ) !== 'data:' ) {\n\n\t\t\t\tif ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;\n\n\t\t\t}\n\n\t\t\tscope.manager.itemStart( url );\n\n\t\t\timage.src = url;\n\n\t\t\treturn image;\n\n\t\t},\n\n\t\tsetCrossOrigin: function ( value ) {\n\n\t\t\tthis.crossOrigin = value;\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetPath: function ( value ) {\n\n\t\t\tthis.path = value;\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction CubeTextureLoader( manager ) {\n\n\t\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n\t}\n\n\tObject.assign( CubeTextureLoader.prototype, {\n\n\t\tcrossOrigin: 'Anonymous',\n\n\t\tload: function ( urls, onLoad, onProgress, onError ) {\n\n\t\t\tvar texture = new CubeTexture();\n\n\t\t\tvar loader = new ImageLoader( this.manager );\n\t\t\tloader.setCrossOrigin( this.crossOrigin );\n\t\t\tloader.setPath( this.path );\n\n\t\t\tvar loaded = 0;\n\n\t\t\tfunction loadTexture( i ) {\n\n\t\t\t\tloader.load( urls[ i ], function ( image ) {\n\n\t\t\t\t\ttexture.images[ i ] = image;\n\n\t\t\t\t\tloaded ++;\n\n\t\t\t\t\tif ( loaded === 6 ) {\n\n\t\t\t\t\t\ttexture.needsUpdate = true;\n\n\t\t\t\t\t\tif ( onLoad ) onLoad( texture );\n\n\t\t\t\t\t}\n\n\t\t\t\t}, undefined, onError );\n\n\t\t\t}\n\n\t\t\tfor ( var i = 0; i < urls.length; ++ i ) {\n\n\t\t\t\tloadTexture( i );\n\n\t\t\t}\n\n\t\t\treturn texture;\n\n\t\t},\n\n\t\tsetCrossOrigin: function ( value ) {\n\n\t\t\tthis.crossOrigin = value;\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetPath: function ( value ) {\n\n\t\t\tthis.path = value;\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction TextureLoader( manager ) {\n\n\t\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n\t}\n\n\tObject.assign( TextureLoader.prototype, {\n\n\t\tcrossOrigin: 'Anonymous',\n\n\t\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\t\tvar loader = new ImageLoader( this.manager );\n\t\t\tloader.setCrossOrigin( this.crossOrigin );\n\t\t\tloader.setPath( this.path );\n\n\t\t\tvar texture = new Texture();\n\t\t\ttexture.image = loader.load( url, function () {\n\n\t\t\t\t// JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB.\n\t\t\t\tvar isJPEG = url.search( /\\.(jpg|jpeg)$/ ) > 0 || url.search( /^data\\:image\\/jpeg/ ) === 0;\n\n\t\t\t\ttexture.format = isJPEG ? RGBFormat : RGBAFormat;\n\t\t\t\ttexture.needsUpdate = true;\n\n\t\t\t\tif ( onLoad !== undefined ) {\n\n\t\t\t\t\tonLoad( texture );\n\n\t\t\t\t}\n\n\t\t\t}, onProgress, onError );\n\n\t\t\treturn texture;\n\n\t\t},\n\n\t\tsetCrossOrigin: function ( value ) {\n\n\t\t\tthis.crossOrigin = value;\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetPath: function ( value ) {\n\n\t\t\tthis.path = value;\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tfunction Light( color, intensity ) {\n\n\t\tObject3D.call( this );\n\n\t\tthis.type = 'Light';\n\n\t\tthis.color = new Color( color );\n\t\tthis.intensity = intensity !== undefined ? intensity : 1;\n\n\t\tthis.receiveShadow = undefined;\n\n\t}\n\n\tLight.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\t\tconstructor: Light,\n\n\t\tisLight: true,\n\n\t\tcopy: function ( source ) {\n\n\t\t\tObject3D.prototype.copy.call( this, source );\n\n\t\t\tthis.color.copy( source.color );\n\t\t\tthis.intensity = source.intensity;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\ttoJSON: function ( meta ) {\n\n\t\t\tvar data = Object3D.prototype.toJSON.call( this, meta );\n\n\t\t\tdata.object.color = this.color.getHex();\n\t\t\tdata.object.intensity = this.intensity;\n\n\t\t\tif ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex();\n\n\t\t\tif ( this.distance !== undefined ) data.object.distance = this.distance;\n\t\t\tif ( this.angle !== undefined ) data.object.angle = this.angle;\n\t\t\tif ( this.decay !== undefined ) data.object.decay = this.decay;\n\t\t\tif ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra;\n\n\t\t\tif ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON();\n\n\t\t\treturn data;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tfunction HemisphereLight( skyColor, groundColor, intensity ) {\n\n\t\tLight.call( this, skyColor, intensity );\n\n\t\tthis.type = 'HemisphereLight';\n\n\t\tthis.castShadow = undefined;\n\n\t\tthis.position.copy( Object3D.DefaultUp );\n\t\tthis.updateMatrix();\n\n\t\tthis.groundColor = new Color( groundColor );\n\n\t}\n\n\tHemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), {\n\n\t\tconstructor: HemisphereLight,\n\n\t\tisHemisphereLight: true,\n\n\t\tcopy: function ( source ) {\n\n\t\t\tLight.prototype.copy.call( this, source );\n\n\t\t\tthis.groundColor.copy( source.groundColor );\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction LightShadow( camera ) {\n\n\t\tthis.camera = camera;\n\n\t\tthis.bias = 0;\n\t\tthis.radius = 1;\n\n\t\tthis.mapSize = new Vector2( 512, 512 );\n\n\t\tthis.map = null;\n\t\tthis.matrix = new Matrix4();\n\n\t}\n\n\tObject.assign( LightShadow.prototype, {\n\n\t\tcopy: function ( source ) {\n\n\t\t\tthis.camera = source.camera.clone();\n\n\t\t\tthis.bias = source.bias;\n\t\t\tthis.radius = source.radius;\n\n\t\t\tthis.mapSize.copy( source.mapSize );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor().copy( this );\n\n\t\t},\n\n\t\ttoJSON: function () {\n\n\t\t\tvar object = {};\n\n\t\t\tif ( this.bias !== 0 ) object.bias = this.bias;\n\t\t\tif ( this.radius !== 1 ) object.radius = this.radius;\n\t\t\tif ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray();\n\n\t\t\tobject.camera = this.camera.toJSON( false ).object;\n\t\t\tdelete object.camera.matrix;\n\n\t\t\treturn object;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction SpotLightShadow() {\n\n\t\tLightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) );\n\n\t}\n\n\tSpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {\n\n\t\tconstructor: SpotLightShadow,\n\n\t\tisSpotLightShadow: true,\n\n\t\tupdate: function ( light ) {\n\n\t\t\tvar camera = this.camera;\n\n\t\t\tvar fov = _Math.RAD2DEG * 2 * light.angle;\n\t\t\tvar aspect = this.mapSize.width / this.mapSize.height;\n\t\t\tvar far = light.distance || camera.far;\n\n\t\t\tif ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) {\n\n\t\t\t\tcamera.fov = fov;\n\t\t\t\tcamera.aspect = aspect;\n\t\t\t\tcamera.far = far;\n\t\t\t\tcamera.updateProjectionMatrix();\n\n\t\t\t}\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tfunction SpotLight( color, intensity, distance, angle, penumbra, decay ) {\n\n\t\tLight.call( this, color, intensity );\n\n\t\tthis.type = 'SpotLight';\n\n\t\tthis.position.copy( Object3D.DefaultUp );\n\t\tthis.updateMatrix();\n\n\t\tthis.target = new Object3D();\n\n\t\tObject.defineProperty( this, 'power', {\n\t\t\tget: function () {\n\t\t\t\t// intensity = power per solid angle.\n\t\t\t\t// ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf\n\t\t\t\treturn this.intensity * Math.PI;\n\t\t\t},\n\t\t\tset: function ( power ) {\n\t\t\t\t// intensity = power per solid angle.\n\t\t\t\t// ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf\n\t\t\t\tthis.intensity = power / Math.PI;\n\t\t\t}\n\t\t} );\n\n\t\tthis.distance = ( distance !== undefined ) ? distance : 0;\n\t\tthis.angle = ( angle !== undefined ) ? angle : Math.PI / 3;\n\t\tthis.penumbra = ( penumbra !== undefined ) ? penumbra : 0;\n\t\tthis.decay = ( decay !== undefined ) ? decay : 1;\t// for physically correct lights, should be 2.\n\n\t\tthis.shadow = new SpotLightShadow();\n\n\t}\n\n\tSpotLight.prototype = Object.assign( Object.create( Light.prototype ), {\n\n\t\tconstructor: SpotLight,\n\n\t\tisSpotLight: true,\n\n\t\tcopy: function ( source ) {\n\n\t\t\tLight.prototype.copy.call( this, source );\n\n\t\t\tthis.distance = source.distance;\n\t\t\tthis.angle = source.angle;\n\t\t\tthis.penumbra = source.penumbra;\n\t\t\tthis.decay = source.decay;\n\n\t\t\tthis.target = source.target.clone();\n\n\t\t\tthis.shadow = source.shadow.clone();\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\n\tfunction PointLight( color, intensity, distance, decay ) {\n\n\t\tLight.call( this, color, intensity );\n\n\t\tthis.type = 'PointLight';\n\n\t\tObject.defineProperty( this, 'power', {\n\t\t\tget: function () {\n\t\t\t\t// intensity = power per solid angle.\n\t\t\t\t// ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf\n\t\t\t\treturn this.intensity * 4 * Math.PI;\n\n\t\t\t},\n\t\t\tset: function ( power ) {\n\t\t\t\t// intensity = power per solid angle.\n\t\t\t\t// ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf\n\t\t\t\tthis.intensity = power / ( 4 * Math.PI );\n\t\t\t}\n\t\t} );\n\n\t\tthis.distance = ( distance !== undefined ) ? distance : 0;\n\t\tthis.decay = ( decay !== undefined ) ? decay : 1;\t// for physically correct lights, should be 2.\n\n\t\tthis.shadow = new LightShadow( new PerspectiveCamera( 90, 1, 0.5, 500 ) );\n\n\t}\n\n\tPointLight.prototype = Object.assign( Object.create( Light.prototype ), {\n\n\t\tconstructor: PointLight,\n\n\t\tisPointLight: true,\n\n\t\tcopy: function ( source ) {\n\n\t\t\tLight.prototype.copy.call( this, source );\n\n\t\t\tthis.distance = source.distance;\n\t\t\tthis.decay = source.decay;\n\n\t\t\tthis.shadow = source.shadow.clone();\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction DirectionalLightShadow( ) {\n\n\t\tLightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) );\n\n\t}\n\n\tDirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {\n\n\t\tconstructor: DirectionalLightShadow\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tfunction DirectionalLight( color, intensity ) {\n\n\t\tLight.call( this, color, intensity );\n\n\t\tthis.type = 'DirectionalLight';\n\n\t\tthis.position.copy( Object3D.DefaultUp );\n\t\tthis.updateMatrix();\n\n\t\tthis.target = new Object3D();\n\n\t\tthis.shadow = new DirectionalLightShadow();\n\n\t}\n\n\tDirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), {\n\n\t\tconstructor: DirectionalLight,\n\n\t\tisDirectionalLight: true,\n\n\t\tcopy: function ( source ) {\n\n\t\t\tLight.prototype.copy.call( this, source );\n\n\t\t\tthis.target = source.target.clone();\n\n\t\t\tthis.shadow = source.shadow.clone();\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction AmbientLight( color, intensity ) {\n\n\t\tLight.call( this, color, intensity );\n\n\t\tthis.type = 'AmbientLight';\n\n\t\tthis.castShadow = undefined;\n\n\t}\n\n\tAmbientLight.prototype = Object.assign( Object.create( Light.prototype ), {\n\n\t\tconstructor: AmbientLight,\n\n\t\tisAmbientLight: true\n\n\t} );\n\n\t/**\n\t * @author abelnation / http://github.com/abelnation\n\t */\n\n\tfunction RectAreaLight( color, intensity, width, height ) {\n\n\t\tLight.call( this, color, intensity );\n\n\t\tthis.type = 'RectAreaLight';\n\n\t\tthis.position.set( 0, 1, 0 );\n\t\tthis.updateMatrix();\n\n\t\tthis.width = ( width !== undefined ) ? width : 10;\n\t\tthis.height = ( height !== undefined ) ? height : 10;\n\n\t\t// TODO (abelnation): distance/decay\n\n\t\t// TODO (abelnation): update method for RectAreaLight to update transform to lookat target\n\n\t\t// TODO (abelnation): shadows\n\n\t}\n\n\t// TODO (abelnation): RectAreaLight update when light shape is changed\n\tRectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), {\n\n\t\tconstructor: RectAreaLight,\n\n\t\tisRectAreaLight: true,\n\n\t\tcopy: function ( source ) {\n\n\t\t\tLight.prototype.copy.call( this, source );\n\n\t\t\tthis.width = source.width;\n\t\t\tthis.height = source.height;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\ttoJSON: function ( meta ) {\n\n\t\t\tvar data = Light.prototype.toJSON.call( this, meta );\n\n\t\t\tdata.object.width = this.width;\n\t\t\tdata.object.height = this.height;\n\n\t\t\treturn data;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author tschw\n\t * @author Ben Houston / http://clara.io/\n\t * @author David Sarno / http://lighthaus.us/\n\t */\n\n\tvar AnimationUtils = {\n\n\t\t// same as Array.prototype.slice, but also works on typed arrays\n\t\tarraySlice: function ( array, from, to ) {\n\n\t\t\tif ( AnimationUtils.isTypedArray( array ) ) {\n\n\t\t\t\t// in ios9 array.subarray(from, undefined) will return empty array\n\t\t\t\t// but array.subarray(from) or array.subarray(from, len) is correct\n\t\t\t\treturn new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) );\n\n\t\t\t}\n\n\t\t\treturn array.slice( from, to );\n\n\t\t},\n\n\t\t// converts an array to a specific type\n\t\tconvertArray: function ( array, type, forceClone ) {\n\n\t\t\tif ( ! array || // let 'undefined' and 'null' pass\n\t\t\t\t\t! forceClone && array.constructor === type ) return array;\n\n\t\t\tif ( typeof type.BYTES_PER_ELEMENT === 'number' ) {\n\n\t\t\t\treturn new type( array ); // create typed array\n\n\t\t\t}\n\n\t\t\treturn Array.prototype.slice.call( array ); // create Array\n\n\t\t},\n\n\t\tisTypedArray: function ( object ) {\n\n\t\t\treturn ArrayBuffer.isView( object ) &&\n\t\t\t\t\t! ( object instanceof DataView );\n\n\t\t},\n\n\t\t// returns an array by which times and values can be sorted\n\t\tgetKeyframeOrder: function ( times ) {\n\n\t\t\tfunction compareTime( i, j ) {\n\n\t\t\t\treturn times[ i ] - times[ j ];\n\n\t\t\t}\n\n\t\t\tvar n = times.length;\n\t\t\tvar result = new Array( n );\n\t\t\tfor ( var i = 0; i !== n; ++ i ) result[ i ] = i;\n\n\t\t\tresult.sort( compareTime );\n\n\t\t\treturn result;\n\n\t\t},\n\n\t\t// uses the array previously returned by 'getKeyframeOrder' to sort data\n\t\tsortedArray: function ( values, stride, order ) {\n\n\t\t\tvar nValues = values.length;\n\t\t\tvar result = new values.constructor( nValues );\n\n\t\t\tfor ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {\n\n\t\t\t\tvar srcOffset = order[ i ] * stride;\n\n\t\t\t\tfor ( var j = 0; j !== stride; ++ j ) {\n\n\t\t\t\t\tresult[ dstOffset ++ ] = values[ srcOffset + j ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn result;\n\n\t\t},\n\n\t\t// function for parsing AOS keyframe formats\n\t\tflattenJSON: function ( jsonKeys, times, values, valuePropertyName ) {\n\n\t\t\tvar i = 1, key = jsonKeys[ 0 ];\n\n\t\t\twhile ( key !== undefined && key[ valuePropertyName ] === undefined ) {\n\n\t\t\t\tkey = jsonKeys[ i ++ ];\n\n\t\t\t}\n\n\t\t\tif ( key === undefined ) return; // no data\n\n\t\t\tvar value = key[ valuePropertyName ];\n\t\t\tif ( value === undefined ) return; // no data\n\n\t\t\tif ( Array.isArray( value ) ) {\n\n\t\t\t\tdo {\n\n\t\t\t\t\tvalue = key[ valuePropertyName ];\n\n\t\t\t\t\tif ( value !== undefined ) {\n\n\t\t\t\t\t\ttimes.push( key.time );\n\t\t\t\t\t\tvalues.push.apply( values, value ); // push all elements\n\n\t\t\t\t\t}\n\n\t\t\t\t\tkey = jsonKeys[ i ++ ];\n\n\t\t\t\t} while ( key !== undefined );\n\n\t\t\t} else if ( value.toArray !== undefined ) {\n\n\t\t\t\t// ...assume THREE.Math-ish\n\n\t\t\t\tdo {\n\n\t\t\t\t\tvalue = key[ valuePropertyName ];\n\n\t\t\t\t\tif ( value !== undefined ) {\n\n\t\t\t\t\t\ttimes.push( key.time );\n\t\t\t\t\t\tvalue.toArray( values, values.length );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tkey = jsonKeys[ i ++ ];\n\n\t\t\t\t} while ( key !== undefined );\n\n\t\t\t} else {\n\n\t\t\t\t// otherwise push as-is\n\n\t\t\t\tdo {\n\n\t\t\t\t\tvalue = key[ valuePropertyName ];\n\n\t\t\t\t\tif ( value !== undefined ) {\n\n\t\t\t\t\t\ttimes.push( key.time );\n\t\t\t\t\t\tvalues.push( value );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tkey = jsonKeys[ i ++ ];\n\n\t\t\t\t} while ( key !== undefined );\n\n\t\t\t}\n\n\t\t}\n\n\t};\n\n\t/**\n\t * Abstract base class of interpolants over parametric samples.\n\t *\n\t * The parameter domain is one dimensional, typically the time or a path\n\t * along a curve defined by the data.\n\t *\n\t * The sample values can have any dimensionality and derived classes may\n\t * apply special interpretations to the data.\n\t *\n\t * This class provides the interval seek in a Template Method, deferring\n\t * the actual interpolation to derived classes.\n\t *\n\t * Time complexity is O(1) for linear access crossing at most two points\n\t * and O(log N) for random access, where N is the number of positions.\n\t *\n\t * References:\n\t *\n\t * \t\thttp://www.oodesign.com/template-method-pattern.html\n\t *\n\t * @author tschw\n\t */\n\n\tfunction Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\t\tthis.parameterPositions = parameterPositions;\n\t\tthis._cachedIndex = 0;\n\n\t\tthis.resultBuffer = resultBuffer !== undefined ?\n\t\t\t\tresultBuffer : new sampleValues.constructor( sampleSize );\n\t\tthis.sampleValues = sampleValues;\n\t\tthis.valueSize = sampleSize;\n\n\t}\n\n\tObject.assign( Interpolant.prototype, {\n\n\t\tevaluate: function( t ) {\n\n\t\t\tvar pp = this.parameterPositions,\n\t\t\t\ti1 = this._cachedIndex,\n\n\t\t\t\tt1 = pp[   i1   ],\n\t\t\t\tt0 = pp[ i1 - 1 ];\n\n\t\t\tvalidate_interval: {\n\n\t\t\t\tseek: {\n\n\t\t\t\t\tvar right;\n\n\t\t\t\t\tlinear_scan: {\n\t\t\t\t\t\t//- See http://jsperf.com/comparison-to-undefined/3\n\t\t\t\t\t\t//- slower code:\n\t\t\t\t\t\t//-\n\t\t\t\t\t\t//- \t\t\t\tif ( t >= t1 || t1 === undefined ) {\n\t\t\t\t\t\tforward_scan: if ( ! ( t < t1 ) ) {\n\n\t\t\t\t\t\t\tfor ( var giveUpAt = i1 + 2; ;) {\n\n\t\t\t\t\t\t\t\tif ( t1 === undefined ) {\n\n\t\t\t\t\t\t\t\t\tif ( t < t0 ) break forward_scan;\n\n\t\t\t\t\t\t\t\t\t// after end\n\n\t\t\t\t\t\t\t\t\ti1 = pp.length;\n\t\t\t\t\t\t\t\t\tthis._cachedIndex = i1;\n\t\t\t\t\t\t\t\t\treturn this.afterEnd_( i1 - 1, t, t0 );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif ( i1 === giveUpAt ) break; // this loop\n\n\t\t\t\t\t\t\t\tt0 = t1;\n\t\t\t\t\t\t\t\tt1 = pp[ ++ i1 ];\n\n\t\t\t\t\t\t\t\tif ( t < t1 ) {\n\n\t\t\t\t\t\t\t\t\t// we have arrived at the sought interval\n\t\t\t\t\t\t\t\t\tbreak seek;\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// prepare binary search on the right side of the index\n\t\t\t\t\t\t\tright = pp.length;\n\t\t\t\t\t\t\tbreak linear_scan;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t//- slower code:\n\t\t\t\t\t\t//-\t\t\t\t\tif ( t < t0 || t0 === undefined ) {\n\t\t\t\t\t\tif ( ! ( t >= t0 ) ) {\n\n\t\t\t\t\t\t\t// looping?\n\n\t\t\t\t\t\t\tvar t1global = pp[ 1 ];\n\n\t\t\t\t\t\t\tif ( t < t1global ) {\n\n\t\t\t\t\t\t\t\ti1 = 2; // + 1, using the scan for the details\n\t\t\t\t\t\t\t\tt0 = t1global;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// linear reverse scan\n\n\t\t\t\t\t\t\tfor ( var giveUpAt = i1 - 2; ;) {\n\n\t\t\t\t\t\t\t\tif ( t0 === undefined ) {\n\n\t\t\t\t\t\t\t\t\t// before start\n\n\t\t\t\t\t\t\t\t\tthis._cachedIndex = 0;\n\t\t\t\t\t\t\t\t\treturn this.beforeStart_( 0, t, t1 );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif ( i1 === giveUpAt ) break; // this loop\n\n\t\t\t\t\t\t\t\tt1 = t0;\n\t\t\t\t\t\t\t\tt0 = pp[ -- i1 - 1 ];\n\n\t\t\t\t\t\t\t\tif ( t >= t0 ) {\n\n\t\t\t\t\t\t\t\t\t// we have arrived at the sought interval\n\t\t\t\t\t\t\t\t\tbreak seek;\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// prepare binary search on the left side of the index\n\t\t\t\t\t\t\tright = i1;\n\t\t\t\t\t\t\ti1 = 0;\n\t\t\t\t\t\t\tbreak linear_scan;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// the interval is valid\n\n\t\t\t\t\t\tbreak validate_interval;\n\n\t\t\t\t\t} // linear scan\n\n\t\t\t\t\t// binary search\n\n\t\t\t\t\twhile ( i1 < right ) {\n\n\t\t\t\t\t\tvar mid = ( i1 + right ) >>> 1;\n\n\t\t\t\t\t\tif ( t < pp[ mid ] ) {\n\n\t\t\t\t\t\t\tright = mid;\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\ti1 = mid + 1;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tt1 = pp[   i1   ];\n\t\t\t\t\tt0 = pp[ i1 - 1 ];\n\n\t\t\t\t\t// check boundary cases, again\n\n\t\t\t\t\tif ( t0 === undefined ) {\n\n\t\t\t\t\t\tthis._cachedIndex = 0;\n\t\t\t\t\t\treturn this.beforeStart_( 0, t, t1 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( t1 === undefined ) {\n\n\t\t\t\t\t\ti1 = pp.length;\n\t\t\t\t\t\tthis._cachedIndex = i1;\n\t\t\t\t\t\treturn this.afterEnd_( i1 - 1, t0, t );\n\n\t\t\t\t\t}\n\n\t\t\t\t} // seek\n\n\t\t\t\tthis._cachedIndex = i1;\n\n\t\t\t\tthis.intervalChanged_( i1, t0, t1 );\n\n\t\t\t} // validate_interval\n\n\t\t\treturn this.interpolate_( i1, t0, t, t1 );\n\n\t\t},\n\n\t\tsettings: null, // optional, subclass-specific settings structure\n\t\t// Note: The indirection allows central control of many interpolants.\n\n\t\t// --- Protected interface\n\n\t\tDefaultSettings_: {},\n\n\t\tgetSettings_: function() {\n\n\t\t\treturn this.settings || this.DefaultSettings_;\n\n\t\t},\n\n\t\tcopySampleValue_: function( index ) {\n\n\t\t\t// copies a sample value to the result buffer\n\n\t\t\tvar result = this.resultBuffer,\n\t\t\t\tvalues = this.sampleValues,\n\t\t\t\tstride = this.valueSize,\n\t\t\t\toffset = index * stride;\n\n\t\t\tfor ( var i = 0; i !== stride; ++ i ) {\n\n\t\t\t\tresult[ i ] = values[ offset + i ];\n\n\t\t\t}\n\n\t\t\treturn result;\n\n\t\t},\n\n\t\t// Template methods for derived classes:\n\n\t\tinterpolate_: function( i1, t0, t, t1 ) {\n\n\t\t\tthrow new Error( \"call to abstract method\" );\n\t\t\t// implementations shall return this.resultBuffer\n\n\t\t},\n\n\t\tintervalChanged_: function( i1, t0, t1 ) {\n\n\t\t\t// empty\n\n\t\t}\n\n\t} );\n\n\t//!\\ DECLARE ALIAS AFTER assign prototype !\n\tObject.assign( Interpolant.prototype, {\n\n\t\t//( 0, t, t0 ), returns this.resultBuffer\n\t\tbeforeStart_: Interpolant.prototype.copySampleValue_,\n\n\t\t//( N-1, tN-1, t ), returns this.resultBuffer\n\t\tafterEnd_: Interpolant.prototype.copySampleValue_,\n\n\t} );\n\n\t/**\n\t * Fast and simple cubic spline interpolant.\n\t *\n\t * It was derived from a Hermitian construction setting the first derivative\n\t * at each sample position to the linear slope between neighboring positions\n\t * over their parameter interval.\n\t *\n\t * @author tschw\n\t */\n\n\tfunction CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\t\tInterpolant.call(\n\t\t\t\tthis, parameterPositions, sampleValues, sampleSize, resultBuffer );\n\n\t\tthis._weightPrev = -0;\n\t\tthis._offsetPrev = -0;\n\t\tthis._weightNext = -0;\n\t\tthis._offsetNext = -0;\n\n\t}\n\n\tCubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {\n\n\t\tconstructor: CubicInterpolant,\n\n\t\tDefaultSettings_: {\n\n\t\t\tendingStart: \tZeroCurvatureEnding,\n\t\t\tendingEnd:\t\tZeroCurvatureEnding\n\n\t\t},\n\n\t\tintervalChanged_: function( i1, t0, t1 ) {\n\n\t\t\tvar pp = this.parameterPositions,\n\t\t\t\tiPrev = i1 - 2,\n\t\t\t\tiNext = i1 + 1,\n\n\t\t\t\ttPrev = pp[ iPrev ],\n\t\t\t\ttNext = pp[ iNext ];\n\n\t\t\tif ( tPrev === undefined ) {\n\n\t\t\t\tswitch ( this.getSettings_().endingStart ) {\n\n\t\t\t\t\tcase ZeroSlopeEnding:\n\n\t\t\t\t\t\t// f'(t0) = 0\n\t\t\t\t\t\tiPrev = i1;\n\t\t\t\t\t\ttPrev = 2 * t0 - t1;\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase WrapAroundEnding:\n\n\t\t\t\t\t\t// use the other end of the curve\n\t\t\t\t\t\tiPrev = pp.length - 2;\n\t\t\t\t\t\ttPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault: // ZeroCurvatureEnding\n\n\t\t\t\t\t\t// f''(t0) = 0 a.k.a. Natural Spline\n\t\t\t\t\t\tiPrev = i1;\n\t\t\t\t\t\ttPrev = t1;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( tNext === undefined ) {\n\n\t\t\t\tswitch ( this.getSettings_().endingEnd ) {\n\n\t\t\t\t\tcase ZeroSlopeEnding:\n\n\t\t\t\t\t\t// f'(tN) = 0\n\t\t\t\t\t\tiNext = i1;\n\t\t\t\t\t\ttNext = 2 * t1 - t0;\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase WrapAroundEnding:\n\n\t\t\t\t\t\t// use the other end of the curve\n\t\t\t\t\t\tiNext = 1;\n\t\t\t\t\t\ttNext = t1 + pp[ 1 ] - pp[ 0 ];\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault: // ZeroCurvatureEnding\n\n\t\t\t\t\t\t// f''(tN) = 0, a.k.a. Natural Spline\n\t\t\t\t\t\tiNext = i1 - 1;\n\t\t\t\t\t\ttNext = t0;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tvar halfDt = ( t1 - t0 ) * 0.5,\n\t\t\t\tstride = this.valueSize;\n\n\t\t\tthis._weightPrev = halfDt / ( t0 - tPrev );\n\t\t\tthis._weightNext = halfDt / ( tNext - t1 );\n\t\t\tthis._offsetPrev = iPrev * stride;\n\t\t\tthis._offsetNext = iNext * stride;\n\n\t\t},\n\n\t\tinterpolate_: function( i1, t0, t, t1 ) {\n\n\t\t\tvar result = this.resultBuffer,\n\t\t\t\tvalues = this.sampleValues,\n\t\t\t\tstride = this.valueSize,\n\n\t\t\t\to1 = i1 * stride,\t\to0 = o1 - stride,\n\t\t\t\toP = this._offsetPrev, \toN = this._offsetNext,\n\t\t\t\twP = this._weightPrev,\twN = this._weightNext,\n\n\t\t\t\tp = ( t - t0 ) / ( t1 - t0 ),\n\t\t\t\tpp = p * p,\n\t\t\t\tppp = pp * p;\n\n\t\t\t// evaluate polynomials\n\n\t\t\tvar sP =     - wP   * ppp   +         2 * wP    * pp    -          wP   * p;\n\t\t\tvar s0 = ( 1 + wP ) * ppp   + (-1.5 - 2 * wP )  * pp    + ( -0.5 + wP ) * p     + 1;\n\t\t\tvar s1 = (-1 - wN ) * ppp   + ( 1.5 +   wN   )  * pp    +    0.5        * p;\n\t\t\tvar sN =       wN   * ppp   -           wN      * pp;\n\n\t\t\t// combine data linearly\n\n\t\t\tfor ( var i = 0; i !== stride; ++ i ) {\n\n\t\t\t\tresult[ i ] =\n\t\t\t\t\t\tsP * values[ oP + i ] +\n\t\t\t\t\t\ts0 * values[ o0 + i ] +\n\t\t\t\t\t\ts1 * values[ o1 + i ] +\n\t\t\t\t\t\tsN * values[ oN + i ];\n\n\t\t\t}\n\n\t\t\treturn result;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author tschw\n\t */\n\n\tfunction LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\t\tInterpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );\n\n\t}\n\n\tLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {\n\n\t\tconstructor: LinearInterpolant,\n\n\t\tinterpolate_: function( i1, t0, t, t1 ) {\n\n\t\t\tvar result = this.resultBuffer,\n\t\t\t\tvalues = this.sampleValues,\n\t\t\t\tstride = this.valueSize,\n\n\t\t\t\toffset1 = i1 * stride,\n\t\t\t\toffset0 = offset1 - stride,\n\n\t\t\t\tweight1 = ( t - t0 ) / ( t1 - t0 ),\n\t\t\t\tweight0 = 1 - weight1;\n\n\t\t\tfor ( var i = 0; i !== stride; ++ i ) {\n\n\t\t\t\tresult[ i ] =\n\t\t\t\t\t\tvalues[ offset0 + i ] * weight0 +\n\t\t\t\t\t\tvalues[ offset1 + i ] * weight1;\n\n\t\t\t}\n\n\t\t\treturn result;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t *\n\t * Interpolant that evaluates to the sample value at the position preceeding\n\t * the parameter.\n\t *\n\t * @author tschw\n\t */\n\n\tfunction DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\t\tInterpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );\n\n\t}\n\n\tDiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {\n\n\t\tconstructor: DiscreteInterpolant,\n\n\t\tinterpolate_: function( i1, t0, t, t1 ) {\n\n\t\t\treturn this.copySampleValue_( i1 - 1 );\n\n\t\t}\n\n\t} );\n\n\tvar KeyframeTrackPrototype;\n\n\tKeyframeTrackPrototype = {\n\n\t\tTimeBufferType: Float32Array,\n\t\tValueBufferType: Float32Array,\n\n\t\tDefaultInterpolation: InterpolateLinear,\n\n\t\tInterpolantFactoryMethodDiscrete: function ( result ) {\n\n\t\t\treturn new DiscreteInterpolant(\n\t\t\t\t\tthis.times, this.values, this.getValueSize(), result );\n\n\t\t},\n\n\t\tInterpolantFactoryMethodLinear: function ( result ) {\n\n\t\t\treturn new LinearInterpolant(\n\t\t\t\t\tthis.times, this.values, this.getValueSize(), result );\n\n\t\t},\n\n\t\tInterpolantFactoryMethodSmooth: function ( result ) {\n\n\t\t\treturn new CubicInterpolant(\n\t\t\t\t\tthis.times, this.values, this.getValueSize(), result );\n\n\t\t},\n\n\t\tsetInterpolation: function ( interpolation ) {\n\n\t\t\tvar factoryMethod;\n\n\t\t\tswitch ( interpolation ) {\n\n\t\t\t\tcase InterpolateDiscrete:\n\n\t\t\t\t\tfactoryMethod = this.InterpolantFactoryMethodDiscrete;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase InterpolateLinear:\n\n\t\t\t\t\tfactoryMethod = this.InterpolantFactoryMethodLinear;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase InterpolateSmooth:\n\n\t\t\t\t\tfactoryMethod = this.InterpolantFactoryMethodSmooth;\n\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tif ( factoryMethod === undefined ) {\n\n\t\t\t\tvar message = \"unsupported interpolation for \" +\n\t\t\t\t\t\tthis.ValueTypeName + \" keyframe track named \" + this.name;\n\n\t\t\t\tif ( this.createInterpolant === undefined ) {\n\n\t\t\t\t\t// fall back to default, unless the default itself is messed up\n\t\t\t\t\tif ( interpolation !== this.DefaultInterpolation ) {\n\n\t\t\t\t\t\tthis.setInterpolation( this.DefaultInterpolation );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tthrow new Error( message ); // fatal, in this case\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tconsole.warn( 'THREE.KeyframeTrackPrototype:', message );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tthis.createInterpolant = factoryMethod;\n\n\t\t},\n\n\t\tgetInterpolation: function () {\n\n\t\t\tswitch ( this.createInterpolant ) {\n\n\t\t\t\tcase this.InterpolantFactoryMethodDiscrete:\n\n\t\t\t\t\treturn InterpolateDiscrete;\n\n\t\t\t\tcase this.InterpolantFactoryMethodLinear:\n\n\t\t\t\t\treturn InterpolateLinear;\n\n\t\t\t\tcase this.InterpolantFactoryMethodSmooth:\n\n\t\t\t\t\treturn InterpolateSmooth;\n\n\t\t\t}\n\n\t\t},\n\n\t\tgetValueSize: function () {\n\n\t\t\treturn this.values.length / this.times.length;\n\n\t\t},\n\n\t\t// move all keyframes either forwards or backwards in time\n\t\tshift: function ( timeOffset ) {\n\n\t\t\tif ( timeOffset !== 0.0 ) {\n\n\t\t\t\tvar times = this.times;\n\n\t\t\t\tfor ( var i = 0, n = times.length; i !== n; ++ i ) {\n\n\t\t\t\t\ttimes[ i ] += timeOffset;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\t// scale all keyframe times by a factor (useful for frame <-> seconds conversions)\n\t\tscale: function ( timeScale ) {\n\n\t\t\tif ( timeScale !== 1.0 ) {\n\n\t\t\t\tvar times = this.times;\n\n\t\t\t\tfor ( var i = 0, n = times.length; i !== n; ++ i ) {\n\n\t\t\t\t\ttimes[ i ] *= timeScale;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\t// removes keyframes before and after animation without changing any values within the range [startTime, endTime].\n\t\t// IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values\n\t\ttrim: function ( startTime, endTime ) {\n\n\t\t\tvar times = this.times,\n\t\t\t\tnKeys = times.length,\n\t\t\t\tfrom = 0,\n\t\t\t\tto = nKeys - 1;\n\n\t\t\twhile ( from !== nKeys && times[ from ] < startTime ) ++ from;\n\t\t\twhile ( to !== - 1 && times[ to ] > endTime ) -- to;\n\n\t\t\t++ to; // inclusive -> exclusive bound\n\n\t\t\tif ( from !== 0 || to !== nKeys ) {\n\n\t\t\t\t// empty tracks are forbidden, so keep at least one keyframe\n\t\t\t\tif ( from >= to ) to = Math.max( to, 1 ), from = to - 1;\n\n\t\t\t\tvar stride = this.getValueSize();\n\t\t\t\tthis.times = AnimationUtils.arraySlice( times, from, to );\n\t\t\t\tthis.values = AnimationUtils.\n\t\t\t\t\t\tarraySlice( this.values, from * stride, to * stride );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\t// ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable\n\t\tvalidate: function () {\n\n\t\t\tvar valid = true;\n\n\t\t\tvar valueSize = this.getValueSize();\n\t\t\tif ( valueSize - Math.floor( valueSize ) !== 0 ) {\n\n\t\t\t\tconsole.error( 'THREE.KeyframeTrackPrototype: Invalid value size in track.', this );\n\t\t\t\tvalid = false;\n\n\t\t\t}\n\n\t\t\tvar times = this.times,\n\t\t\t\tvalues = this.values,\n\n\t\t\t\tnKeys = times.length;\n\n\t\t\tif ( nKeys === 0 ) {\n\n\t\t\t\tconsole.error( 'THREE.KeyframeTrackPrototype: Track is empty.', this );\n\t\t\t\tvalid = false;\n\n\t\t\t}\n\n\t\t\tvar prevTime = null;\n\n\t\t\tfor ( var i = 0; i !== nKeys; i ++ ) {\n\n\t\t\t\tvar currTime = times[ i ];\n\n\t\t\t\tif ( typeof currTime === 'number' && isNaN( currTime ) ) {\n\n\t\t\t\t\tconsole.error( 'THREE.KeyframeTrackPrototype: Time is not a valid number.', this, i, currTime );\n\t\t\t\t\tvalid = false;\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t\tif ( prevTime !== null && prevTime > currTime ) {\n\n\t\t\t\t\tconsole.error( 'THREE.KeyframeTrackPrototype: Out of order keys.', this, i, currTime, prevTime );\n\t\t\t\t\tvalid = false;\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t\tprevTime = currTime;\n\n\t\t\t}\n\n\t\t\tif ( values !== undefined ) {\n\n\t\t\t\tif ( AnimationUtils.isTypedArray( values ) ) {\n\n\t\t\t\t\tfor ( var i = 0, n = values.length; i !== n; ++ i ) {\n\n\t\t\t\t\t\tvar value = values[ i ];\n\n\t\t\t\t\t\tif ( isNaN( value ) ) {\n\n\t\t\t\t\t\t\tconsole.error( 'THREE.KeyframeTrackPrototype: Value is not a valid number.', this, i, value );\n\t\t\t\t\t\t\tvalid = false;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn valid;\n\n\t\t},\n\n\t\t// removes equivalent sequential keys as common in morph target sequences\n\t\t// (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0)\n\t\toptimize: function () {\n\n\t\t\tvar times = this.times,\n\t\t\t\tvalues = this.values,\n\t\t\t\tstride = this.getValueSize(),\n\n\t\t\t\tsmoothInterpolation = this.getInterpolation() === InterpolateSmooth,\n\n\t\t\t\twriteIndex = 1,\n\t\t\t\tlastIndex = times.length - 1;\n\n\t\t\tfor ( var i = 1; i < lastIndex; ++ i ) {\n\n\t\t\t\tvar keep = false;\n\n\t\t\t\tvar time = times[ i ];\n\t\t\t\tvar timeNext = times[ i + 1 ];\n\n\t\t\t\t// remove adjacent keyframes scheduled at the same time\n\n\t\t\t\tif ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) {\n\n\t\t\t\t\tif ( ! smoothInterpolation ) {\n\n\t\t\t\t\t\t// remove unnecessary keyframes same as their neighbors\n\n\t\t\t\t\t\tvar offset = i * stride,\n\t\t\t\t\t\t\toffsetP = offset - stride,\n\t\t\t\t\t\t\toffsetN = offset + stride;\n\n\t\t\t\t\t\tfor ( var j = 0; j !== stride; ++ j ) {\n\n\t\t\t\t\t\t\tvar value = values[ offset + j ];\n\n\t\t\t\t\t\t\tif ( value !== values[ offsetP + j ] ||\n\t\t\t\t\t\t\t\t\tvalue !== values[ offsetN + j ] ) {\n\n\t\t\t\t\t\t\t\tkeep = true;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else keep = true;\n\n\t\t\t\t}\n\n\t\t\t\t// in-place compaction\n\n\t\t\t\tif ( keep ) {\n\n\t\t\t\t\tif ( i !== writeIndex ) {\n\n\t\t\t\t\t\ttimes[ writeIndex ] = times[ i ];\n\n\t\t\t\t\t\tvar readOffset = i * stride,\n\t\t\t\t\t\t\twriteOffset = writeIndex * stride;\n\n\t\t\t\t\t\tfor ( var j = 0; j !== stride; ++ j )\n\n\t\t\t\t\t\t\tvalues[ writeOffset + j ] = values[ readOffset + j ];\n\n\t\t\t\t\t}\n\n\t\t\t\t\t++ writeIndex;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// flush last keyframe (compaction looks ahead)\n\n\t\t\tif ( lastIndex > 0 ) {\n\n\t\t\t\ttimes[ writeIndex ] = times[ lastIndex ];\n\n\t\t\t\tfor ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j )\n\n\t\t\t\t\tvalues[ writeOffset + j ] = values[ readOffset + j ];\n\n\t\t\t\t++ writeIndex;\n\n\t\t\t}\n\n\t\t\tif ( writeIndex !== times.length ) {\n\n\t\t\t\tthis.times = AnimationUtils.arraySlice( times, 0, writeIndex );\n\t\t\t\tthis.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t}\n\n\t};\n\n\tfunction KeyframeTrackConstructor( name, times, values, interpolation ) {\n\n\t\tif ( name === undefined ) throw new Error( \"track name is undefined\" );\n\n\t\tif ( times === undefined || times.length === 0 ) {\n\n\t\t\tthrow new Error( \"no keyframes in track named \" + name );\n\n\t\t}\n\n\t\tthis.name = name;\n\n\t\tthis.times = AnimationUtils.convertArray( times, this.TimeBufferType );\n\t\tthis.values = AnimationUtils.convertArray( values, this.ValueBufferType );\n\n\t\tthis.setInterpolation( interpolation || this.DefaultInterpolation );\n\n\t\tthis.validate();\n\t\tthis.optimize();\n\n\t}\n\n\t/**\n\t *\n\t * A Track of vectored keyframe values.\n\t *\n\t *\n\t * @author Ben Houston / http://clara.io/\n\t * @author David Sarno / http://lighthaus.us/\n\t * @author tschw\n\t */\n\n\tfunction VectorKeyframeTrack( name, times, values, interpolation ) {\n\n\t\tKeyframeTrackConstructor.call( this, name, times, values, interpolation );\n\n\t}\n\n\tVectorKeyframeTrack.prototype =\n\t\t\tObject.assign( Object.create( KeyframeTrackPrototype ), {\n\n\t\tconstructor: VectorKeyframeTrack,\n\n\t\tValueTypeName: 'vector'\n\n\t\t// ValueBufferType is inherited\n\n\t\t// DefaultInterpolation is inherited\n\n\t} );\n\n\t/**\n\t * Spherical linear unit quaternion interpolant.\n\t *\n\t * @author tschw\n\t */\n\n\tfunction QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\t\tInterpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );\n\n\t}\n\n\tQuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {\n\n\t\tconstructor: QuaternionLinearInterpolant,\n\n\t\tinterpolate_: function( i1, t0, t, t1 ) {\n\n\t\t\tvar result = this.resultBuffer,\n\t\t\t\tvalues = this.sampleValues,\n\t\t\t\tstride = this.valueSize,\n\n\t\t\t\toffset = i1 * stride,\n\n\t\t\t\talpha = ( t - t0 ) / ( t1 - t0 );\n\n\t\t\tfor ( var end = offset + stride; offset !== end; offset += 4 ) {\n\n\t\t\t\tQuaternion.slerpFlat( result, 0,\n\t\t\t\t\t\tvalues, offset - stride, values, offset, alpha );\n\n\t\t\t}\n\n\t\t\treturn result;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t *\n\t * A Track of quaternion keyframe values.\n\t *\n\t * @author Ben Houston / http://clara.io/\n\t * @author David Sarno / http://lighthaus.us/\n\t * @author tschw\n\t */\n\n\tfunction QuaternionKeyframeTrack( name, times, values, interpolation ) {\n\n\t\tKeyframeTrackConstructor.call( this, name, times, values, interpolation );\n\n\t}\n\n\tQuaternionKeyframeTrack.prototype =\n\t\t\tObject.assign( Object.create( KeyframeTrackPrototype ), {\n\n\t\tconstructor: QuaternionKeyframeTrack,\n\n\t\tValueTypeName: 'quaternion',\n\n\t\t// ValueBufferType is inherited\n\n\t\tDefaultInterpolation: InterpolateLinear,\n\n\t\tInterpolantFactoryMethodLinear: function( result ) {\n\n\t\t\treturn new QuaternionLinearInterpolant(\n\t\t\t\t\tthis.times, this.values, this.getValueSize(), result );\n\n\t\t},\n\n\t\tInterpolantFactoryMethodSmooth: undefined // not yet implemented\n\n\t} );\n\n\t/**\n\t *\n\t * A Track of numeric keyframe values.\n\t *\n\t * @author Ben Houston / http://clara.io/\n\t * @author David Sarno / http://lighthaus.us/\n\t * @author tschw\n\t */\n\n\tfunction NumberKeyframeTrack( name, times, values, interpolation ) {\n\n\t\tKeyframeTrackConstructor.call( this, name, times, values, interpolation );\n\n\t}\n\n\tNumberKeyframeTrack.prototype =\n\t\t\tObject.assign( Object.create( KeyframeTrackPrototype ), {\n\n\t\tconstructor: NumberKeyframeTrack,\n\n\t\tValueTypeName: 'number'\n\n\t\t// ValueBufferType is inherited\n\n\t\t// DefaultInterpolation is inherited\n\n\t} );\n\n\t/**\n\t *\n\t * A Track that interpolates Strings\n\t *\n\t *\n\t * @author Ben Houston / http://clara.io/\n\t * @author David Sarno / http://lighthaus.us/\n\t * @author tschw\n\t */\n\n\tfunction StringKeyframeTrack( name, times, values, interpolation ) {\n\n\t\tKeyframeTrackConstructor.call( this, name, times, values, interpolation );\n\n\t}\n\n\tStringKeyframeTrack.prototype =\n\t\t\tObject.assign( Object.create( KeyframeTrackPrototype ), {\n\n\t\tconstructor: StringKeyframeTrack,\n\n\t\tValueTypeName: 'string',\n\t\tValueBufferType: Array,\n\n\t\tDefaultInterpolation: InterpolateDiscrete,\n\n\t\tInterpolantFactoryMethodLinear: undefined,\n\n\t\tInterpolantFactoryMethodSmooth: undefined\n\n\t} );\n\n\t/**\n\t *\n\t * A Track of Boolean keyframe values.\n\t *\n\t *\n\t * @author Ben Houston / http://clara.io/\n\t * @author David Sarno / http://lighthaus.us/\n\t * @author tschw\n\t */\n\n\tfunction BooleanKeyframeTrack( name, times, values ) {\n\n\t\tKeyframeTrackConstructor.call( this, name, times, values );\n\n\t}\n\n\tBooleanKeyframeTrack.prototype =\n\t\t\tObject.assign( Object.create( KeyframeTrackPrototype ), {\n\n\t\tconstructor: BooleanKeyframeTrack,\n\n\t\tValueTypeName: 'bool',\n\t\tValueBufferType: Array,\n\n\t\tDefaultInterpolation: InterpolateDiscrete,\n\n\t\tInterpolantFactoryMethodLinear: undefined,\n\t\tInterpolantFactoryMethodSmooth: undefined\n\n\t\t// Note: Actually this track could have a optimized / compressed\n\t\t// representation of a single value and a custom interpolant that\n\t\t// computes \"firstValue ^ isOdd( index )\".\n\n\t} );\n\n\t/**\n\t *\n\t * A Track of keyframe values that represent color.\n\t *\n\t *\n\t * @author Ben Houston / http://clara.io/\n\t * @author David Sarno / http://lighthaus.us/\n\t * @author tschw\n\t */\n\n\tfunction ColorKeyframeTrack( name, times, values, interpolation ) {\n\n\t\tKeyframeTrackConstructor.call( this, name, times, values, interpolation );\n\n\t}\n\n\tColorKeyframeTrack.prototype =\n\t\t\tObject.assign( Object.create( KeyframeTrackPrototype ), {\n\n\t\tconstructor: ColorKeyframeTrack,\n\n\t\tValueTypeName: 'color'\n\n\t\t// ValueBufferType is inherited\n\n\t\t// DefaultInterpolation is inherited\n\n\n\t\t// Note: Very basic implementation and nothing special yet.\n\t\t// However, this is the place for color space parameterization.\n\n\t} );\n\n\t/**\n\t *\n\t * A timed sequence of keyframes for a specific property.\n\t *\n\t *\n\t * @author Ben Houston / http://clara.io/\n\t * @author David Sarno / http://lighthaus.us/\n\t * @author tschw\n\t */\n\n\tfunction KeyframeTrack( name, times, values, interpolation ) {\n\n\t\tKeyframeTrackConstructor.apply( this, arguments );\n\n\t}\n\n\tKeyframeTrack.prototype = KeyframeTrackPrototype;\n\tKeyframeTrackPrototype.constructor = KeyframeTrack;\n\n\t// Static methods:\n\n\tObject.assign( KeyframeTrack, {\n\n\t\t// Serialization (in static context, because of constructor invocation\n\t\t// and automatic invocation of .toJSON):\n\n\t\tparse: function( json ) {\n\n\t\t\tif( json.type === undefined ) {\n\n\t\t\t\tthrow new Error( \"track type undefined, can not parse\" );\n\n\t\t\t}\n\n\t\t\tvar trackType = KeyframeTrack._getTrackTypeForValueTypeName( json.type );\n\n\t\t\tif ( json.times === undefined ) {\n\n\t\t\t\tvar times = [], values = [];\n\n\t\t\t\tAnimationUtils.flattenJSON( json.keys, times, values, 'value' );\n\n\t\t\t\tjson.times = times;\n\t\t\t\tjson.values = values;\n\n\t\t\t}\n\n\t\t\t// derived classes can define a static parse method\n\t\t\tif ( trackType.parse !== undefined ) {\n\n\t\t\t\treturn trackType.parse( json );\n\n\t\t\t} else {\n\n\t\t\t\t// by default, we assume a constructor compatible with the base\n\t\t\t\treturn new trackType(\n\t\t\t\t\t\tjson.name, json.times, json.values, json.interpolation );\n\n\t\t\t}\n\n\t\t},\n\n\t\ttoJSON: function( track ) {\n\n\t\t\tvar trackType = track.constructor;\n\n\t\t\tvar json;\n\n\t\t\t// derived classes can define a static toJSON method\n\t\t\tif ( trackType.toJSON !== undefined ) {\n\n\t\t\t\tjson = trackType.toJSON( track );\n\n\t\t\t} else {\n\n\t\t\t\t// by default, we assume the data can be serialized as-is\n\t\t\t\tjson = {\n\n\t\t\t\t\t'name': track.name,\n\t\t\t\t\t'times': AnimationUtils.convertArray( track.times, Array ),\n\t\t\t\t\t'values': AnimationUtils.convertArray( track.values, Array )\n\n\t\t\t\t};\n\n\t\t\t\tvar interpolation = track.getInterpolation();\n\n\t\t\t\tif ( interpolation !== track.DefaultInterpolation ) {\n\n\t\t\t\t\tjson.interpolation = interpolation;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tjson.type = track.ValueTypeName; // mandatory\n\n\t\t\treturn json;\n\n\t\t},\n\n\t\t_getTrackTypeForValueTypeName: function( typeName ) {\n\n\t\t\tswitch( typeName.toLowerCase() ) {\n\n\t\t\t\tcase \"scalar\":\n\t\t\t\tcase \"double\":\n\t\t\t\tcase \"float\":\n\t\t\t\tcase \"number\":\n\t\t\t\tcase \"integer\":\n\n\t\t\t\t\treturn NumberKeyframeTrack;\n\n\t\t\t\tcase \"vector\":\n\t\t\t\tcase \"vector2\":\n\t\t\t\tcase \"vector3\":\n\t\t\t\tcase \"vector4\":\n\n\t\t\t\t\treturn VectorKeyframeTrack;\n\n\t\t\t\tcase \"color\":\n\n\t\t\t\t\treturn ColorKeyframeTrack;\n\n\t\t\t\tcase \"quaternion\":\n\n\t\t\t\t\treturn QuaternionKeyframeTrack;\n\n\t\t\t\tcase \"bool\":\n\t\t\t\tcase \"boolean\":\n\n\t\t\t\t\treturn BooleanKeyframeTrack;\n\n\t\t\t\tcase \"string\":\n\n\t\t\t\t\treturn StringKeyframeTrack;\n\n\t\t\t}\n\n\t\t\tthrow new Error( \"Unsupported typeName: \" + typeName );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t *\n\t * Reusable set of Tracks that represent an animation.\n\t *\n\t * @author Ben Houston / http://clara.io/\n\t * @author David Sarno / http://lighthaus.us/\n\t */\n\n\tfunction AnimationClip( name, duration, tracks ) {\n\n\t\tthis.name = name;\n\t\tthis.tracks = tracks;\n\t\tthis.duration = ( duration !== undefined ) ? duration : - 1;\n\n\t\tthis.uuid = _Math.generateUUID();\n\n\t\t// this means it should figure out its duration by scanning the tracks\n\t\tif ( this.duration < 0 ) {\n\n\t\t\tthis.resetDuration();\n\n\t\t}\n\n\t\tthis.optimize();\n\n\t}\n\n\tObject.assign( AnimationClip, {\n\n\t\tparse: function ( json ) {\n\n\t\t\tvar tracks = [],\n\t\t\t\tjsonTracks = json.tracks,\n\t\t\t\tframeTime = 1.0 / ( json.fps || 1.0 );\n\n\t\t\tfor ( var i = 0, n = jsonTracks.length; i !== n; ++ i ) {\n\n\t\t\t\ttracks.push( KeyframeTrack.parse( jsonTracks[ i ] ).scale( frameTime ) );\n\n\t\t\t}\n\n\t\t\treturn new AnimationClip( json.name, json.duration, tracks );\n\n\t\t},\n\n\t\ttoJSON: function ( clip ) {\n\n\t\t\tvar tracks = [],\n\t\t\t\tclipTracks = clip.tracks;\n\n\t\t\tvar json = {\n\n\t\t\t\t'name': clip.name,\n\t\t\t\t'duration': clip.duration,\n\t\t\t\t'tracks': tracks\n\n\t\t\t};\n\n\t\t\tfor ( var i = 0, n = clipTracks.length; i !== n; ++ i ) {\n\n\t\t\t\ttracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) );\n\n\t\t\t}\n\n\t\t\treturn json;\n\n\t\t},\n\n\t\tCreateFromMorphTargetSequence: function ( name, morphTargetSequence, fps, noLoop ) {\n\n\t\t\tvar numMorphTargets = morphTargetSequence.length;\n\t\t\tvar tracks = [];\n\n\t\t\tfor ( var i = 0; i < numMorphTargets; i ++ ) {\n\n\t\t\t\tvar times = [];\n\t\t\t\tvar values = [];\n\n\t\t\t\ttimes.push(\n\t\t\t\t\t\t( i + numMorphTargets - 1 ) % numMorphTargets,\n\t\t\t\t\t\ti,\n\t\t\t\t\t\t( i + 1 ) % numMorphTargets );\n\n\t\t\t\tvalues.push( 0, 1, 0 );\n\n\t\t\t\tvar order = AnimationUtils.getKeyframeOrder( times );\n\t\t\t\ttimes = AnimationUtils.sortedArray( times, 1, order );\n\t\t\t\tvalues = AnimationUtils.sortedArray( values, 1, order );\n\n\t\t\t\t// if there is a key at the first frame, duplicate it as the\n\t\t\t\t// last frame as well for perfect loop.\n\t\t\t\tif ( ! noLoop && times[ 0 ] === 0 ) {\n\n\t\t\t\t\ttimes.push( numMorphTargets );\n\t\t\t\t\tvalues.push( values[ 0 ] );\n\n\t\t\t\t}\n\n\t\t\t\ttracks.push(\n\t\t\t\t\t\tnew NumberKeyframeTrack(\n\t\t\t\t\t\t\t'.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']',\n\t\t\t\t\t\t\ttimes, values\n\t\t\t\t\t\t).scale( 1.0 / fps ) );\n\n\t\t\t}\n\n\t\t\treturn new AnimationClip( name, - 1, tracks );\n\n\t\t},\n\n\t\tfindByName: function ( objectOrClipArray, name ) {\n\n\t\t\tvar clipArray = objectOrClipArray;\n\n\t\t\tif ( ! Array.isArray( objectOrClipArray ) ) {\n\n\t\t\t\tvar o = objectOrClipArray;\n\t\t\t\tclipArray = o.geometry && o.geometry.animations || o.animations;\n\n\t\t\t}\n\n\t\t\tfor ( var i = 0; i < clipArray.length; i ++ ) {\n\n\t\t\t\tif ( clipArray[ i ].name === name ) {\n\n\t\t\t\t\treturn clipArray[ i ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn null;\n\n\t\t},\n\n\t\tCreateClipsFromMorphTargetSequences: function ( morphTargets, fps, noLoop ) {\n\n\t\t\tvar animationToMorphTargets = {};\n\n\t\t\t// tested with https://regex101.com/ on trick sequences\n\t\t\t// such flamingo_flyA_003, flamingo_run1_003, crdeath0059\n\t\t\tvar pattern = /^([\\w-]*?)([\\d]+)$/;\n\n\t\t\t// sort morph target names into animation groups based\n\t\t\t// patterns like Walk_001, Walk_002, Run_001, Run_002\n\t\t\tfor ( var i = 0, il = morphTargets.length; i < il; i ++ ) {\n\n\t\t\t\tvar morphTarget = morphTargets[ i ];\n\t\t\t\tvar parts = morphTarget.name.match( pattern );\n\n\t\t\t\tif ( parts && parts.length > 1 ) {\n\n\t\t\t\t\tvar name = parts[ 1 ];\n\n\t\t\t\t\tvar animationMorphTargets = animationToMorphTargets[ name ];\n\t\t\t\t\tif ( ! animationMorphTargets ) {\n\n\t\t\t\t\t\tanimationToMorphTargets[ name ] = animationMorphTargets = [];\n\n\t\t\t\t\t}\n\n\t\t\t\t\tanimationMorphTargets.push( morphTarget );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tvar clips = [];\n\n\t\t\tfor ( var name in animationToMorphTargets ) {\n\n\t\t\t\tclips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) );\n\n\t\t\t}\n\n\t\t\treturn clips;\n\n\t\t},\n\n\t\t// parse the animation.hierarchy format\n\t\tparseAnimation: function ( animation, bones ) {\n\n\t\t\tif ( ! animation ) {\n\n\t\t\t\tconsole.error( 'THREE.AnimationClip: No animation in JSONLoader data.' );\n\t\t\t\treturn null;\n\n\t\t\t}\n\n\t\t\tvar addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) {\n\n\t\t\t\t// only return track if there are actually keys.\n\t\t\t\tif ( animationKeys.length !== 0 ) {\n\n\t\t\t\t\tvar times = [];\n\t\t\t\t\tvar values = [];\n\n\t\t\t\t\tAnimationUtils.flattenJSON( animationKeys, times, values, propertyName );\n\n\t\t\t\t\t// empty keys are filtered out, so check again\n\t\t\t\t\tif ( times.length !== 0 ) {\n\n\t\t\t\t\t\tdestTracks.push( new trackType( trackName, times, values ) );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t\tvar tracks = [];\n\n\t\t\tvar clipName = animation.name || 'default';\n\t\t\t// automatic length determination in AnimationClip.\n\t\t\tvar duration = animation.length || - 1;\n\t\t\tvar fps = animation.fps || 30;\n\n\t\t\tvar hierarchyTracks = animation.hierarchy || [];\n\n\t\t\tfor ( var h = 0; h < hierarchyTracks.length; h ++ ) {\n\n\t\t\t\tvar animationKeys = hierarchyTracks[ h ].keys;\n\n\t\t\t\t// skip empty tracks\n\t\t\t\tif ( ! animationKeys || animationKeys.length === 0 ) continue;\n\n\t\t\t\t// process morph targets\n\t\t\t\tif ( animationKeys[ 0 ].morphTargets ) {\n\n\t\t\t\t\t// figure out all morph targets used in this track\n\t\t\t\t\tvar morphTargetNames = {};\n\n\t\t\t\t\tfor ( var k = 0; k < animationKeys.length; k ++ ) {\n\n\t\t\t\t\t\tif ( animationKeys[ k ].morphTargets ) {\n\n\t\t\t\t\t\t\tfor ( var m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) {\n\n\t\t\t\t\t\t\t\tmorphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// create a track for each morph target with all zero\n\t\t\t\t\t// morphTargetInfluences except for the keys in which\n\t\t\t\t\t// the morphTarget is named.\n\t\t\t\t\tfor ( var morphTargetName in morphTargetNames ) {\n\n\t\t\t\t\t\tvar times = [];\n\t\t\t\t\t\tvar values = [];\n\n\t\t\t\t\t\tfor ( var m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) {\n\n\t\t\t\t\t\t\tvar animationKey = animationKeys[ k ];\n\n\t\t\t\t\t\t\ttimes.push( animationKey.time );\n\t\t\t\t\t\t\tvalues.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ttracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tduration = morphTargetNames.length * ( fps || 1.0 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// ...assume skeletal animation\n\n\t\t\t\t\tvar boneName = '.bones[' + bones[ h ].name + ']';\n\n\t\t\t\t\taddNonemptyTrack(\n\t\t\t\t\t\t\tVectorKeyframeTrack, boneName + '.position',\n\t\t\t\t\t\t\tanimationKeys, 'pos', tracks );\n\n\t\t\t\t\taddNonemptyTrack(\n\t\t\t\t\t\t\tQuaternionKeyframeTrack, boneName + '.quaternion',\n\t\t\t\t\t\t\tanimationKeys, 'rot', tracks );\n\n\t\t\t\t\taddNonemptyTrack(\n\t\t\t\t\t\t\tVectorKeyframeTrack, boneName + '.scale',\n\t\t\t\t\t\t\tanimationKeys, 'scl', tracks );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( tracks.length === 0 ) {\n\n\t\t\t\treturn null;\n\n\t\t\t}\n\n\t\t\tvar clip = new AnimationClip( clipName, duration, tracks );\n\n\t\t\treturn clip;\n\n\t\t}\n\n\t} );\n\n\tObject.assign( AnimationClip.prototype, {\n\n\t\tresetDuration: function () {\n\n\t\t\tvar tracks = this.tracks, duration = 0;\n\n\t\t\tfor ( var i = 0, n = tracks.length; i !== n; ++ i ) {\n\n\t\t\t\tvar track = this.tracks[ i ];\n\n\t\t\t\tduration = Math.max( duration, track.times[ track.times.length - 1 ] );\n\n\t\t\t}\n\n\t\t\tthis.duration = duration;\n\n\t\t},\n\n\t\ttrim: function () {\n\n\t\t\tfor ( var i = 0; i < this.tracks.length; i ++ ) {\n\n\t\t\t\tthis.tracks[ i ].trim( 0, this.duration );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\toptimize: function () {\n\n\t\t\tfor ( var i = 0; i < this.tracks.length; i ++ ) {\n\n\t\t\t\tthis.tracks[ i ].optimize();\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction MaterialLoader( manager ) {\n\n\t\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\t\tthis.textures = {};\n\n\t}\n\n\tObject.assign( MaterialLoader.prototype, {\n\n\t\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\t\tvar scope = this;\n\n\t\t\tvar loader = new FileLoader( scope.manager );\n\t\t\tloader.load( url, function ( text ) {\n\n\t\t\t\tonLoad( scope.parse( JSON.parse( text ) ) );\n\n\t\t\t}, onProgress, onError );\n\n\t\t},\n\n\t\tsetTextures: function ( value ) {\n\n\t\t\tthis.textures = value;\n\n\t\t},\n\n\t\tparse: function ( json ) {\n\n\t\t\tvar textures = this.textures;\n\n\t\t\tfunction getTexture( name ) {\n\n\t\t\t\tif ( textures[ name ] === undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.MaterialLoader: Undefined texture', name );\n\n\t\t\t\t}\n\n\t\t\t\treturn textures[ name ];\n\n\t\t\t}\n\n\t\t\tvar material = new Materials[ json.type ]();\n\n\t\t\tif ( json.uuid !== undefined ) material.uuid = json.uuid;\n\t\t\tif ( json.name !== undefined ) material.name = json.name;\n\t\t\tif ( json.color !== undefined ) material.color.setHex( json.color );\n\t\t\tif ( json.roughness !== undefined ) material.roughness = json.roughness;\n\t\t\tif ( json.metalness !== undefined ) material.metalness = json.metalness;\n\t\t\tif ( json.emissive !== undefined ) material.emissive.setHex( json.emissive );\n\t\t\tif ( json.specular !== undefined ) material.specular.setHex( json.specular );\n\t\t\tif ( json.shininess !== undefined ) material.shininess = json.shininess;\n\t\t\tif ( json.clearCoat !== undefined ) material.clearCoat = json.clearCoat;\n\t\t\tif ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness;\n\t\t\tif ( json.uniforms !== undefined ) material.uniforms = json.uniforms;\n\t\t\tif ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader;\n\t\t\tif ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader;\n\t\t\tif ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors;\n\t\t\tif ( json.fog !== undefined ) material.fog = json.fog;\n\t\t\tif ( json.flatShading !== undefined ) material.flatShading = json.flatShading;\n\t\t\tif ( json.blending !== undefined ) material.blending = json.blending;\n\t\t\tif ( json.side !== undefined ) material.side = json.side;\n\t\t\tif ( json.opacity !== undefined ) material.opacity = json.opacity;\n\t\t\tif ( json.transparent !== undefined ) material.transparent = json.transparent;\n\t\t\tif ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest;\n\t\t\tif ( json.depthTest !== undefined ) material.depthTest = json.depthTest;\n\t\t\tif ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite;\n\t\t\tif ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite;\n\t\t\tif ( json.wireframe !== undefined ) material.wireframe = json.wireframe;\n\t\t\tif ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth;\n\t\t\tif ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap;\n\t\t\tif ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin;\n\n\t\t\tif ( json.skinning !== undefined ) material.skinning = json.skinning;\n\t\t\tif ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets;\n\t\t\tif ( json.dithering !== undefined ) material.dithering = json.dithering;\n\n\t\t\tif ( json.visible !== undefined ) material.visible = json.visible;\n\t\t\tif ( json.userData !== undefined ) material.userData = json.userData;\n\n\t\t\t// Deprecated\n\n\t\t\tif ( json.shading !== undefined ) material.flatShading = json.shading === 1; // THREE.FlatShading\n\n\t\t\t// for PointsMaterial\n\n\t\t\tif ( json.size !== undefined ) material.size = json.size;\n\t\t\tif ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation;\n\n\t\t\t// maps\n\n\t\t\tif ( json.map !== undefined ) material.map = getTexture( json.map );\n\n\t\t\tif ( json.alphaMap !== undefined ) {\n\n\t\t\t\tmaterial.alphaMap = getTexture( json.alphaMap );\n\t\t\t\tmaterial.transparent = true;\n\n\t\t\t}\n\n\t\t\tif ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap );\n\t\t\tif ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale;\n\n\t\t\tif ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap );\n\t\t\tif ( json.normalScale !== undefined ) {\n\n\t\t\t\tvar normalScale = json.normalScale;\n\n\t\t\t\tif ( Array.isArray( normalScale ) === false ) {\n\n\t\t\t\t\t// Blender exporter used to export a scalar. See #7459\n\n\t\t\t\t\tnormalScale = [ normalScale, normalScale ];\n\n\t\t\t\t}\n\n\t\t\t\tmaterial.normalScale = new Vector2().fromArray( normalScale );\n\n\t\t\t}\n\n\t\t\tif ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap );\n\t\t\tif ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale;\n\t\t\tif ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias;\n\n\t\t\tif ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap );\n\t\t\tif ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap );\n\n\t\t\tif ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap );\n\t\t\tif ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity;\n\n\t\t\tif ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap );\n\n\t\t\tif ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap );\n\n\t\t\tif ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity;\n\n\t\t\tif ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap );\n\t\t\tif ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity;\n\n\t\t\tif ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap );\n\t\t\tif ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity;\n\n\t\t\tif ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap );\n\n\t\t\treturn material;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction BufferGeometryLoader( manager ) {\n\n\t\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n\t}\n\n\tObject.assign( BufferGeometryLoader.prototype, {\n\n\t\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\t\tvar scope = this;\n\n\t\t\tvar loader = new FileLoader( scope.manager );\n\t\t\tloader.load( url, function ( text ) {\n\n\t\t\t\tonLoad( scope.parse( JSON.parse( text ) ) );\n\n\t\t\t}, onProgress, onError );\n\n\t\t},\n\n\t\tparse: function ( json ) {\n\n\t\t\tvar geometry = new BufferGeometry();\n\n\t\t\tvar index = json.data.index;\n\n\t\t\tif ( index !== undefined ) {\n\n\t\t\t\tvar typedArray = new TYPED_ARRAYS[ index.type ]( index.array );\n\t\t\t\tgeometry.setIndex( new BufferAttribute( typedArray, 1 ) );\n\n\t\t\t}\n\n\t\t\tvar attributes = json.data.attributes;\n\n\t\t\tfor ( var key in attributes ) {\n\n\t\t\t\tvar attribute = attributes[ key ];\n\t\t\t\tvar typedArray = new TYPED_ARRAYS[ attribute.type ]( attribute.array );\n\n\t\t\t\tgeometry.addAttribute( key, new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ) );\n\n\t\t\t}\n\n\t\t\tvar groups = json.data.groups || json.data.drawcalls || json.data.offsets;\n\n\t\t\tif ( groups !== undefined ) {\n\n\t\t\t\tfor ( var i = 0, n = groups.length; i !== n; ++ i ) {\n\n\t\t\t\t\tvar group = groups[ i ];\n\n\t\t\t\t\tgeometry.addGroup( group.start, group.count, group.materialIndex );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tvar boundingSphere = json.data.boundingSphere;\n\n\t\t\tif ( boundingSphere !== undefined ) {\n\n\t\t\t\tvar center = new Vector3();\n\n\t\t\t\tif ( boundingSphere.center !== undefined ) {\n\n\t\t\t\t\tcenter.fromArray( boundingSphere.center );\n\n\t\t\t\t}\n\n\t\t\t\tgeometry.boundingSphere = new Sphere( center, boundingSphere.radius );\n\n\t\t\t}\n\n\t\t\treturn geometry;\n\n\t\t}\n\n\t} );\n\n\tvar TYPED_ARRAYS = {\n\t\tInt8Array: Int8Array,\n\t\tUint8Array: Uint8Array,\n\t\t// Workaround for IE11 pre KB2929437. See #11440\n\t\tUint8ClampedArray: typeof Uint8ClampedArray !== 'undefined' ? Uint8ClampedArray : Uint8Array,\n\t\tInt16Array: Int16Array,\n\t\tUint16Array: Uint16Array,\n\t\tInt32Array: Int32Array,\n\t\tUint32Array: Uint32Array,\n\t\tFloat32Array: Float32Array,\n\t\tFloat64Array: Float64Array\n\t};\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tfunction Loader() {\n\n\t\tthis.onLoadStart = function () {};\n\t\tthis.onLoadProgress = function () {};\n\t\tthis.onLoadComplete = function () {};\n\n\t}\n\n\tLoader.Handlers = {\n\n\t\thandlers: [],\n\n\t\tadd: function ( regex, loader ) {\n\n\t\t\tthis.handlers.push( regex, loader );\n\n\t\t},\n\n\t\tget: function ( file ) {\n\n\t\t\tvar handlers = this.handlers;\n\n\t\t\tfor ( var i = 0, l = handlers.length; i < l; i += 2 ) {\n\n\t\t\t\tvar regex = handlers[ i ];\n\t\t\t\tvar loader = handlers[ i + 1 ];\n\n\t\t\t\tif ( regex.test( file ) ) {\n\n\t\t\t\t\treturn loader;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn null;\n\n\t\t}\n\n\t};\n\n\tObject.assign( Loader.prototype, {\n\n\t\tcrossOrigin: undefined,\n\n\t\textractUrlBase: function ( url ) {\n\n\t\t\tvar parts = url.split( '/' );\n\n\t\t\tif ( parts.length === 1 ) return './';\n\n\t\t\tparts.pop();\n\n\t\t\treturn parts.join( '/' ) + '/';\n\n\t\t},\n\n\t\tinitMaterials: function ( materials, texturePath, crossOrigin ) {\n\n\t\t\tvar array = [];\n\n\t\t\tfor ( var i = 0; i < materials.length; ++ i ) {\n\n\t\t\t\tarray[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin );\n\n\t\t\t}\n\n\t\t\treturn array;\n\n\t\t},\n\n\t\tcreateMaterial: ( function () {\n\n\t\t\tvar BlendingMode = {\n\t\t\t\tNoBlending: NoBlending,\n\t\t\t\tNormalBlending: NormalBlending,\n\t\t\t\tAdditiveBlending: AdditiveBlending,\n\t\t\t\tSubtractiveBlending: SubtractiveBlending,\n\t\t\t\tMultiplyBlending: MultiplyBlending,\n\t\t\t\tCustomBlending: CustomBlending\n\t\t\t};\n\n\t\t\tvar color = new Color();\n\t\t\tvar textureLoader = new TextureLoader();\n\t\t\tvar materialLoader = new MaterialLoader();\n\n\t\t\treturn function createMaterial( m, texturePath, crossOrigin ) {\n\n\t\t\t\t// convert from old material format\n\n\t\t\t\tvar textures = {};\n\n\t\t\t\tfunction loadTexture( path, repeat, offset, wrap, anisotropy ) {\n\n\t\t\t\t\tvar fullPath = texturePath + path;\n\t\t\t\t\tvar loader = Loader.Handlers.get( fullPath );\n\n\t\t\t\t\tvar texture;\n\n\t\t\t\t\tif ( loader !== null ) {\n\n\t\t\t\t\t\ttexture = loader.load( fullPath );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\ttextureLoader.setCrossOrigin( crossOrigin );\n\t\t\t\t\t\ttexture = textureLoader.load( fullPath );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( repeat !== undefined ) {\n\n\t\t\t\t\t\ttexture.repeat.fromArray( repeat );\n\n\t\t\t\t\t\tif ( repeat[ 0 ] !== 1 ) texture.wrapS = RepeatWrapping;\n\t\t\t\t\t\tif ( repeat[ 1 ] !== 1 ) texture.wrapT = RepeatWrapping;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( offset !== undefined ) {\n\n\t\t\t\t\t\ttexture.offset.fromArray( offset );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( wrap !== undefined ) {\n\n\t\t\t\t\t\tif ( wrap[ 0 ] === 'repeat' ) texture.wrapS = RepeatWrapping;\n\t\t\t\t\t\tif ( wrap[ 0 ] === 'mirror' ) texture.wrapS = MirroredRepeatWrapping;\n\n\t\t\t\t\t\tif ( wrap[ 1 ] === 'repeat' ) texture.wrapT = RepeatWrapping;\n\t\t\t\t\t\tif ( wrap[ 1 ] === 'mirror' ) texture.wrapT = MirroredRepeatWrapping;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( anisotropy !== undefined ) {\n\n\t\t\t\t\t\ttexture.anisotropy = anisotropy;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tvar uuid = _Math.generateUUID();\n\n\t\t\t\t\ttextures[ uuid ] = texture;\n\n\t\t\t\t\treturn uuid;\n\n\t\t\t\t}\n\n\t\t\t\t//\n\n\t\t\t\tvar json = {\n\t\t\t\t\tuuid: _Math.generateUUID(),\n\t\t\t\t\ttype: 'MeshLambertMaterial'\n\t\t\t\t};\n\n\t\t\t\tfor ( var name in m ) {\n\n\t\t\t\t\tvar value = m[ name ];\n\n\t\t\t\t\tswitch ( name ) {\n\n\t\t\t\t\t\tcase 'DbgColor':\n\t\t\t\t\t\tcase 'DbgIndex':\n\t\t\t\t\t\tcase 'opticalDensity':\n\t\t\t\t\t\tcase 'illumination':\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'DbgName':\n\t\t\t\t\t\t\tjson.name = value;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'blending':\n\t\t\t\t\t\t\tjson.blending = BlendingMode[ value ];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'colorAmbient':\n\t\t\t\t\t\tcase 'mapAmbient':\n\t\t\t\t\t\t\tconsole.warn( 'THREE.Loader.createMaterial:', name, 'is no longer supported.' );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'colorDiffuse':\n\t\t\t\t\t\t\tjson.color = color.fromArray( value ).getHex();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'colorSpecular':\n\t\t\t\t\t\t\tjson.specular = color.fromArray( value ).getHex();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'colorEmissive':\n\t\t\t\t\t\t\tjson.emissive = color.fromArray( value ).getHex();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'specularCoef':\n\t\t\t\t\t\t\tjson.shininess = value;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'shading':\n\t\t\t\t\t\t\tif ( value.toLowerCase() === 'basic' ) json.type = 'MeshBasicMaterial';\n\t\t\t\t\t\t\tif ( value.toLowerCase() === 'phong' ) json.type = 'MeshPhongMaterial';\n\t\t\t\t\t\t\tif ( value.toLowerCase() === 'standard' ) json.type = 'MeshStandardMaterial';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapDiffuse':\n\t\t\t\t\t\t\tjson.map = loadTexture( value, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapDiffuseRepeat':\n\t\t\t\t\t\tcase 'mapDiffuseOffset':\n\t\t\t\t\t\tcase 'mapDiffuseWrap':\n\t\t\t\t\t\tcase 'mapDiffuseAnisotropy':\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapEmissive':\n\t\t\t\t\t\t\tjson.emissiveMap = loadTexture( value, m.mapEmissiveRepeat, m.mapEmissiveOffset, m.mapEmissiveWrap, m.mapEmissiveAnisotropy );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapEmissiveRepeat':\n\t\t\t\t\t\tcase 'mapEmissiveOffset':\n\t\t\t\t\t\tcase 'mapEmissiveWrap':\n\t\t\t\t\t\tcase 'mapEmissiveAnisotropy':\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapLight':\n\t\t\t\t\t\t\tjson.lightMap = loadTexture( value, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapLightRepeat':\n\t\t\t\t\t\tcase 'mapLightOffset':\n\t\t\t\t\t\tcase 'mapLightWrap':\n\t\t\t\t\t\tcase 'mapLightAnisotropy':\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapAO':\n\t\t\t\t\t\t\tjson.aoMap = loadTexture( value, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapAORepeat':\n\t\t\t\t\t\tcase 'mapAOOffset':\n\t\t\t\t\t\tcase 'mapAOWrap':\n\t\t\t\t\t\tcase 'mapAOAnisotropy':\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapBump':\n\t\t\t\t\t\t\tjson.bumpMap = loadTexture( value, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapBumpScale':\n\t\t\t\t\t\t\tjson.bumpScale = value;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapBumpRepeat':\n\t\t\t\t\t\tcase 'mapBumpOffset':\n\t\t\t\t\t\tcase 'mapBumpWrap':\n\t\t\t\t\t\tcase 'mapBumpAnisotropy':\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapNormal':\n\t\t\t\t\t\t\tjson.normalMap = loadTexture( value, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapNormalFactor':\n\t\t\t\t\t\t\tjson.normalScale = [ value, value ];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapNormalRepeat':\n\t\t\t\t\t\tcase 'mapNormalOffset':\n\t\t\t\t\t\tcase 'mapNormalWrap':\n\t\t\t\t\t\tcase 'mapNormalAnisotropy':\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapSpecular':\n\t\t\t\t\t\t\tjson.specularMap = loadTexture( value, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapSpecularRepeat':\n\t\t\t\t\t\tcase 'mapSpecularOffset':\n\t\t\t\t\t\tcase 'mapSpecularWrap':\n\t\t\t\t\t\tcase 'mapSpecularAnisotropy':\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapMetalness':\n\t\t\t\t\t\t\tjson.metalnessMap = loadTexture( value, m.mapMetalnessRepeat, m.mapMetalnessOffset, m.mapMetalnessWrap, m.mapMetalnessAnisotropy );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapMetalnessRepeat':\n\t\t\t\t\t\tcase 'mapMetalnessOffset':\n\t\t\t\t\t\tcase 'mapMetalnessWrap':\n\t\t\t\t\t\tcase 'mapMetalnessAnisotropy':\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapRoughness':\n\t\t\t\t\t\t\tjson.roughnessMap = loadTexture( value, m.mapRoughnessRepeat, m.mapRoughnessOffset, m.mapRoughnessWrap, m.mapRoughnessAnisotropy );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapRoughnessRepeat':\n\t\t\t\t\t\tcase 'mapRoughnessOffset':\n\t\t\t\t\t\tcase 'mapRoughnessWrap':\n\t\t\t\t\t\tcase 'mapRoughnessAnisotropy':\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapAlpha':\n\t\t\t\t\t\t\tjson.alphaMap = loadTexture( value, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'mapAlphaRepeat':\n\t\t\t\t\t\tcase 'mapAlphaOffset':\n\t\t\t\t\t\tcase 'mapAlphaWrap':\n\t\t\t\t\t\tcase 'mapAlphaAnisotropy':\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'flipSided':\n\t\t\t\t\t\t\tjson.side = BackSide;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'doubleSided':\n\t\t\t\t\t\t\tjson.side = DoubleSide;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'transparency':\n\t\t\t\t\t\t\tconsole.warn( 'THREE.Loader.createMaterial: transparency has been renamed to opacity' );\n\t\t\t\t\t\t\tjson.opacity = value;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'depthTest':\n\t\t\t\t\t\tcase 'depthWrite':\n\t\t\t\t\t\tcase 'colorWrite':\n\t\t\t\t\t\tcase 'opacity':\n\t\t\t\t\t\tcase 'reflectivity':\n\t\t\t\t\t\tcase 'transparent':\n\t\t\t\t\t\tcase 'visible':\n\t\t\t\t\t\tcase 'wireframe':\n\t\t\t\t\t\t\tjson[ name ] = value;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'vertexColors':\n\t\t\t\t\t\t\tif ( value === true ) json.vertexColors = VertexColors;\n\t\t\t\t\t\t\tif ( value === 'face' ) json.vertexColors = FaceColors;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tconsole.error( 'THREE.Loader.createMaterial: Unsupported', name, value );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( json.type === 'MeshBasicMaterial' ) delete json.emissive;\n\t\t\t\tif ( json.type !== 'MeshPhongMaterial' ) delete json.specular;\n\n\t\t\t\tif ( json.opacity < 1 ) json.transparent = true;\n\n\t\t\t\tmaterialLoader.setTextures( textures );\n\n\t\t\t\treturn materialLoader.parse( json );\n\n\t\t\t};\n\n\t\t} )()\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tfunction JSONLoader( manager ) {\n\n\t\tif ( typeof manager === 'boolean' ) {\n\n\t\t\tconsole.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' );\n\t\t\tmanager = undefined;\n\n\t\t}\n\n\t\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n\t\tthis.withCredentials = false;\n\n\t}\n\n\tObject.assign( JSONLoader.prototype, {\n\n\t\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\t\tvar scope = this;\n\n\t\t\tvar texturePath = this.texturePath && ( typeof this.texturePath === \"string\" ) ? this.texturePath : Loader.prototype.extractUrlBase( url );\n\n\t\t\tvar loader = new FileLoader( this.manager );\n\t\t\tloader.setWithCredentials( this.withCredentials );\n\t\t\tloader.load( url, function ( text ) {\n\n\t\t\t\tvar json = JSON.parse( text );\n\t\t\t\tvar metadata = json.metadata;\n\n\t\t\t\tif ( metadata !== undefined ) {\n\n\t\t\t\t\tvar type = metadata.type;\n\n\t\t\t\t\tif ( type !== undefined ) {\n\n\t\t\t\t\t\tif ( type.toLowerCase() === 'object' ) {\n\n\t\t\t\t\t\t\tconsole.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' );\n\t\t\t\t\t\t\treturn;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( type.toLowerCase() === 'scene' ) {\n\n\t\t\t\t\t\t\tconsole.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.SceneLoader instead.' );\n\t\t\t\t\t\t\treturn;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tvar object = scope.parse( json, texturePath );\n\t\t\t\tonLoad( object.geometry, object.materials );\n\n\t\t\t}, onProgress, onError );\n\n\t\t},\n\n\t\tsetTexturePath: function ( value ) {\n\n\t\t\tthis.texturePath = value;\n\n\t\t},\n\n\t\tparse: ( function () {\n\n\t\t\tfunction parseModel( json, geometry ) {\n\n\t\t\t\tfunction isBitSet( value, position ) {\n\n\t\t\t\t\treturn value & ( 1 << position );\n\n\t\t\t\t}\n\n\t\t\t\tvar i, j, fi,\n\n\t\t\t\t\toffset, zLength,\n\n\t\t\t\t\tcolorIndex, normalIndex, uvIndex, materialIndex,\n\n\t\t\t\t\ttype,\n\t\t\t\t\tisQuad,\n\t\t\t\t\thasMaterial,\n\t\t\t\t\thasFaceVertexUv,\n\t\t\t\t\thasFaceNormal, hasFaceVertexNormal,\n\t\t\t\t\thasFaceColor, hasFaceVertexColor,\n\n\t\t\t\t\tvertex, face, faceA, faceB, hex, normal,\n\n\t\t\t\t\tuvLayer, uv, u, v,\n\n\t\t\t\t\tfaces = json.faces,\n\t\t\t\t\tvertices = json.vertices,\n\t\t\t\t\tnormals = json.normals,\n\t\t\t\t\tcolors = json.colors,\n\n\t\t\t\t\tscale = json.scale,\n\n\t\t\t\t\tnUvLayers = 0;\n\n\n\t\t\t\tif ( json.uvs !== undefined ) {\n\n\t\t\t\t\t// disregard empty arrays\n\n\t\t\t\t\tfor ( i = 0; i < json.uvs.length; i ++ ) {\n\n\t\t\t\t\t\tif ( json.uvs[ i ].length ) nUvLayers ++;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfor ( i = 0; i < nUvLayers; i ++ ) {\n\n\t\t\t\t\t\tgeometry.faceVertexUvs[ i ] = [];\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\toffset = 0;\n\t\t\t\tzLength = vertices.length;\n\n\t\t\t\twhile ( offset < zLength ) {\n\n\t\t\t\t\tvertex = new Vector3();\n\n\t\t\t\t\tvertex.x = vertices[ offset ++ ] * scale;\n\t\t\t\t\tvertex.y = vertices[ offset ++ ] * scale;\n\t\t\t\t\tvertex.z = vertices[ offset ++ ] * scale;\n\n\t\t\t\t\tgeometry.vertices.push( vertex );\n\n\t\t\t\t}\n\n\t\t\t\toffset = 0;\n\t\t\t\tzLength = faces.length;\n\n\t\t\t\twhile ( offset < zLength ) {\n\n\t\t\t\t\ttype = faces[ offset ++ ];\n\n\t\t\t\t\tisQuad = isBitSet( type, 0 );\n\t\t\t\t\thasMaterial = isBitSet( type, 1 );\n\t\t\t\t\thasFaceVertexUv = isBitSet( type, 3 );\n\t\t\t\t\thasFaceNormal = isBitSet( type, 4 );\n\t\t\t\t\thasFaceVertexNormal = isBitSet( type, 5 );\n\t\t\t\t\thasFaceColor = isBitSet( type, 6 );\n\t\t\t\t\thasFaceVertexColor = isBitSet( type, 7 );\n\n\t\t\t\t\t// console.log(\"type\", type, \"bits\", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor);\n\n\t\t\t\t\tif ( isQuad ) {\n\n\t\t\t\t\t\tfaceA = new Face3();\n\t\t\t\t\t\tfaceA.a = faces[ offset ];\n\t\t\t\t\t\tfaceA.b = faces[ offset + 1 ];\n\t\t\t\t\t\tfaceA.c = faces[ offset + 3 ];\n\n\t\t\t\t\t\tfaceB = new Face3();\n\t\t\t\t\t\tfaceB.a = faces[ offset + 1 ];\n\t\t\t\t\t\tfaceB.b = faces[ offset + 2 ];\n\t\t\t\t\t\tfaceB.c = faces[ offset + 3 ];\n\n\t\t\t\t\t\toffset += 4;\n\n\t\t\t\t\t\tif ( hasMaterial ) {\n\n\t\t\t\t\t\t\tmaterialIndex = faces[ offset ++ ];\n\t\t\t\t\t\t\tfaceA.materialIndex = materialIndex;\n\t\t\t\t\t\t\tfaceB.materialIndex = materialIndex;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// to get face <=> uv index correspondence\n\n\t\t\t\t\t\tfi = geometry.faces.length;\n\n\t\t\t\t\t\tif ( hasFaceVertexUv ) {\n\n\t\t\t\t\t\t\tfor ( i = 0; i < nUvLayers; i ++ ) {\n\n\t\t\t\t\t\t\t\tuvLayer = json.uvs[ i ];\n\n\t\t\t\t\t\t\t\tgeometry.faceVertexUvs[ i ][ fi ] = [];\n\t\t\t\t\t\t\t\tgeometry.faceVertexUvs[ i ][ fi + 1 ] = [];\n\n\t\t\t\t\t\t\t\tfor ( j = 0; j < 4; j ++ ) {\n\n\t\t\t\t\t\t\t\t\tuvIndex = faces[ offset ++ ];\n\n\t\t\t\t\t\t\t\t\tu = uvLayer[ uvIndex * 2 ];\n\t\t\t\t\t\t\t\t\tv = uvLayer[ uvIndex * 2 + 1 ];\n\n\t\t\t\t\t\t\t\t\tuv = new Vector2( u, v );\n\n\t\t\t\t\t\t\t\t\tif ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv );\n\t\t\t\t\t\t\t\t\tif ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( hasFaceNormal ) {\n\n\t\t\t\t\t\t\tnormalIndex = faces[ offset ++ ] * 3;\n\n\t\t\t\t\t\t\tfaceA.normal.set(\n\t\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\n\t\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\n\t\t\t\t\t\t\t\tnormals[ normalIndex ]\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tfaceB.normal.copy( faceA.normal );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( hasFaceVertexNormal ) {\n\n\t\t\t\t\t\t\tfor ( i = 0; i < 4; i ++ ) {\n\n\t\t\t\t\t\t\t\tnormalIndex = faces[ offset ++ ] * 3;\n\n\t\t\t\t\t\t\t\tnormal = new Vector3(\n\t\t\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\n\t\t\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\n\t\t\t\t\t\t\t\t\tnormals[ normalIndex ]\n\t\t\t\t\t\t\t\t);\n\n\n\t\t\t\t\t\t\t\tif ( i !== 2 ) faceA.vertexNormals.push( normal );\n\t\t\t\t\t\t\t\tif ( i !== 0 ) faceB.vertexNormals.push( normal );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\n\t\t\t\t\t\tif ( hasFaceColor ) {\n\n\t\t\t\t\t\t\tcolorIndex = faces[ offset ++ ];\n\t\t\t\t\t\t\thex = colors[ colorIndex ];\n\n\t\t\t\t\t\t\tfaceA.color.setHex( hex );\n\t\t\t\t\t\t\tfaceB.color.setHex( hex );\n\n\t\t\t\t\t\t}\n\n\n\t\t\t\t\t\tif ( hasFaceVertexColor ) {\n\n\t\t\t\t\t\t\tfor ( i = 0; i < 4; i ++ ) {\n\n\t\t\t\t\t\t\t\tcolorIndex = faces[ offset ++ ];\n\t\t\t\t\t\t\t\thex = colors[ colorIndex ];\n\n\t\t\t\t\t\t\t\tif ( i !== 2 ) faceA.vertexColors.push( new Color( hex ) );\n\t\t\t\t\t\t\t\tif ( i !== 0 ) faceB.vertexColors.push( new Color( hex ) );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tgeometry.faces.push( faceA );\n\t\t\t\t\t\tgeometry.faces.push( faceB );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tface = new Face3();\n\t\t\t\t\t\tface.a = faces[ offset ++ ];\n\t\t\t\t\t\tface.b = faces[ offset ++ ];\n\t\t\t\t\t\tface.c = faces[ offset ++ ];\n\n\t\t\t\t\t\tif ( hasMaterial ) {\n\n\t\t\t\t\t\t\tmaterialIndex = faces[ offset ++ ];\n\t\t\t\t\t\t\tface.materialIndex = materialIndex;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// to get face <=> uv index correspondence\n\n\t\t\t\t\t\tfi = geometry.faces.length;\n\n\t\t\t\t\t\tif ( hasFaceVertexUv ) {\n\n\t\t\t\t\t\t\tfor ( i = 0; i < nUvLayers; i ++ ) {\n\n\t\t\t\t\t\t\t\tuvLayer = json.uvs[ i ];\n\n\t\t\t\t\t\t\t\tgeometry.faceVertexUvs[ i ][ fi ] = [];\n\n\t\t\t\t\t\t\t\tfor ( j = 0; j < 3; j ++ ) {\n\n\t\t\t\t\t\t\t\t\tuvIndex = faces[ offset ++ ];\n\n\t\t\t\t\t\t\t\t\tu = uvLayer[ uvIndex * 2 ];\n\t\t\t\t\t\t\t\t\tv = uvLayer[ uvIndex * 2 + 1 ];\n\n\t\t\t\t\t\t\t\t\tuv = new Vector2( u, v );\n\n\t\t\t\t\t\t\t\t\tgeometry.faceVertexUvs[ i ][ fi ].push( uv );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( hasFaceNormal ) {\n\n\t\t\t\t\t\t\tnormalIndex = faces[ offset ++ ] * 3;\n\n\t\t\t\t\t\t\tface.normal.set(\n\t\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\n\t\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\n\t\t\t\t\t\t\t\tnormals[ normalIndex ]\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( hasFaceVertexNormal ) {\n\n\t\t\t\t\t\t\tfor ( i = 0; i < 3; i ++ ) {\n\n\t\t\t\t\t\t\t\tnormalIndex = faces[ offset ++ ] * 3;\n\n\t\t\t\t\t\t\t\tnormal = new Vector3(\n\t\t\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\n\t\t\t\t\t\t\t\t\tnormals[ normalIndex ++ ],\n\t\t\t\t\t\t\t\t\tnormals[ normalIndex ]\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\tface.vertexNormals.push( normal );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\n\t\t\t\t\t\tif ( hasFaceColor ) {\n\n\t\t\t\t\t\t\tcolorIndex = faces[ offset ++ ];\n\t\t\t\t\t\t\tface.color.setHex( colors[ colorIndex ] );\n\n\t\t\t\t\t\t}\n\n\n\t\t\t\t\t\tif ( hasFaceVertexColor ) {\n\n\t\t\t\t\t\t\tfor ( i = 0; i < 3; i ++ ) {\n\n\t\t\t\t\t\t\t\tcolorIndex = faces[ offset ++ ];\n\t\t\t\t\t\t\t\tface.vertexColors.push( new Color( colors[ colorIndex ] ) );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tgeometry.faces.push( face );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tfunction parseSkin( json, geometry ) {\n\n\t\t\t\tvar influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2;\n\n\t\t\t\tif ( json.skinWeights ) {\n\n\t\t\t\t\tfor ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) {\n\n\t\t\t\t\t\tvar x = json.skinWeights[ i ];\n\t\t\t\t\t\tvar y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0;\n\t\t\t\t\t\tvar z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0;\n\t\t\t\t\t\tvar w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0;\n\n\t\t\t\t\t\tgeometry.skinWeights.push( new Vector4( x, y, z, w ) );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( json.skinIndices ) {\n\n\t\t\t\t\tfor ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) {\n\n\t\t\t\t\t\tvar a = json.skinIndices[ i ];\n\t\t\t\t\t\tvar b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0;\n\t\t\t\t\t\tvar c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0;\n\t\t\t\t\t\tvar d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0;\n\n\t\t\t\t\t\tgeometry.skinIndices.push( new Vector4( a, b, c, d ) );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tgeometry.bones = json.bones;\n\n\t\t\t\tif ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) {\n\n\t\t\t\t\tconsole.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' +\n\t\t\t\t\t\tgeometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tfunction parseMorphing( json, geometry ) {\n\n\t\t\t\tvar scale = json.scale;\n\n\t\t\t\tif ( json.morphTargets !== undefined ) {\n\n\t\t\t\t\tfor ( var i = 0, l = json.morphTargets.length; i < l; i ++ ) {\n\n\t\t\t\t\t\tgeometry.morphTargets[ i ] = {};\n\t\t\t\t\t\tgeometry.morphTargets[ i ].name = json.morphTargets[ i ].name;\n\t\t\t\t\t\tgeometry.morphTargets[ i ].vertices = [];\n\n\t\t\t\t\t\tvar dstVertices = geometry.morphTargets[ i ].vertices;\n\t\t\t\t\t\tvar srcVertices = json.morphTargets[ i ].vertices;\n\n\t\t\t\t\t\tfor ( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) {\n\n\t\t\t\t\t\t\tvar vertex = new Vector3();\n\t\t\t\t\t\t\tvertex.x = srcVertices[ v ] * scale;\n\t\t\t\t\t\t\tvertex.y = srcVertices[ v + 1 ] * scale;\n\t\t\t\t\t\t\tvertex.z = srcVertices[ v + 2 ] * scale;\n\n\t\t\t\t\t\t\tdstVertices.push( vertex );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( json.morphColors !== undefined && json.morphColors.length > 0 ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.JSONLoader: \"morphColors\" no longer supported. Using them as face colors.' );\n\n\t\t\t\t\tvar faces = geometry.faces;\n\t\t\t\t\tvar morphColors = json.morphColors[ 0 ].colors;\n\n\t\t\t\t\tfor ( var i = 0, l = faces.length; i < l; i ++ ) {\n\n\t\t\t\t\t\tfaces[ i ].color.fromArray( morphColors, i * 3 );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tfunction parseAnimations( json, geometry ) {\n\n\t\t\t\tvar outputAnimations = [];\n\n\t\t\t\t// parse old style Bone/Hierarchy animations\n\t\t\t\tvar animations = [];\n\n\t\t\t\tif ( json.animation !== undefined ) {\n\n\t\t\t\t\tanimations.push( json.animation );\n\n\t\t\t\t}\n\n\t\t\t\tif ( json.animations !== undefined ) {\n\n\t\t\t\t\tif ( json.animations.length ) {\n\n\t\t\t\t\t\tanimations = animations.concat( json.animations );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tanimations.push( json.animations );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tfor ( var i = 0; i < animations.length; i ++ ) {\n\n\t\t\t\t\tvar clip = AnimationClip.parseAnimation( animations[ i ], geometry.bones );\n\t\t\t\t\tif ( clip ) outputAnimations.push( clip );\n\n\t\t\t\t}\n\n\t\t\t\t// parse implicit morph animations\n\t\t\t\tif ( geometry.morphTargets ) {\n\n\t\t\t\t\t// TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary.\n\t\t\t\t\tvar morphAnimationClips = AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 );\n\t\t\t\t\toutputAnimations = outputAnimations.concat( morphAnimationClips );\n\n\t\t\t\t}\n\n\t\t\t\tif ( outputAnimations.length > 0 ) geometry.animations = outputAnimations;\n\n\t\t\t}\n\n\t\t\treturn function ( json, texturePath ) {\n\n\t\t\t\tif ( json.data !== undefined ) {\n\n\t\t\t\t\t// Geometry 4.0 spec\n\t\t\t\t\tjson = json.data;\n\n\t\t\t\t}\n\n\t\t\t\tif ( json.scale !== undefined ) {\n\n\t\t\t\t\tjson.scale = 1.0 / json.scale;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tjson.scale = 1.0;\n\n\t\t\t\t}\n\n\t\t\t\tvar geometry = new Geometry();\n\n\t\t\t\tparseModel( json, geometry );\n\t\t\t\tparseSkin( json, geometry );\n\t\t\t\tparseMorphing( json, geometry );\n\t\t\t\tparseAnimations( json, geometry );\n\n\t\t\t\tgeometry.computeFaceNormals();\n\t\t\t\tgeometry.computeBoundingSphere();\n\n\t\t\t\tif ( json.materials === undefined || json.materials.length === 0 ) {\n\n\t\t\t\t\treturn { geometry: geometry };\n\n\t\t\t\t} else {\n\n\t\t\t\t\tvar materials = Loader.prototype.initMaterials( json.materials, texturePath, this.crossOrigin );\n\n\t\t\t\t\treturn { geometry: geometry, materials: materials };\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t} )()\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction ObjectLoader( manager ) {\n\n\t\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\t\tthis.texturePath = '';\n\n\t}\n\n\tObject.assign( ObjectLoader.prototype, {\n\n\t\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\t\tif ( this.texturePath === '' ) {\n\n\t\t\t\tthis.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 );\n\n\t\t\t}\n\n\t\t\tvar scope = this;\n\n\t\t\tvar loader = new FileLoader( scope.manager );\n\t\t\tloader.load( url, function ( text ) {\n\n\t\t\t\tvar json = null;\n\n\t\t\t\ttry {\n\n\t\t\t\t\tjson = JSON.parse( text );\n\n\t\t\t\t} catch ( error ) {\n\n\t\t\t\t\tif ( onError !== undefined ) onError( error );\n\n\t\t\t\t\tconsole.error( 'THREE:ObjectLoader: Can\\'t parse ' + url + '.', error.message );\n\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\tvar metadata = json.metadata;\n\n\t\t\t\tif ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {\n\n\t\t\t\t\tconsole.error( 'THREE.ObjectLoader: Can\\'t load ' + url + '. Use THREE.JSONLoader instead.' );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\tscope.parse( json, onLoad );\n\n\t\t\t}, onProgress, onError );\n\n\t\t},\n\n\t\tsetTexturePath: function ( value ) {\n\n\t\t\tthis.texturePath = value;\n\n\t\t},\n\n\t\tsetCrossOrigin: function ( value ) {\n\n\t\t\tthis.crossOrigin = value;\n\n\t\t},\n\n\t\tparse: function ( json, onLoad ) {\n\n\t\t\tvar geometries = this.parseGeometries( json.geometries );\n\n\t\t\tvar images = this.parseImages( json.images, function () {\n\n\t\t\t\tif ( onLoad !== undefined ) onLoad( object );\n\n\t\t\t} );\n\n\t\t\tvar textures = this.parseTextures( json.textures, images );\n\t\t\tvar materials = this.parseMaterials( json.materials, textures );\n\n\t\t\tvar object = this.parseObject( json.object, geometries, materials );\n\n\t\t\tif ( json.animations ) {\n\n\t\t\t\tobject.animations = this.parseAnimations( json.animations );\n\n\t\t\t}\n\n\t\t\tif ( json.images === undefined || json.images.length === 0 ) {\n\n\t\t\t\tif ( onLoad !== undefined ) onLoad( object );\n\n\t\t\t}\n\n\t\t\treturn object;\n\n\t\t},\n\n\t\tparseGeometries: function ( json ) {\n\n\t\t\tvar geometries = {};\n\n\t\t\tif ( json !== undefined ) {\n\n\t\t\t\tvar geometryLoader = new JSONLoader();\n\t\t\t\tvar bufferGeometryLoader = new BufferGeometryLoader();\n\n\t\t\t\tfor ( var i = 0, l = json.length; i < l; i ++ ) {\n\n\t\t\t\t\tvar geometry;\n\t\t\t\t\tvar data = json[ i ];\n\n\t\t\t\t\tswitch ( data.type ) {\n\n\t\t\t\t\t\tcase 'PlaneGeometry':\n\t\t\t\t\t\tcase 'PlaneBufferGeometry':\n\n\t\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\t\tdata.width,\n\t\t\t\t\t\t\t\tdata.height,\n\t\t\t\t\t\t\t\tdata.widthSegments,\n\t\t\t\t\t\t\t\tdata.heightSegments\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'BoxGeometry':\n\t\t\t\t\t\tcase 'BoxBufferGeometry':\n\t\t\t\t\t\tcase 'CubeGeometry': // backwards compatible\n\n\t\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\t\tdata.width,\n\t\t\t\t\t\t\t\tdata.height,\n\t\t\t\t\t\t\t\tdata.depth,\n\t\t\t\t\t\t\t\tdata.widthSegments,\n\t\t\t\t\t\t\t\tdata.heightSegments,\n\t\t\t\t\t\t\t\tdata.depthSegments\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'CircleGeometry':\n\t\t\t\t\t\tcase 'CircleBufferGeometry':\n\n\t\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\t\tdata.radius,\n\t\t\t\t\t\t\t\tdata.segments,\n\t\t\t\t\t\t\t\tdata.thetaStart,\n\t\t\t\t\t\t\t\tdata.thetaLength\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'CylinderGeometry':\n\t\t\t\t\t\tcase 'CylinderBufferGeometry':\n\n\t\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\t\tdata.radiusTop,\n\t\t\t\t\t\t\t\tdata.radiusBottom,\n\t\t\t\t\t\t\t\tdata.height,\n\t\t\t\t\t\t\t\tdata.radialSegments,\n\t\t\t\t\t\t\t\tdata.heightSegments,\n\t\t\t\t\t\t\t\tdata.openEnded,\n\t\t\t\t\t\t\t\tdata.thetaStart,\n\t\t\t\t\t\t\t\tdata.thetaLength\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'ConeGeometry':\n\t\t\t\t\t\tcase 'ConeBufferGeometry':\n\n\t\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\t\tdata.radius,\n\t\t\t\t\t\t\t\tdata.height,\n\t\t\t\t\t\t\t\tdata.radialSegments,\n\t\t\t\t\t\t\t\tdata.heightSegments,\n\t\t\t\t\t\t\t\tdata.openEnded,\n\t\t\t\t\t\t\t\tdata.thetaStart,\n\t\t\t\t\t\t\t\tdata.thetaLength\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'SphereGeometry':\n\t\t\t\t\t\tcase 'SphereBufferGeometry':\n\n\t\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\t\tdata.radius,\n\t\t\t\t\t\t\t\tdata.widthSegments,\n\t\t\t\t\t\t\t\tdata.heightSegments,\n\t\t\t\t\t\t\t\tdata.phiStart,\n\t\t\t\t\t\t\t\tdata.phiLength,\n\t\t\t\t\t\t\t\tdata.thetaStart,\n\t\t\t\t\t\t\t\tdata.thetaLength\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'DodecahedronGeometry':\n\t\t\t\t\t\tcase 'IcosahedronGeometry':\n\t\t\t\t\t\tcase 'OctahedronGeometry':\n\t\t\t\t\t\tcase 'TetrahedronGeometry':\n\n\t\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\t\tdata.radius,\n\t\t\t\t\t\t\t\tdata.detail\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'RingGeometry':\n\t\t\t\t\t\tcase 'RingBufferGeometry':\n\n\t\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\t\tdata.innerRadius,\n\t\t\t\t\t\t\t\tdata.outerRadius,\n\t\t\t\t\t\t\t\tdata.thetaSegments,\n\t\t\t\t\t\t\t\tdata.phiSegments,\n\t\t\t\t\t\t\t\tdata.thetaStart,\n\t\t\t\t\t\t\t\tdata.thetaLength\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'TorusGeometry':\n\t\t\t\t\t\tcase 'TorusBufferGeometry':\n\n\t\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\t\tdata.radius,\n\t\t\t\t\t\t\t\tdata.tube,\n\t\t\t\t\t\t\t\tdata.radialSegments,\n\t\t\t\t\t\t\t\tdata.tubularSegments,\n\t\t\t\t\t\t\t\tdata.arc\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'TorusKnotGeometry':\n\t\t\t\t\t\tcase 'TorusKnotBufferGeometry':\n\n\t\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\t\tdata.radius,\n\t\t\t\t\t\t\t\tdata.tube,\n\t\t\t\t\t\t\t\tdata.tubularSegments,\n\t\t\t\t\t\t\t\tdata.radialSegments,\n\t\t\t\t\t\t\t\tdata.p,\n\t\t\t\t\t\t\t\tdata.q\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'LatheGeometry':\n\t\t\t\t\t\tcase 'LatheBufferGeometry':\n\n\t\t\t\t\t\t\tgeometry = new Geometries[ data.type ](\n\t\t\t\t\t\t\t\tdata.points,\n\t\t\t\t\t\t\t\tdata.segments,\n\t\t\t\t\t\t\t\tdata.phiStart,\n\t\t\t\t\t\t\t\tdata.phiLength\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'BufferGeometry':\n\n\t\t\t\t\t\t\tgeometry = bufferGeometryLoader.parse( data );\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'Geometry':\n\n\t\t\t\t\t\t\tgeometry = geometryLoader.parse( data, this.texturePath ).geometry;\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\n\t\t\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader: Unsupported geometry type \"' + data.type + '\"' );\n\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tgeometry.uuid = data.uuid;\n\n\t\t\t\t\tif ( data.name !== undefined ) geometry.name = data.name;\n\n\t\t\t\t\tgeometries[ data.uuid ] = geometry;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn geometries;\n\n\t\t},\n\n\t\tparseMaterials: function ( json, textures ) {\n\n\t\t\tvar materials = {};\n\n\t\t\tif ( json !== undefined ) {\n\n\t\t\t\tvar loader = new MaterialLoader();\n\t\t\t\tloader.setTextures( textures );\n\n\t\t\t\tfor ( var i = 0, l = json.length; i < l; i ++ ) {\n\n\t\t\t\t\tvar data = json[ i ];\n\n\t\t\t\t\tif ( data.type === 'MultiMaterial' ) {\n\n\t\t\t\t\t\t// Deprecated\n\n\t\t\t\t\t\tvar array = [];\n\n\t\t\t\t\t\tfor ( var j = 0; j < data.materials.length; j ++ ) {\n\n\t\t\t\t\t\t\tarray.push( loader.parse( data.materials[ j ] ) );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tmaterials[ data.uuid ] = array;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tmaterials[ data.uuid ] = loader.parse( data );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn materials;\n\n\t\t},\n\n\t\tparseAnimations: function ( json ) {\n\n\t\t\tvar animations = [];\n\n\t\t\tfor ( var i = 0; i < json.length; i ++ ) {\n\n\t\t\t\tvar clip = AnimationClip.parse( json[ i ] );\n\n\t\t\t\tanimations.push( clip );\n\n\t\t\t}\n\n\t\t\treturn animations;\n\n\t\t},\n\n\t\tparseImages: function ( json, onLoad ) {\n\n\t\t\tvar scope = this;\n\t\t\tvar images = {};\n\n\t\t\tfunction loadImage( url ) {\n\n\t\t\t\tscope.manager.itemStart( url );\n\n\t\t\t\treturn loader.load( url, function () {\n\n\t\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t\t}, undefined, function () {\n\n\t\t\t\t\tscope.manager.itemEnd( url );\n\t\t\t\t\tscope.manager.itemError( url );\n\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t\tif ( json !== undefined && json.length > 0 ) {\n\n\t\t\t\tvar manager = new LoadingManager( onLoad );\n\n\t\t\t\tvar loader = new ImageLoader( manager );\n\t\t\t\tloader.setCrossOrigin( this.crossOrigin );\n\n\t\t\t\tfor ( var i = 0, l = json.length; i < l; i ++ ) {\n\n\t\t\t\t\tvar image = json[ i ];\n\t\t\t\t\tvar path = /^(\\/\\/)|([a-z]+:(\\/\\/)?)/i.test( image.url ) ? image.url : scope.texturePath + image.url;\n\n\t\t\t\t\timages[ image.uuid ] = loadImage( path );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn images;\n\n\t\t},\n\n\t\tparseTextures: function ( json, images ) {\n\n\t\t\tfunction parseConstant( value, type ) {\n\n\t\t\t\tif ( typeof( value ) === 'number' ) return value;\n\n\t\t\t\tconsole.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value );\n\n\t\t\t\treturn type[ value ];\n\n\t\t\t}\n\n\t\t\tvar textures = {};\n\n\t\t\tif ( json !== undefined ) {\n\n\t\t\t\tfor ( var i = 0, l = json.length; i < l; i ++ ) {\n\n\t\t\t\t\tvar data = json[ i ];\n\n\t\t\t\t\tif ( data.image === undefined ) {\n\n\t\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader: No \"image\" specified for', data.uuid );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( images[ data.image ] === undefined ) {\n\n\t\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader: Undefined image', data.image );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tvar texture = new Texture( images[ data.image ] );\n\t\t\t\t\ttexture.needsUpdate = true;\n\n\t\t\t\t\ttexture.uuid = data.uuid;\n\n\t\t\t\t\tif ( data.name !== undefined ) texture.name = data.name;\n\n\t\t\t\t\tif ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING );\n\n\t\t\t\t\tif ( data.offset !== undefined ) texture.offset.fromArray( data.offset );\n\t\t\t\t\tif ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat );\n\t\t\t\t\tif ( data.wrap !== undefined ) {\n\n\t\t\t\t\t\ttexture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING );\n\t\t\t\t\t\ttexture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER );\n\t\t\t\t\tif ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER );\n\t\t\t\t\tif ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy;\n\n\t\t\t\t\tif ( data.flipY !== undefined ) texture.flipY = data.flipY;\n\n\t\t\t\t\ttextures[ data.uuid ] = texture;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn textures;\n\n\t\t},\n\n\t\tparseObject: function () {\n\n\t\t\tvar matrix = new Matrix4();\n\n\t\t\treturn function parseObject( data, geometries, materials ) {\n\n\t\t\t\tvar object;\n\n\t\t\t\tfunction getGeometry( name ) {\n\n\t\t\t\t\tif ( geometries[ name ] === undefined ) {\n\n\t\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader: Undefined geometry', name );\n\n\t\t\t\t\t}\n\n\t\t\t\t\treturn geometries[ name ];\n\n\t\t\t\t}\n\n\t\t\t\tfunction getMaterial( name ) {\n\n\t\t\t\t\tif ( name === undefined ) return undefined;\n\n\t\t\t\t\tif ( Array.isArray( name ) ) {\n\n\t\t\t\t\t\tvar array = [];\n\n\t\t\t\t\t\tfor ( var i = 0, l = name.length; i < l; i ++ ) {\n\n\t\t\t\t\t\t\tvar uuid = name[ i ];\n\n\t\t\t\t\t\t\tif ( materials[ uuid ] === undefined ) {\n\n\t\t\t\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader: Undefined material', uuid );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tarray.push( materials[ uuid ] );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn array;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( materials[ name ] === undefined ) {\n\n\t\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader: Undefined material', name );\n\n\t\t\t\t\t}\n\n\t\t\t\t\treturn materials[ name ];\n\n\t\t\t\t}\n\n\t\t\t\tswitch ( data.type ) {\n\n\t\t\t\t\tcase 'Scene':\n\n\t\t\t\t\t\tobject = new Scene();\n\n\t\t\t\t\t\tif ( data.background !== undefined ) {\n\n\t\t\t\t\t\t\tif ( Number.isInteger( data.background ) ) {\n\n\t\t\t\t\t\t\t\tobject.background = new Color( data.background );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( data.fog !== undefined ) {\n\n\t\t\t\t\t\t\tif ( data.fog.type === 'Fog' ) {\n\n\t\t\t\t\t\t\t\tobject.fog = new Fog( data.fog.color, data.fog.near, data.fog.far );\n\n\t\t\t\t\t\t\t} else if ( data.fog.type === 'FogExp2' ) {\n\n\t\t\t\t\t\t\t\tobject.fog = new FogExp2( data.fog.color, data.fog.density );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'PerspectiveCamera':\n\n\t\t\t\t\t\tobject = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far );\n\n\t\t\t\t\t\tif ( data.focus !== undefined ) object.focus = data.focus;\n\t\t\t\t\t\tif ( data.zoom !== undefined ) object.zoom = data.zoom;\n\t\t\t\t\t\tif ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge;\n\t\t\t\t\t\tif ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset;\n\t\t\t\t\t\tif ( data.view !== undefined ) object.view = Object.assign( {}, data.view );\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'OrthographicCamera':\n\n\t\t\t\t\t\tobject = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far );\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'AmbientLight':\n\n\t\t\t\t\t\tobject = new AmbientLight( data.color, data.intensity );\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'DirectionalLight':\n\n\t\t\t\t\t\tobject = new DirectionalLight( data.color, data.intensity );\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'PointLight':\n\n\t\t\t\t\t\tobject = new PointLight( data.color, data.intensity, data.distance, data.decay );\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'RectAreaLight':\n\n\t\t\t\t\t\tobject = new RectAreaLight( data.color, data.intensity, data.width, data.height );\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'SpotLight':\n\n\t\t\t\t\t\tobject = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay );\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'HemisphereLight':\n\n\t\t\t\t\t\tobject = new HemisphereLight( data.color, data.groundColor, data.intensity );\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'SkinnedMesh':\n\n\t\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh yet.' );\n\n\t\t\t\t\tcase 'Mesh':\n\n\t\t\t\t\t\tvar geometry = getGeometry( data.geometry );\n\t\t\t\t\t\tvar material = getMaterial( data.material );\n\n\t\t\t\t\t\tif ( geometry.bones && geometry.bones.length > 0 ) {\n\n\t\t\t\t\t\t\tobject = new SkinnedMesh( geometry, material );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tobject = new Mesh( geometry, material );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'LOD':\n\n\t\t\t\t\t\tobject = new LOD();\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'Line':\n\n\t\t\t\t\t\tobject = new Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode );\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'LineLoop':\n\n\t\t\t\t\t\tobject = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) );\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'LineSegments':\n\n\t\t\t\t\t\tobject = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) );\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'PointCloud':\n\t\t\t\t\tcase 'Points':\n\n\t\t\t\t\t\tobject = new Points( getGeometry( data.geometry ), getMaterial( data.material ) );\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'Sprite':\n\n\t\t\t\t\t\tobject = new Sprite( getMaterial( data.material ) );\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'Group':\n\n\t\t\t\t\t\tobject = new Group();\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\n\t\t\t\t\t\tobject = new Object3D();\n\n\t\t\t\t}\n\n\t\t\t\tobject.uuid = data.uuid;\n\n\t\t\t\tif ( data.name !== undefined ) object.name = data.name;\n\t\t\t\tif ( data.matrix !== undefined ) {\n\n\t\t\t\t\tmatrix.fromArray( data.matrix );\n\t\t\t\t\tmatrix.decompose( object.position, object.quaternion, object.scale );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( data.position !== undefined ) object.position.fromArray( data.position );\n\t\t\t\t\tif ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation );\n\t\t\t\t\tif ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion );\n\t\t\t\t\tif ( data.scale !== undefined ) object.scale.fromArray( data.scale );\n\n\t\t\t\t}\n\n\t\t\t\tif ( data.castShadow !== undefined ) object.castShadow = data.castShadow;\n\t\t\t\tif ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow;\n\n\t\t\t\tif ( data.shadow ) {\n\n\t\t\t\t\tif ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias;\n\t\t\t\t\tif ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius;\n\t\t\t\t\tif ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize );\n\t\t\t\t\tif ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera );\n\n\t\t\t\t}\n\n\t\t\t\tif ( data.visible !== undefined ) object.visible = data.visible;\n\t\t\t\tif ( data.userData !== undefined ) object.userData = data.userData;\n\n\t\t\t\tif ( data.children !== undefined ) {\n\n\t\t\t\t\tvar children = data.children;\n\n\t\t\t\t\tfor ( var  i = 0; i < children.length; i ++ ) {\n\n\t\t\t\t\t\tobject.add( this.parseObject( children[ i ], geometries, materials ) );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( data.type === 'LOD' ) {\n\n\t\t\t\t\tvar levels = data.levels;\n\n\t\t\t\t\tfor ( var l = 0; l < levels.length; l ++ ) {\n\n\t\t\t\t\t\tvar level = levels[ l ];\n\t\t\t\t\t\tvar child = object.getObjectByProperty( 'uuid', level.object );\n\n\t\t\t\t\t\tif ( child !== undefined ) {\n\n\t\t\t\t\t\t\tobject.addLevel( child, level.distance );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\treturn object;\n\n\t\t\t};\n\n\t\t}()\n\n\t} );\n\n\tvar TEXTURE_MAPPING = {\n\t\tUVMapping: UVMapping,\n\t\tCubeReflectionMapping: CubeReflectionMapping,\n\t\tCubeRefractionMapping: CubeRefractionMapping,\n\t\tEquirectangularReflectionMapping: EquirectangularReflectionMapping,\n\t\tEquirectangularRefractionMapping: EquirectangularRefractionMapping,\n\t\tSphericalReflectionMapping: SphericalReflectionMapping,\n\t\tCubeUVReflectionMapping: CubeUVReflectionMapping,\n\t\tCubeUVRefractionMapping: CubeUVRefractionMapping\n\t};\n\n\tvar TEXTURE_WRAPPING = {\n\t\tRepeatWrapping: RepeatWrapping,\n\t\tClampToEdgeWrapping: ClampToEdgeWrapping,\n\t\tMirroredRepeatWrapping: MirroredRepeatWrapping\n\t};\n\n\tvar TEXTURE_FILTER = {\n\t\tNearestFilter: NearestFilter,\n\t\tNearestMipMapNearestFilter: NearestMipMapNearestFilter,\n\t\tNearestMipMapLinearFilter: NearestMipMapLinearFilter,\n\t\tLinearFilter: LinearFilter,\n\t\tLinearMipMapNearestFilter: LinearMipMapNearestFilter,\n\t\tLinearMipMapLinearFilter: LinearMipMapLinearFilter\n\t};\n\n\t/**\n\t * @author zz85 / http://www.lab4games.net/zz85/blog\n\t *\n\t * Bezier Curves formulas obtained from\n\t * http://en.wikipedia.org/wiki/Bézier_curve\n\t */\n\n\tfunction CatmullRom( t, p0, p1, p2, p3 ) {\n\n\t\tvar v0 = ( p2 - p0 ) * 0.5;\n\t\tvar v1 = ( p3 - p1 ) * 0.5;\n\t\tvar t2 = t * t;\n\t\tvar t3 = t * t2;\n\t\treturn ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;\n\n\t}\n\n\t//\n\n\tfunction QuadraticBezierP0( t, p ) {\n\n\t\tvar k = 1 - t;\n\t\treturn k * k * p;\n\n\t}\n\n\tfunction QuadraticBezierP1( t, p ) {\n\n\t\treturn 2 * ( 1 - t ) * t * p;\n\n\t}\n\n\tfunction QuadraticBezierP2( t, p ) {\n\n\t\treturn t * t * p;\n\n\t}\n\n\tfunction QuadraticBezier( t, p0, p1, p2 ) {\n\n\t\treturn QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) +\n\t\t\tQuadraticBezierP2( t, p2 );\n\n\t}\n\n\t//\n\n\tfunction CubicBezierP0( t, p ) {\n\n\t\tvar k = 1 - t;\n\t\treturn k * k * k * p;\n\n\t}\n\n\tfunction CubicBezierP1( t, p ) {\n\n\t\tvar k = 1 - t;\n\t\treturn 3 * k * k * t * p;\n\n\t}\n\n\tfunction CubicBezierP2( t, p ) {\n\n\t\treturn 3 * ( 1 - t ) * t * t * p;\n\n\t}\n\n\tfunction CubicBezierP3( t, p ) {\n\n\t\treturn t * t * t * p;\n\n\t}\n\n\tfunction CubicBezier( t, p0, p1, p2, p3 ) {\n\n\t\treturn CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) +\n\t\t\tCubicBezierP3( t, p3 );\n\n\t}\n\n\t/**\n\t * @author zz85 / http://www.lab4games.net/zz85/blog\n\t * Extensible curve object\n\t *\n\t * Some common of curve methods:\n\t * .getPoint(t), getTangent(t)\n\t * .getPointAt(u), getTangentAt(u)\n\t * .getPoints(), .getSpacedPoints()\n\t * .getLength()\n\t * .updateArcLengths()\n\t *\n\t * This following curves inherit from THREE.Curve:\n\t *\n\t * -- 2D curves --\n\t * THREE.ArcCurve\n\t * THREE.CubicBezierCurve\n\t * THREE.EllipseCurve\n\t * THREE.LineCurve\n\t * THREE.QuadraticBezierCurve\n\t * THREE.SplineCurve\n\t *\n\t * -- 3D curves --\n\t * THREE.CatmullRomCurve3\n\t * THREE.CubicBezierCurve3\n\t * THREE.LineCurve3\n\t * THREE.QuadraticBezierCurve3\n\t *\n\t * A series of curves can be represented as a THREE.CurvePath.\n\t *\n\t **/\n\n\t/**************************************************************\n\t *\tAbstract Curve base class\n\t **************************************************************/\n\n\tfunction Curve() {\n\n\t\tthis.arcLengthDivisions = 200;\n\n\t}\n\n\tObject.assign( Curve.prototype, {\n\n\t\t// Virtual base class method to overwrite and implement in subclasses\n\t\t//\t- t [0 .. 1]\n\n\t\tgetPoint: function () {\n\n\t\t\tconsole.warn( 'THREE.Curve: .getPoint() not implemented.' );\n\t\t\treturn null;\n\n\t\t},\n\n\t\t// Get point at relative position in curve according to arc length\n\t\t// - u [0 .. 1]\n\n\t\tgetPointAt: function ( u ) {\n\n\t\t\tvar t = this.getUtoTmapping( u );\n\t\t\treturn this.getPoint( t );\n\n\t\t},\n\n\t\t// Get sequence of points using getPoint( t )\n\n\t\tgetPoints: function ( divisions ) {\n\n\t\t\tif ( divisions === undefined ) divisions = 5;\n\n\t\t\tvar points = [];\n\n\t\t\tfor ( var d = 0; d <= divisions; d ++ ) {\n\n\t\t\t\tpoints.push( this.getPoint( d / divisions ) );\n\n\t\t\t}\n\n\t\t\treturn points;\n\n\t\t},\n\n\t\t// Get sequence of points using getPointAt( u )\n\n\t\tgetSpacedPoints: function ( divisions ) {\n\n\t\t\tif ( divisions === undefined ) divisions = 5;\n\n\t\t\tvar points = [];\n\n\t\t\tfor ( var d = 0; d <= divisions; d ++ ) {\n\n\t\t\t\tpoints.push( this.getPointAt( d / divisions ) );\n\n\t\t\t}\n\n\t\t\treturn points;\n\n\t\t},\n\n\t\t// Get total curve arc length\n\n\t\tgetLength: function () {\n\n\t\t\tvar lengths = this.getLengths();\n\t\t\treturn lengths[ lengths.length - 1 ];\n\n\t\t},\n\n\t\t// Get list of cumulative segment lengths\n\n\t\tgetLengths: function ( divisions ) {\n\n\t\t\tif ( divisions === undefined ) divisions = this.arcLengthDivisions;\n\n\t\t\tif ( this.cacheArcLengths &&\n\t\t\t\t( this.cacheArcLengths.length === divisions + 1 ) &&\n\t\t\t\t! this.needsUpdate ) {\n\n\t\t\t\treturn this.cacheArcLengths;\n\n\t\t\t}\n\n\t\t\tthis.needsUpdate = false;\n\n\t\t\tvar cache = [];\n\t\t\tvar current, last = this.getPoint( 0 );\n\t\t\tvar p, sum = 0;\n\n\t\t\tcache.push( 0 );\n\n\t\t\tfor ( p = 1; p <= divisions; p ++ ) {\n\n\t\t\t\tcurrent = this.getPoint( p / divisions );\n\t\t\t\tsum += current.distanceTo( last );\n\t\t\t\tcache.push( sum );\n\t\t\t\tlast = current;\n\n\t\t\t}\n\n\t\t\tthis.cacheArcLengths = cache;\n\n\t\t\treturn cache; // { sums: cache, sum: sum }; Sum is in the last element.\n\n\t\t},\n\n\t\tupdateArcLengths: function () {\n\n\t\t\tthis.needsUpdate = true;\n\t\t\tthis.getLengths();\n\n\t\t},\n\n\t\t// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant\n\n\t\tgetUtoTmapping: function ( u, distance ) {\n\n\t\t\tvar arcLengths = this.getLengths();\n\n\t\t\tvar i = 0, il = arcLengths.length;\n\n\t\t\tvar targetArcLength; // The targeted u distance value to get\n\n\t\t\tif ( distance ) {\n\n\t\t\t\ttargetArcLength = distance;\n\n\t\t\t} else {\n\n\t\t\t\ttargetArcLength = u * arcLengths[ il - 1 ];\n\n\t\t\t}\n\n\t\t\t// binary search for the index with largest value smaller than target u distance\n\n\t\t\tvar low = 0, high = il - 1, comparison;\n\n\t\t\twhile ( low <= high ) {\n\n\t\t\t\ti = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats\n\n\t\t\t\tcomparison = arcLengths[ i ] - targetArcLength;\n\n\t\t\t\tif ( comparison < 0 ) {\n\n\t\t\t\t\tlow = i + 1;\n\n\t\t\t\t} else if ( comparison > 0 ) {\n\n\t\t\t\t\thigh = i - 1;\n\n\t\t\t\t} else {\n\n\t\t\t\t\thigh = i;\n\t\t\t\t\tbreak;\n\n\t\t\t\t\t// DONE\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\ti = high;\n\n\t\t\tif ( arcLengths[ i ] === targetArcLength ) {\n\n\t\t\t\treturn i / ( il - 1 );\n\n\t\t\t}\n\n\t\t\t// we could get finer grain at lengths, or use simple interpolation between two points\n\n\t\t\tvar lengthBefore = arcLengths[ i ];\n\t\t\tvar lengthAfter = arcLengths[ i + 1 ];\n\n\t\t\tvar segmentLength = lengthAfter - lengthBefore;\n\n\t\t\t// determine where we are between the 'before' and 'after' points\n\n\t\t\tvar segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;\n\n\t\t\t// add that fractional amount to t\n\n\t\t\tvar t = ( i + segmentFraction ) / ( il - 1 );\n\n\t\t\treturn t;\n\n\t\t},\n\n\t\t// Returns a unit vector tangent at t\n\t\t// In case any sub curve does not implement its tangent derivation,\n\t\t// 2 points a small delta apart will be used to find its gradient\n\t\t// which seems to give a reasonable approximation\n\n\t\tgetTangent: function ( t ) {\n\n\t\t\tvar delta = 0.0001;\n\t\t\tvar t1 = t - delta;\n\t\t\tvar t2 = t + delta;\n\n\t\t\t// Capping in case of danger\n\n\t\t\tif ( t1 < 0 ) t1 = 0;\n\t\t\tif ( t2 > 1 ) t2 = 1;\n\n\t\t\tvar pt1 = this.getPoint( t1 );\n\t\t\tvar pt2 = this.getPoint( t2 );\n\n\t\t\tvar vec = pt2.clone().sub( pt1 );\n\t\t\treturn vec.normalize();\n\n\t\t},\n\n\t\tgetTangentAt: function ( u ) {\n\n\t\t\tvar t = this.getUtoTmapping( u );\n\t\t\treturn this.getTangent( t );\n\n\t\t},\n\n\t\tcomputeFrenetFrames: function ( segments, closed ) {\n\n\t\t\t// see http://www.cs.indiana.edu/pub/techreports/TR425.pdf\n\n\t\t\tvar normal = new Vector3();\n\n\t\t\tvar tangents = [];\n\t\t\tvar normals = [];\n\t\t\tvar binormals = [];\n\n\t\t\tvar vec = new Vector3();\n\t\t\tvar mat = new Matrix4();\n\n\t\t\tvar i, u, theta;\n\n\t\t\t// compute the tangent vectors for each segment on the curve\n\n\t\t\tfor ( i = 0; i <= segments; i ++ ) {\n\n\t\t\t\tu = i / segments;\n\n\t\t\t\ttangents[ i ] = this.getTangentAt( u );\n\t\t\t\ttangents[ i ].normalize();\n\n\t\t\t}\n\n\t\t\t// select an initial normal vector perpendicular to the first tangent vector,\n\t\t\t// and in the direction of the minimum tangent xyz component\n\n\t\t\tnormals[ 0 ] = new Vector3();\n\t\t\tbinormals[ 0 ] = new Vector3();\n\t\t\tvar min = Number.MAX_VALUE;\n\t\t\tvar tx = Math.abs( tangents[ 0 ].x );\n\t\t\tvar ty = Math.abs( tangents[ 0 ].y );\n\t\t\tvar tz = Math.abs( tangents[ 0 ].z );\n\n\t\t\tif ( tx <= min ) {\n\n\t\t\t\tmin = tx;\n\t\t\t\tnormal.set( 1, 0, 0 );\n\n\t\t\t}\n\n\t\t\tif ( ty <= min ) {\n\n\t\t\t\tmin = ty;\n\t\t\t\tnormal.set( 0, 1, 0 );\n\n\t\t\t}\n\n\t\t\tif ( tz <= min ) {\n\n\t\t\t\tnormal.set( 0, 0, 1 );\n\n\t\t\t}\n\n\t\t\tvec.crossVectors( tangents[ 0 ], normal ).normalize();\n\n\t\t\tnormals[ 0 ].crossVectors( tangents[ 0 ], vec );\n\t\t\tbinormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );\n\n\n\t\t\t// compute the slowly-varying normal and binormal vectors for each segment on the curve\n\n\t\t\tfor ( i = 1; i <= segments; i ++ ) {\n\n\t\t\t\tnormals[ i ] = normals[ i - 1 ].clone();\n\n\t\t\t\tbinormals[ i ] = binormals[ i - 1 ].clone();\n\n\t\t\t\tvec.crossVectors( tangents[ i - 1 ], tangents[ i ] );\n\n\t\t\t\tif ( vec.length() > Number.EPSILON ) {\n\n\t\t\t\t\tvec.normalize();\n\n\t\t\t\t\ttheta = Math.acos( _Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors\n\n\t\t\t\t\tnormals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );\n\n\t\t\t\t}\n\n\t\t\t\tbinormals[ i ].crossVectors( tangents[ i ], normals[ i ] );\n\n\t\t\t}\n\n\t\t\t// if the curve is closed, postprocess the vectors so the first and last normal vectors are the same\n\n\t\t\tif ( closed === true ) {\n\n\t\t\t\ttheta = Math.acos( _Math.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) );\n\t\t\t\ttheta /= segments;\n\n\t\t\t\tif ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) {\n\n\t\t\t\t\ttheta = - theta;\n\n\t\t\t\t}\n\n\t\t\t\tfor ( i = 1; i <= segments; i ++ ) {\n\n\t\t\t\t\t// twist a little...\n\t\t\t\t\tnormals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );\n\t\t\t\t\tbinormals[ i ].crossVectors( tangents[ i ], normals[ i ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttangents: tangents,\n\t\t\t\tnormals: normals,\n\t\t\t\tbinormals: binormals\n\t\t\t};\n\n\t\t}\n\n\t} );\n\n\tfunction LineCurve( v1, v2 ) {\n\n\t\tCurve.call( this );\n\n\t\tthis.v1 = v1;\n\t\tthis.v2 = v2;\n\n\t}\n\n\tLineCurve.prototype = Object.create( Curve.prototype );\n\tLineCurve.prototype.constructor = LineCurve;\n\n\tLineCurve.prototype.isLineCurve = true;\n\n\tLineCurve.prototype.getPoint = function ( t ) {\n\n\t\tif ( t === 1 ) {\n\n\t\t\treturn this.v2.clone();\n\n\t\t}\n\n\t\tvar point = this.v2.clone().sub( this.v1 );\n\t\tpoint.multiplyScalar( t ).add( this.v1 );\n\n\t\treturn point;\n\n\t};\n\n\t// Line curve is linear, so we can overwrite default getPointAt\n\n\tLineCurve.prototype.getPointAt = function ( u ) {\n\n\t\treturn this.getPoint( u );\n\n\t};\n\n\tLineCurve.prototype.getTangent = function ( t ) {\n\n\t\tvar tangent = this.v2.clone().sub( this.v1 );\n\n\t\treturn tangent.normalize();\n\n\t};\n\n\t/**\n\t * @author zz85 / http://www.lab4games.net/zz85/blog\n\t *\n\t **/\n\n\t/**************************************************************\n\t *\tCurved Path - a curve path is simply a array of connected\n\t *  curves, but retains the api of a curve\n\t **************************************************************/\n\n\tfunction CurvePath() {\n\n\t\tCurve.call( this );\n\n\t\tthis.curves = [];\n\n\t\tthis.autoClose = false; // Automatically closes the path\n\n\t}\n\n\tCurvePath.prototype = Object.assign( Object.create( Curve.prototype ), {\n\n\t\tconstructor: CurvePath,\n\n\t\tadd: function ( curve ) {\n\n\t\t\tthis.curves.push( curve );\n\n\t\t},\n\n\t\tclosePath: function () {\n\n\t\t\t// Add a line curve if start and end of lines are not connected\n\t\t\tvar startPoint = this.curves[ 0 ].getPoint( 0 );\n\t\t\tvar endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );\n\n\t\t\tif ( ! startPoint.equals( endPoint ) ) {\n\n\t\t\t\tthis.curves.push( new LineCurve( endPoint, startPoint ) );\n\n\t\t\t}\n\n\t\t},\n\n\t\t// To get accurate point with reference to\n\t\t// entire path distance at time t,\n\t\t// following has to be done:\n\n\t\t// 1. Length of each sub path have to be known\n\t\t// 2. Locate and identify type of curve\n\t\t// 3. Get t for the curve\n\t\t// 4. Return curve.getPointAt(t')\n\n\t\tgetPoint: function ( t ) {\n\n\t\t\tvar d = t * this.getLength();\n\t\t\tvar curveLengths = this.getCurveLengths();\n\t\t\tvar i = 0;\n\n\t\t\t// To think about boundaries points.\n\n\t\t\twhile ( i < curveLengths.length ) {\n\n\t\t\t\tif ( curveLengths[ i ] >= d ) {\n\n\t\t\t\t\tvar diff = curveLengths[ i ] - d;\n\t\t\t\t\tvar curve = this.curves[ i ];\n\n\t\t\t\t\tvar segmentLength = curve.getLength();\n\t\t\t\t\tvar u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;\n\n\t\t\t\t\treturn curve.getPointAt( u );\n\n\t\t\t\t}\n\n\t\t\t\ti ++;\n\n\t\t\t}\n\n\t\t\treturn null;\n\n\t\t\t// loop where sum != 0, sum > d , sum+1 <d\n\n\t\t},\n\n\t\t// We cannot use the default THREE.Curve getPoint() with getLength() because in\n\t\t// THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath\n\t\t// getPoint() depends on getLength\n\n\t\tgetLength: function () {\n\n\t\t\tvar lens = this.getCurveLengths();\n\t\t\treturn lens[ lens.length - 1 ];\n\n\t\t},\n\n\t\t// cacheLengths must be recalculated.\n\t\tupdateArcLengths: function () {\n\n\t\t\tthis.needsUpdate = true;\n\t\t\tthis.cacheLengths = null;\n\t\t\tthis.getCurveLengths();\n\n\t\t},\n\n\t\t// Compute lengths and cache them\n\t\t// We cannot overwrite getLengths() because UtoT mapping uses it.\n\n\t\tgetCurveLengths: function () {\n\n\t\t\t// We use cache values if curves and cache array are same length\n\n\t\t\tif ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) {\n\n\t\t\t\treturn this.cacheLengths;\n\n\t\t\t}\n\n\t\t\t// Get length of sub-curve\n\t\t\t// Push sums into cached array\n\n\t\t\tvar lengths = [], sums = 0;\n\n\t\t\tfor ( var i = 0, l = this.curves.length; i < l; i ++ ) {\n\n\t\t\t\tsums += this.curves[ i ].getLength();\n\t\t\t\tlengths.push( sums );\n\n\t\t\t}\n\n\t\t\tthis.cacheLengths = lengths;\n\n\t\t\treturn lengths;\n\n\t\t},\n\n\t\tgetSpacedPoints: function ( divisions ) {\n\n\t\t\tif ( divisions === undefined ) divisions = 40;\n\n\t\t\tvar points = [];\n\n\t\t\tfor ( var i = 0; i <= divisions; i ++ ) {\n\n\t\t\t\tpoints.push( this.getPoint( i / divisions ) );\n\n\t\t\t}\n\n\t\t\tif ( this.autoClose ) {\n\n\t\t\t\tpoints.push( points[ 0 ] );\n\n\t\t\t}\n\n\t\t\treturn points;\n\n\t\t},\n\n\t\tgetPoints: function ( divisions ) {\n\n\t\t\tdivisions = divisions || 12;\n\n\t\t\tvar points = [], last;\n\n\t\t\tfor ( var i = 0, curves = this.curves; i < curves.length; i ++ ) {\n\n\t\t\t\tvar curve = curves[ i ];\n\t\t\t\tvar resolution = (curve && curve.isEllipseCurve) ? divisions * 2\n\t\t\t\t\t: (curve && curve.isLineCurve) ? 1\n\t\t\t\t\t: (curve && curve.isSplineCurve) ? divisions * curve.points.length\n\t\t\t\t\t: divisions;\n\n\t\t\t\tvar pts = curve.getPoints( resolution );\n\n\t\t\t\tfor ( var j = 0; j < pts.length; j++ ) {\n\n\t\t\t\t\tvar point = pts[ j ];\n\n\t\t\t\t\tif ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates\n\n\t\t\t\t\tpoints.push( point );\n\t\t\t\t\tlast = point;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( this.autoClose && points.length > 1 && !points[ points.length - 1 ].equals( points[ 0 ] ) ) {\n\n\t\t\t\tpoints.push( points[ 0 ] );\n\n\t\t\t}\n\n\t\t\treturn points;\n\n\t\t},\n\n\t\t/**************************************************************\n\t\t *\tCreate Geometries Helpers\n\t\t **************************************************************/\n\n\t\t/// Generate geometry from path points (for Line or Points objects)\n\n\t\tcreatePointsGeometry: function ( divisions ) {\n\n\t\t\tvar pts = this.getPoints( divisions );\n\t\t\treturn this.createGeometry( pts );\n\n\t\t},\n\n\t\t// Generate geometry from equidistant sampling along the path\n\n\t\tcreateSpacedPointsGeometry: function ( divisions ) {\n\n\t\t\tvar pts = this.getSpacedPoints( divisions );\n\t\t\treturn this.createGeometry( pts );\n\n\t\t},\n\n\t\tcreateGeometry: function ( points ) {\n\n\t\t\tvar geometry = new Geometry();\n\n\t\t\tfor ( var i = 0, l = points.length; i < l; i ++ ) {\n\n\t\t\t\tvar point = points[ i ];\n\t\t\t\tgeometry.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) );\n\n\t\t\t}\n\n\t\t\treturn geometry;\n\n\t\t}\n\n\t} );\n\n\tfunction EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {\n\n\t\tCurve.call( this );\n\n\t\tthis.aX = aX;\n\t\tthis.aY = aY;\n\n\t\tthis.xRadius = xRadius;\n\t\tthis.yRadius = yRadius;\n\n\t\tthis.aStartAngle = aStartAngle;\n\t\tthis.aEndAngle = aEndAngle;\n\n\t\tthis.aClockwise = aClockwise;\n\n\t\tthis.aRotation = aRotation || 0;\n\n\t}\n\n\tEllipseCurve.prototype = Object.create( Curve.prototype );\n\tEllipseCurve.prototype.constructor = EllipseCurve;\n\n\tEllipseCurve.prototype.isEllipseCurve = true;\n\n\tEllipseCurve.prototype.getPoint = function ( t ) {\n\n\t\tvar twoPi = Math.PI * 2;\n\t\tvar deltaAngle = this.aEndAngle - this.aStartAngle;\n\t\tvar samePoints = Math.abs( deltaAngle ) < Number.EPSILON;\n\n\t\t// ensures that deltaAngle is 0 .. 2 PI\n\t\twhile ( deltaAngle < 0 ) deltaAngle += twoPi;\n\t\twhile ( deltaAngle > twoPi ) deltaAngle -= twoPi;\n\n\t\tif ( deltaAngle < Number.EPSILON ) {\n\n\t\t\tif ( samePoints ) {\n\n\t\t\t\tdeltaAngle = 0;\n\n\t\t\t} else {\n\n\t\t\t\tdeltaAngle = twoPi;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( this.aClockwise === true && ! samePoints ) {\n\n\t\t\tif ( deltaAngle === twoPi ) {\n\n\t\t\t\tdeltaAngle = - twoPi;\n\n\t\t\t} else {\n\n\t\t\t\tdeltaAngle = deltaAngle - twoPi;\n\n\t\t\t}\n\n\t\t}\n\n\t\tvar angle = this.aStartAngle + t * deltaAngle;\n\t\tvar x = this.aX + this.xRadius * Math.cos( angle );\n\t\tvar y = this.aY + this.yRadius * Math.sin( angle );\n\n\t\tif ( this.aRotation !== 0 ) {\n\n\t\t\tvar cos = Math.cos( this.aRotation );\n\t\t\tvar sin = Math.sin( this.aRotation );\n\n\t\t\tvar tx = x - this.aX;\n\t\t\tvar ty = y - this.aY;\n\n\t\t\t// Rotate the point about the center of the ellipse.\n\t\t\tx = tx * cos - ty * sin + this.aX;\n\t\t\ty = tx * sin + ty * cos + this.aY;\n\n\t\t}\n\n\t\treturn new Vector2( x, y );\n\n\t};\n\n\tfunction SplineCurve( points /* array of Vector2 */ ) {\n\n\t\tCurve.call( this );\n\n\t\tthis.points = ( points === undefined ) ? [] : points;\n\n\t}\n\n\tSplineCurve.prototype = Object.create( Curve.prototype );\n\tSplineCurve.prototype.constructor = SplineCurve;\n\n\tSplineCurve.prototype.isSplineCurve = true;\n\n\tSplineCurve.prototype.getPoint = function ( t ) {\n\n\t\tvar points = this.points;\n\t\tvar point = ( points.length - 1 ) * t;\n\n\t\tvar intPoint = Math.floor( point );\n\t\tvar weight = point - intPoint;\n\n\t\tvar point0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ];\n\t\tvar point1 = points[ intPoint ];\n\t\tvar point2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];\n\t\tvar point3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];\n\n\t\treturn new Vector2(\n\t\t\tCatmullRom( weight, point0.x, point1.x, point2.x, point3.x ),\n\t\t\tCatmullRom( weight, point0.y, point1.y, point2.y, point3.y )\n\t\t);\n\n\t};\n\n\tfunction CubicBezierCurve( v0, v1, v2, v3 ) {\n\n\t\tCurve.call( this );\n\n\t\tthis.v0 = v0;\n\t\tthis.v1 = v1;\n\t\tthis.v2 = v2;\n\t\tthis.v3 = v3;\n\n\t}\n\n\tCubicBezierCurve.prototype = Object.create( Curve.prototype );\n\tCubicBezierCurve.prototype.constructor = CubicBezierCurve;\n\n\tCubicBezierCurve.prototype.getPoint = function ( t ) {\n\n\t\tvar v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;\n\n\t\treturn new Vector2(\n\t\t\tCubicBezier( t, v0.x, v1.x, v2.x, v3.x ),\n\t\t\tCubicBezier( t, v0.y, v1.y, v2.y, v3.y )\n\t\t);\n\n\t};\n\n\tfunction QuadraticBezierCurve( v0, v1, v2 ) {\n\n\t\tCurve.call( this );\n\n\t\tthis.v0 = v0;\n\t\tthis.v1 = v1;\n\t\tthis.v2 = v2;\n\n\t}\n\n\tQuadraticBezierCurve.prototype = Object.create( Curve.prototype );\n\tQuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve;\n\n\tQuadraticBezierCurve.prototype.getPoint = function ( t ) {\n\n\t\tvar v0 = this.v0, v1 = this.v1, v2 = this.v2;\n\n\t\treturn new Vector2(\n\t\t\tQuadraticBezier( t, v0.x, v1.x, v2.x ),\n\t\t\tQuadraticBezier( t, v0.y, v1.y, v2.y )\n\t\t);\n\n\t};\n\n\tvar PathPrototype = Object.assign( Object.create( CurvePath.prototype ), {\n\n\t\tfromPoints: function ( vectors ) {\n\n\t\t\tthis.moveTo( vectors[ 0 ].x, vectors[ 0 ].y );\n\n\t\t\tfor ( var i = 1, l = vectors.length; i < l; i ++ ) {\n\n\t\t\t\tthis.lineTo( vectors[ i ].x, vectors[ i ].y );\n\n\t\t\t}\n\n\t\t},\n\n\t\tmoveTo: function ( x, y ) {\n\n\t\t\tthis.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying?\n\n\t\t},\n\n\t\tlineTo: function ( x, y ) {\n\n\t\t\tvar curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) );\n\t\t\tthis.curves.push( curve );\n\n\t\t\tthis.currentPoint.set( x, y );\n\n\t\t},\n\n\t\tquadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {\n\n\t\t\tvar curve = new QuadraticBezierCurve(\n\t\t\t\tthis.currentPoint.clone(),\n\t\t\t\tnew Vector2( aCPx, aCPy ),\n\t\t\t\tnew Vector2( aX, aY )\n\t\t\t);\n\n\t\t\tthis.curves.push( curve );\n\n\t\t\tthis.currentPoint.set( aX, aY );\n\n\t\t},\n\n\t\tbezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {\n\n\t\t\tvar curve = new CubicBezierCurve(\n\t\t\t\tthis.currentPoint.clone(),\n\t\t\t\tnew Vector2( aCP1x, aCP1y ),\n\t\t\t\tnew Vector2( aCP2x, aCP2y ),\n\t\t\t\tnew Vector2( aX, aY )\n\t\t\t);\n\n\t\t\tthis.curves.push( curve );\n\n\t\t\tthis.currentPoint.set( aX, aY );\n\n\t\t},\n\n\t\tsplineThru: function ( pts /*Array of Vector*/ ) {\n\n\t\t\tvar npts = [ this.currentPoint.clone() ].concat( pts );\n\n\t\t\tvar curve = new SplineCurve( npts );\n\t\t\tthis.curves.push( curve );\n\n\t\t\tthis.currentPoint.copy( pts[ pts.length - 1 ] );\n\n\t\t},\n\n\t\tarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {\n\n\t\t\tvar x0 = this.currentPoint.x;\n\t\t\tvar y0 = this.currentPoint.y;\n\n\t\t\tthis.absarc( aX + x0, aY + y0, aRadius,\n\t\t\t\taStartAngle, aEndAngle, aClockwise );\n\n\t\t},\n\n\t\tabsarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {\n\n\t\t\tthis.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );\n\n\t\t},\n\n\t\tellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {\n\n\t\t\tvar x0 = this.currentPoint.x;\n\t\t\tvar y0 = this.currentPoint.y;\n\n\t\t\tthis.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );\n\n\t\t},\n\n\t\tabsellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {\n\n\t\t\tvar curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );\n\n\t\t\tif ( this.curves.length > 0 ) {\n\n\t\t\t\t// if a previous curve is present, attempt to join\n\t\t\t\tvar firstPoint = curve.getPoint( 0 );\n\n\t\t\t\tif ( ! firstPoint.equals( this.currentPoint ) ) {\n\n\t\t\t\t\tthis.lineTo( firstPoint.x, firstPoint.y );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.curves.push( curve );\n\n\t\t\tvar lastPoint = curve.getPoint( 1 );\n\t\t\tthis.currentPoint.copy( lastPoint );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author zz85 / http://www.lab4games.net/zz85/blog\n\t * Creates free form 2d path using series of points, lines or curves.\n\t **/\n\n\tfunction Path( points ) {\n\n\t\tCurvePath.call( this );\n\t\tthis.currentPoint = new Vector2();\n\n\t\tif ( points ) {\n\n\t\t\tthis.fromPoints( points );\n\n\t\t}\n\n\t}\n\n\tPath.prototype = PathPrototype;\n\tPathPrototype.constructor = Path;\n\n\t/**\n\t * @author zz85 / http://www.lab4games.net/zz85/blog\n\t * Defines a 2d shape plane using paths.\n\t **/\n\n\t// STEP 1 Create a path.\n\t// STEP 2 Turn path into shape.\n\t// STEP 3 ExtrudeGeometry takes in Shape/Shapes\n\t// STEP 3a - Extract points from each shape, turn to vertices\n\t// STEP 3b - Triangulate each shape, add faces.\n\n\tfunction Shape() {\n\n\t\tPath.apply( this, arguments );\n\n\t\tthis.holes = [];\n\n\t}\n\n\tShape.prototype = Object.assign( Object.create( PathPrototype ), {\n\n\t\tconstructor: Shape,\n\n\t\tgetPointsHoles: function ( divisions ) {\n\n\t\t\tvar holesPts = [];\n\n\t\t\tfor ( var i = 0, l = this.holes.length; i < l; i ++ ) {\n\n\t\t\t\tholesPts[ i ] = this.holes[ i ].getPoints( divisions );\n\n\t\t\t}\n\n\t\t\treturn holesPts;\n\n\t\t},\n\n\t\t// Get points of shape and holes (keypoints based on segments parameter)\n\n\t\textractAllPoints: function ( divisions ) {\n\n\t\t\treturn {\n\n\t\t\t\tshape: this.getPoints( divisions ),\n\t\t\t\tholes: this.getPointsHoles( divisions )\n\n\t\t\t};\n\n\t\t},\n\n\t\textractPoints: function ( divisions ) {\n\n\t\t\treturn this.extractAllPoints( divisions );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author zz85 / http://www.lab4games.net/zz85/blog\n\t * minimal class for proxing functions to Path. Replaces old \"extractSubpaths()\"\n\t **/\n\n\tfunction ShapePath() {\n\n\t\tthis.subPaths = [];\n\t\tthis.currentPath = null;\n\n\t}\n\n\tObject.assign( ShapePath.prototype, {\n\n\t\tmoveTo: function ( x, y ) {\n\n\t\t\tthis.currentPath = new Path();\n\t\t\tthis.subPaths.push( this.currentPath );\n\t\t\tthis.currentPath.moveTo( x, y );\n\n\t\t},\n\n\t\tlineTo: function ( x, y ) {\n\n\t\t\tthis.currentPath.lineTo( x, y );\n\n\t\t},\n\n\t\tquadraticCurveTo: function ( aCPx, aCPy, aX, aY ) {\n\n\t\t\tthis.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY );\n\n\t\t},\n\n\t\tbezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {\n\n\t\t\tthis.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY );\n\n\t\t},\n\n\t\tsplineThru: function ( pts ) {\n\n\t\t\tthis.currentPath.splineThru( pts );\n\n\t\t},\n\n\t\ttoShapes: function ( isCCW, noHoles ) {\n\n\t\t\tfunction toShapesNoHoles( inSubpaths ) {\n\n\t\t\t\tvar shapes = [];\n\n\t\t\t\tfor ( var i = 0, l = inSubpaths.length; i < l; i ++ ) {\n\n\t\t\t\t\tvar tmpPath = inSubpaths[ i ];\n\n\t\t\t\t\tvar tmpShape = new Shape();\n\t\t\t\t\ttmpShape.curves = tmpPath.curves;\n\n\t\t\t\t\tshapes.push( tmpShape );\n\n\t\t\t\t}\n\n\t\t\t\treturn shapes;\n\n\t\t\t}\n\n\t\t\tfunction isPointInsidePolygon( inPt, inPolygon ) {\n\n\t\t\t\tvar polyLen = inPolygon.length;\n\n\t\t\t\t// inPt on polygon contour => immediate success    or\n\t\t\t\t// toggling of inside/outside at every single! intersection point of an edge\n\t\t\t\t//  with the horizontal line through inPt, left of inPt\n\t\t\t\t//  not counting lowerY endpoints of edges and whole edges on that line\n\t\t\t\tvar inside = false;\n\t\t\t\tfor ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {\n\n\t\t\t\t\tvar edgeLowPt  = inPolygon[ p ];\n\t\t\t\t\tvar edgeHighPt = inPolygon[ q ];\n\n\t\t\t\t\tvar edgeDx = edgeHighPt.x - edgeLowPt.x;\n\t\t\t\t\tvar edgeDy = edgeHighPt.y - edgeLowPt.y;\n\n\t\t\t\t\tif ( Math.abs( edgeDy ) > Number.EPSILON ) {\n\n\t\t\t\t\t\t// not parallel\n\t\t\t\t\t\tif ( edgeDy < 0 ) {\n\n\t\t\t\t\t\t\tedgeLowPt  = inPolygon[ q ]; edgeDx = - edgeDx;\n\t\t\t\t\t\t\tedgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;\n\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) \t\tcontinue;\n\n\t\t\t\t\t\tif ( inPt.y === edgeLowPt.y ) {\n\n\t\t\t\t\t\t\tif ( inPt.x === edgeLowPt.x )\t\treturn\ttrue;\t\t// inPt is on contour ?\n\t\t\t\t\t\t\t// continue;\t\t\t\t// no intersection or edgeLowPt => doesn't count !!!\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tvar perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y );\n\t\t\t\t\t\t\tif ( perpEdge === 0 )\t\t\t\treturn\ttrue;\t\t// inPt is on contour ?\n\t\t\t\t\t\t\tif ( perpEdge < 0 ) \t\t\t\tcontinue;\n\t\t\t\t\t\t\tinside = ! inside;\t\t// true intersection left of inPt\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// parallel or collinear\n\t\t\t\t\t\tif ( inPt.y !== edgeLowPt.y ) \t\tcontinue;\t\t\t// parallel\n\t\t\t\t\t\t// edge lies on the same horizontal line as inPt\n\t\t\t\t\t\tif ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||\n\t\t\t\t\t\t\t ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) )\t\treturn\ttrue;\t// inPt: Point on contour !\n\t\t\t\t\t\t// continue;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\treturn\tinside;\n\n\t\t\t}\n\n\t\t\tvar isClockWise = ShapeUtils.isClockWise;\n\n\t\t\tvar subPaths = this.subPaths;\n\t\t\tif ( subPaths.length === 0 ) return [];\n\n\t\t\tif ( noHoles === true )\treturn\ttoShapesNoHoles( subPaths );\n\n\n\t\t\tvar solid, tmpPath, tmpShape, shapes = [];\n\n\t\t\tif ( subPaths.length === 1 ) {\n\n\t\t\t\ttmpPath = subPaths[ 0 ];\n\t\t\t\ttmpShape = new Shape();\n\t\t\t\ttmpShape.curves = tmpPath.curves;\n\t\t\t\tshapes.push( tmpShape );\n\t\t\t\treturn shapes;\n\n\t\t\t}\n\n\t\t\tvar holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() );\n\t\t\tholesFirst = isCCW ? ! holesFirst : holesFirst;\n\n\t\t\t// console.log(\"Holes first\", holesFirst);\n\n\t\t\tvar betterShapeHoles = [];\n\t\t\tvar newShapes = [];\n\t\t\tvar newShapeHoles = [];\n\t\t\tvar mainIdx = 0;\n\t\t\tvar tmpPoints;\n\n\t\t\tnewShapes[ mainIdx ] = undefined;\n\t\t\tnewShapeHoles[ mainIdx ] = [];\n\n\t\t\tfor ( var i = 0, l = subPaths.length; i < l; i ++ ) {\n\n\t\t\t\ttmpPath = subPaths[ i ];\n\t\t\t\ttmpPoints = tmpPath.getPoints();\n\t\t\t\tsolid = isClockWise( tmpPoints );\n\t\t\t\tsolid = isCCW ? ! solid : solid;\n\n\t\t\t\tif ( solid ) {\n\n\t\t\t\t\tif ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) )\tmainIdx ++;\n\n\t\t\t\t\tnewShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints };\n\t\t\t\t\tnewShapes[ mainIdx ].s.curves = tmpPath.curves;\n\n\t\t\t\t\tif ( holesFirst )\tmainIdx ++;\n\t\t\t\t\tnewShapeHoles[ mainIdx ] = [];\n\n\t\t\t\t\t//console.log('cw', i);\n\n\t\t\t\t} else {\n\n\t\t\t\t\tnewShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } );\n\n\t\t\t\t\t//console.log('ccw', i);\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// only Holes? -> probably all Shapes with wrong orientation\n\t\t\tif ( ! newShapes[ 0 ] )\treturn\ttoShapesNoHoles( subPaths );\n\n\n\t\t\tif ( newShapes.length > 1 ) {\n\n\t\t\t\tvar ambiguous = false;\n\t\t\t\tvar toChange = [];\n\n\t\t\t\tfor ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {\n\n\t\t\t\t\tbetterShapeHoles[ sIdx ] = [];\n\n\t\t\t\t}\n\n\t\t\t\tfor ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {\n\n\t\t\t\t\tvar sho = newShapeHoles[ sIdx ];\n\n\t\t\t\t\tfor ( var hIdx = 0; hIdx < sho.length; hIdx ++ ) {\n\n\t\t\t\t\t\tvar ho = sho[ hIdx ];\n\t\t\t\t\t\tvar hole_unassigned = true;\n\n\t\t\t\t\t\tfor ( var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {\n\n\t\t\t\t\t\t\tif ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) {\n\n\t\t\t\t\t\t\t\tif ( sIdx !== s2Idx )\ttoChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } );\n\t\t\t\t\t\t\t\tif ( hole_unassigned ) {\n\n\t\t\t\t\t\t\t\t\thole_unassigned = false;\n\t\t\t\t\t\t\t\t\tbetterShapeHoles[ s2Idx ].push( ho );\n\n\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\tambiguous = true;\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( hole_unassigned ) {\n\n\t\t\t\t\t\t\tbetterShapeHoles[ sIdx ].push( ho );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t\t// console.log(\"ambiguous: \", ambiguous);\n\t\t\t\tif ( toChange.length > 0 ) {\n\n\t\t\t\t\t// console.log(\"to change: \", toChange);\n\t\t\t\t\tif ( ! ambiguous )\tnewShapeHoles = betterShapeHoles;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tvar tmpHoles;\n\n\t\t\tfor ( var i = 0, il = newShapes.length; i < il; i ++ ) {\n\n\t\t\t\ttmpShape = newShapes[ i ].s;\n\t\t\t\tshapes.push( tmpShape );\n\t\t\t\ttmpHoles = newShapeHoles[ i ];\n\n\t\t\t\tfor ( var j = 0, jl = tmpHoles.length; j < jl; j ++ ) {\n\n\t\t\t\t\ttmpShape.holes.push( tmpHoles[ j ].h );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t//console.log(\"shape\", shapes);\n\n\t\t\treturn shapes;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author zz85 / http://www.lab4games.net/zz85/blog\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction Font( data ) {\n\n\t\tthis.data = data;\n\n\t}\n\n\tObject.assign( Font.prototype, {\n\n\t\tisFont: true,\n\n\t\tgenerateShapes: function ( text, size, divisions ) {\n\n\t\t\tfunction createPaths( text ) {\n\n\t\t\t\tvar chars = String( text ).split( '' );\n\t\t\t\tvar scale = size / data.resolution;\n\t\t\t\tvar line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale;\n\n\t\t\t\tvar offsetX = 0, offsetY = 0;\n\n\t\t\t\tvar paths = [];\n\n\t\t\t\tfor ( var i = 0; i < chars.length; i ++ ) {\n\n\t\t\t\t\tvar char = chars[ i ];\n\n\t\t\t\t\tif ( char === '\\n' ) {\n\n\t\t\t\t\t\toffsetX = 0;\n\t\t\t\t\t\toffsetY -= line_height;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tvar ret = createPath( char, scale, offsetX, offsetY );\n\t\t\t\t\t\toffsetX += ret.offsetX;\n\t\t\t\t\t\tpaths.push( ret.path );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\treturn paths;\n\n\t\t\t}\n\n\t\t\tfunction createPath( c, scale, offsetX, offsetY ) {\n\n\t\t\t\tvar glyph = data.glyphs[ c ] || data.glyphs[ '?' ];\n\n\t\t\t\tif ( ! glyph ) return;\n\n\t\t\t\tvar path = new ShapePath();\n\n\t\t\t\tvar pts = [];\n\t\t\t\tvar x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2, laste;\n\n\t\t\t\tif ( glyph.o ) {\n\n\t\t\t\t\tvar outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );\n\n\t\t\t\t\tfor ( var i = 0, l = outline.length; i < l; ) {\n\n\t\t\t\t\t\tvar action = outline[ i ++ ];\n\n\t\t\t\t\t\tswitch ( action ) {\n\n\t\t\t\t\t\t\tcase 'm': // moveTo\n\n\t\t\t\t\t\t\t\tx = outline[ i ++ ] * scale + offsetX;\n\t\t\t\t\t\t\t\ty = outline[ i ++ ] * scale + offsetY;\n\n\t\t\t\t\t\t\t\tpath.moveTo( x, y );\n\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase 'l': // lineTo\n\n\t\t\t\t\t\t\t\tx = outline[ i ++ ] * scale + offsetX;\n\t\t\t\t\t\t\t\ty = outline[ i ++ ] * scale + offsetY;\n\n\t\t\t\t\t\t\t\tpath.lineTo( x, y );\n\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase 'q': // quadraticCurveTo\n\n\t\t\t\t\t\t\t\tcpx  = outline[ i ++ ] * scale + offsetX;\n\t\t\t\t\t\t\t\tcpy  = outline[ i ++ ] * scale + offsetY;\n\t\t\t\t\t\t\t\tcpx1 = outline[ i ++ ] * scale + offsetX;\n\t\t\t\t\t\t\t\tcpy1 = outline[ i ++ ] * scale + offsetY;\n\n\t\t\t\t\t\t\t\tpath.quadraticCurveTo( cpx1, cpy1, cpx, cpy );\n\n\t\t\t\t\t\t\t\tlaste = pts[ pts.length - 1 ];\n\n\t\t\t\t\t\t\t\tif ( laste ) {\n\n\t\t\t\t\t\t\t\t\tcpx0 = laste.x;\n\t\t\t\t\t\t\t\t\tcpy0 = laste.y;\n\n\t\t\t\t\t\t\t\t\tfor ( var i2 = 1; i2 <= divisions; i2 ++ ) {\n\n\t\t\t\t\t\t\t\t\t\tvar t = i2 / divisions;\n\t\t\t\t\t\t\t\t\t\tQuadraticBezier( t, cpx0, cpx1, cpx );\n\t\t\t\t\t\t\t\t\t\tQuadraticBezier( t, cpy0, cpy1, cpy );\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase 'b': // bezierCurveTo\n\n\t\t\t\t\t\t\t\tcpx  = outline[ i ++ ] * scale + offsetX;\n\t\t\t\t\t\t\t\tcpy  = outline[ i ++ ] * scale + offsetY;\n\t\t\t\t\t\t\t\tcpx1 = outline[ i ++ ] * scale + offsetX;\n\t\t\t\t\t\t\t\tcpy1 = outline[ i ++ ] * scale + offsetY;\n\t\t\t\t\t\t\t\tcpx2 = outline[ i ++ ] * scale + offsetX;\n\t\t\t\t\t\t\t\tcpy2 = outline[ i ++ ] * scale + offsetY;\n\n\t\t\t\t\t\t\t\tpath.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy );\n\n\t\t\t\t\t\t\t\tlaste = pts[ pts.length - 1 ];\n\n\t\t\t\t\t\t\t\tif ( laste ) {\n\n\t\t\t\t\t\t\t\t\tcpx0 = laste.x;\n\t\t\t\t\t\t\t\t\tcpy0 = laste.y;\n\n\t\t\t\t\t\t\t\t\tfor ( var i2 = 1; i2 <= divisions; i2 ++ ) {\n\n\t\t\t\t\t\t\t\t\t\tvar t = i2 / divisions;\n\t\t\t\t\t\t\t\t\t\tCubicBezier( t, cpx0, cpx1, cpx2, cpx );\n\t\t\t\t\t\t\t\t\t\tCubicBezier( t, cpy0, cpy1, cpy2, cpy );\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\treturn { offsetX: glyph.ha * scale, path: path };\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tif ( size === undefined ) size = 100;\n\t\t\tif ( divisions === undefined ) divisions = 4;\n\n\t\t\tvar data = this.data;\n\n\t\t\tvar paths = createPaths( text );\n\t\t\tvar shapes = [];\n\n\t\t\tfor ( var p = 0, pl = paths.length; p < pl; p ++ ) {\n\n\t\t\t\tArray.prototype.push.apply( shapes, paths[ p ].toShapes() );\n\n\t\t\t}\n\n\t\t\treturn shapes;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction FontLoader( manager ) {\n\n\t\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n\t}\n\n\tObject.assign( FontLoader.prototype, {\n\n\t\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\t\tvar scope = this;\n\n\t\t\tvar loader = new FileLoader( this.manager );\n\t\t\tloader.load( url, function ( text ) {\n\n\t\t\t\tvar json;\n\n\t\t\t\ttry {\n\n\t\t\t\t\tjson = JSON.parse( text );\n\n\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.' );\n\t\t\t\t\tjson = JSON.parse( text.substring( 65, text.length - 2 ) );\n\n\t\t\t\t}\n\n\t\t\t\tvar font = scope.parse( json );\n\n\t\t\t\tif ( onLoad ) onLoad( font );\n\n\t\t\t}, onProgress, onError );\n\n\t\t},\n\n\t\tparse: function ( json ) {\n\n\t\t\treturn new Font( json );\n\n\t\t}\n\n\t} );\n\n\tvar context;\n\n\tvar AudioContext = {\n\n\t\tgetContext: function () {\n\n\t\t\tif ( context === undefined ) {\n\n\t\t\t\tcontext = new ( window.AudioContext || window.webkitAudioContext )();\n\n\t\t\t}\n\n\t\t\treturn context;\n\n\t\t},\n\n\t\tsetContext: function ( value ) {\n\n\t\t\tcontext = value;\n\n\t\t}\n\n\t};\n\n\t/**\n\t * @author Reece Aaron Lecrivain / http://reecenotes.com/\n\t */\n\n\tfunction AudioLoader( manager ) {\n\n\t\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n\t}\n\n\tObject.assign( AudioLoader.prototype, {\n\n\t\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\t\tvar loader = new FileLoader( this.manager );\n\t\t\tloader.setResponseType( 'arraybuffer' );\n\t\t\tloader.load( url, function ( buffer ) {\n\n\t\t\t\tvar context = AudioContext.getContext();\n\n\t\t\t\tcontext.decodeAudioData( buffer, function ( audioBuffer ) {\n\n\t\t\t\t\tonLoad( audioBuffer );\n\n\t\t\t\t} );\n\n\t\t\t}, onProgress, onError );\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction StereoCamera() {\n\n\t\tthis.type = 'StereoCamera';\n\n\t\tthis.aspect = 1;\n\n\t\tthis.eyeSep = 0.064;\n\n\t\tthis.cameraL = new PerspectiveCamera();\n\t\tthis.cameraL.layers.enable( 1 );\n\t\tthis.cameraL.matrixAutoUpdate = false;\n\n\t\tthis.cameraR = new PerspectiveCamera();\n\t\tthis.cameraR.layers.enable( 2 );\n\t\tthis.cameraR.matrixAutoUpdate = false;\n\n\t}\n\n\tObject.assign( StereoCamera.prototype, {\n\n\t\tupdate: ( function () {\n\n\t\t\tvar instance, focus, fov, aspect, near, far, zoom, eyeSep;\n\n\t\t\tvar eyeRight = new Matrix4();\n\t\t\tvar eyeLeft = new Matrix4();\n\n\t\t\treturn function update( camera ) {\n\n\t\t\t\tvar needsUpdate = instance !== this || focus !== camera.focus || fov !== camera.fov ||\n\t\t\t\t\t\t\t\t\t\t\t\t\taspect !== camera.aspect * this.aspect || near !== camera.near ||\n\t\t\t\t\t\t\t\t\t\t\t\t\tfar !== camera.far || zoom !== camera.zoom || eyeSep !== this.eyeSep;\n\n\t\t\t\tif ( needsUpdate ) {\n\n\t\t\t\t\tinstance = this;\n\t\t\t\t\tfocus = camera.focus;\n\t\t\t\t\tfov = camera.fov;\n\t\t\t\t\taspect = camera.aspect * this.aspect;\n\t\t\t\t\tnear = camera.near;\n\t\t\t\t\tfar = camera.far;\n\t\t\t\t\tzoom = camera.zoom;\n\n\t\t\t\t\t// Off-axis stereoscopic effect based on\n\t\t\t\t\t// http://paulbourke.net/stereographics/stereorender/\n\n\t\t\t\t\tvar projectionMatrix = camera.projectionMatrix.clone();\n\t\t\t\t\teyeSep = this.eyeSep / 2;\n\t\t\t\t\tvar eyeSepOnProjection = eyeSep * near / focus;\n\t\t\t\t\tvar ymax = ( near * Math.tan( _Math.DEG2RAD * fov * 0.5 ) ) / zoom;\n\t\t\t\t\tvar xmin, xmax;\n\n\t\t\t\t\t// translate xOffset\n\n\t\t\t\t\teyeLeft.elements[ 12 ] = - eyeSep;\n\t\t\t\t\teyeRight.elements[ 12 ] = eyeSep;\n\n\t\t\t\t\t// for left eye\n\n\t\t\t\t\txmin = - ymax * aspect + eyeSepOnProjection;\n\t\t\t\t\txmax = ymax * aspect + eyeSepOnProjection;\n\n\t\t\t\t\tprojectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin );\n\t\t\t\t\tprojectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );\n\n\t\t\t\t\tthis.cameraL.projectionMatrix.copy( projectionMatrix );\n\n\t\t\t\t\t// for right eye\n\n\t\t\t\t\txmin = - ymax * aspect - eyeSepOnProjection;\n\t\t\t\t\txmax = ymax * aspect - eyeSepOnProjection;\n\n\t\t\t\t\tprojectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin );\n\t\t\t\t\tprojectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );\n\n\t\t\t\t\tthis.cameraR.projectionMatrix.copy( projectionMatrix );\n\n\t\t\t\t}\n\n\t\t\t\tthis.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( eyeLeft );\n\t\t\t\tthis.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( eyeRight );\n\n\t\t\t};\n\n\t\t} )()\n\n\t} );\n\n\t/**\n\t * Camera for rendering cube maps\n\t *\t- renders scene into axis-aligned cube\n\t *\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tfunction CubeCamera( near, far, cubeResolution ) {\n\n\t\tObject3D.call( this );\n\n\t\tthis.type = 'CubeCamera';\n\n\t\tvar fov = 90, aspect = 1;\n\n\t\tvar cameraPX = new PerspectiveCamera( fov, aspect, near, far );\n\t\tcameraPX.up.set( 0, - 1, 0 );\n\t\tcameraPX.lookAt( new Vector3( 1, 0, 0 ) );\n\t\tthis.add( cameraPX );\n\n\t\tvar cameraNX = new PerspectiveCamera( fov, aspect, near, far );\n\t\tcameraNX.up.set( 0, - 1, 0 );\n\t\tcameraNX.lookAt( new Vector3( - 1, 0, 0 ) );\n\t\tthis.add( cameraNX );\n\n\t\tvar cameraPY = new PerspectiveCamera( fov, aspect, near, far );\n\t\tcameraPY.up.set( 0, 0, 1 );\n\t\tcameraPY.lookAt( new Vector3( 0, 1, 0 ) );\n\t\tthis.add( cameraPY );\n\n\t\tvar cameraNY = new PerspectiveCamera( fov, aspect, near, far );\n\t\tcameraNY.up.set( 0, 0, - 1 );\n\t\tcameraNY.lookAt( new Vector3( 0, - 1, 0 ) );\n\t\tthis.add( cameraNY );\n\n\t\tvar cameraPZ = new PerspectiveCamera( fov, aspect, near, far );\n\t\tcameraPZ.up.set( 0, - 1, 0 );\n\t\tcameraPZ.lookAt( new Vector3( 0, 0, 1 ) );\n\t\tthis.add( cameraPZ );\n\n\t\tvar cameraNZ = new PerspectiveCamera( fov, aspect, near, far );\n\t\tcameraNZ.up.set( 0, - 1, 0 );\n\t\tcameraNZ.lookAt( new Vector3( 0, 0, - 1 ) );\n\t\tthis.add( cameraNZ );\n\n\t\tvar options = { format: RGBFormat, magFilter: LinearFilter, minFilter: LinearFilter };\n\n\t\tthis.renderTarget = new WebGLRenderTargetCube( cubeResolution, cubeResolution, options );\n\t\tthis.renderTarget.texture.name = \"CubeCamera\";\n\n\t\tthis.update = function ( renderer, scene ) {\n\n\t\t\tif ( this.parent === null ) this.updateMatrixWorld();\n\n\t\t\tvar renderTarget = this.renderTarget;\n\t\t\tvar generateMipmaps = renderTarget.texture.generateMipmaps;\n\n\t\t\trenderTarget.texture.generateMipmaps = false;\n\n\t\t\trenderTarget.activeCubeFace = 0;\n\t\t\trenderer.render( scene, cameraPX, renderTarget );\n\n\t\t\trenderTarget.activeCubeFace = 1;\n\t\t\trenderer.render( scene, cameraNX, renderTarget );\n\n\t\t\trenderTarget.activeCubeFace = 2;\n\t\t\trenderer.render( scene, cameraPY, renderTarget );\n\n\t\t\trenderTarget.activeCubeFace = 3;\n\t\t\trenderer.render( scene, cameraNY, renderTarget );\n\n\t\t\trenderTarget.activeCubeFace = 4;\n\t\t\trenderer.render( scene, cameraPZ, renderTarget );\n\n\t\t\trenderTarget.texture.generateMipmaps = generateMipmaps;\n\n\t\t\trenderTarget.activeCubeFace = 5;\n\t\t\trenderer.render( scene, cameraNZ, renderTarget );\n\n\t\t\trenderer.setRenderTarget( null );\n\n\t\t};\n\n\t\tthis.clear = function ( renderer, color, depth, stencil ) {\n\n\t\t\tvar renderTarget = this.renderTarget;\n\n\t\t\tfor ( var i = 0; i < 6; i ++ ) {\n\n\t\t\t\trenderTarget.activeCubeFace = i;\n\t\t\t\trenderer.setRenderTarget( renderTarget );\n\n\t\t\t\trenderer.clear( color, depth, stencil );\n\n\t\t\t}\n\n\t\t\trenderer.setRenderTarget( null );\n\n\t\t};\n\n\t}\n\n\tCubeCamera.prototype = Object.create( Object3D.prototype );\n\tCubeCamera.prototype.constructor = CubeCamera;\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction AudioListener() {\n\n\t\tObject3D.call( this );\n\n\t\tthis.type = 'AudioListener';\n\n\t\tthis.context = AudioContext.getContext();\n\n\t\tthis.gain = this.context.createGain();\n\t\tthis.gain.connect( this.context.destination );\n\n\t\tthis.filter = null;\n\n\t}\n\n\tAudioListener.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\t\tconstructor: AudioListener,\n\n\t\tgetInput: function () {\n\n\t\t\treturn this.gain;\n\n\t\t},\n\n\t\tremoveFilter: function ( ) {\n\n\t\t\tif ( this.filter !== null ) {\n\n\t\t\t\tthis.gain.disconnect( this.filter );\n\t\t\t\tthis.filter.disconnect( this.context.destination );\n\t\t\t\tthis.gain.connect( this.context.destination );\n\t\t\t\tthis.filter = null;\n\n\t\t\t}\n\n\t\t},\n\n\t\tgetFilter: function () {\n\n\t\t\treturn this.filter;\n\n\t\t},\n\n\t\tsetFilter: function ( value ) {\n\n\t\t\tif ( this.filter !== null ) {\n\n\t\t\t\tthis.gain.disconnect( this.filter );\n\t\t\t\tthis.filter.disconnect( this.context.destination );\n\n\t\t\t} else {\n\n\t\t\t\tthis.gain.disconnect( this.context.destination );\n\n\t\t\t}\n\n\t\t\tthis.filter = value;\n\t\t\tthis.gain.connect( this.filter );\n\t\t\tthis.filter.connect( this.context.destination );\n\n\t\t},\n\n\t\tgetMasterVolume: function () {\n\n\t\t\treturn this.gain.gain.value;\n\n\t\t},\n\n\t\tsetMasterVolume: function ( value ) {\n\n\t\t\tthis.gain.gain.value = value;\n\n\t\t},\n\n\t\tupdateMatrixWorld: ( function () {\n\n\t\t\tvar position = new Vector3();\n\t\t\tvar quaternion = new Quaternion();\n\t\t\tvar scale = new Vector3();\n\n\t\t\tvar orientation = new Vector3();\n\n\t\t\treturn function updateMatrixWorld( force ) {\n\n\t\t\t\tObject3D.prototype.updateMatrixWorld.call( this, force );\n\n\t\t\t\tvar listener = this.context.listener;\n\t\t\t\tvar up = this.up;\n\n\t\t\t\tthis.matrixWorld.decompose( position, quaternion, scale );\n\n\t\t\t\torientation.set( 0, 0, - 1 ).applyQuaternion( quaternion );\n\n\t\t\t\tif ( listener.positionX ) {\n\n\t\t\t\t\tlistener.positionX.setValueAtTime( position.x, this.context.currentTime );\n\t\t\t\t\tlistener.positionY.setValueAtTime( position.y, this.context.currentTime );\n\t\t\t\t\tlistener.positionZ.setValueAtTime( position.z, this.context.currentTime );\n\t\t\t\t\tlistener.forwardX.setValueAtTime( orientation.x, this.context.currentTime );\n\t\t\t\t\tlistener.forwardY.setValueAtTime( orientation.y, this.context.currentTime );\n\t\t\t\t\tlistener.forwardZ.setValueAtTime( orientation.z, this.context.currentTime );\n\t\t\t\t\tlistener.upX.setValueAtTime( up.x, this.context.currentTime );\n\t\t\t\t\tlistener.upY.setValueAtTime( up.y, this.context.currentTime );\n\t\t\t\t\tlistener.upZ.setValueAtTime( up.z, this.context.currentTime );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tlistener.setPosition( position.x, position.y, position.z );\n\t\t\t\t\tlistener.setOrientation( orientation.x, orientation.y, orientation.z, up.x, up.y, up.z );\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t} )()\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author Reece Aaron Lecrivain / http://reecenotes.com/\n\t */\n\n\tfunction Audio( listener ) {\n\n\t\tObject3D.call( this );\n\n\t\tthis.type = 'Audio';\n\n\t\tthis.context = listener.context;\n\n\t\tthis.gain = this.context.createGain();\n\t\tthis.gain.connect( listener.getInput() );\n\n\t\tthis.autoplay = false;\n\n\t\tthis.buffer = null;\n\t\tthis.loop = false;\n\t\tthis.startTime = 0;\n\t\tthis.playbackRate = 1;\n\t\tthis.isPlaying = false;\n\t\tthis.hasPlaybackControl = true;\n\t\tthis.sourceType = 'empty';\n\n\t\tthis.filters = [];\n\n\t}\n\n\tAudio.prototype = Object.assign( Object.create( Object3D.prototype ), {\n\n\t\tconstructor: Audio,\n\n\t\tgetOutput: function () {\n\n\t\t\treturn this.gain;\n\n\t\t},\n\n\t\tsetNodeSource: function ( audioNode ) {\n\n\t\t\tthis.hasPlaybackControl = false;\n\t\t\tthis.sourceType = 'audioNode';\n\t\t\tthis.source = audioNode;\n\t\t\tthis.connect();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetBuffer: function ( audioBuffer ) {\n\n\t\t\tthis.buffer = audioBuffer;\n\t\t\tthis.sourceType = 'buffer';\n\n\t\t\tif ( this.autoplay ) this.play();\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tplay: function () {\n\n\t\t\tif ( this.isPlaying === true ) {\n\n\t\t\t\tconsole.warn( 'THREE.Audio: Audio is already playing.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tvar source = this.context.createBufferSource();\n\n\t\t\tsource.buffer = this.buffer;\n\t\t\tsource.loop = this.loop;\n\t\t\tsource.onended = this.onEnded.bind( this );\n\t\t\tsource.playbackRate.setValueAtTime( this.playbackRate, this.startTime );\n\t\t\tsource.start( 0, this.startTime );\n\n\t\t\tthis.isPlaying = true;\n\n\t\t\tthis.source = source;\n\n\t\t\treturn this.connect();\n\n\t\t},\n\n\t\tpause: function () {\n\n\t\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tthis.source.stop();\n\t\t\tthis.startTime = this.context.currentTime;\n\t\t\tthis.isPlaying = false;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tstop: function () {\n\n\t\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tthis.source.stop();\n\t\t\tthis.startTime = 0;\n\t\t\tthis.isPlaying = false;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tconnect: function () {\n\n\t\t\tif ( this.filters.length > 0 ) {\n\n\t\t\t\tthis.source.connect( this.filters[ 0 ] );\n\n\t\t\t\tfor ( var i = 1, l = this.filters.length; i < l; i ++ ) {\n\n\t\t\t\t\tthis.filters[ i - 1 ].connect( this.filters[ i ] );\n\n\t\t\t\t}\n\n\t\t\t\tthis.filters[ this.filters.length - 1 ].connect( this.getOutput() );\n\n\t\t\t} else {\n\n\t\t\t\tthis.source.connect( this.getOutput() );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tdisconnect: function () {\n\n\t\t\tif ( this.filters.length > 0 ) {\n\n\t\t\t\tthis.source.disconnect( this.filters[ 0 ] );\n\n\t\t\t\tfor ( var i = 1, l = this.filters.length; i < l; i ++ ) {\n\n\t\t\t\t\tthis.filters[ i - 1 ].disconnect( this.filters[ i ] );\n\n\t\t\t\t}\n\n\t\t\t\tthis.filters[ this.filters.length - 1 ].disconnect( this.getOutput() );\n\n\t\t\t} else {\n\n\t\t\t\tthis.source.disconnect( this.getOutput() );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetFilters: function () {\n\n\t\t\treturn this.filters;\n\n\t\t},\n\n\t\tsetFilters: function ( value ) {\n\n\t\t\tif ( ! value ) value = [];\n\n\t\t\tif ( this.isPlaying === true ) {\n\n\t\t\t\tthis.disconnect();\n\t\t\t\tthis.filters = value;\n\t\t\t\tthis.connect();\n\n\t\t\t} else {\n\n\t\t\t\tthis.filters = value;\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetFilter: function () {\n\n\t\t\treturn this.getFilters()[ 0 ];\n\n\t\t},\n\n\t\tsetFilter: function ( filter ) {\n\n\t\t\treturn this.setFilters( filter ? [ filter ] : [] );\n\n\t\t},\n\n\t\tsetPlaybackRate: function ( value ) {\n\n\t\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tthis.playbackRate = value;\n\n\t\t\tif ( this.isPlaying === true ) {\n\n\t\t\t\tthis.source.playbackRate.setValueAtTime( this.playbackRate, this.context.currentTime );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetPlaybackRate: function () {\n\n\t\t\treturn this.playbackRate;\n\n\t\t},\n\n\t\tonEnded: function () {\n\n\t\t\tthis.isPlaying = false;\n\n\t\t},\n\n\t\tgetLoop: function () {\n\n\t\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t\treturn this.loop;\n\n\t\t},\n\n\t\tsetLoop: function ( value ) {\n\n\t\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tthis.loop = value;\n\n\t\t\tif ( this.isPlaying === true ) {\n\n\t\t\t\tthis.source.loop = this.loop;\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetVolume: function () {\n\n\t\t\treturn this.gain.gain.value;\n\n\t\t},\n\n\t\tsetVolume: function ( value ) {\n\n\t\t\tthis.gain.gain.value = value;\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction PositionalAudio( listener ) {\n\n\t\tAudio.call( this, listener );\n\n\t\tthis.panner = this.context.createPanner();\n\t\tthis.panner.connect( this.gain );\n\n\t}\n\n\tPositionalAudio.prototype = Object.assign( Object.create( Audio.prototype ), {\n\n\t\tconstructor: PositionalAudio,\n\n\t\tgetOutput: function () {\n\n\t\t\treturn this.panner;\n\n\t\t},\n\n\t\tgetRefDistance: function () {\n\n\t\t\treturn this.panner.refDistance;\n\n\t\t},\n\n\t\tsetRefDistance: function ( value ) {\n\n\t\t\tthis.panner.refDistance = value;\n\n\t\t},\n\n\t\tgetRolloffFactor: function () {\n\n\t\t\treturn this.panner.rolloffFactor;\n\n\t\t},\n\n\t\tsetRolloffFactor: function ( value ) {\n\n\t\t\tthis.panner.rolloffFactor = value;\n\n\t\t},\n\n\t\tgetDistanceModel: function () {\n\n\t\t\treturn this.panner.distanceModel;\n\n\t\t},\n\n\t\tsetDistanceModel: function ( value ) {\n\n\t\t\tthis.panner.distanceModel = value;\n\n\t\t},\n\n\t\tgetMaxDistance: function () {\n\n\t\t\treturn this.panner.maxDistance;\n\n\t\t},\n\n\t\tsetMaxDistance: function ( value ) {\n\n\t\t\tthis.panner.maxDistance = value;\n\n\t\t},\n\n\t\tupdateMatrixWorld: ( function () {\n\n\t\t\tvar position = new Vector3();\n\n\t\t\treturn function updateMatrixWorld( force ) {\n\n\t\t\t\tObject3D.prototype.updateMatrixWorld.call( this, force );\n\n\t\t\t\tposition.setFromMatrixPosition( this.matrixWorld );\n\n\t\t\t\tthis.panner.setPosition( position.x, position.y, position.z );\n\n\t\t\t};\n\n\t\t} )()\n\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction AudioAnalyser( audio, fftSize ) {\n\n\t\tthis.analyser = audio.context.createAnalyser();\n\t\tthis.analyser.fftSize = fftSize !== undefined ? fftSize : 2048;\n\n\t\tthis.data = new Uint8Array( this.analyser.frequencyBinCount );\n\n\t\taudio.getOutput().connect( this.analyser );\n\n\t}\n\n\tObject.assign( AudioAnalyser.prototype, {\n\n\t\tgetFrequencyData: function () {\n\n\t\t\tthis.analyser.getByteFrequencyData( this.data );\n\n\t\t\treturn this.data;\n\n\t\t},\n\n\t\tgetAverageFrequency: function () {\n\n\t\t\tvar value = 0, data = this.getFrequencyData();\n\n\t\t\tfor ( var i = 0; i < data.length; i ++ ) {\n\n\t\t\t\tvalue += data[ i ];\n\n\t\t\t}\n\n\t\t\treturn value / data.length;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t *\n\t * Buffered scene graph property that allows weighted accumulation.\n\t *\n\t *\n\t * @author Ben Houston / http://clara.io/\n\t * @author David Sarno / http://lighthaus.us/\n\t * @author tschw\n\t */\n\n\tfunction PropertyMixer( binding, typeName, valueSize ) {\n\n\t\tthis.binding = binding;\n\t\tthis.valueSize = valueSize;\n\n\t\tvar bufferType = Float64Array,\n\t\t\tmixFunction;\n\n\t\tswitch ( typeName ) {\n\n\t\t\tcase 'quaternion':\n\t\t\t\tmixFunction = this._slerp;\n\t\t\t\tbreak;\n\n\t\t\tcase 'string':\n\t\t\tcase 'bool':\n\t\t\t\tbufferType = Array;\n\t\t\t\tmixFunction = this._select;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tmixFunction = this._lerp;\n\n\t\t}\n\n\t\tthis.buffer = new bufferType( valueSize * 4 );\n\t\t// layout: [ incoming | accu0 | accu1 | orig ]\n\t\t//\n\t\t// interpolators can use .buffer as their .result\n\t\t// the data then goes to 'incoming'\n\t\t//\n\t\t// 'accu0' and 'accu1' are used frame-interleaved for\n\t\t// the cumulative result and are compared to detect\n\t\t// changes\n\t\t//\n\t\t// 'orig' stores the original state of the property\n\n\t\tthis._mixBufferRegion = mixFunction;\n\n\t\tthis.cumulativeWeight = 0;\n\n\t\tthis.useCount = 0;\n\t\tthis.referenceCount = 0;\n\n\t}\n\n\tObject.assign( PropertyMixer.prototype, {\n\n\t\t// accumulate data in the 'incoming' region into 'accu<i>'\n\t\taccumulate: function ( accuIndex, weight ) {\n\n\t\t\t// note: happily accumulating nothing when weight = 0, the caller knows\n\t\t\t// the weight and shouldn't have made the call in the first place\n\n\t\t\tvar buffer = this.buffer,\n\t\t\t\tstride = this.valueSize,\n\t\t\t\toffset = accuIndex * stride + stride,\n\n\t\t\t\tcurrentWeight = this.cumulativeWeight;\n\n\t\t\tif ( currentWeight === 0 ) {\n\n\t\t\t\t// accuN := incoming * weight\n\n\t\t\t\tfor ( var i = 0; i !== stride; ++ i ) {\n\n\t\t\t\t\tbuffer[ offset + i ] = buffer[ i ];\n\n\t\t\t\t}\n\n\t\t\t\tcurrentWeight = weight;\n\n\t\t\t} else {\n\n\t\t\t\t// accuN := accuN + incoming * weight\n\n\t\t\t\tcurrentWeight += weight;\n\t\t\t\tvar mix = weight / currentWeight;\n\t\t\t\tthis._mixBufferRegion( buffer, offset, 0, mix, stride );\n\n\t\t\t}\n\n\t\t\tthis.cumulativeWeight = currentWeight;\n\n\t\t},\n\n\t\t// apply the state of 'accu<i>' to the binding when accus differ\n\t\tapply: function ( accuIndex ) {\n\n\t\t\tvar stride = this.valueSize,\n\t\t\t\tbuffer = this.buffer,\n\t\t\t\toffset = accuIndex * stride + stride,\n\n\t\t\t\tweight = this.cumulativeWeight,\n\n\t\t\t\tbinding = this.binding;\n\n\t\t\tthis.cumulativeWeight = 0;\n\n\t\t\tif ( weight < 1 ) {\n\n\t\t\t\t// accuN := accuN + original * ( 1 - cumulativeWeight )\n\n\t\t\t\tvar originalValueOffset = stride * 3;\n\n\t\t\t\tthis._mixBufferRegion(\n\t\t\t\t\tbuffer, offset, originalValueOffset, 1 - weight, stride );\n\n\t\t\t}\n\n\t\t\tfor ( var i = stride, e = stride + stride; i !== e; ++ i ) {\n\n\t\t\t\tif ( buffer[ i ] !== buffer[ i + stride ] ) {\n\n\t\t\t\t\t// value has changed -> update scene graph\n\n\t\t\t\t\tbinding.setValue( buffer, offset );\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t},\n\n\t\t// remember the state of the bound property and copy it to both accus\n\t\tsaveOriginalState: function () {\n\n\t\t\tvar binding = this.binding;\n\n\t\t\tvar buffer = this.buffer,\n\t\t\t\tstride = this.valueSize,\n\n\t\t\t\toriginalValueOffset = stride * 3;\n\n\t\t\tbinding.getValue( buffer, originalValueOffset );\n\n\t\t\t// accu[0..1] := orig -- initially detect changes against the original\n\t\t\tfor ( var i = stride, e = originalValueOffset; i !== e; ++ i ) {\n\n\t\t\t\tbuffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ];\n\n\t\t\t}\n\n\t\t\tthis.cumulativeWeight = 0;\n\n\t\t},\n\n\t\t// apply the state previously taken via 'saveOriginalState' to the binding\n\t\trestoreOriginalState: function () {\n\n\t\t\tvar originalValueOffset = this.valueSize * 3;\n\t\t\tthis.binding.setValue( this.buffer, originalValueOffset );\n\n\t\t},\n\n\n\t\t// mix functions\n\n\t\t_select: function ( buffer, dstOffset, srcOffset, t, stride ) {\n\n\t\t\tif ( t >= 0.5 ) {\n\n\t\t\t\tfor ( var i = 0; i !== stride; ++ i ) {\n\n\t\t\t\t\tbuffer[ dstOffset + i ] = buffer[ srcOffset + i ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t},\n\n\t\t_slerp: function ( buffer, dstOffset, srcOffset, t ) {\n\n\t\t\tQuaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t );\n\n\t\t},\n\n\t\t_lerp: function ( buffer, dstOffset, srcOffset, t, stride ) {\n\n\t\t\tvar s = 1 - t;\n\n\t\t\tfor ( var i = 0; i !== stride; ++ i ) {\n\n\t\t\t\tvar j = dstOffset + i;\n\n\t\t\t\tbuffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t;\n\n\t\t\t}\n\n\t\t}\n\n\t} );\n\n\t/**\n\t *\n\t * A reference to a real property in the scene graph.\n\t *\n\t *\n\t * @author Ben Houston / http://clara.io/\n\t * @author David Sarno / http://lighthaus.us/\n\t * @author tschw\n\t */\n\n\tfunction Composite( targetGroup, path, optionalParsedPath ) {\n\n\t\tvar parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path );\n\n\t\tthis._targetGroup = targetGroup;\n\t\tthis._bindings = targetGroup.subscribe_( path, parsedPath );\n\n\t}\n\n\tObject.assign( Composite.prototype, {\n\n\t\tgetValue: function ( array, offset ) {\n\n\t\t\tthis.bind(); // bind all binding\n\n\t\t\tvar firstValidIndex = this._targetGroup.nCachedObjects_,\n\t\t\t\tbinding = this._bindings[ firstValidIndex ];\n\n\t\t\t// and only call .getValue on the first\n\t\t\tif ( binding !== undefined ) binding.getValue( array, offset );\n\n\t\t},\n\n\t\tsetValue: function ( array, offset ) {\n\n\t\t\tvar bindings = this._bindings;\n\n\t\t\tfor ( var i = this._targetGroup.nCachedObjects_,\n\t\t\t\t\t  n = bindings.length; i !== n; ++ i ) {\n\n\t\t\t\tbindings[ i ].setValue( array, offset );\n\n\t\t\t}\n\n\t\t},\n\n\t\tbind: function () {\n\n\t\t\tvar bindings = this._bindings;\n\n\t\t\tfor ( var i = this._targetGroup.nCachedObjects_,\n\t\t\t\t\t  n = bindings.length; i !== n; ++ i ) {\n\n\t\t\t\tbindings[ i ].bind();\n\n\t\t\t}\n\n\t\t},\n\n\t\tunbind: function () {\n\n\t\t\tvar bindings = this._bindings;\n\n\t\t\tfor ( var i = this._targetGroup.nCachedObjects_,\n\t\t\t\t\t  n = bindings.length; i !== n; ++ i ) {\n\n\t\t\t\tbindings[ i ].unbind();\n\n\t\t\t}\n\n\t\t}\n\n\t} );\n\n\n\tfunction PropertyBinding( rootNode, path, parsedPath ) {\n\n\t\tthis.path = path;\n\t\tthis.parsedPath = parsedPath || PropertyBinding.parseTrackName( path );\n\n\t\tthis.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode;\n\n\t\tthis.rootNode = rootNode;\n\n\t}\n\n\tObject.assign( PropertyBinding, {\n\n\t\tComposite: Composite,\n\n\t\tcreate: function ( root, path, parsedPath ) {\n\n\t\t\tif ( ! ( root && root.isAnimationObjectGroup ) ) {\n\n\t\t\t\treturn new PropertyBinding( root, path, parsedPath );\n\n\t\t\t} else {\n\n\t\t\t\treturn new PropertyBinding.Composite( root, path, parsedPath );\n\n\t\t\t}\n\n\t\t},\n\n\t\t/**\n\t\t * Replaces spaces with underscores and removes unsupported characters from\n\t\t * node names, to ensure compatibility with parseTrackName().\n\t\t *\n\t\t * @param  {string} name Node name to be sanitized.\n\t\t * @return {string}\n\t\t */\n\t\tsanitizeNodeName: function ( name ) {\n\n\t\t\treturn name.replace( /\\s/g, '_' ).replace( /[^\\w-]/g, '' );\n\n\t\t},\n\n\t\tparseTrackName: function () {\n\n\t\t\t// Parent directories, delimited by '/' or ':'. Currently unused, but must\n\t\t\t// be matched to parse the rest of the track name.\n\t\t\tvar directoryRe = /((?:[\\w-]+[\\/:])*)/;\n\n\t\t\t// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.\n\t\t\tvar nodeRe = /([\\w-\\.]+)?/;\n\n\t\t\t// Object on target node, and accessor. Name may contain only word\n\t\t\t// characters. Accessor may contain any character except closing bracket.\n\t\t\tvar objectRe = /(?:\\.([\\w-]+)(?:\\[(.+)\\])?)?/;\n\n\t\t\t// Property and accessor. May contain only word characters. Accessor may\n\t\t\t// contain any non-bracket characters.\n\t\t\tvar propertyRe = /\\.([\\w-]+)(?:\\[(.+)\\])?/;\n\n\t\t\tvar trackRe = new RegExp(''\n\t\t\t\t+ '^'\n\t\t\t\t+ directoryRe.source\n\t\t\t\t+ nodeRe.source\n\t\t\t\t+ objectRe.source\n\t\t\t\t+ propertyRe.source\n\t\t\t\t+ '$'\n\t\t\t);\n\n\t\t\tvar supportedObjectNames = [ 'material', 'materials', 'bones' ];\n\n\t\t\treturn function ( trackName ) {\n\n\t\t\t\t\tvar matches = trackRe.exec( trackName );\n\n\t\t\t\t\tif ( ! matches ) {\n\n\t\t\t\t\t\tthrow new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tvar results = {\n\t\t\t\t\t\t// directoryName: matches[ 1 ], // (tschw) currently unused\n\t\t\t\t\t\tnodeName: matches[ 2 ],\n\t\t\t\t\t\tobjectName: matches[ 3 ],\n\t\t\t\t\t\tobjectIndex: matches[ 4 ],\n\t\t\t\t\t\tpropertyName: matches[ 5 ],     // required\n\t\t\t\t\t\tpropertyIndex: matches[ 6 ]\n\t\t\t\t\t};\n\n\t\t\t\t\tvar lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );\n\n\t\t\t\t\tif ( lastDot !== undefined && lastDot !== -1 ) {\n\n\t\t\t\t\t\tvar objectName = results.nodeName.substring( lastDot + 1 );\n\n\t\t\t\t\t\t// Object names must be checked against a whitelist. Otherwise, there\n\t\t\t\t\t\t// is no way to parse 'foo.bar.baz': 'baz' must be a property, but\n\t\t\t\t\t\t// 'bar' could be the objectName, or part of a nodeName (which can\n\t\t\t\t\t\t// include '.' characters).\n\t\t\t\t\t\tif ( supportedObjectNames.indexOf( objectName ) !== -1 ) {\n\n\t\t\t\t\t\t\tresults.nodeName = results.nodeName.substring( 0, lastDot );\n\t\t\t\t\t\t\tresults.objectName = objectName;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( results.propertyName === null || results.propertyName.length === 0 ) {\n\n\t\t\t\t\t\tthrow new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );\n\n\t\t\t\t\t}\n\n\t\t\t\t\treturn results;\n\n\t\t\t\t};\n\n\t\t}(),\n\n\t\tfindNode: function ( root, nodeName ) {\n\n\t\t\tif ( ! nodeName || nodeName === \"\" || nodeName === \"root\" || nodeName === \".\" || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) {\n\n\t\t\t\treturn root;\n\n\t\t\t}\n\n\t\t\t// search into skeleton bones.\n\t\t\tif ( root.skeleton ) {\n\n\t\t\t\tvar searchSkeleton = function ( skeleton ) {\n\n\t\t\t\t\tfor ( var i = 0; i < skeleton.bones.length; i ++ ) {\n\n\t\t\t\t\t\tvar bone = skeleton.bones[ i ];\n\n\t\t\t\t\t\tif ( bone.name === nodeName ) {\n\n\t\t\t\t\t\t\treturn bone;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\treturn null;\n\n\t\t\t\t};\n\n\t\t\t\tvar bone = searchSkeleton( root.skeleton );\n\n\t\t\t\tif ( bone ) {\n\n\t\t\t\t\treturn bone;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// search into node subtree.\n\t\t\tif ( root.children ) {\n\n\t\t\t\tvar searchNodeSubtree = function ( children ) {\n\n\t\t\t\t\tfor ( var i = 0; i < children.length; i ++ ) {\n\n\t\t\t\t\t\tvar childNode = children[ i ];\n\n\t\t\t\t\t\tif ( childNode.name === nodeName || childNode.uuid === nodeName ) {\n\n\t\t\t\t\t\t\treturn childNode;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar result = searchNodeSubtree( childNode.children );\n\n\t\t\t\t\t\tif ( result ) return result;\n\n\t\t\t\t\t}\n\n\t\t\t\t\treturn null;\n\n\t\t\t\t};\n\n\t\t\t\tvar subTreeNode = searchNodeSubtree( root.children );\n\n\t\t\t\tif ( subTreeNode ) {\n\n\t\t\t\t\treturn subTreeNode;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn null;\n\n\t\t}\n\n\t} );\n\n\tObject.assign( PropertyBinding.prototype, { // prototype, continued\n\n\t\t// these are used to \"bind\" a nonexistent property\n\t\t_getValue_unavailable: function () {},\n\t\t_setValue_unavailable: function () {},\n\n\t\tBindingType: {\n\t\t\tDirect: 0,\n\t\t\tEntireArray: 1,\n\t\t\tArrayElement: 2,\n\t\t\tHasFromToArray: 3\n\t\t},\n\n\t\tVersioning: {\n\t\t\tNone: 0,\n\t\t\tNeedsUpdate: 1,\n\t\t\tMatrixWorldNeedsUpdate: 2\n\t\t},\n\n\t\tGetterByBindingType: [\n\n\t\t\tfunction getValue_direct( buffer, offset ) {\n\n\t\t\t\tbuffer[ offset ] = this.node[ this.propertyName ];\n\n\t\t\t},\n\n\t\t\tfunction getValue_array( buffer, offset ) {\n\n\t\t\t\tvar source = this.resolvedProperty;\n\n\t\t\t\tfor ( var i = 0, n = source.length; i !== n; ++ i ) {\n\n\t\t\t\t\tbuffer[ offset ++ ] = source[ i ];\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tfunction getValue_arrayElement( buffer, offset ) {\n\n\t\t\t\tbuffer[ offset ] = this.resolvedProperty[ this.propertyIndex ];\n\n\t\t\t},\n\n\t\t\tfunction getValue_toArray( buffer, offset ) {\n\n\t\t\t\tthis.resolvedProperty.toArray( buffer, offset );\n\n\t\t\t}\n\n\t\t],\n\n\t\tSetterByBindingTypeAndVersioning: [\n\n\t\t\t[\n\t\t\t\t// Direct\n\n\t\t\t\tfunction setValue_direct( buffer, offset ) {\n\n\t\t\t\t\tthis.node[ this.propertyName ] = buffer[ offset ];\n\n\t\t\t\t},\n\n\t\t\t\tfunction setValue_direct_setNeedsUpdate( buffer, offset ) {\n\n\t\t\t\t\tthis.node[ this.propertyName ] = buffer[ offset ];\n\t\t\t\t\tthis.targetObject.needsUpdate = true;\n\n\t\t\t\t},\n\n\t\t\t\tfunction setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) {\n\n\t\t\t\t\tthis.node[ this.propertyName ] = buffer[ offset ];\n\t\t\t\t\tthis.targetObject.matrixWorldNeedsUpdate = true;\n\n\t\t\t\t}\n\n\t\t\t], [\n\n\t\t\t\t// EntireArray\n\n\t\t\t\tfunction setValue_array( buffer, offset ) {\n\n\t\t\t\t\tvar dest = this.resolvedProperty;\n\n\t\t\t\t\tfor ( var i = 0, n = dest.length; i !== n; ++ i ) {\n\n\t\t\t\t\t\tdest[ i ] = buffer[ offset ++ ];\n\n\t\t\t\t\t}\n\n\t\t\t\t},\n\n\t\t\t\tfunction setValue_array_setNeedsUpdate( buffer, offset ) {\n\n\t\t\t\t\tvar dest = this.resolvedProperty;\n\n\t\t\t\t\tfor ( var i = 0, n = dest.length; i !== n; ++ i ) {\n\n\t\t\t\t\t\tdest[ i ] = buffer[ offset ++ ];\n\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.targetObject.needsUpdate = true;\n\n\t\t\t\t},\n\n\t\t\t\tfunction setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) {\n\n\t\t\t\t\tvar dest = this.resolvedProperty;\n\n\t\t\t\t\tfor ( var i = 0, n = dest.length; i !== n; ++ i ) {\n\n\t\t\t\t\t\tdest[ i ] = buffer[ offset ++ ];\n\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.targetObject.matrixWorldNeedsUpdate = true;\n\n\t\t\t\t}\n\n\t\t\t], [\n\n\t\t\t\t// ArrayElement\n\n\t\t\t\tfunction setValue_arrayElement( buffer, offset ) {\n\n\t\t\t\t\tthis.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];\n\n\t\t\t\t},\n\n\t\t\t\tfunction setValue_arrayElement_setNeedsUpdate( buffer, offset ) {\n\n\t\t\t\t\tthis.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];\n\t\t\t\t\tthis.targetObject.needsUpdate = true;\n\n\t\t\t\t},\n\n\t\t\t\tfunction setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) {\n\n\t\t\t\t\tthis.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];\n\t\t\t\t\tthis.targetObject.matrixWorldNeedsUpdate = true;\n\n\t\t\t\t}\n\n\t\t\t], [\n\n\t\t\t\t// HasToFromArray\n\n\t\t\t\tfunction setValue_fromArray( buffer, offset ) {\n\n\t\t\t\t\tthis.resolvedProperty.fromArray( buffer, offset );\n\n\t\t\t\t},\n\n\t\t\t\tfunction setValue_fromArray_setNeedsUpdate( buffer, offset ) {\n\n\t\t\t\t\tthis.resolvedProperty.fromArray( buffer, offset );\n\t\t\t\t\tthis.targetObject.needsUpdate = true;\n\n\t\t\t\t},\n\n\t\t\t\tfunction setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) {\n\n\t\t\t\t\tthis.resolvedProperty.fromArray( buffer, offset );\n\t\t\t\t\tthis.targetObject.matrixWorldNeedsUpdate = true;\n\n\t\t\t\t}\n\n\t\t\t]\n\n\t\t],\n\n\t\tgetValue: function getValue_unbound( targetArray, offset ) {\n\n\t\t\tthis.bind();\n\t\t\tthis.getValue( targetArray, offset );\n\n\t\t\t// Note: This class uses a State pattern on a per-method basis:\n\t\t\t// 'bind' sets 'this.getValue' / 'setValue' and shadows the\n\t\t\t// prototype version of these methods with one that represents\n\t\t\t// the bound state. When the property is not found, the methods\n\t\t\t// become no-ops.\n\n\t\t},\n\n\t\tsetValue: function getValue_unbound( sourceArray, offset ) {\n\n\t\t\tthis.bind();\n\t\t\tthis.setValue( sourceArray, offset );\n\n\t\t},\n\n\t\t// create getter / setter pair for a property in the scene graph\n\t\tbind: function () {\n\n\t\t\tvar targetObject = this.node,\n\t\t\t\tparsedPath = this.parsedPath,\n\n\t\t\t\tobjectName = parsedPath.objectName,\n\t\t\t\tpropertyName = parsedPath.propertyName,\n\t\t\t\tpropertyIndex = parsedPath.propertyIndex;\n\n\t\t\tif ( ! targetObject ) {\n\n\t\t\t\ttargetObject = PropertyBinding.findNode(\n\t\t\t\t\t\tthis.rootNode, parsedPath.nodeName ) || this.rootNode;\n\n\t\t\t\tthis.node = targetObject;\n\n\t\t\t}\n\n\t\t\t// set fail state so we can just 'return' on error\n\t\t\tthis.getValue = this._getValue_unavailable;\n\t\t\tthis.setValue = this._setValue_unavailable;\n\n\t\t\t// ensure there is a value node\n\t\t\tif ( ! targetObject ) {\n\n\t\t\t\tconsole.error( 'THREE.PropertyBinding: Trying to update node for track: ' + this.path + ' but it wasn\\'t found.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tif ( objectName ) {\n\n\t\t\t\tvar objectIndex = parsedPath.objectIndex;\n\n\t\t\t\t// special cases were we need to reach deeper into the hierarchy to get the face materials....\n\t\t\t\tswitch ( objectName ) {\n\n\t\t\t\t\tcase 'materials':\n\n\t\t\t\t\t\tif ( ! targetObject.material ) {\n\n\t\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );\n\t\t\t\t\t\t\treturn;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( ! targetObject.material.materials ) {\n\n\t\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this );\n\t\t\t\t\t\t\treturn;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ttargetObject = targetObject.material.materials;\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'bones':\n\n\t\t\t\t\t\tif ( ! targetObject.skeleton ) {\n\n\t\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this );\n\t\t\t\t\t\t\treturn;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// potential future optimization: skip this if propertyIndex is already an integer\n\t\t\t\t\t\t// and convert the integer string to a true integer.\n\n\t\t\t\t\t\ttargetObject = targetObject.skeleton.bones;\n\n\t\t\t\t\t\t// support resolving morphTarget names into indices.\n\t\t\t\t\t\tfor ( var i = 0; i < targetObject.length; i ++ ) {\n\n\t\t\t\t\t\t\tif ( targetObject[ i ].name === objectIndex ) {\n\n\t\t\t\t\t\t\t\tobjectIndex = i;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\n\t\t\t\t\t\tif ( targetObject[ objectName ] === undefined ) {\n\n\t\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this );\n\t\t\t\t\t\t\treturn;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ttargetObject = targetObject[ objectName ];\n\n\t\t\t\t}\n\n\n\t\t\t\tif ( objectIndex !== undefined ) {\n\n\t\t\t\t\tif ( targetObject[ objectIndex ] === undefined ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttargetObject = targetObject[ objectIndex ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// resolve property\n\t\t\tvar nodeProperty = targetObject[ propertyName ];\n\n\t\t\tif ( nodeProperty === undefined ) {\n\n\t\t\t\tvar nodeName = parsedPath.nodeName;\n\n\t\t\t\tconsole.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName +\n\t\t\t\t\t'.' + propertyName + ' but it wasn\\'t found.', targetObject );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\t// determine versioning scheme\n\t\t\tvar versioning = this.Versioning.None;\n\n\t\t\tif ( targetObject.needsUpdate !== undefined ) { // material\n\n\t\t\t\tversioning = this.Versioning.NeedsUpdate;\n\t\t\t\tthis.targetObject = targetObject;\n\n\t\t\t} else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform\n\n\t\t\t\tversioning = this.Versioning.MatrixWorldNeedsUpdate;\n\t\t\t\tthis.targetObject = targetObject;\n\n\t\t\t}\n\n\t\t\t// determine how the property gets bound\n\t\t\tvar bindingType = this.BindingType.Direct;\n\n\t\t\tif ( propertyIndex !== undefined ) {\n\n\t\t\t\t// access a sub element of the property array (only primitives are supported right now)\n\n\t\t\t\tif ( propertyName === \"morphTargetInfluences\" ) {\n\n\t\t\t\t\t// potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.\n\n\t\t\t\t\t// support resolving morphTarget names into indices.\n\t\t\t\t\tif ( ! targetObject.geometry ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( targetObject.geometry.isBufferGeometry ) {\n\n\t\t\t\t\t\tif ( ! targetObject.geometry.morphAttributes ) {\n\n\t\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this );\n\t\t\t\t\t\t\treturn;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor ( var i = 0; i < this.node.geometry.morphAttributes.position.length; i ++ ) {\n\n\t\t\t\t\t\t\tif ( targetObject.geometry.morphAttributes.position[ i ].name === propertyIndex ) {\n\n\t\t\t\t\t\t\t\tpropertyIndex = i;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( ! targetObject.geometry.morphTargets ) {\n\n\t\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphTargets.', this );\n\t\t\t\t\t\t\treturn;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) {\n\n\t\t\t\t\t\t\tif ( targetObject.geometry.morphTargets[ i ].name === propertyIndex ) {\n\n\t\t\t\t\t\t\t\tpropertyIndex = i;\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tbindingType = this.BindingType.ArrayElement;\n\n\t\t\t\tthis.resolvedProperty = nodeProperty;\n\t\t\t\tthis.propertyIndex = propertyIndex;\n\n\t\t\t} else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {\n\n\t\t\t\t// must use copy for Object3D.Euler/Quaternion\n\n\t\t\t\tbindingType = this.BindingType.HasFromToArray;\n\n\t\t\t\tthis.resolvedProperty = nodeProperty;\n\n\t\t\t} else if ( Array.isArray( nodeProperty ) ) {\n\n\t\t\t\tbindingType = this.BindingType.EntireArray;\n\n\t\t\t\tthis.resolvedProperty = nodeProperty;\n\n\t\t\t} else {\n\n\t\t\t\tthis.propertyName = propertyName;\n\n\t\t\t}\n\n\t\t\t// select getter / setter\n\t\t\tthis.getValue = this.GetterByBindingType[ bindingType ];\n\t\t\tthis.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];\n\n\t\t},\n\n\t\tunbind: function () {\n\n\t\t\tthis.node = null;\n\n\t\t\t// back to the prototype version of getValue / setValue\n\t\t\t// note: avoiding to mutate the shape of 'this' via 'delete'\n\t\t\tthis.getValue = this._getValue_unbound;\n\t\t\tthis.setValue = this._setValue_unbound;\n\n\t\t}\n\n\t} );\n\n\t//!\\ DECLARE ALIAS AFTER assign prototype !\n\tObject.assign( PropertyBinding.prototype, {\n\n\t\t// initial state of these methods that calls 'bind'\n\t\t_getValue_unbound: PropertyBinding.prototype.getValue,\n\t\t_setValue_unbound: PropertyBinding.prototype.setValue,\n\n\t} );\n\n\t/**\n\t *\n\t * A group of objects that receives a shared animation state.\n\t *\n\t * Usage:\n\t *\n\t * \t-\tAdd objects you would otherwise pass as 'root' to the\n\t * \t\tconstructor or the .clipAction method of AnimationMixer.\n\t *\n\t * \t-\tInstead pass this object as 'root'.\n\t *\n\t * \t-\tYou can also add and remove objects later when the mixer\n\t * \t\tis running.\n\t *\n\t * Note:\n\t *\n\t *  \tObjects of this class appear as one object to the mixer,\n\t *  \tso cache control of the individual objects must be done\n\t *  \ton the group.\n\t *\n\t * Limitation:\n\t *\n\t * \t- \tThe animated properties must be compatible among the\n\t * \t\tall objects in the group.\n\t *\n\t *  -\tA single property can either be controlled through a\n\t *  \ttarget group or directly, but not both.\n\t *\n\t * @author tschw\n\t */\n\n\tfunction AnimationObjectGroup( var_args ) {\n\n\t\tthis.uuid = _Math.generateUUID();\n\n\t\t// cached objects followed by the active ones\n\t\tthis._objects = Array.prototype.slice.call( arguments );\n\n\t\tthis.nCachedObjects_ = 0;\t\t\t// threshold\n\t\t// note: read by PropertyBinding.Composite\n\n\t\tvar indices = {};\n\t\tthis._indicesByUUID = indices;\t\t// for bookkeeping\n\n\t\tfor ( var i = 0, n = arguments.length; i !== n; ++ i ) {\n\n\t\t\tindices[ arguments[ i ].uuid ] = i;\n\n\t\t}\n\n\t\tthis._paths = [];\t\t\t\t\t// inside: string\n\t\tthis._parsedPaths = [];\t\t\t\t// inside: { we don't care, here }\n\t\tthis._bindings = []; \t\t\t\t// inside: Array< PropertyBinding >\n\t\tthis._bindingsIndicesByPath = {}; \t// inside: indices in these arrays\n\n\t\tvar scope = this;\n\n\t\tthis.stats = {\n\n\t\t\tobjects: {\n\t\t\t\tget total() { return scope._objects.length; },\n\t\t\t\tget inUse() { return this.total - scope.nCachedObjects_; }\n\t\t\t},\n\n\t\t\tget bindingsPerObject() { return scope._bindings.length; }\n\n\t\t};\n\n\t}\n\n\tObject.assign( AnimationObjectGroup.prototype, {\n\n\t\tisAnimationObjectGroup: true,\n\n\t\tadd: function( var_args ) {\n\n\t\t\tvar objects = this._objects,\n\t\t\t\tnObjects = objects.length,\n\t\t\t\tnCachedObjects = this.nCachedObjects_,\n\t\t\t\tindicesByUUID = this._indicesByUUID,\n\t\t\t\tpaths = this._paths,\n\t\t\t\tparsedPaths = this._parsedPaths,\n\t\t\t\tbindings = this._bindings,\n\t\t\t\tnBindings = bindings.length;\n\n\t\t\tfor ( var i = 0, n = arguments.length; i !== n; ++ i ) {\n\n\t\t\t\tvar object = arguments[ i ],\n\t\t\t\t\tuuid = object.uuid,\n\t\t\t\t\tindex = indicesByUUID[ uuid ],\n\t\t\t\t\tknownObject = undefined;\n\n\t\t\t\tif ( index === undefined ) {\n\n\t\t\t\t\t// unknown object -> add it to the ACTIVE region\n\n\t\t\t\t\tindex = nObjects ++;\n\t\t\t\t\tindicesByUUID[ uuid ] = index;\n\t\t\t\t\tobjects.push( object );\n\n\t\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\t\tfor ( var j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\t\tbindings[ j ].push(\n\t\t\t\t\t\t\t\tnew PropertyBinding(\n\t\t\t\t\t\t\t\t\tobject, paths[ j ], parsedPaths[ j ] ) );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( index < nCachedObjects ) {\n\n\t\t\t\t\tknownObject = objects[ index ];\n\n\t\t\t\t\t// move existing object to the ACTIVE region\n\n\t\t\t\t\tvar firstActiveIndex = -- nCachedObjects,\n\t\t\t\t\t\tlastCachedObject = objects[ firstActiveIndex ];\n\n\t\t\t\t\tindicesByUUID[ lastCachedObject.uuid ] = index;\n\t\t\t\t\tobjects[ index ] = lastCachedObject;\n\n\t\t\t\t\tindicesByUUID[ uuid ] = firstActiveIndex;\n\t\t\t\t\tobjects[ firstActiveIndex ] = object;\n\n\t\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\t\tfor ( var j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\t\tvar bindingsForPath = bindings[ j ],\n\t\t\t\t\t\t\tlastCached = bindingsForPath[ firstActiveIndex ],\n\t\t\t\t\t\t\tbinding = bindingsForPath[ index ];\n\n\t\t\t\t\t\tbindingsForPath[ index ] = lastCached;\n\n\t\t\t\t\t\tif ( binding === undefined ) {\n\n\t\t\t\t\t\t\t// since we do not bother to create new bindings\n\t\t\t\t\t\t\t// for objects that are cached, the binding may\n\t\t\t\t\t\t\t// or may not exist\n\n\t\t\t\t\t\t\tbinding = new PropertyBinding(\n\t\t\t\t\t\t\t\t\tobject, paths[ j ], parsedPaths[ j ] );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbindingsForPath[ firstActiveIndex ] = binding;\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( objects[ index ] !== knownObject ) {\n\n\t\t\t\t\tconsole.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' +\n\t\t\t\t\t\t\t'detected. Clean the caches or recreate your infrastructure when reloading scenes.' );\n\n\t\t\t\t} // else the object is already where we want it to be\n\n\t\t\t} // for arguments\n\n\t\t\tthis.nCachedObjects_ = nCachedObjects;\n\n\t\t},\n\n\t\tremove: function( var_args ) {\n\n\t\t\tvar objects = this._objects,\n\t\t\t\tnCachedObjects = this.nCachedObjects_,\n\t\t\t\tindicesByUUID = this._indicesByUUID,\n\t\t\t\tbindings = this._bindings,\n\t\t\t\tnBindings = bindings.length;\n\n\t\t\tfor ( var i = 0, n = arguments.length; i !== n; ++ i ) {\n\n\t\t\t\tvar object = arguments[ i ],\n\t\t\t\t\tuuid = object.uuid,\n\t\t\t\t\tindex = indicesByUUID[ uuid ];\n\n\t\t\t\tif ( index !== undefined && index >= nCachedObjects ) {\n\n\t\t\t\t\t// move existing object into the CACHED region\n\n\t\t\t\t\tvar lastCachedIndex = nCachedObjects ++,\n\t\t\t\t\t\tfirstActiveObject = objects[ lastCachedIndex ];\n\n\t\t\t\t\tindicesByUUID[ firstActiveObject.uuid ] = index;\n\t\t\t\t\tobjects[ index ] = firstActiveObject;\n\n\t\t\t\t\tindicesByUUID[ uuid ] = lastCachedIndex;\n\t\t\t\t\tobjects[ lastCachedIndex ] = object;\n\n\t\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\t\tfor ( var j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\t\tvar bindingsForPath = bindings[ j ],\n\t\t\t\t\t\t\tfirstActive = bindingsForPath[ lastCachedIndex ],\n\t\t\t\t\t\t\tbinding = bindingsForPath[ index ];\n\n\t\t\t\t\t\tbindingsForPath[ index ] = firstActive;\n\t\t\t\t\t\tbindingsForPath[ lastCachedIndex ] = binding;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} // for arguments\n\n\t\t\tthis.nCachedObjects_ = nCachedObjects;\n\n\t\t},\n\n\t\t// remove & forget\n\t\tuncache: function( var_args ) {\n\n\t\t\tvar objects = this._objects,\n\t\t\t\tnObjects = objects.length,\n\t\t\t\tnCachedObjects = this.nCachedObjects_,\n\t\t\t\tindicesByUUID = this._indicesByUUID,\n\t\t\t\tbindings = this._bindings,\n\t\t\t\tnBindings = bindings.length;\n\n\t\t\tfor ( var i = 0, n = arguments.length; i !== n; ++ i ) {\n\n\t\t\t\tvar object = arguments[ i ],\n\t\t\t\t\tuuid = object.uuid,\n\t\t\t\t\tindex = indicesByUUID[ uuid ];\n\n\t\t\t\tif ( index !== undefined ) {\n\n\t\t\t\t\tdelete indicesByUUID[ uuid ];\n\n\t\t\t\t\tif ( index < nCachedObjects ) {\n\n\t\t\t\t\t\t// object is cached, shrink the CACHED region\n\n\t\t\t\t\t\tvar firstActiveIndex = -- nCachedObjects,\n\t\t\t\t\t\t\tlastCachedObject = objects[ firstActiveIndex ],\n\t\t\t\t\t\t\tlastIndex = -- nObjects,\n\t\t\t\t\t\t\tlastObject = objects[ lastIndex ];\n\n\t\t\t\t\t\t// last cached object takes this object's place\n\t\t\t\t\t\tindicesByUUID[ lastCachedObject.uuid ] = index;\n\t\t\t\t\t\tobjects[ index ] = lastCachedObject;\n\n\t\t\t\t\t\t// last object goes to the activated slot and pop\n\t\t\t\t\t\tindicesByUUID[ lastObject.uuid ] = firstActiveIndex;\n\t\t\t\t\t\tobjects[ firstActiveIndex ] = lastObject;\n\t\t\t\t\t\tobjects.pop();\n\n\t\t\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\t\t\tfor ( var j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\t\t\tvar bindingsForPath = bindings[ j ],\n\t\t\t\t\t\t\t\tlastCached = bindingsForPath[ firstActiveIndex ],\n\t\t\t\t\t\t\t\tlast = bindingsForPath[ lastIndex ];\n\n\t\t\t\t\t\t\tbindingsForPath[ index ] = lastCached;\n\t\t\t\t\t\t\tbindingsForPath[ firstActiveIndex ] = last;\n\t\t\t\t\t\t\tbindingsForPath.pop();\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// object is active, just swap with the last and pop\n\n\t\t\t\t\t\tvar lastIndex = -- nObjects,\n\t\t\t\t\t\t\tlastObject = objects[ lastIndex ];\n\n\t\t\t\t\t\tindicesByUUID[ lastObject.uuid ] = index;\n\t\t\t\t\t\tobjects[ index ] = lastObject;\n\t\t\t\t\t\tobjects.pop();\n\n\t\t\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\t\t\tfor ( var j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\t\t\tvar bindingsForPath = bindings[ j ];\n\n\t\t\t\t\t\t\tbindingsForPath[ index ] = bindingsForPath[ lastIndex ];\n\t\t\t\t\t\t\tbindingsForPath.pop();\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} // cached or active\n\n\t\t\t\t} // if object is known\n\n\t\t\t} // for arguments\n\n\t\t\tthis.nCachedObjects_ = nCachedObjects;\n\n\t\t},\n\n\t\t// Internal interface used by befriended PropertyBinding.Composite:\n\n\t\tsubscribe_: function ( path, parsedPath ) {\n\n\t\t\t// returns an array of bindings for the given path that is changed\n\t\t\t// according to the contained objects in the group\n\n\t\t\tvar indicesByPath = this._bindingsIndicesByPath,\n\t\t\t\tindex = indicesByPath[ path ],\n\t\t\t\tbindings = this._bindings;\n\n\t\t\tif ( index !== undefined ) return bindings[ index ];\n\n\t\t\tvar paths = this._paths,\n\t\t\t\tparsedPaths = this._parsedPaths,\n\t\t\t\tobjects = this._objects,\n\t\t\t\tnObjects = objects.length,\n\t\t\t\tnCachedObjects = this.nCachedObjects_,\n\t\t\t\tbindingsForPath = new Array( nObjects );\n\n\t\t\tindex = bindings.length;\n\n\t\t\tindicesByPath[ path ] = index;\n\n\t\t\tpaths.push( path );\n\t\t\tparsedPaths.push( parsedPath );\n\t\t\tbindings.push( bindingsForPath );\n\n\t\t\tfor ( var i = nCachedObjects, n = objects.length; i !== n; ++ i ) {\n\n\t\t\t\tvar object = objects[ i ];\n\t\t\t\tbindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath );\n\n\t\t\t}\n\n\t\t\treturn bindingsForPath;\n\n\t\t},\n\n\t\tunsubscribe_: function ( path ) {\n\n\t\t\t// tells the group to forget about a property path and no longer\n\t\t\t// update the array previously obtained with 'subscribe_'\n\n\t\t\tvar indicesByPath = this._bindingsIndicesByPath,\n\t\t\t\tindex = indicesByPath[ path ];\n\n\t\t\tif ( index !== undefined ) {\n\n\t\t\t\tvar paths = this._paths,\n\t\t\t\t\tparsedPaths = this._parsedPaths,\n\t\t\t\t\tbindings = this._bindings,\n\t\t\t\t\tlastBindingsIndex = bindings.length - 1,\n\t\t\t\t\tlastBindings = bindings[ lastBindingsIndex ],\n\t\t\t\t\tlastBindingsPath = path[ lastBindingsIndex ];\n\n\t\t\t\tindicesByPath[ lastBindingsPath ] = index;\n\n\t\t\t\tbindings[ index ] = lastBindings;\n\t\t\t\tbindings.pop();\n\n\t\t\t\tparsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];\n\t\t\t\tparsedPaths.pop();\n\n\t\t\t\tpaths[ index ] = paths[ lastBindingsIndex ];\n\t\t\t\tpaths.pop();\n\n\t\t\t}\n\n\t\t}\n\n\t} );\n\n\t/**\n\t *\n\t * Action provided by AnimationMixer for scheduling clip playback on specific\n\t * objects.\n\t *\n\t * @author Ben Houston / http://clara.io/\n\t * @author David Sarno / http://lighthaus.us/\n\t * @author tschw\n\t *\n\t */\n\n\tfunction AnimationAction( mixer, clip, localRoot ) {\n\n\t\tthis._mixer = mixer;\n\t\tthis._clip = clip;\n\t\tthis._localRoot = localRoot || null;\n\n\t\tvar tracks = clip.tracks,\n\t\t\tnTracks = tracks.length,\n\t\t\tinterpolants = new Array( nTracks );\n\n\t\tvar interpolantSettings = {\n\t\t\t\tendingStart: \tZeroCurvatureEnding,\n\t\t\t\tendingEnd:\t\tZeroCurvatureEnding\n\t\t};\n\n\t\tfor ( var i = 0; i !== nTracks; ++ i ) {\n\n\t\t\tvar interpolant = tracks[ i ].createInterpolant( null );\n\t\t\tinterpolants[ i ] = interpolant;\n\t\t\tinterpolant.settings = interpolantSettings;\n\n\t\t}\n\n\t\tthis._interpolantSettings = interpolantSettings;\n\n\t\tthis._interpolants = interpolants;\t// bound by the mixer\n\n\t\t// inside: PropertyMixer (managed by the mixer)\n\t\tthis._propertyBindings = new Array( nTracks );\n\n\t\tthis._cacheIndex = null;\t\t\t// for the memory manager\n\t\tthis._byClipCacheIndex = null;\t\t// for the memory manager\n\n\t\tthis._timeScaleInterpolant = null;\n\t\tthis._weightInterpolant = null;\n\n\t\tthis.loop = LoopRepeat;\n\t\tthis._loopCount = -1;\n\n\t\t// global mixer time when the action is to be started\n\t\t// it's set back to 'null' upon start of the action\n\t\tthis._startTime = null;\n\n\t\t// scaled local time of the action\n\t\t// gets clamped or wrapped to 0..clip.duration according to loop\n\t\tthis.time = 0;\n\n\t\tthis.timeScale = 1;\n\t\tthis._effectiveTimeScale = 1;\n\n\t\tthis.weight = 1;\n\t\tthis._effectiveWeight = 1;\n\n\t\tthis.repetitions = Infinity; \t\t// no. of repetitions when looping\n\n\t\tthis.paused = false;\t\t\t\t// true -> zero effective time scale\n\t\tthis.enabled = true;\t\t\t\t// false -> zero effective weight\n\n\t\tthis.clampWhenFinished \t= false;\t// keep feeding the last frame?\n\n\t\tthis.zeroSlopeAtStart \t= true;\t\t// for smooth interpolation w/o separate\n\t\tthis.zeroSlopeAtEnd\t\t= true;\t\t// clips for start, loop and end\n\n\t}\n\n\tObject.assign( AnimationAction.prototype, {\n\n\t\t// State & Scheduling\n\n\t\tplay: function() {\n\n\t\t\tthis._mixer._activateAction( this );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tstop: function() {\n\n\t\t\tthis._mixer._deactivateAction( this );\n\n\t\t\treturn this.reset();\n\n\t\t},\n\n\t\treset: function() {\n\n\t\t\tthis.paused = false;\n\t\t\tthis.enabled = true;\n\n\t\t\tthis.time = 0;\t\t\t// restart clip\n\t\t\tthis._loopCount = -1;\t// forget previous loops\n\t\t\tthis._startTime = null;\t// forget scheduling\n\n\t\t\treturn this.stopFading().stopWarping();\n\n\t\t},\n\n\t\tisRunning: function() {\n\n\t\t\treturn this.enabled && ! this.paused && this.timeScale !== 0 &&\n\t\t\t\t\tthis._startTime === null && this._mixer._isActiveAction( this );\n\n\t\t},\n\n\t\t// return true when play has been called\n\t\tisScheduled: function() {\n\n\t\t\treturn this._mixer._isActiveAction( this );\n\n\t\t},\n\n\t\tstartAt: function( time ) {\n\n\t\t\tthis._startTime = time;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetLoop: function( mode, repetitions ) {\n\n\t\t\tthis.loop = mode;\n\t\t\tthis.repetitions = repetitions;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\t// Weight\n\n\t\t// set the weight stopping any scheduled fading\n\t\t// although .enabled = false yields an effective weight of zero, this\n\t\t// method does *not* change .enabled, because it would be confusing\n\t\tsetEffectiveWeight: function( weight ) {\n\n\t\t\tthis.weight = weight;\n\n\t\t\t// note: same logic as when updated at runtime\n\t\t\tthis._effectiveWeight = this.enabled ? weight : 0;\n\n\t\t\treturn this.stopFading();\n\n\t\t},\n\n\t\t// return the weight considering fading and .enabled\n\t\tgetEffectiveWeight: function() {\n\n\t\t\treturn this._effectiveWeight;\n\n\t\t},\n\n\t\tfadeIn: function( duration ) {\n\n\t\t\treturn this._scheduleFading( duration, 0, 1 );\n\n\t\t},\n\n\t\tfadeOut: function( duration ) {\n\n\t\t\treturn this._scheduleFading( duration, 1, 0 );\n\n\t\t},\n\n\t\tcrossFadeFrom: function( fadeOutAction, duration, warp ) {\n\n\t\t\tfadeOutAction.fadeOut( duration );\n\t\t\tthis.fadeIn( duration );\n\n\t\t\tif( warp ) {\n\n\t\t\t\tvar fadeInDuration = this._clip.duration,\n\t\t\t\t\tfadeOutDuration = fadeOutAction._clip.duration,\n\n\t\t\t\t\tstartEndRatio = fadeOutDuration / fadeInDuration,\n\t\t\t\t\tendStartRatio = fadeInDuration / fadeOutDuration;\n\n\t\t\t\tfadeOutAction.warp( 1.0, startEndRatio, duration );\n\t\t\t\tthis.warp( endStartRatio, 1.0, duration );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcrossFadeTo: function( fadeInAction, duration, warp ) {\n\n\t\t\treturn fadeInAction.crossFadeFrom( this, duration, warp );\n\n\t\t},\n\n\t\tstopFading: function() {\n\n\t\t\tvar weightInterpolant = this._weightInterpolant;\n\n\t\t\tif ( weightInterpolant !== null ) {\n\n\t\t\t\tthis._weightInterpolant = null;\n\t\t\t\tthis._mixer._takeBackControlInterpolant( weightInterpolant );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\t// Time Scale Control\n\n\t\t// set the time scale stopping any scheduled warping\n\t\t// although .paused = true yields an effective time scale of zero, this\n\t\t// method does *not* change .paused, because it would be confusing\n\t\tsetEffectiveTimeScale: function( timeScale ) {\n\n\t\t\tthis.timeScale = timeScale;\n\t\t\tthis._effectiveTimeScale = this.paused ? 0 :timeScale;\n\n\t\t\treturn this.stopWarping();\n\n\t\t},\n\n\t\t// return the time scale considering warping and .paused\n\t\tgetEffectiveTimeScale: function() {\n\n\t\t\treturn this._effectiveTimeScale;\n\n\t\t},\n\n\t\tsetDuration: function( duration ) {\n\n\t\t\tthis.timeScale = this._clip.duration / duration;\n\n\t\t\treturn this.stopWarping();\n\n\t\t},\n\n\t\tsyncWith: function( action ) {\n\n\t\t\tthis.time = action.time;\n\t\t\tthis.timeScale = action.timeScale;\n\n\t\t\treturn this.stopWarping();\n\n\t\t},\n\n\t\thalt: function( duration ) {\n\n\t\t\treturn this.warp( this._effectiveTimeScale, 0, duration );\n\n\t\t},\n\n\t\twarp: function( startTimeScale, endTimeScale, duration ) {\n\n\t\t\tvar mixer = this._mixer, now = mixer.time,\n\t\t\t\tinterpolant = this._timeScaleInterpolant,\n\n\t\t\t\ttimeScale = this.timeScale;\n\n\t\t\tif ( interpolant === null ) {\n\n\t\t\t\tinterpolant = mixer._lendControlInterpolant();\n\t\t\t\tthis._timeScaleInterpolant = interpolant;\n\n\t\t\t}\n\n\t\t\tvar times = interpolant.parameterPositions,\n\t\t\t\tvalues = interpolant.sampleValues;\n\n\t\t\ttimes[ 0 ] = now;\n\t\t\ttimes[ 1 ] = now + duration;\n\n\t\t\tvalues[ 0 ] = startTimeScale / timeScale;\n\t\t\tvalues[ 1 ] = endTimeScale / timeScale;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tstopWarping: function() {\n\n\t\t\tvar timeScaleInterpolant = this._timeScaleInterpolant;\n\n\t\t\tif ( timeScaleInterpolant !== null ) {\n\n\t\t\t\tthis._timeScaleInterpolant = null;\n\t\t\t\tthis._mixer._takeBackControlInterpolant( timeScaleInterpolant );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\t// Object Accessors\n\n\t\tgetMixer: function() {\n\n\t\t\treturn this._mixer;\n\n\t\t},\n\n\t\tgetClip: function() {\n\n\t\t\treturn this._clip;\n\n\t\t},\n\n\t\tgetRoot: function() {\n\n\t\t\treturn this._localRoot || this._mixer._root;\n\n\t\t},\n\n\t\t// Interna\n\n\t\t_update: function( time, deltaTime, timeDirection, accuIndex ) {\n\n\t\t\t// called by the mixer\n\n\t\t\tif ( ! this.enabled ) {\n\n\t\t\t\t// call ._updateWeight() to update ._effectiveWeight\n\n\t\t\t\tthis._updateWeight( time );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tvar startTime = this._startTime;\n\n\t\t\tif ( startTime !== null ) {\n\n\t\t\t\t// check for scheduled start of action\n\n\t\t\t\tvar timeRunning = ( time - startTime ) * timeDirection;\n\t\t\t\tif ( timeRunning < 0 || timeDirection === 0 ) {\n\n\t\t\t\t\treturn; // yet to come / don't decide when delta = 0\n\n\t\t\t\t}\n\n\t\t\t\t// start\n\n\t\t\t\tthis._startTime = null; // unschedule\n\t\t\t\tdeltaTime = timeDirection * timeRunning;\n\n\t\t\t}\n\n\t\t\t// apply time scale and advance time\n\n\t\t\tdeltaTime *= this._updateTimeScale( time );\n\t\t\tvar clipTime = this._updateTime( deltaTime );\n\n\t\t\t// note: _updateTime may disable the action resulting in\n\t\t\t// an effective weight of 0\n\n\t\t\tvar weight = this._updateWeight( time );\n\n\t\t\tif ( weight > 0 ) {\n\n\t\t\t\tvar interpolants = this._interpolants;\n\t\t\t\tvar propertyMixers = this._propertyBindings;\n\n\t\t\t\tfor ( var j = 0, m = interpolants.length; j !== m; ++ j ) {\n\n\t\t\t\t\tinterpolants[ j ].evaluate( clipTime );\n\t\t\t\t\tpropertyMixers[ j ].accumulate( accuIndex, weight );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t},\n\n\t\t_updateWeight: function( time ) {\n\n\t\t\tvar weight = 0;\n\n\t\t\tif ( this.enabled ) {\n\n\t\t\t\tweight = this.weight;\n\t\t\t\tvar interpolant = this._weightInterpolant;\n\n\t\t\t\tif ( interpolant !== null ) {\n\n\t\t\t\t\tvar interpolantValue = interpolant.evaluate( time )[ 0 ];\n\n\t\t\t\t\tweight *= interpolantValue;\n\n\t\t\t\t\tif ( time > interpolant.parameterPositions[ 1 ] ) {\n\n\t\t\t\t\t\tthis.stopFading();\n\n\t\t\t\t\t\tif ( interpolantValue === 0 ) {\n\n\t\t\t\t\t\t\t// faded out, disable\n\t\t\t\t\t\t\tthis.enabled = false;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis._effectiveWeight = weight;\n\t\t\treturn weight;\n\n\t\t},\n\n\t\t_updateTimeScale: function( time ) {\n\n\t\t\tvar timeScale = 0;\n\n\t\t\tif ( ! this.paused ) {\n\n\t\t\t\ttimeScale = this.timeScale;\n\n\t\t\t\tvar interpolant = this._timeScaleInterpolant;\n\n\t\t\t\tif ( interpolant !== null ) {\n\n\t\t\t\t\tvar interpolantValue = interpolant.evaluate( time )[ 0 ];\n\n\t\t\t\t\ttimeScale *= interpolantValue;\n\n\t\t\t\t\tif ( time > interpolant.parameterPositions[ 1 ] ) {\n\n\t\t\t\t\t\tthis.stopWarping();\n\n\t\t\t\t\t\tif ( timeScale === 0 ) {\n\n\t\t\t\t\t\t\t// motion has halted, pause\n\t\t\t\t\t\t\tthis.paused = true;\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// warp done - apply final time scale\n\t\t\t\t\t\t\tthis.timeScale = timeScale;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis._effectiveTimeScale = timeScale;\n\t\t\treturn timeScale;\n\n\t\t},\n\n\t\t_updateTime: function( deltaTime ) {\n\n\t\t\tvar time = this.time + deltaTime;\n\n\t\t\tif ( deltaTime === 0 ) return time;\n\n\t\t\tvar duration = this._clip.duration,\n\n\t\t\t\tloop = this.loop,\n\t\t\t\tloopCount = this._loopCount;\n\n\t\t\tif ( loop === LoopOnce ) {\n\n\t\t\t\tif ( loopCount === -1 ) {\n\t\t\t\t\t// just started\n\n\t\t\t\t\tthis._loopCount = 0;\n\t\t\t\t\tthis._setEndings( true, true, false );\n\n\t\t\t\t}\n\n\t\t\t\thandle_stop: {\n\n\t\t\t\t\tif ( time >= duration ) {\n\n\t\t\t\t\t\ttime = duration;\n\n\t\t\t\t\t} else if ( time < 0 ) {\n\n\t\t\t\t\t\ttime = 0;\n\n\t\t\t\t\t} else break handle_stop;\n\n\t\t\t\t\tif ( this.clampWhenFinished ) this.paused = true;\n\t\t\t\t\telse this.enabled = false;\n\n\t\t\t\t\tthis._mixer.dispatchEvent( {\n\t\t\t\t\t\ttype: 'finished', action: this,\n\t\t\t\t\t\tdirection: deltaTime < 0 ? -1 : 1\n\t\t\t\t\t} );\n\n\t\t\t\t}\n\n\t\t\t} else { // repetitive Repeat or PingPong\n\n\t\t\t\tvar pingPong = ( loop === LoopPingPong );\n\n\t\t\t\tif ( loopCount === -1 ) {\n\t\t\t\t\t// just started\n\n\t\t\t\t\tif ( deltaTime >= 0 ) {\n\n\t\t\t\t\t\tloopCount = 0;\n\n\t\t\t\t\t\tthis._setEndings(\n\t\t\t\t\t\t\t\ttrue, this.repetitions === 0, pingPong );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// when looping in reverse direction, the initial\n\t\t\t\t\t\t// transition through zero counts as a repetition,\n\t\t\t\t\t\t// so leave loopCount at -1\n\n\t\t\t\t\t\tthis._setEndings(\n\t\t\t\t\t\t\t\tthis.repetitions === 0, true, pingPong );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( time >= duration || time < 0 ) {\n\t\t\t\t\t// wrap around\n\n\t\t\t\t\tvar loopDelta = Math.floor( time / duration ); // signed\n\t\t\t\t\ttime -= duration * loopDelta;\n\n\t\t\t\t\tloopCount += Math.abs( loopDelta );\n\n\t\t\t\t\tvar pending = this.repetitions - loopCount;\n\n\t\t\t\t\tif ( pending < 0 ) {\n\t\t\t\t\t\t// have to stop (switch state, clamp time, fire event)\n\n\t\t\t\t\t\tif ( this.clampWhenFinished ) this.paused = true;\n\t\t\t\t\t\telse this.enabled = false;\n\n\t\t\t\t\t\ttime = deltaTime > 0 ? duration : 0;\n\n\t\t\t\t\t\tthis._mixer.dispatchEvent( {\n\t\t\t\t\t\t\ttype: 'finished', action: this,\n\t\t\t\t\t\t\tdirection: deltaTime > 0 ? 1 : -1\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// keep running\n\n\t\t\t\t\t\tif ( pending === 0 ) {\n\t\t\t\t\t\t\t// entering the last round\n\n\t\t\t\t\t\t\tvar atStart = deltaTime < 0;\n\t\t\t\t\t\t\tthis._setEndings( atStart, ! atStart, pingPong );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tthis._setEndings( false, false, pingPong );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthis._loopCount = loopCount;\n\n\t\t\t\t\t\tthis._mixer.dispatchEvent( {\n\t\t\t\t\t\t\ttype: 'loop', action: this, loopDelta: loopDelta\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( pingPong && ( loopCount & 1 ) === 1 ) {\n\t\t\t\t\t// invert time for the \"pong round\"\n\n\t\t\t\t\tthis.time = time;\n\t\t\t\t\treturn duration - time;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.time = time;\n\t\t\treturn time;\n\n\t\t},\n\n\t\t_setEndings: function( atStart, atEnd, pingPong ) {\n\n\t\t\tvar settings = this._interpolantSettings;\n\n\t\t\tif ( pingPong ) {\n\n\t\t\t\tsettings.endingStart \t= ZeroSlopeEnding;\n\t\t\t\tsettings.endingEnd\t\t= ZeroSlopeEnding;\n\n\t\t\t} else {\n\n\t\t\t\t// assuming for LoopOnce atStart == atEnd == true\n\n\t\t\t\tif ( atStart ) {\n\n\t\t\t\t\tsettings.endingStart = this.zeroSlopeAtStart ?\n\t\t\t\t\t\t\tZeroSlopeEnding : ZeroCurvatureEnding;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tsettings.endingStart = WrapAroundEnding;\n\n\t\t\t\t}\n\n\t\t\t\tif ( atEnd ) {\n\n\t\t\t\t\tsettings.endingEnd = this.zeroSlopeAtEnd ?\n\t\t\t\t\t\t\tZeroSlopeEnding : ZeroCurvatureEnding;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tsettings.endingEnd \t = WrapAroundEnding;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t},\n\n\t\t_scheduleFading: function( duration, weightNow, weightThen ) {\n\n\t\t\tvar mixer = this._mixer, now = mixer.time,\n\t\t\t\tinterpolant = this._weightInterpolant;\n\n\t\t\tif ( interpolant === null ) {\n\n\t\t\t\tinterpolant = mixer._lendControlInterpolant();\n\t\t\t\tthis._weightInterpolant = interpolant;\n\n\t\t\t}\n\n\t\t\tvar times = interpolant.parameterPositions,\n\t\t\t\tvalues = interpolant.sampleValues;\n\n\t\t\ttimes[ 0 ] = now; \t\t\t\tvalues[ 0 ] = weightNow;\n\t\t\ttimes[ 1 ] = now + duration;\tvalues[ 1 ] = weightThen;\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t *\n\t * Player for AnimationClips.\n\t *\n\t *\n\t * @author Ben Houston / http://clara.io/\n\t * @author David Sarno / http://lighthaus.us/\n\t * @author tschw\n\t */\n\n\tfunction AnimationMixer( root ) {\n\n\t\tthis._root = root;\n\t\tthis._initMemoryManager();\n\t\tthis._accuIndex = 0;\n\n\t\tthis.time = 0;\n\n\t\tthis.timeScale = 1.0;\n\n\t}\n\n\tObject.assign( AnimationMixer.prototype, EventDispatcher.prototype, {\n\n\t\t_bindAction: function ( action, prototypeAction ) {\n\n\t\t\tvar root = action._localRoot || this._root,\n\t\t\t\ttracks = action._clip.tracks,\n\t\t\t\tnTracks = tracks.length,\n\t\t\t\tbindings = action._propertyBindings,\n\t\t\t\tinterpolants = action._interpolants,\n\t\t\t\trootUuid = root.uuid,\n\t\t\t\tbindingsByRoot = this._bindingsByRootAndName,\n\t\t\t\tbindingsByName = bindingsByRoot[ rootUuid ];\n\n\t\t\tif ( bindingsByName === undefined ) {\n\n\t\t\t\tbindingsByName = {};\n\t\t\t\tbindingsByRoot[ rootUuid ] = bindingsByName;\n\n\t\t\t}\n\n\t\t\tfor ( var i = 0; i !== nTracks; ++ i ) {\n\n\t\t\t\tvar track = tracks[ i ],\n\t\t\t\t\ttrackName = track.name,\n\t\t\t\t\tbinding = bindingsByName[ trackName ];\n\n\t\t\t\tif ( binding !== undefined ) {\n\n\t\t\t\t\tbindings[ i ] = binding;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tbinding = bindings[ i ];\n\n\t\t\t\t\tif ( binding !== undefined ) {\n\n\t\t\t\t\t\t// existing binding, make sure the cache knows\n\n\t\t\t\t\t\tif ( binding._cacheIndex === null ) {\n\n\t\t\t\t\t\t\t++ binding.referenceCount;\n\t\t\t\t\t\t\tthis._addInactiveBinding( binding, rootUuid, trackName );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tvar path = prototypeAction && prototypeAction.\n\t\t\t\t\t\t\t_propertyBindings[ i ].binding.parsedPath;\n\n\t\t\t\t\tbinding = new PropertyMixer(\n\t\t\t\t\t\tPropertyBinding.create( root, trackName, path ),\n\t\t\t\t\t\ttrack.ValueTypeName, track.getValueSize() );\n\n\t\t\t\t\t++ binding.referenceCount;\n\t\t\t\t\tthis._addInactiveBinding( binding, rootUuid, trackName );\n\n\t\t\t\t\tbindings[ i ] = binding;\n\n\t\t\t\t}\n\n\t\t\t\tinterpolants[ i ].resultBuffer = binding.buffer;\n\n\t\t\t}\n\n\t\t},\n\n\t\t_activateAction: function ( action ) {\n\n\t\t\tif ( ! this._isActiveAction( action ) ) {\n\n\t\t\t\tif ( action._cacheIndex === null ) {\n\n\t\t\t\t\t// this action has been forgotten by the cache, but the user\n\t\t\t\t\t// appears to be still using it -> rebind\n\n\t\t\t\t\tvar rootUuid = ( action._localRoot || this._root ).uuid,\n\t\t\t\t\t\tclipUuid = action._clip.uuid,\n\t\t\t\t\t\tactionsForClip = this._actionsByClip[ clipUuid ];\n\n\t\t\t\t\tthis._bindAction( action,\n\t\t\t\t\t\tactionsForClip && actionsForClip.knownActions[ 0 ] );\n\n\t\t\t\t\tthis._addInactiveAction( action, clipUuid, rootUuid );\n\n\t\t\t\t}\n\n\t\t\t\tvar bindings = action._propertyBindings;\n\n\t\t\t\t// increment reference counts / sort out state\n\t\t\t\tfor ( var i = 0, n = bindings.length; i !== n; ++ i ) {\n\n\t\t\t\t\tvar binding = bindings[ i ];\n\n\t\t\t\t\tif ( binding.useCount ++ === 0 ) {\n\n\t\t\t\t\t\tthis._lendBinding( binding );\n\t\t\t\t\t\tbinding.saveOriginalState();\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tthis._lendAction( action );\n\n\t\t\t}\n\n\t\t},\n\n\t\t_deactivateAction: function ( action ) {\n\n\t\t\tif ( this._isActiveAction( action ) ) {\n\n\t\t\t\tvar bindings = action._propertyBindings;\n\n\t\t\t\t// decrement reference counts / sort out state\n\t\t\t\tfor ( var i = 0, n = bindings.length; i !== n; ++ i ) {\n\n\t\t\t\t\tvar binding = bindings[ i ];\n\n\t\t\t\t\tif ( -- binding.useCount === 0 ) {\n\n\t\t\t\t\t\tbinding.restoreOriginalState();\n\t\t\t\t\t\tthis._takeBackBinding( binding );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tthis._takeBackAction( action );\n\n\t\t\t}\n\n\t\t},\n\n\t\t// Memory manager\n\n\t\t_initMemoryManager: function () {\n\n\t\t\tthis._actions = []; // 'nActiveActions' followed by inactive ones\n\t\t\tthis._nActiveActions = 0;\n\n\t\t\tthis._actionsByClip = {};\n\t\t\t// inside:\n\t\t\t// {\n\t\t\t// \t\tknownActions: Array< AnimationAction >\t- used as prototypes\n\t\t\t// \t\tactionByRoot: AnimationAction\t\t\t- lookup\n\t\t\t// }\n\n\n\t\t\tthis._bindings = []; // 'nActiveBindings' followed by inactive ones\n\t\t\tthis._nActiveBindings = 0;\n\n\t\t\tthis._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer >\n\n\n\t\t\tthis._controlInterpolants = []; // same game as above\n\t\t\tthis._nActiveControlInterpolants = 0;\n\n\t\t\tvar scope = this;\n\n\t\t\tthis.stats = {\n\n\t\t\t\tactions: {\n\t\t\t\t\tget total() { return scope._actions.length; },\n\t\t\t\t\tget inUse() { return scope._nActiveActions; }\n\t\t\t\t},\n\t\t\t\tbindings: {\n\t\t\t\t\tget total() { return scope._bindings.length; },\n\t\t\t\t\tget inUse() { return scope._nActiveBindings; }\n\t\t\t\t},\n\t\t\t\tcontrolInterpolants: {\n\t\t\t\t\tget total() { return scope._controlInterpolants.length; },\n\t\t\t\t\tget inUse() { return scope._nActiveControlInterpolants; }\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t},\n\n\t\t// Memory management for AnimationAction objects\n\n\t\t_isActiveAction: function ( action ) {\n\n\t\t\tvar index = action._cacheIndex;\n\t\t\treturn index !== null && index < this._nActiveActions;\n\n\t\t},\n\n\t\t_addInactiveAction: function ( action, clipUuid, rootUuid ) {\n\n\t\t\tvar actions = this._actions,\n\t\t\t\tactionsByClip = this._actionsByClip,\n\t\t\t\tactionsForClip = actionsByClip[ clipUuid ];\n\n\t\t\tif ( actionsForClip === undefined ) {\n\n\t\t\t\tactionsForClip = {\n\n\t\t\t\t\tknownActions: [ action ],\n\t\t\t\t\tactionByRoot: {}\n\n\t\t\t\t};\n\n\t\t\t\taction._byClipCacheIndex = 0;\n\n\t\t\t\tactionsByClip[ clipUuid ] = actionsForClip;\n\n\t\t\t} else {\n\n\t\t\t\tvar knownActions = actionsForClip.knownActions;\n\n\t\t\t\taction._byClipCacheIndex = knownActions.length;\n\t\t\t\tknownActions.push( action );\n\n\t\t\t}\n\n\t\t\taction._cacheIndex = actions.length;\n\t\t\tactions.push( action );\n\n\t\t\tactionsForClip.actionByRoot[ rootUuid ] = action;\n\n\t\t},\n\n\t\t_removeInactiveAction: function ( action ) {\n\n\t\t\tvar actions = this._actions,\n\t\t\t\tlastInactiveAction = actions[ actions.length - 1 ],\n\t\t\t\tcacheIndex = action._cacheIndex;\n\n\t\t\tlastInactiveAction._cacheIndex = cacheIndex;\n\t\t\tactions[ cacheIndex ] = lastInactiveAction;\n\t\t\tactions.pop();\n\n\t\t\taction._cacheIndex = null;\n\n\n\t\t\tvar clipUuid = action._clip.uuid,\n\t\t\t\tactionsByClip = this._actionsByClip,\n\t\t\t\tactionsForClip = actionsByClip[ clipUuid ],\n\t\t\t\tknownActionsForClip = actionsForClip.knownActions,\n\n\t\t\t\tlastKnownAction =\n\t\t\t\t\tknownActionsForClip[ knownActionsForClip.length - 1 ],\n\n\t\t\t\tbyClipCacheIndex = action._byClipCacheIndex;\n\n\t\t\tlastKnownAction._byClipCacheIndex = byClipCacheIndex;\n\t\t\tknownActionsForClip[ byClipCacheIndex ] = lastKnownAction;\n\t\t\tknownActionsForClip.pop();\n\n\t\t\taction._byClipCacheIndex = null;\n\n\n\t\t\tvar actionByRoot = actionsForClip.actionByRoot,\n\t\t\t\trootUuid = ( action._localRoot || this._root ).uuid;\n\n\t\t\tdelete actionByRoot[ rootUuid ];\n\n\t\t\tif ( knownActionsForClip.length === 0 ) {\n\n\t\t\t\tdelete actionsByClip[ clipUuid ];\n\n\t\t\t}\n\n\t\t\tthis._removeInactiveBindingsForAction( action );\n\n\t\t},\n\n\t\t_removeInactiveBindingsForAction: function ( action ) {\n\n\t\t\tvar bindings = action._propertyBindings;\n\t\t\tfor ( var i = 0, n = bindings.length; i !== n; ++ i ) {\n\n\t\t\t\tvar binding = bindings[ i ];\n\n\t\t\t\tif ( -- binding.referenceCount === 0 ) {\n\n\t\t\t\t\tthis._removeInactiveBinding( binding );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t},\n\n\t\t_lendAction: function ( action ) {\n\n\t\t\t// [ active actions |  inactive actions  ]\n\t\t\t// [  active actions >| inactive actions ]\n\t\t\t//                 s        a\n\t\t\t//                  <-swap->\n\t\t\t//                 a        s\n\n\t\t\tvar actions = this._actions,\n\t\t\t\tprevIndex = action._cacheIndex,\n\n\t\t\t\tlastActiveIndex = this._nActiveActions ++,\n\n\t\t\t\tfirstInactiveAction = actions[ lastActiveIndex ];\n\n\t\t\taction._cacheIndex = lastActiveIndex;\n\t\t\tactions[ lastActiveIndex ] = action;\n\n\t\t\tfirstInactiveAction._cacheIndex = prevIndex;\n\t\t\tactions[ prevIndex ] = firstInactiveAction;\n\n\t\t},\n\n\t\t_takeBackAction: function ( action ) {\n\n\t\t\t// [  active actions  | inactive actions ]\n\t\t\t// [ active actions |< inactive actions  ]\n\t\t\t//        a        s\n\t\t\t//         <-swap->\n\t\t\t//        s        a\n\n\t\t\tvar actions = this._actions,\n\t\t\t\tprevIndex = action._cacheIndex,\n\n\t\t\t\tfirstInactiveIndex = -- this._nActiveActions,\n\n\t\t\t\tlastActiveAction = actions[ firstInactiveIndex ];\n\n\t\t\taction._cacheIndex = firstInactiveIndex;\n\t\t\tactions[ firstInactiveIndex ] = action;\n\n\t\t\tlastActiveAction._cacheIndex = prevIndex;\n\t\t\tactions[ prevIndex ] = lastActiveAction;\n\n\t\t},\n\n\t\t// Memory management for PropertyMixer objects\n\n\t\t_addInactiveBinding: function ( binding, rootUuid, trackName ) {\n\n\t\t\tvar bindingsByRoot = this._bindingsByRootAndName,\n\t\t\t\tbindingByName = bindingsByRoot[ rootUuid ],\n\n\t\t\t\tbindings = this._bindings;\n\n\t\t\tif ( bindingByName === undefined ) {\n\n\t\t\t\tbindingByName = {};\n\t\t\t\tbindingsByRoot[ rootUuid ] = bindingByName;\n\n\t\t\t}\n\n\t\t\tbindingByName[ trackName ] = binding;\n\n\t\t\tbinding._cacheIndex = bindings.length;\n\t\t\tbindings.push( binding );\n\n\t\t},\n\n\t\t_removeInactiveBinding: function ( binding ) {\n\n\t\t\tvar bindings = this._bindings,\n\t\t\t\tpropBinding = binding.binding,\n\t\t\t\trootUuid = propBinding.rootNode.uuid,\n\t\t\t\ttrackName = propBinding.path,\n\t\t\t\tbindingsByRoot = this._bindingsByRootAndName,\n\t\t\t\tbindingByName = bindingsByRoot[ rootUuid ],\n\n\t\t\t\tlastInactiveBinding = bindings[ bindings.length - 1 ],\n\t\t\t\tcacheIndex = binding._cacheIndex;\n\n\t\t\tlastInactiveBinding._cacheIndex = cacheIndex;\n\t\t\tbindings[ cacheIndex ] = lastInactiveBinding;\n\t\t\tbindings.pop();\n\n\t\t\tdelete bindingByName[ trackName ];\n\n\t\t\tremove_empty_map: {\n\n\t\t\t\tfor ( var _ in bindingByName ) break remove_empty_map;\n\n\t\t\t\tdelete bindingsByRoot[ rootUuid ];\n\n\t\t\t}\n\n\t\t},\n\n\t\t_lendBinding: function ( binding ) {\n\n\t\t\tvar bindings = this._bindings,\n\t\t\t\tprevIndex = binding._cacheIndex,\n\n\t\t\t\tlastActiveIndex = this._nActiveBindings ++,\n\n\t\t\t\tfirstInactiveBinding = bindings[ lastActiveIndex ];\n\n\t\t\tbinding._cacheIndex = lastActiveIndex;\n\t\t\tbindings[ lastActiveIndex ] = binding;\n\n\t\t\tfirstInactiveBinding._cacheIndex = prevIndex;\n\t\t\tbindings[ prevIndex ] = firstInactiveBinding;\n\n\t\t},\n\n\t\t_takeBackBinding: function ( binding ) {\n\n\t\t\tvar bindings = this._bindings,\n\t\t\t\tprevIndex = binding._cacheIndex,\n\n\t\t\t\tfirstInactiveIndex = -- this._nActiveBindings,\n\n\t\t\t\tlastActiveBinding = bindings[ firstInactiveIndex ];\n\n\t\t\tbinding._cacheIndex = firstInactiveIndex;\n\t\t\tbindings[ firstInactiveIndex ] = binding;\n\n\t\t\tlastActiveBinding._cacheIndex = prevIndex;\n\t\t\tbindings[ prevIndex ] = lastActiveBinding;\n\n\t\t},\n\n\n\t\t// Memory management of Interpolants for weight and time scale\n\n\t\t_lendControlInterpolant: function () {\n\n\t\t\tvar interpolants = this._controlInterpolants,\n\t\t\t\tlastActiveIndex = this._nActiveControlInterpolants ++,\n\t\t\t\tinterpolant = interpolants[ lastActiveIndex ];\n\n\t\t\tif ( interpolant === undefined ) {\n\n\t\t\t\tinterpolant = new LinearInterpolant(\n\t\t\t\t\tnew Float32Array( 2 ), new Float32Array( 2 ),\n\t\t\t\t\t1, this._controlInterpolantsResultBuffer );\n\n\t\t\t\tinterpolant.__cacheIndex = lastActiveIndex;\n\t\t\t\tinterpolants[ lastActiveIndex ] = interpolant;\n\n\t\t\t}\n\n\t\t\treturn interpolant;\n\n\t\t},\n\n\t\t_takeBackControlInterpolant: function ( interpolant ) {\n\n\t\t\tvar interpolants = this._controlInterpolants,\n\t\t\t\tprevIndex = interpolant.__cacheIndex,\n\n\t\t\t\tfirstInactiveIndex = -- this._nActiveControlInterpolants,\n\n\t\t\t\tlastActiveInterpolant = interpolants[ firstInactiveIndex ];\n\n\t\t\tinterpolant.__cacheIndex = firstInactiveIndex;\n\t\t\tinterpolants[ firstInactiveIndex ] = interpolant;\n\n\t\t\tlastActiveInterpolant.__cacheIndex = prevIndex;\n\t\t\tinterpolants[ prevIndex ] = lastActiveInterpolant;\n\n\t\t},\n\n\t\t_controlInterpolantsResultBuffer: new Float32Array( 1 ),\n\n\t\t// return an action for a clip optionally using a custom root target\n\t\t// object (this method allocates a lot of dynamic memory in case a\n\t\t// previously unknown clip/root combination is specified)\n\t\tclipAction: function ( clip, optionalRoot ) {\n\n\t\t\tvar root = optionalRoot || this._root,\n\t\t\t\trootUuid = root.uuid,\n\n\t\t\t\tclipObject = typeof clip === 'string' ?\n\t\t\t\t\tAnimationClip.findByName( root, clip ) : clip,\n\n\t\t\t\tclipUuid = clipObject !== null ? clipObject.uuid : clip,\n\n\t\t\t\tactionsForClip = this._actionsByClip[ clipUuid ],\n\t\t\t\tprototypeAction = null;\n\n\t\t\tif ( actionsForClip !== undefined ) {\n\n\t\t\t\tvar existingAction =\n\t\t\t\t\t\tactionsForClip.actionByRoot[ rootUuid ];\n\n\t\t\t\tif ( existingAction !== undefined ) {\n\n\t\t\t\t\treturn existingAction;\n\n\t\t\t\t}\n\n\t\t\t\t// we know the clip, so we don't have to parse all\n\t\t\t\t// the bindings again but can just copy\n\t\t\t\tprototypeAction = actionsForClip.knownActions[ 0 ];\n\n\t\t\t\t// also, take the clip from the prototype action\n\t\t\t\tif ( clipObject === null )\n\t\t\t\t\tclipObject = prototypeAction._clip;\n\n\t\t\t}\n\n\t\t\t// clip must be known when specified via string\n\t\t\tif ( clipObject === null ) return null;\n\n\t\t\t// allocate all resources required to run it\n\t\t\tvar newAction = new AnimationAction( this, clipObject, optionalRoot );\n\n\t\t\tthis._bindAction( newAction, prototypeAction );\n\n\t\t\t// and make the action known to the memory manager\n\t\t\tthis._addInactiveAction( newAction, clipUuid, rootUuid );\n\n\t\t\treturn newAction;\n\n\t\t},\n\n\t\t// get an existing action\n\t\texistingAction: function ( clip, optionalRoot ) {\n\n\t\t\tvar root = optionalRoot || this._root,\n\t\t\t\trootUuid = root.uuid,\n\n\t\t\t\tclipObject = typeof clip === 'string' ?\n\t\t\t\t\tAnimationClip.findByName( root, clip ) : clip,\n\n\t\t\t\tclipUuid = clipObject ? clipObject.uuid : clip,\n\n\t\t\t\tactionsForClip = this._actionsByClip[ clipUuid ];\n\n\t\t\tif ( actionsForClip !== undefined ) {\n\n\t\t\t\treturn actionsForClip.actionByRoot[ rootUuid ] || null;\n\n\t\t\t}\n\n\t\t\treturn null;\n\n\t\t},\n\n\t\t// deactivates all previously scheduled actions\n\t\tstopAllAction: function () {\n\n\t\t\tvar actions = this._actions,\n\t\t\t\tnActions = this._nActiveActions,\n\t\t\t\tbindings = this._bindings,\n\t\t\t\tnBindings = this._nActiveBindings;\n\n\t\t\tthis._nActiveActions = 0;\n\t\t\tthis._nActiveBindings = 0;\n\n\t\t\tfor ( var i = 0; i !== nActions; ++ i ) {\n\n\t\t\t\tactions[ i ].reset();\n\n\t\t\t}\n\n\t\t\tfor ( var i = 0; i !== nBindings; ++ i ) {\n\n\t\t\t\tbindings[ i ].useCount = 0;\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\t// advance the time and update apply the animation\n\t\tupdate: function ( deltaTime ) {\n\n\t\t\tdeltaTime *= this.timeScale;\n\n\t\t\tvar actions = this._actions,\n\t\t\t\tnActions = this._nActiveActions,\n\n\t\t\t\ttime = this.time += deltaTime,\n\t\t\t\ttimeDirection = Math.sign( deltaTime ),\n\n\t\t\t\taccuIndex = this._accuIndex ^= 1;\n\n\t\t\t// run active actions\n\n\t\t\tfor ( var i = 0; i !== nActions; ++ i ) {\n\n\t\t\t\tvar action = actions[ i ];\n\n\t\t\t\taction._update( time, deltaTime, timeDirection, accuIndex );\n\n\t\t\t}\n\n\t\t\t// update scene graph\n\n\t\t\tvar bindings = this._bindings,\n\t\t\t\tnBindings = this._nActiveBindings;\n\n\t\t\tfor ( var i = 0; i !== nBindings; ++ i ) {\n\n\t\t\t\tbindings[ i ].apply( accuIndex );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\t// return this mixer's root target object\n\t\tgetRoot: function () {\n\n\t\t\treturn this._root;\n\n\t\t},\n\n\t\t// free all resources specific to a particular clip\n\t\tuncacheClip: function ( clip ) {\n\n\t\t\tvar actions = this._actions,\n\t\t\t\tclipUuid = clip.uuid,\n\t\t\t\tactionsByClip = this._actionsByClip,\n\t\t\t\tactionsForClip = actionsByClip[ clipUuid ];\n\n\t\t\tif ( actionsForClip !== undefined ) {\n\n\t\t\t\t// note: just calling _removeInactiveAction would mess up the\n\t\t\t\t// iteration state and also require updating the state we can\n\t\t\t\t// just throw away\n\n\t\t\t\tvar actionsToRemove = actionsForClip.knownActions;\n\n\t\t\t\tfor ( var i = 0, n = actionsToRemove.length; i !== n; ++ i ) {\n\n\t\t\t\t\tvar action = actionsToRemove[ i ];\n\n\t\t\t\t\tthis._deactivateAction( action );\n\n\t\t\t\t\tvar cacheIndex = action._cacheIndex,\n\t\t\t\t\t\tlastInactiveAction = actions[ actions.length - 1 ];\n\n\t\t\t\t\taction._cacheIndex = null;\n\t\t\t\t\taction._byClipCacheIndex = null;\n\n\t\t\t\t\tlastInactiveAction._cacheIndex = cacheIndex;\n\t\t\t\t\tactions[ cacheIndex ] = lastInactiveAction;\n\t\t\t\t\tactions.pop();\n\n\t\t\t\t\tthis._removeInactiveBindingsForAction( action );\n\n\t\t\t\t}\n\n\t\t\t\tdelete actionsByClip[ clipUuid ];\n\n\t\t\t}\n\n\t\t},\n\n\t\t// free all resources specific to a particular root target object\n\t\tuncacheRoot: function ( root ) {\n\n\t\t\tvar rootUuid = root.uuid,\n\t\t\t\tactionsByClip = this._actionsByClip;\n\n\t\t\tfor ( var clipUuid in actionsByClip ) {\n\n\t\t\t\tvar actionByRoot = actionsByClip[ clipUuid ].actionByRoot,\n\t\t\t\t\taction = actionByRoot[ rootUuid ];\n\n\t\t\t\tif ( action !== undefined ) {\n\n\t\t\t\t\tthis._deactivateAction( action );\n\t\t\t\t\tthis._removeInactiveAction( action );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tvar bindingsByRoot = this._bindingsByRootAndName,\n\t\t\t\tbindingByName = bindingsByRoot[ rootUuid ];\n\n\t\t\tif ( bindingByName !== undefined ) {\n\n\t\t\t\tfor ( var trackName in bindingByName ) {\n\n\t\t\t\t\tvar binding = bindingByName[ trackName ];\n\t\t\t\t\tbinding.restoreOriginalState();\n\t\t\t\t\tthis._removeInactiveBinding( binding );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t},\n\n\t\t// remove a targeted clip from the cache\n\t\tuncacheAction: function ( clip, optionalRoot ) {\n\n\t\t\tvar action = this.existingAction( clip, optionalRoot );\n\n\t\t\tif ( action !== null ) {\n\n\t\t\t\tthis._deactivateAction( action );\n\t\t\t\tthis._removeInactiveAction( action );\n\n\t\t\t}\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction Uniform( value ) {\n\n\t\tif ( typeof value === 'string' ) {\n\n\t\t\tconsole.warn( 'THREE.Uniform: Type parameter is no longer needed.' );\n\t\t\tvalue = arguments[ 1 ];\n\n\t\t}\n\n\t\tthis.value = value;\n\n\t}\n\n\tUniform.prototype.clone = function () {\n\n\t\treturn new Uniform( this.value.clone === undefined ? this.value : this.value.clone() );\n\n\t};\n\n\t/**\n\t * @author benaadams / https://twitter.com/ben_a_adams\n\t */\n\n\tfunction InstancedBufferGeometry() {\n\n\t\tBufferGeometry.call( this );\n\n\t\tthis.type = 'InstancedBufferGeometry';\n\t\tthis.maxInstancedCount = undefined;\n\n\t}\n\n\tInstancedBufferGeometry.prototype = Object.assign( Object.create( BufferGeometry.prototype ), {\n\n\t\tconstructor: InstancedBufferGeometry,\n\n\t\tisInstancedBufferGeometry: true,\n\n\t\taddGroup: function ( start, count, materialIndex ) {\n\n\t\t\tthis.groups.push( {\n\n\t\t\t\tstart: start,\n\t\t\t\tcount: count,\n\t\t\t\tmaterialIndex: materialIndex\n\n\t\t\t} );\n\n\t\t},\n\n\t\tcopy: function ( source ) {\n\n\t\t\tvar index = source.index;\n\n\t\t\tif ( index !== null ) {\n\n\t\t\t\tthis.setIndex( index.clone() );\n\n\t\t\t}\n\n\t\t\tvar attributes = source.attributes;\n\n\t\t\tfor ( var name in attributes ) {\n\n\t\t\t\tvar attribute = attributes[ name ];\n\t\t\t\tthis.addAttribute( name, attribute.clone() );\n\n\t\t\t}\n\n\t\t\tvar groups = source.groups;\n\n\t\t\tfor ( var i = 0, l = groups.length; i < l; i ++ ) {\n\n\t\t\t\tvar group = groups[ i ];\n\t\t\t\tthis.addGroup( group.start, group.count, group.materialIndex );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author benaadams / https://twitter.com/ben_a_adams\n\t */\n\n\tfunction InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, normalized ) {\n\n\t\tthis.uuid = _Math.generateUUID();\n\n\t\tthis.data = interleavedBuffer;\n\t\tthis.itemSize = itemSize;\n\t\tthis.offset = offset;\n\n\t\tthis.normalized = normalized === true;\n\n\t}\n\n\tObject.defineProperties( InterleavedBufferAttribute.prototype, {\n\n\t\tcount: {\n\n\t\t\tget: function () {\n\n\t\t\t\treturn this.data.count;\n\n\t\t\t}\n\n\t\t},\n\n\t\tarray: {\n\n\t\t\tget: function () {\n\n\t\t\t\treturn this.data.array;\n\n\t\t\t}\n\n\t\t}\n\n\t} );\n\n\tObject.assign( InterleavedBufferAttribute.prototype, {\n\n\t\tisInterleavedBufferAttribute: true,\n\n\t\tsetX: function ( index, x ) {\n\n\t\t\tthis.data.array[ index * this.data.stride + this.offset ] = x;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetY: function ( index, y ) {\n\n\t\t\tthis.data.array[ index * this.data.stride + this.offset + 1 ] = y;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetZ: function ( index, z ) {\n\n\t\t\tthis.data.array[ index * this.data.stride + this.offset + 2 ] = z;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetW: function ( index, w ) {\n\n\t\t\tthis.data.array[ index * this.data.stride + this.offset + 3 ] = w;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tgetX: function ( index ) {\n\n\t\t\treturn this.data.array[ index * this.data.stride + this.offset ];\n\n\t\t},\n\n\t\tgetY: function ( index ) {\n\n\t\t\treturn this.data.array[ index * this.data.stride + this.offset + 1 ];\n\n\t\t},\n\n\t\tgetZ: function ( index ) {\n\n\t\t\treturn this.data.array[ index * this.data.stride + this.offset + 2 ];\n\n\t\t},\n\n\t\tgetW: function ( index ) {\n\n\t\t\treturn this.data.array[ index * this.data.stride + this.offset + 3 ];\n\n\t\t},\n\n\t\tsetXY: function ( index, x, y ) {\n\n\t\t\tindex = index * this.data.stride + this.offset;\n\n\t\t\tthis.data.array[ index + 0 ] = x;\n\t\t\tthis.data.array[ index + 1 ] = y;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetXYZ: function ( index, x, y, z ) {\n\n\t\t\tindex = index * this.data.stride + this.offset;\n\n\t\t\tthis.data.array[ index + 0 ] = x;\n\t\t\tthis.data.array[ index + 1 ] = y;\n\t\t\tthis.data.array[ index + 2 ] = z;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetXYZW: function ( index, x, y, z, w ) {\n\n\t\t\tindex = index * this.data.stride + this.offset;\n\n\t\t\tthis.data.array[ index + 0 ] = x;\n\t\t\tthis.data.array[ index + 1 ] = y;\n\t\t\tthis.data.array[ index + 2 ] = z;\n\t\t\tthis.data.array[ index + 3 ] = w;\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author benaadams / https://twitter.com/ben_a_adams\n\t */\n\n\tfunction InterleavedBuffer( array, stride ) {\n\n\t\tthis.uuid = _Math.generateUUID();\n\n\t\tthis.array = array;\n\t\tthis.stride = stride;\n\t\tthis.count = array !== undefined ? array.length / stride : 0;\n\n\t\tthis.dynamic = false;\n\t\tthis.updateRange = { offset: 0, count: - 1 };\n\n\t\tthis.onUploadCallback = function () {};\n\n\t\tthis.version = 0;\n\n\t}\n\n\tObject.defineProperty( InterleavedBuffer.prototype, 'needsUpdate', {\n\n\t\tset: function ( value ) {\n\n\t\t\tif ( value === true ) this.version ++;\n\n\t\t}\n\n\t} );\n\n\tObject.assign( InterleavedBuffer.prototype, {\n\n\t\tisInterleavedBuffer: true,\n\n\t\tsetArray: function ( array ) {\n\n\t\t\tif ( Array.isArray( array ) ) {\n\n\t\t\t\tthrow new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );\n\n\t\t\t}\n\n\t\t\tthis.count = array !== undefined ? array.length / this.stride : 0;\n\t\t\tthis.array = array;\n\n\t\t},\n\n\t\tsetDynamic: function ( value ) {\n\n\t\t\tthis.dynamic = value;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcopy: function ( source ) {\n\n\t\t\tthis.array = new source.array.constructor( source.array );\n\t\t\tthis.count = source.count;\n\t\t\tthis.stride = source.stride;\n\t\t\tthis.dynamic = source.dynamic;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tcopyAt: function ( index1, attribute, index2 ) {\n\n\t\t\tindex1 *= this.stride;\n\t\t\tindex2 *= attribute.stride;\n\n\t\t\tfor ( var i = 0, l = this.stride; i < l; i ++ ) {\n\n\t\t\t\tthis.array[ index1 + i ] = attribute.array[ index2 + i ];\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tset: function ( value, offset ) {\n\n\t\t\tif ( offset === undefined ) offset = 0;\n\n\t\t\tthis.array.set( value, offset );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor().copy( this );\n\n\t\t},\n\n\t\tonUpload: function ( callback ) {\n\n\t\t\tthis.onUploadCallback = callback;\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author benaadams / https://twitter.com/ben_a_adams\n\t */\n\n\tfunction InstancedInterleavedBuffer( array, stride, meshPerAttribute ) {\n\n\t\tInterleavedBuffer.call( this, array, stride );\n\n\t\tthis.meshPerAttribute = meshPerAttribute || 1;\n\n\t}\n\n\tInstancedInterleavedBuffer.prototype = Object.assign( Object.create( InterleavedBuffer.prototype ), {\n\n\t\tconstructor: InstancedInterleavedBuffer,\n\n\t\tisInstancedInterleavedBuffer: true,\n\n\t\tcopy: function ( source ) {\n\n\t\t\tInterleavedBuffer.prototype.copy.call( this, source );\n\n\t\t\tthis.meshPerAttribute = source.meshPerAttribute;\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author benaadams / https://twitter.com/ben_a_adams\n\t */\n\n\tfunction InstancedBufferAttribute( array, itemSize, meshPerAttribute ) {\n\n\t\tBufferAttribute.call( this, array, itemSize );\n\n\t\tthis.meshPerAttribute = meshPerAttribute || 1;\n\n\t}\n\n\tInstancedBufferAttribute.prototype = Object.assign( Object.create( BufferAttribute.prototype ), {\n\n\t\tconstructor: InstancedBufferAttribute,\n\n\t\tisInstancedBufferAttribute: true,\n\n\t\tcopy: function ( source ) {\n\n\t\t\tBufferAttribute.prototype.copy.call( this, source );\n\n\t\t\tthis.meshPerAttribute = source.meshPerAttribute;\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author bhouston / http://clara.io/\n\t * @author stephomi / http://stephaneginier.com/\n\t */\n\n\tfunction Raycaster( origin, direction, near, far ) {\n\n\t\tthis.ray = new Ray( origin, direction );\n\t\t// direction is assumed to be normalized (for accurate distance calculations)\n\n\t\tthis.near = near || 0;\n\t\tthis.far = far || Infinity;\n\n\t\tthis.params = {\n\t\t\tMesh: {},\n\t\t\tLine: {},\n\t\t\tLOD: {},\n\t\t\tPoints: { threshold: 1 },\n\t\t\tSprite: {}\n\t\t};\n\n\t\tObject.defineProperties( this.params, {\n\t\t\tPointCloud: {\n\t\t\t\tget: function () {\n\t\t\t\t\tconsole.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' );\n\t\t\t\t\treturn this.Points;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t}\n\n\tfunction ascSort( a, b ) {\n\n\t\treturn a.distance - b.distance;\n\n\t}\n\n\tfunction intersectObject( object, raycaster, intersects, recursive ) {\n\n\t\tif ( object.visible === false ) return;\n\n\t\tobject.raycast( raycaster, intersects );\n\n\t\tif ( recursive === true ) {\n\n\t\t\tvar children = object.children;\n\n\t\t\tfor ( var i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\t\tintersectObject( children[ i ], raycaster, intersects, true );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tObject.assign( Raycaster.prototype, {\n\n\t\tlinePrecision: 1,\n\n\t\tset: function ( origin, direction ) {\n\n\t\t\t// direction is assumed to be normalized (for accurate distance calculations)\n\n\t\t\tthis.ray.set( origin, direction );\n\n\t\t},\n\n\t\tsetFromCamera: function ( coords, camera ) {\n\n\t\t\tif ( ( camera && camera.isPerspectiveCamera ) ) {\n\n\t\t\t\tthis.ray.origin.setFromMatrixPosition( camera.matrixWorld );\n\t\t\t\tthis.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();\n\n\t\t\t} else if ( ( camera && camera.isOrthographicCamera ) ) {\n\n\t\t\t\tthis.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera\n\t\t\t\tthis.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );\n\n\t\t\t} else {\n\n\t\t\t\tconsole.error( 'THREE.Raycaster: Unsupported camera type.' );\n\n\t\t\t}\n\n\t\t},\n\n\t\tintersectObject: function ( object, recursive ) {\n\n\t\t\tvar intersects = [];\n\n\t\t\tintersectObject( object, this, intersects, recursive );\n\n\t\t\tintersects.sort( ascSort );\n\n\t\t\treturn intersects;\n\n\t\t},\n\n\t\tintersectObjects: function ( objects, recursive ) {\n\n\t\t\tvar intersects = [];\n\n\t\t\tif ( Array.isArray( objects ) === false ) {\n\n\t\t\t\tconsole.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' );\n\t\t\t\treturn intersects;\n\n\t\t\t}\n\n\t\t\tfor ( var i = 0, l = objects.length; i < l; i ++ ) {\n\n\t\t\t\tintersectObject( objects[ i ], this, intersects, recursive );\n\n\t\t\t}\n\n\t\t\tintersects.sort( ascSort );\n\n\t\t\treturn intersects;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tfunction Clock( autoStart ) {\n\n\t\tthis.autoStart = ( autoStart !== undefined ) ? autoStart : true;\n\n\t\tthis.startTime = 0;\n\t\tthis.oldTime = 0;\n\t\tthis.elapsedTime = 0;\n\n\t\tthis.running = false;\n\n\t}\n\n\tObject.assign( Clock.prototype, {\n\n\t\tstart: function () {\n\n\t\t\tthis.startTime = ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732\n\n\t\t\tthis.oldTime = this.startTime;\n\t\t\tthis.elapsedTime = 0;\n\t\t\tthis.running = true;\n\n\t\t},\n\n\t\tstop: function () {\n\n\t\t\tthis.getElapsedTime();\n\t\t\tthis.running = false;\n\t\t\tthis.autoStart = false;\n\n\t\t},\n\n\t\tgetElapsedTime: function () {\n\n\t\t\tthis.getDelta();\n\t\t\treturn this.elapsedTime;\n\n\t\t},\n\n\t\tgetDelta: function () {\n\n\t\t\tvar diff = 0;\n\n\t\t\tif ( this.autoStart && ! this.running ) {\n\n\t\t\t\tthis.start();\n\t\t\t\treturn 0;\n\n\t\t\t}\n\n\t\t\tif ( this.running ) {\n\n\t\t\t\tvar newTime = ( typeof performance === 'undefined' ? Date : performance ).now();\n\n\t\t\t\tdiff = ( newTime - this.oldTime ) / 1000;\n\t\t\t\tthis.oldTime = newTime;\n\n\t\t\t\tthis.elapsedTime += diff;\n\n\t\t\t}\n\n\t\t\treturn diff;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author bhouston / http://clara.io\n\t * @author WestLangley / http://github.com/WestLangley\n\t *\n\t * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system\n\t *\n\t * The poles (phi) are at the positive and negative y axis.\n\t * The equator starts at positive z.\n\t */\n\n\tfunction Spherical( radius, phi, theta ) {\n\n\t\tthis.radius = ( radius !== undefined ) ? radius : 1.0;\n\t\tthis.phi = ( phi !== undefined ) ? phi : 0; // up / down towards top and bottom pole\n\t\tthis.theta = ( theta !== undefined ) ? theta : 0; // around the equator of the sphere\n\n\t\treturn this;\n\n\t}\n\n\tObject.assign( Spherical.prototype, {\n\n\t\tset: function ( radius, phi, theta ) {\n\n\t\t\tthis.radius = radius;\n\t\t\tthis.phi = phi;\n\t\t\tthis.theta = theta;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor().copy( this );\n\n\t\t},\n\n\t\tcopy: function ( other ) {\n\n\t\t\tthis.radius = other.radius;\n\t\t\tthis.phi = other.phi;\n\t\t\tthis.theta = other.theta;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\t// restrict phi to be betwee EPS and PI-EPS\n\t\tmakeSafe: function() {\n\n\t\t\tvar EPS = 0.000001;\n\t\t\tthis.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) );\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromVector3: function( vec3 ) {\n\n\t\t\tthis.radius = vec3.length();\n\n\t\t\tif ( this.radius === 0 ) {\n\n\t\t\t\tthis.theta = 0;\n\t\t\t\tthis.phi = 0;\n\n\t\t\t} else {\n\n\t\t\t\tthis.theta = Math.atan2( vec3.x, vec3.z ); // equator angle around y-up axis\n\t\t\t\tthis.phi = Math.acos( _Math.clamp( vec3.y / this.radius, - 1, 1 ) ); // polar angle\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author Mugen87 / https://github.com/Mugen87\n\t *\n\t * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system\n\t *\n\t */\n\n\tfunction Cylindrical( radius, theta, y ) {\n\n\t\tthis.radius = ( radius !== undefined ) ? radius : 1.0; // distance from the origin to a point in the x-z plane\n\t\tthis.theta = ( theta !== undefined ) ? theta : 0; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis\n\t\tthis.y = ( y !== undefined ) ? y : 0; // height above the x-z plane\n\n\t\treturn this;\n\n\t}\n\n\tObject.assign( Cylindrical.prototype, {\n\n\t\tset: function ( radius, theta, y ) {\n\n\t\t\tthis.radius = radius;\n\t\t\tthis.theta = theta;\n\t\t\tthis.y = y;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tclone: function () {\n\n\t\t\treturn new this.constructor().copy( this );\n\n\t\t},\n\n\t\tcopy: function ( other ) {\n\n\t\t\tthis.radius = other.radius;\n\t\t\tthis.theta = other.theta;\n\t\t\tthis.y = other.y;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tsetFromVector3: function( vec3 ) {\n\n\t\t\tthis.radius = Math.sqrt( vec3.x * vec3.x + vec3.z * vec3.z );\n\t\t\tthis.theta = Math.atan2( vec3.x, vec3.z );\n\t\t\tthis.y = vec3.y;\n\n\t\t\treturn this;\n\n\t\t}\n\n\t} );\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tfunction ImmediateRenderObject( material ) {\n\n\t\tObject3D.call( this );\n\n\t\tthis.material = material;\n\t\tthis.render = function ( renderCallback ) {};\n\n\t}\n\n\tImmediateRenderObject.prototype = Object.create( Object3D.prototype );\n\tImmediateRenderObject.prototype.constructor = ImmediateRenderObject;\n\n\tImmediateRenderObject.prototype.isImmediateRenderObject = true;\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author WestLangley / http://github.com/WestLangley\n\t */\n\n\tfunction VertexNormalsHelper( object, size, hex, linewidth ) {\n\n\t\tthis.object = object;\n\n\t\tthis.size = ( size !== undefined ) ? size : 1;\n\n\t\tvar color = ( hex !== undefined ) ? hex : 0xff0000;\n\n\t\tvar width = ( linewidth !== undefined ) ? linewidth : 1;\n\n\t\t//\n\n\t\tvar nNormals = 0;\n\n\t\tvar objGeometry = this.object.geometry;\n\n\t\tif ( objGeometry && objGeometry.isGeometry ) {\n\n\t\t\tnNormals = objGeometry.faces.length * 3;\n\n\t\t} else if ( objGeometry && objGeometry.isBufferGeometry ) {\n\n\t\t\tnNormals = objGeometry.attributes.normal.count;\n\n\t\t}\n\n\t\t//\n\n\t\tvar geometry = new BufferGeometry();\n\n\t\tvar positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 );\n\n\t\tgeometry.addAttribute( 'position', positions );\n\n\t\tLineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) );\n\n\t\t//\n\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.update();\n\n\t}\n\n\tVertexNormalsHelper.prototype = Object.create( LineSegments.prototype );\n\tVertexNormalsHelper.prototype.constructor = VertexNormalsHelper;\n\n\tVertexNormalsHelper.prototype.update = ( function () {\n\n\t\tvar v1 = new Vector3();\n\t\tvar v2 = new Vector3();\n\t\tvar normalMatrix = new Matrix3();\n\n\t\treturn function update() {\n\n\t\t\tvar keys = [ 'a', 'b', 'c' ];\n\n\t\t\tthis.object.updateMatrixWorld( true );\n\n\t\t\tnormalMatrix.getNormalMatrix( this.object.matrixWorld );\n\n\t\t\tvar matrixWorld = this.object.matrixWorld;\n\n\t\t\tvar position = this.geometry.attributes.position;\n\n\t\t\t//\n\n\t\t\tvar objGeometry = this.object.geometry;\n\n\t\t\tif ( objGeometry && objGeometry.isGeometry ) {\n\n\t\t\t\tvar vertices = objGeometry.vertices;\n\n\t\t\t\tvar faces = objGeometry.faces;\n\n\t\t\t\tvar idx = 0;\n\n\t\t\t\tfor ( var i = 0, l = faces.length; i < l; i ++ ) {\n\n\t\t\t\t\tvar face = faces[ i ];\n\n\t\t\t\t\tfor ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {\n\n\t\t\t\t\t\tvar vertex = vertices[ face[ keys[ j ] ] ];\n\n\t\t\t\t\t\tvar normal = face.vertexNormals[ j ];\n\n\t\t\t\t\t\tv1.copy( vertex ).applyMatrix4( matrixWorld );\n\n\t\t\t\t\t\tv2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 );\n\n\t\t\t\t\t\tposition.setXYZ( idx, v1.x, v1.y, v1.z );\n\n\t\t\t\t\t\tidx = idx + 1;\n\n\t\t\t\t\t\tposition.setXYZ( idx, v2.x, v2.y, v2.z );\n\n\t\t\t\t\t\tidx = idx + 1;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else if ( objGeometry && objGeometry.isBufferGeometry ) {\n\n\t\t\t\tvar objPos = objGeometry.attributes.position;\n\n\t\t\t\tvar objNorm = objGeometry.attributes.normal;\n\n\t\t\t\tvar idx = 0;\n\n\t\t\t\t// for simplicity, ignore index and drawcalls, and render every normal\n\n\t\t\t\tfor ( var j = 0, jl = objPos.count; j < jl; j ++ ) {\n\n\t\t\t\t\tv1.set( objPos.getX( j ), objPos.getY( j ), objPos.getZ( j ) ).applyMatrix4( matrixWorld );\n\n\t\t\t\t\tv2.set( objNorm.getX( j ), objNorm.getY( j ), objNorm.getZ( j ) );\n\n\t\t\t\t\tv2.applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 );\n\n\t\t\t\t\tposition.setXYZ( idx, v1.x, v1.y, v1.z );\n\n\t\t\t\t\tidx = idx + 1;\n\n\t\t\t\t\tposition.setXYZ( idx, v2.x, v2.y, v2.z );\n\n\t\t\t\t\tidx = idx + 1;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tposition.needsUpdate = true;\n\n\t\t};\n\n\t}() );\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author WestLangley / http://github.com/WestLangley\n\t */\n\n\tfunction SpotLightHelper( light, color ) {\n\n\t\tObject3D.call( this );\n\n\t\tthis.light = light;\n\t\tthis.light.updateMatrixWorld();\n\n\t\tthis.matrix = light.matrixWorld;\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.color = color;\n\n\t\tvar geometry = new BufferGeometry();\n\n\t\tvar positions = [\n\t\t\t0, 0, 0,   0,   0,   1,\n\t\t\t0, 0, 0,   1,   0,   1,\n\t\t\t0, 0, 0, - 1,   0,   1,\n\t\t\t0, 0, 0,   0,   1,   1,\n\t\t\t0, 0, 0,   0, - 1,   1\n\t\t];\n\n\t\tfor ( var i = 0, j = 1, l = 32; i < l; i ++, j ++ ) {\n\n\t\t\tvar p1 = ( i / l ) * Math.PI * 2;\n\t\t\tvar p2 = ( j / l ) * Math.PI * 2;\n\n\t\t\tpositions.push(\n\t\t\t\tMath.cos( p1 ), Math.sin( p1 ), 1,\n\t\t\t\tMath.cos( p2 ), Math.sin( p2 ), 1\n\t\t\t);\n\n\t\t}\n\n\t\tgeometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );\n\n\t\tvar material = new LineBasicMaterial( { fog: false } );\n\n\t\tthis.cone = new LineSegments( geometry, material );\n\t\tthis.add( this.cone );\n\n\t\tthis.update();\n\n\t}\n\n\tSpotLightHelper.prototype = Object.create( Object3D.prototype );\n\tSpotLightHelper.prototype.constructor = SpotLightHelper;\n\n\tSpotLightHelper.prototype.dispose = function () {\n\n\t\tthis.cone.geometry.dispose();\n\t\tthis.cone.material.dispose();\n\n\t};\n\n\tSpotLightHelper.prototype.update = function () {\n\n\t\tvar vector = new Vector3();\n\t\tvar vector2 = new Vector3();\n\n\t\treturn function update() {\n\n\t\t\tthis.light.updateMatrixWorld();\n\n\t\t\tvar coneLength = this.light.distance ? this.light.distance : 1000;\n\t\t\tvar coneWidth = coneLength * Math.tan( this.light.angle );\n\n\t\t\tthis.cone.scale.set( coneWidth, coneWidth, coneLength );\n\n\t\t\tvector.setFromMatrixPosition( this.light.matrixWorld );\n\t\t\tvector2.setFromMatrixPosition( this.light.target.matrixWorld );\n\n\t\t\tthis.cone.lookAt( vector2.sub( vector ) );\n\n\t\t\tif ( this.color !== undefined ) {\n\n\t\t\t\tthis.cone.material.color.set( this.color );\n\n\t\t\t} else {\n\n\t\t\t\tthis.cone.material.color.copy( this.light.color );\n\n\t\t\t}\n\n\t\t};\n\n\t}();\n\n\t/**\n\t * @author Sean Griffin / http://twitter.com/sgrif\n\t * @author Michael Guerrero / http://realitymeltdown.com\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author ikerr / http://verold.com\n\t * @author Mugen87 / https://github.com/Mugen87\n\t */\n\n\tfunction getBoneList( object ) {\n\n\t\tvar boneList = [];\n\n\t\tif ( object && object.isBone ) {\n\n\t\t\tboneList.push( object );\n\n\t\t}\n\n\t\tfor ( var i = 0; i < object.children.length; i ++ ) {\n\n\t\t\tboneList.push.apply( boneList, getBoneList( object.children[ i ] ) );\n\n\t\t}\n\n\t\treturn boneList;\n\n\t}\n\n\tfunction SkeletonHelper( object ) {\n\n\t\tvar bones = getBoneList( object );\n\n\t\tvar geometry = new BufferGeometry();\n\n\t\tvar vertices = [];\n\t\tvar colors = [];\n\n\t\tvar color1 = new Color( 0, 0, 1 );\n\t\tvar color2 = new Color( 0, 1, 0 );\n\n\t\tfor ( var i = 0; i < bones.length; i ++ ) {\n\n\t\t\tvar bone = bones[ i ];\n\n\t\t\tif ( bone.parent && bone.parent.isBone ) {\n\n\t\t\t\tvertices.push( 0, 0, 0 );\n\t\t\t\tvertices.push( 0, 0, 0 );\n\t\t\t\tcolors.push( color1.r, color1.g, color1.b );\n\t\t\t\tcolors.push( color2.r, color2.g, color2.b );\n\n\t\t\t}\n\n\t\t}\n\n\t\tgeometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tgeometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\t\tvar material = new LineBasicMaterial( { vertexColors: VertexColors, depthTest: false, depthWrite: false, transparent: true } );\n\n\t\tLineSegments.call( this, geometry, material );\n\n\t\tthis.root = object;\n\t\tthis.bones = bones;\n\n\t\tthis.matrix = object.matrixWorld;\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.onBeforeRender();\n\n\t}\n\n\tSkeletonHelper.prototype = Object.create( LineSegments.prototype );\n\tSkeletonHelper.prototype.constructor = SkeletonHelper;\n\n\tSkeletonHelper.prototype.onBeforeRender = function () {\n\n\t\tvar vector = new Vector3();\n\n\t\tvar boneMatrix = new Matrix4();\n\t\tvar matrixWorldInv = new Matrix4();\n\n\t\treturn function onBeforeRender() {\n\n\t\t\tvar bones = this.bones;\n\n\t\t\tvar geometry = this.geometry;\n\t\t\tvar position = geometry.getAttribute( 'position' );\n\n\t\t\tmatrixWorldInv.getInverse( this.root.matrixWorld );\n\n\t\t\tfor ( var i = 0, j = 0; i < bones.length; i ++ ) {\n\n\t\t\t\tvar bone = bones[ i ];\n\n\t\t\t\tif ( bone.parent && bone.parent.isBone ) {\n\n\t\t\t\t\tboneMatrix.multiplyMatrices( matrixWorldInv, bone.matrixWorld );\n\t\t\t\t\tvector.setFromMatrixPosition( boneMatrix );\n\t\t\t\t\tposition.setXYZ( j, vector.x, vector.y, vector.z );\n\n\t\t\t\t\tboneMatrix.multiplyMatrices( matrixWorldInv, bone.parent.matrixWorld );\n\t\t\t\t\tvector.setFromMatrixPosition( boneMatrix );\n\t\t\t\t\tposition.setXYZ( j + 1, vector.x, vector.y, vector.z );\n\n\t\t\t\t\tj += 2;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tgeometry.getAttribute( 'position' ).needsUpdate = true;\n\n\t\t};\n\n\t}();\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction PointLightHelper( light, sphereSize, color ) {\n\n\t\tthis.light = light;\n\t\tthis.light.updateMatrixWorld();\n\n\t\tthis.color = color;\n\n\t\tvar geometry = new SphereBufferGeometry( sphereSize, 4, 2 );\n\t\tvar material = new MeshBasicMaterial( { wireframe: true, fog: false } );\n\n\t\tMesh.call( this, geometry, material );\n\n\t\tthis.matrix = this.light.matrixWorld;\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.update();\n\n\n\t\t/*\n\t\tvar distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 );\n\t\tvar distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } );\n\n\t\tthis.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial );\n\t\tthis.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial );\n\n\t\tvar d = light.distance;\n\n\t\tif ( d === 0.0 ) {\n\n\t\t\tthis.lightDistance.visible = false;\n\n\t\t} else {\n\n\t\t\tthis.lightDistance.scale.set( d, d, d );\n\n\t\t}\n\n\t\tthis.add( this.lightDistance );\n\t\t*/\n\n\t}\n\n\tPointLightHelper.prototype = Object.create( Mesh.prototype );\n\tPointLightHelper.prototype.constructor = PointLightHelper;\n\n\tPointLightHelper.prototype.dispose = function () {\n\n\t\tthis.geometry.dispose();\n\t\tthis.material.dispose();\n\n\t};\n\n\tPointLightHelper.prototype.update = function () {\n\n\t\tif ( this.color !== undefined ) {\n\n\t\t\tthis.material.color.set( this.color );\n\n\t\t} else {\n\n\t\t\tthis.material.color.copy( this.light.color );\n\n\t\t}\n\n\t\t/*\n\t\tvar d = this.light.distance;\n\n\t\tif ( d === 0.0 ) {\n\n\t\t\tthis.lightDistance.visible = false;\n\n\t\t} else {\n\n\t\t\tthis.lightDistance.visible = true;\n\t\t\tthis.lightDistance.scale.set( d, d, d );\n\n\t\t}\n\t\t*/\n\n\t};\n\n\t/**\n\t * @author abelnation / http://github.com/abelnation\n\t * @author Mugen87 / http://github.com/Mugen87\n\t * @author WestLangley / http://github.com/WestLangley\n\t */\n\n\tfunction RectAreaLightHelper( light, color ) {\n\n\t\tObject3D.call( this );\n\n\t\tthis.light = light;\n\t\tthis.light.updateMatrixWorld();\n\n\t\tthis.matrix = light.matrixWorld;\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.color = color;\n\n\t\tvar material = new LineBasicMaterial( { fog: false } );\n\n\t\tvar geometry = new BufferGeometry();\n\n\t\tgeometry.addAttribute( 'position', new BufferAttribute( new Float32Array( 5 * 3 ), 3 ) );\n\n\t\tthis.line = new Line( geometry, material );\n\t\tthis.add( this.line );\n\n\n\t\tthis.update();\n\n\t}\n\n\tRectAreaLightHelper.prototype = Object.create( Object3D.prototype );\n\tRectAreaLightHelper.prototype.constructor = RectAreaLightHelper;\n\n\tRectAreaLightHelper.prototype.dispose = function () {\n\n\t\tthis.children[ 0 ].geometry.dispose();\n\t\tthis.children[ 0 ].material.dispose();\n\n\t};\n\n\tRectAreaLightHelper.prototype.update = function () {\n\n\t\t// calculate new dimensions of the helper\n\n\t\tvar hx = this.light.width * 0.5;\n\t\tvar hy = this.light.height * 0.5;\n\n\t\tvar position = this.line.geometry.attributes.position;\n\t\tvar array = position.array;\n\n\t\t// update vertices\n\n\t\tarray[  0 ] =   hx; array[  1 ] = - hy; array[  2 ] = 0;\n\t\tarray[  3 ] =   hx; array[  4 ] =   hy; array[  5 ] = 0;\n\t\tarray[  6 ] = - hx; array[  7 ] =   hy; array[  8 ] = 0;\n\t\tarray[  9 ] = - hx; array[ 10 ] = - hy; array[ 11 ] = 0;\n\t\tarray[ 12 ] =   hx; array[ 13 ] = - hy; array[ 14 ] = 0;\n\n\t\tposition.needsUpdate = true;\n\n\t\tif ( this.color !== undefined ) {\n\n\t\t\tthis.line.material.color.set( this.color );\n\n\t\t} else {\n\n\t\t\tthis.line.material.color.copy( this.light.color );\n\n\t\t}\n\n\t};\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author Mugen87 / https://github.com/Mugen87\n\t */\n\n\tfunction HemisphereLightHelper( light, size, color ) {\n\n\t\tObject3D.call( this );\n\n\t\tthis.light = light;\n\t\tthis.light.updateMatrixWorld();\n\n\t\tthis.matrix = light.matrixWorld;\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.color = color;\n\n\t\tvar geometry = new OctahedronBufferGeometry( size );\n\t\tgeometry.rotateY( Math.PI * 0.5 );\n\n\t\tthis.material = new MeshBasicMaterial( { wireframe: true, fog: false } );\n\t\tif ( this.color === undefined ) this.material.vertexColors = VertexColors;\n\n\t\tvar position = geometry.getAttribute( 'position' );\n\t\tvar colors = new Float32Array( position.count * 3 );\n\n\t\tgeometry.addAttribute( 'color', new BufferAttribute( colors, 3 ) );\n\n\t\tthis.add( new Mesh( geometry, this.material ) );\n\n\t\tthis.update();\n\n\t}\n\n\tHemisphereLightHelper.prototype = Object.create( Object3D.prototype );\n\tHemisphereLightHelper.prototype.constructor = HemisphereLightHelper;\n\n\tHemisphereLightHelper.prototype.dispose = function () {\n\n\t\tthis.children[ 0 ].geometry.dispose();\n\t\tthis.children[ 0 ].material.dispose();\n\n\t};\n\n\tHemisphereLightHelper.prototype.update = function () {\n\n\t\tvar vector = new Vector3();\n\n\t\tvar color1 = new Color();\n\t\tvar color2 = new Color();\n\n\t\treturn function update() {\n\n\t\t\tvar mesh = this.children[ 0 ];\n\n\t\t\tif ( this.color !== undefined ) {\n\n\t\t\t\tthis.material.color.set( this.color );\n\n\t\t\t} else {\n\n\t\t\t\tvar colors = mesh.geometry.getAttribute( 'color' );\n\n\t\t\t\tcolor1.copy( this.light.color );\n\t\t\t\tcolor2.copy( this.light.groundColor );\n\n\t\t\t\tfor ( var i = 0, l = colors.count; i < l; i ++ ) {\n\n\t\t\t\t\tvar color = ( i < ( l / 2 ) ) ? color1 : color2;\n\n\t\t\t\t\tcolors.setXYZ( i, color.r, color.g, color.b );\n\n\t\t\t\t}\n\n\t\t\t\tcolors.needsUpdate = true;\n\n\t\t\t}\n\n\t\t\tmesh.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() );\n\n\t\t};\n\n\t}();\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction GridHelper( size, divisions, color1, color2 ) {\n\n\t\tsize = size || 10;\n\t\tdivisions = divisions || 10;\n\t\tcolor1 = new Color( color1 !== undefined ? color1 : 0x444444 );\n\t\tcolor2 = new Color( color2 !== undefined ? color2 : 0x888888 );\n\n\t\tvar center = divisions / 2;\n\t\tvar step = size / divisions;\n\t\tvar halfSize = size / 2;\n\n\t\tvar vertices = [], colors = [];\n\n\t\tfor ( var i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) {\n\n\t\t\tvertices.push( - halfSize, 0, k, halfSize, 0, k );\n\t\t\tvertices.push( k, 0, - halfSize, k, 0, halfSize );\n\n\t\t\tvar color = i === center ? color1 : color2;\n\n\t\t\tcolor.toArray( colors, j ); j += 3;\n\t\t\tcolor.toArray( colors, j ); j += 3;\n\t\t\tcolor.toArray( colors, j ); j += 3;\n\t\t\tcolor.toArray( colors, j ); j += 3;\n\n\t\t}\n\n\t\tvar geometry = new BufferGeometry();\n\t\tgeometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tgeometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\t\tvar material = new LineBasicMaterial( { vertexColors: VertexColors } );\n\n\t\tLineSegments.call( this, geometry, material );\n\n\t}\n\n\tGridHelper.prototype = Object.create( LineSegments.prototype );\n\tGridHelper.prototype.constructor = GridHelper;\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author Mugen87 / http://github.com/Mugen87\n\t * @author Hectate / http://www.github.com/Hectate\n\t */\n\n\tfunction PolarGridHelper( radius, radials, circles, divisions, color1, color2 ) {\n\n\t\tradius = radius || 10;\n\t\tradials = radials || 16;\n\t\tcircles = circles || 8;\n\t\tdivisions = divisions || 64;\n\t\tcolor1 = new Color( color1 !== undefined ? color1 : 0x444444 );\n\t\tcolor2 = new Color( color2 !== undefined ? color2 : 0x888888 );\n\n\t\tvar vertices = [];\n\t\tvar colors = [];\n\n\t\tvar x, z;\n\t\tvar v, i, j, r, color;\n\n\t\t// create the radials\n\n\t\tfor ( i = 0; i <= radials; i ++ ) {\n\n\t\t\tv = ( i / radials ) * ( Math.PI * 2 );\n\n\t\t\tx = Math.sin( v ) * radius;\n\t\t\tz = Math.cos( v ) * radius;\n\n\t\t\tvertices.push( 0, 0, 0 );\n\t\t\tvertices.push( x, 0, z );\n\n\t\t\tcolor = ( i & 1 ) ? color1 : color2;\n\n\t\t\tcolors.push( color.r, color.g, color.b );\n\t\t\tcolors.push( color.r, color.g, color.b );\n\n\t\t}\n\n\t\t// create the circles\n\n\t\tfor ( i = 0; i <= circles; i ++ ) {\n\n\t\t\tcolor = ( i & 1 ) ? color1 : color2;\n\n\t\t\tr = radius - ( radius / circles * i );\n\n\t\t\tfor ( j = 0; j < divisions; j ++ ) {\n\n\t\t\t\t// first vertex\n\n\t\t\t\tv = ( j / divisions ) * ( Math.PI * 2 );\n\n\t\t\t\tx = Math.sin( v ) * r;\n\t\t\t\tz = Math.cos( v ) * r;\n\n\t\t\t\tvertices.push( x, 0, z );\n\t\t\t\tcolors.push( color.r, color.g, color.b );\n\n\t\t\t\t// second vertex\n\n\t\t\t\tv = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 );\n\n\t\t\t\tx = Math.sin( v ) * r;\n\t\t\t\tz = Math.cos( v ) * r;\n\n\t\t\t\tvertices.push( x, 0, z );\n\t\t\t\tcolors.push( color.r, color.g, color.b );\n\n\t\t\t}\n\n\t\t}\n\n\t\tvar geometry = new BufferGeometry();\n\t\tgeometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tgeometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\t\tvar material = new LineBasicMaterial( { vertexColors: VertexColors } );\n\n\t\tLineSegments.call( this, geometry, material );\n\n\t}\n\n\tPolarGridHelper.prototype = Object.create( LineSegments.prototype );\n\tPolarGridHelper.prototype.constructor = PolarGridHelper;\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author WestLangley / http://github.com/WestLangley\n\t */\n\n\tfunction FaceNormalsHelper( object, size, hex, linewidth ) {\n\n\t\t// FaceNormalsHelper only supports THREE.Geometry\n\n\t\tthis.object = object;\n\n\t\tthis.size = ( size !== undefined ) ? size : 1;\n\n\t\tvar color = ( hex !== undefined ) ? hex : 0xffff00;\n\n\t\tvar width = ( linewidth !== undefined ) ? linewidth : 1;\n\n\t\t//\n\n\t\tvar nNormals = 0;\n\n\t\tvar objGeometry = this.object.geometry;\n\n\t\tif ( objGeometry && objGeometry.isGeometry ) {\n\n\t\t\tnNormals = objGeometry.faces.length;\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'THREE.FaceNormalsHelper: only THREE.Geometry is supported. Use THREE.VertexNormalsHelper, instead.' );\n\n\t\t}\n\n\t\t//\n\n\t\tvar geometry = new BufferGeometry();\n\n\t\tvar positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 );\n\n\t\tgeometry.addAttribute( 'position', positions );\n\n\t\tLineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) );\n\n\t\t//\n\n\t\tthis.matrixAutoUpdate = false;\n\t\tthis.update();\n\n\t}\n\n\tFaceNormalsHelper.prototype = Object.create( LineSegments.prototype );\n\tFaceNormalsHelper.prototype.constructor = FaceNormalsHelper;\n\n\tFaceNormalsHelper.prototype.update = ( function () {\n\n\t\tvar v1 = new Vector3();\n\t\tvar v2 = new Vector3();\n\t\tvar normalMatrix = new Matrix3();\n\n\t\treturn function update() {\n\n\t\t\tthis.object.updateMatrixWorld( true );\n\n\t\t\tnormalMatrix.getNormalMatrix( this.object.matrixWorld );\n\n\t\t\tvar matrixWorld = this.object.matrixWorld;\n\n\t\t\tvar position = this.geometry.attributes.position;\n\n\t\t\t//\n\n\t\t\tvar objGeometry = this.object.geometry;\n\n\t\t\tvar vertices = objGeometry.vertices;\n\n\t\t\tvar faces = objGeometry.faces;\n\n\t\t\tvar idx = 0;\n\n\t\t\tfor ( var i = 0, l = faces.length; i < l; i ++ ) {\n\n\t\t\t\tvar face = faces[ i ];\n\n\t\t\t\tvar normal = face.normal;\n\n\t\t\t\tv1.copy( vertices[ face.a ] )\n\t\t\t\t\t.add( vertices[ face.b ] )\n\t\t\t\t\t.add( vertices[ face.c ] )\n\t\t\t\t\t.divideScalar( 3 )\n\t\t\t\t\t.applyMatrix4( matrixWorld );\n\n\t\t\t\tv2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 );\n\n\t\t\t\tposition.setXYZ( idx, v1.x, v1.y, v1.z );\n\n\t\t\t\tidx = idx + 1;\n\n\t\t\t\tposition.setXYZ( idx, v2.x, v2.y, v2.z );\n\n\t\t\t\tidx = idx + 1;\n\n\t\t\t}\n\n\t\t\tposition.needsUpdate = true;\n\n\t\t};\n\n\t}() );\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author WestLangley / http://github.com/WestLangley\n\t */\n\n\tfunction DirectionalLightHelper( light, size, color ) {\n\n\t\tObject3D.call( this );\n\n\t\tthis.light = light;\n\t\tthis.light.updateMatrixWorld();\n\n\t\tthis.matrix = light.matrixWorld;\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.color = color;\n\n\t\tif ( size === undefined ) size = 1;\n\n\t\tvar geometry = new BufferGeometry();\n\t\tgeometry.addAttribute( 'position', new Float32BufferAttribute( [\n\t\t\t- size,   size, 0,\n\t\t\t  size,   size, 0,\n\t\t\t  size, - size, 0,\n\t\t\t- size, - size, 0,\n\t\t\t- size,   size, 0\n\t\t], 3 ) );\n\n\t\tvar material = new LineBasicMaterial( { fog: false } );\n\n\t\tthis.lightPlane = new Line( geometry, material );\n\t\tthis.add( this.lightPlane );\n\n\t\tgeometry = new BufferGeometry();\n\t\tgeometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) );\n\n\t\tthis.targetLine = new Line( geometry, material );\n\t\tthis.add( this.targetLine );\n\n\t\tthis.update();\n\n\t}\n\n\tDirectionalLightHelper.prototype = Object.create( Object3D.prototype );\n\tDirectionalLightHelper.prototype.constructor = DirectionalLightHelper;\n\n\tDirectionalLightHelper.prototype.dispose = function () {\n\n\t\tthis.lightPlane.geometry.dispose();\n\t\tthis.lightPlane.material.dispose();\n\t\tthis.targetLine.geometry.dispose();\n\t\tthis.targetLine.material.dispose();\n\n\t};\n\n\tDirectionalLightHelper.prototype.update = function () {\n\n\t\tvar v1 = new Vector3();\n\t\tvar v2 = new Vector3();\n\t\tvar v3 = new Vector3();\n\n\t\treturn function update() {\n\n\t\t\tv1.setFromMatrixPosition( this.light.matrixWorld );\n\t\t\tv2.setFromMatrixPosition( this.light.target.matrixWorld );\n\t\t\tv3.subVectors( v2, v1 );\n\n\t\t\tthis.lightPlane.lookAt( v3 );\n\n\t\t\tif ( this.color !== undefined ) {\n\n\t\t\t\tthis.lightPlane.material.color.set( this.color );\n\t\t\t\tthis.targetLine.material.color.set( this.color );\n\n\t\t\t} else {\n\n\t\t\t\tthis.lightPlane.material.color.copy( this.light.color );\n\t\t\t\tthis.targetLine.material.color.copy( this.light.color );\n\n\t\t\t}\n\n\t\t\tthis.targetLine.lookAt( v3 );\n\t\t\tthis.targetLine.scale.z = v3.length();\n\n\t\t};\n\n\t}();\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t * @author Mugen87 / https://github.com/Mugen87\n\t *\n\t *\t- shows frustum, line of sight and up of the camera\n\t *\t- suitable for fast updates\n\t * \t- based on frustum visualization in lightgl.js shadowmap example\n\t *\t\thttp://evanw.github.com/lightgl.js/tests/shadowmap.html\n\t */\n\n\tfunction CameraHelper( camera ) {\n\n\t\tvar geometry = new BufferGeometry();\n\t\tvar material = new LineBasicMaterial( { color: 0xffffff, vertexColors: FaceColors } );\n\n\t\tvar vertices = [];\n\t\tvar colors = [];\n\n\t\tvar pointMap = {};\n\n\t\t// colors\n\n\t\tvar colorFrustum = new Color( 0xffaa00 );\n\t\tvar colorCone = new Color( 0xff0000 );\n\t\tvar colorUp = new Color( 0x00aaff );\n\t\tvar colorTarget = new Color( 0xffffff );\n\t\tvar colorCross = new Color( 0x333333 );\n\n\t\t// near\n\n\t\taddLine( \"n1\", \"n2\", colorFrustum );\n\t\taddLine( \"n2\", \"n4\", colorFrustum );\n\t\taddLine( \"n4\", \"n3\", colorFrustum );\n\t\taddLine( \"n3\", \"n1\", colorFrustum );\n\n\t\t// far\n\n\t\taddLine( \"f1\", \"f2\", colorFrustum );\n\t\taddLine( \"f2\", \"f4\", colorFrustum );\n\t\taddLine( \"f4\", \"f3\", colorFrustum );\n\t\taddLine( \"f3\", \"f1\", colorFrustum );\n\n\t\t// sides\n\n\t\taddLine( \"n1\", \"f1\", colorFrustum );\n\t\taddLine( \"n2\", \"f2\", colorFrustum );\n\t\taddLine( \"n3\", \"f3\", colorFrustum );\n\t\taddLine( \"n4\", \"f4\", colorFrustum );\n\n\t\t// cone\n\n\t\taddLine( \"p\", \"n1\", colorCone );\n\t\taddLine( \"p\", \"n2\", colorCone );\n\t\taddLine( \"p\", \"n3\", colorCone );\n\t\taddLine( \"p\", \"n4\", colorCone );\n\n\t\t// up\n\n\t\taddLine( \"u1\", \"u2\", colorUp );\n\t\taddLine( \"u2\", \"u3\", colorUp );\n\t\taddLine( \"u3\", \"u1\", colorUp );\n\n\t\t// target\n\n\t\taddLine( \"c\", \"t\", colorTarget );\n\t\taddLine( \"p\", \"c\", colorCross );\n\n\t\t// cross\n\n\t\taddLine( \"cn1\", \"cn2\", colorCross );\n\t\taddLine( \"cn3\", \"cn4\", colorCross );\n\n\t\taddLine( \"cf1\", \"cf2\", colorCross );\n\t\taddLine( \"cf3\", \"cf4\", colorCross );\n\n\t\tfunction addLine( a, b, color ) {\n\n\t\t\taddPoint( a, color );\n\t\t\taddPoint( b, color );\n\n\t\t}\n\n\t\tfunction addPoint( id, color ) {\n\n\t\t\tvertices.push( 0, 0, 0 );\n\t\t\tcolors.push( color.r, color.g, color.b );\n\n\t\t\tif ( pointMap[ id ] === undefined ) {\n\n\t\t\t\tpointMap[ id ] = [];\n\n\t\t\t}\n\n\t\t\tpointMap[ id ].push( ( vertices.length / 3 ) - 1 );\n\n\t\t}\n\n\t\tgeometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tgeometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\t\tLineSegments.call( this, geometry, material );\n\n\t\tthis.camera = camera;\n\t\tif ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix();\n\n\t\tthis.matrix = camera.matrixWorld;\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.pointMap = pointMap;\n\n\t\tthis.update();\n\n\t}\n\n\tCameraHelper.prototype = Object.create( LineSegments.prototype );\n\tCameraHelper.prototype.constructor = CameraHelper;\n\n\tCameraHelper.prototype.update = function () {\n\n\t\tvar geometry, pointMap;\n\n\t\tvar vector = new Vector3();\n\t\tvar camera = new Camera();\n\n\t\tfunction setPoint( point, x, y, z ) {\n\n\t\t\tvector.set( x, y, z ).unproject( camera );\n\n\t\t\tvar points = pointMap[ point ];\n\n\t\t\tif ( points !== undefined ) {\n\n\t\t\t\tvar position = geometry.getAttribute( 'position' );\n\n\t\t\t\tfor ( var i = 0, l = points.length; i < l; i ++ ) {\n\n\t\t\t\t\tposition.setXYZ( points[ i ], vector.x, vector.y, vector.z );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn function update() {\n\n\t\t\tgeometry = this.geometry;\n\t\t\tpointMap = this.pointMap;\n\n\t\t\tvar w = 1, h = 1;\n\n\t\t\t// we need just camera projection matrix\n\t\t\t// world matrix must be identity\n\n\t\t\tcamera.projectionMatrix.copy( this.camera.projectionMatrix );\n\n\t\t\t// center / target\n\n\t\t\tsetPoint( \"c\", 0, 0, - 1 );\n\t\t\tsetPoint( \"t\", 0, 0,  1 );\n\n\t\t\t// near\n\n\t\t\tsetPoint( \"n1\", - w, - h, - 1 );\n\t\t\tsetPoint( \"n2\",   w, - h, - 1 );\n\t\t\tsetPoint( \"n3\", - w,   h, - 1 );\n\t\t\tsetPoint( \"n4\",   w,   h, - 1 );\n\n\t\t\t// far\n\n\t\t\tsetPoint( \"f1\", - w, - h, 1 );\n\t\t\tsetPoint( \"f2\",   w, - h, 1 );\n\t\t\tsetPoint( \"f3\", - w,   h, 1 );\n\t\t\tsetPoint( \"f4\",   w,   h, 1 );\n\n\t\t\t// up\n\n\t\t\tsetPoint( \"u1\",   w * 0.7, h * 1.1, - 1 );\n\t\t\tsetPoint( \"u2\", - w * 0.7, h * 1.1, - 1 );\n\t\t\tsetPoint( \"u3\",         0, h * 2,   - 1 );\n\n\t\t\t// cross\n\n\t\t\tsetPoint( \"cf1\", - w,   0, 1 );\n\t\t\tsetPoint( \"cf2\",   w,   0, 1 );\n\t\t\tsetPoint( \"cf3\",   0, - h, 1 );\n\t\t\tsetPoint( \"cf4\",   0,   h, 1 );\n\n\t\t\tsetPoint( \"cn1\", - w,   0, - 1 );\n\t\t\tsetPoint( \"cn2\",   w,   0, - 1 );\n\t\t\tsetPoint( \"cn3\",   0, - h, - 1 );\n\t\t\tsetPoint( \"cn4\",   0,   h, - 1 );\n\n\t\t\tgeometry.getAttribute( 'position' ).needsUpdate = true;\n\n\t\t};\n\n\t}();\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t * @author Mugen87 / http://github.com/Mugen87\n\t */\n\n\tfunction BoxHelper( object, color ) {\n\n\t\tthis.object = object;\n\n\t\tif ( color === undefined ) color = 0xffff00;\n\n\t\tvar indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] );\n\t\tvar positions = new Float32Array( 8 * 3 );\n\n\t\tvar geometry = new BufferGeometry();\n\t\tgeometry.setIndex( new BufferAttribute( indices, 1 ) );\n\t\tgeometry.addAttribute( 'position', new BufferAttribute( positions, 3 ) );\n\n\t\tLineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) );\n\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.update();\n\n\t}\n\n\tBoxHelper.prototype = Object.create( LineSegments.prototype );\n\tBoxHelper.prototype.constructor = BoxHelper;\n\n\tBoxHelper.prototype.update = ( function () {\n\n\t\tvar box = new Box3();\n\n\t\treturn function update( object ) {\n\n\t\t\tif ( object !== undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.BoxHelper: .update() has no longer arguments.' );\n\n\t\t\t}\n\n\t\t\tif ( this.object !== undefined ) {\n\n\t\t\t\tbox.setFromObject( this.object );\n\n\t\t\t}\n\n\t\t\tif ( box.isEmpty() ) return;\n\n\t\t\tvar min = box.min;\n\t\t\tvar max = box.max;\n\n\t\t\t/*\n\t\t\t  5____4\n\t\t\t1/___0/|\n\t\t\t| 6__|_7\n\t\t\t2/___3/\n\n\t\t\t0: max.x, max.y, max.z\n\t\t\t1: min.x, max.y, max.z\n\t\t\t2: min.x, min.y, max.z\n\t\t\t3: max.x, min.y, max.z\n\t\t\t4: max.x, max.y, min.z\n\t\t\t5: min.x, max.y, min.z\n\t\t\t6: min.x, min.y, min.z\n\t\t\t7: max.x, min.y, min.z\n\t\t\t*/\n\n\t\t\tvar position = this.geometry.attributes.position;\n\t\t\tvar array = position.array;\n\n\t\t\tarray[  0 ] = max.x; array[  1 ] = max.y; array[  2 ] = max.z;\n\t\t\tarray[  3 ] = min.x; array[  4 ] = max.y; array[  5 ] = max.z;\n\t\t\tarray[  6 ] = min.x; array[  7 ] = min.y; array[  8 ] = max.z;\n\t\t\tarray[  9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z;\n\t\t\tarray[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z;\n\t\t\tarray[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z;\n\t\t\tarray[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z;\n\t\t\tarray[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z;\n\n\t\t\tposition.needsUpdate = true;\n\n\t\t\tthis.geometry.computeBoundingSphere();\n\n\t\t};\n\n\t} )();\n\n\tBoxHelper.prototype.setFromObject = function ( object ) {\n\n\t\tthis.object = object;\n\t\tthis.update();\n\n\t\treturn this;\n\n\t};\n\n\t/**\n\t * @author WestLangley / http://github.com/WestLangley\n\t */\n\n\tfunction Box3Helper( box, hex ) {\n\n\t\tthis.type = 'Box3Helper';\n\n\t\tthis.box = box;\n\n\t\tvar color = ( hex !== undefined ) ? hex : 0xffff00;\n\n\t\tvar indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] );\n\n\t\tvar positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ];\n\n\t\tvar geometry = new BufferGeometry();\n\n\t\tgeometry.setIndex( new BufferAttribute( indices, 1 ) );\n\n\t\tgeometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );\n\n\t\tLineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) );\n\n\t\tthis.geometry.computeBoundingSphere();\n\n\t\tthis.onBeforeRender();\n\n\t}\n\n\tBox3Helper.prototype = Object.create( LineSegments.prototype );\n\tBox3Helper.prototype.constructor = Box3Helper;\n\n\tBox3Helper.prototype.onBeforeRender = function () {\n\n\t\tvar box = this.box;\n\n\t\tif ( box.isEmpty() ) return;\n\n\t\tbox.getCenter( this.position );\n\n\t\tbox.getSize( this.scale );\n\n\t\tthis.scale.multiplyScalar( 0.5 );\n\n\t};\n\n\t/**\n\t * @author WestLangley / http://github.com/WestLangley\n\t */\n\n\tfunction PlaneHelper( plane, size, hex ) {\n\n\t\tthis.type = 'PlaneHelper';\n\n\t\tthis.plane = plane;\n\n\t\tthis.size = ( size === undefined ) ? 1 : size;\n\n\t\tvar color = ( hex !== undefined ) ? hex : 0xffff00;\n\n\t\tvar positions = [ 1, - 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0 ];\n\n\t\tvar geometry = new BufferGeometry();\n\t\tgeometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );\n\t\tgeometry.computeBoundingSphere();\n\n\t\tLine.call( this, geometry, new LineBasicMaterial( { color: color } ) );\n\n\t\t//\n\n\t\tvar positions2 = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, 1, 1, - 1, - 1, 1, 1, - 1, 1 ];\n\n\t\tvar geometry2 = new BufferGeometry();\n\t\tgeometry2.addAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) );\n\t\tgeometry2.computeBoundingSphere();\n\n\t\tthis.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false } ) ) );\n\n\t\t//\n\n\t\tthis.onBeforeRender();\n\n\t}\n\n\tPlaneHelper.prototype = Object.create( Line.prototype );\n\tPlaneHelper.prototype.constructor = PlaneHelper;\n\n\tPlaneHelper.prototype.onBeforeRender = function () {\n\n\t\tvar scale = - this.plane.constant;\n\n\t\tif ( Math.abs( scale ) < 1e-8 ) scale = 1e-8; // sign does not matter\n\n\t\tthis.scale.set( 0.5 * this.size, 0.5 * this.size, scale );\n\n\t\tthis.lookAt( this.plane.normal );\n\n\t\tthis.updateMatrixWorld();\n\n\t};\n\n\t/**\n\t * @author WestLangley / http://github.com/WestLangley\n\t * @author zz85 / http://github.com/zz85\n\t * @author bhouston / http://clara.io\n\t *\n\t * Creates an arrow for visualizing directions\n\t *\n\t * Parameters:\n\t *  dir - Vector3\n\t *  origin - Vector3\n\t *  length - Number\n\t *  color - color in hex value\n\t *  headLength - Number\n\t *  headWidth - Number\n\t */\n\n\tvar lineGeometry;\n\tvar coneGeometry;\n\n\tfunction ArrowHelper( dir, origin, length, color, headLength, headWidth ) {\n\n\t\t// dir is assumed to be normalized\n\n\t\tObject3D.call( this );\n\n\t\tif ( color === undefined ) color = 0xffff00;\n\t\tif ( length === undefined ) length = 1;\n\t\tif ( headLength === undefined ) headLength = 0.2 * length;\n\t\tif ( headWidth === undefined ) headWidth = 0.2 * headLength;\n\n\t\tif ( lineGeometry === undefined ) {\n\n\t\t\tlineGeometry = new BufferGeometry();\n\t\t\tlineGeometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );\n\n\t\t\tconeGeometry = new CylinderBufferGeometry( 0, 0.5, 1, 5, 1 );\n\t\t\tconeGeometry.translate( 0, - 0.5, 0 );\n\n\t\t}\n\n\t\tthis.position.copy( origin );\n\n\t\tthis.line = new Line( lineGeometry, new LineBasicMaterial( { color: color } ) );\n\t\tthis.line.matrixAutoUpdate = false;\n\t\tthis.add( this.line );\n\n\t\tthis.cone = new Mesh( coneGeometry, new MeshBasicMaterial( { color: color } ) );\n\t\tthis.cone.matrixAutoUpdate = false;\n\t\tthis.add( this.cone );\n\n\t\tthis.setDirection( dir );\n\t\tthis.setLength( length, headLength, headWidth );\n\n\t}\n\n\tArrowHelper.prototype = Object.create( Object3D.prototype );\n\tArrowHelper.prototype.constructor = ArrowHelper;\n\n\tArrowHelper.prototype.setDirection = ( function () {\n\n\t\tvar axis = new Vector3();\n\t\tvar radians;\n\n\t\treturn function setDirection( dir ) {\n\n\t\t\t// dir is assumed to be normalized\n\n\t\t\tif ( dir.y > 0.99999 ) {\n\n\t\t\t\tthis.quaternion.set( 0, 0, 0, 1 );\n\n\t\t\t} else if ( dir.y < - 0.99999 ) {\n\n\t\t\t\tthis.quaternion.set( 1, 0, 0, 0 );\n\n\t\t\t} else {\n\n\t\t\t\taxis.set( dir.z, 0, - dir.x ).normalize();\n\n\t\t\t\tradians = Math.acos( dir.y );\n\n\t\t\t\tthis.quaternion.setFromAxisAngle( axis, radians );\n\n\t\t\t}\n\n\t\t};\n\n\t}() );\n\n\tArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) {\n\n\t\tif ( headLength === undefined ) headLength = 0.2 * length;\n\t\tif ( headWidth === undefined ) headWidth = 0.2 * headLength;\n\n\t\tthis.line.scale.set( 1, Math.max( 0, length - headLength ), 1 );\n\t\tthis.line.updateMatrix();\n\n\t\tthis.cone.scale.set( headWidth, headLength, headWidth );\n\t\tthis.cone.position.y = length;\n\t\tthis.cone.updateMatrix();\n\n\t};\n\n\tArrowHelper.prototype.setColor = function ( color ) {\n\n\t\tthis.line.material.color.copy( color );\n\t\tthis.cone.material.color.copy( color );\n\n\t};\n\n\t/**\n\t * @author sroucheray / http://sroucheray.org/\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction AxisHelper( size ) {\n\n\t\tsize = size || 1;\n\n\t\tvar vertices = [\n\t\t\t0, 0, 0,  size, 0, 0,\n\t\t\t0, 0, 0,  0, size, 0,\n\t\t\t0, 0, 0,  0, 0, size\n\t\t];\n\n\t\tvar colors = [\n\t\t\t1, 0, 0,  1, 0.6, 0,\n\t\t\t0, 1, 0,  0.6, 1, 0,\n\t\t\t0, 0, 1,  0, 0.6, 1\n\t\t];\n\n\t\tvar geometry = new BufferGeometry();\n\t\tgeometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tgeometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\t\tvar material = new LineBasicMaterial( { vertexColors: VertexColors } );\n\n\t\tLineSegments.call( this, geometry, material );\n\n\t}\n\n\tAxisHelper.prototype = Object.create( LineSegments.prototype );\n\tAxisHelper.prototype.constructor = AxisHelper;\n\n\t/**\n\t * @author zz85 https://github.com/zz85\n\t *\n\t * Centripetal CatmullRom Curve - which is useful for avoiding\n\t * cusps and self-intersections in non-uniform catmull rom curves.\n\t * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf\n\t *\n\t * curve.type accepts centripetal(default), chordal and catmullrom\n\t * curve.tension is used for catmullrom which defaults to 0.5\n\t */\n\n\n\t/*\n\tBased on an optimized c++ solution in\n\t - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/\n\t - http://ideone.com/NoEbVM\n\n\tThis CubicPoly class could be used for reusing some variables and calculations,\n\tbut for three.js curve use, it could be possible inlined and flatten into a single function call\n\twhich can be placed in CurveUtils.\n\t*/\n\n\tfunction CubicPoly() {\n\n\t\tvar c0 = 0, c1 = 0, c2 = 0, c3 = 0;\n\n\t\t/*\n\t\t * Compute coefficients for a cubic polynomial\n\t\t *   p(s) = c0 + c1*s + c2*s^2 + c3*s^3\n\t\t * such that\n\t\t *   p(0) = x0, p(1) = x1\n\t\t *  and\n\t\t *   p'(0) = t0, p'(1) = t1.\n\t\t */\n\t\tfunction init( x0, x1, t0, t1 ) {\n\n\t\t\tc0 = x0;\n\t\t\tc1 = t0;\n\t\t\tc2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;\n\t\t\tc3 = 2 * x0 - 2 * x1 + t0 + t1;\n\n\t\t}\n\n\t\treturn {\n\n\t\t\tinitCatmullRom: function ( x0, x1, x2, x3, tension ) {\n\n\t\t\t\tinit( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );\n\n\t\t\t},\n\n\t\t\tinitNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {\n\n\t\t\t\t// compute tangents when parameterized in [t1,t2]\n\t\t\t\tvar t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;\n\t\t\t\tvar t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;\n\n\t\t\t\t// rescale tangents for parametrization in [0,1]\n\t\t\t\tt1 *= dt1;\n\t\t\t\tt2 *= dt1;\n\n\t\t\t\tinit( x1, x2, t1, t2 );\n\n\t\t\t},\n\n\t\t\tcalc: function ( t ) {\n\n\t\t\t\tvar t2 = t * t;\n\t\t\t\tvar t3 = t2 * t;\n\t\t\t\treturn c0 + c1 * t + c2 * t2 + c3 * t3;\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\t//\n\n\tvar tmp = new Vector3();\n\tvar px = new CubicPoly();\n\tvar py = new CubicPoly();\n\tvar pz = new CubicPoly();\n\n\tfunction CatmullRomCurve3( points ) {\n\n\t\tCurve.call( this );\n\n\t\tif ( points.length < 2 ) console.warn( 'THREE.CatmullRomCurve3: Points array needs at least two entries.' );\n\n\t\tthis.points = points || [];\n\t\tthis.closed = false;\n\n\t}\n\n\tCatmullRomCurve3.prototype = Object.create( Curve.prototype );\n\tCatmullRomCurve3.prototype.constructor = CatmullRomCurve3;\n\n\tCatmullRomCurve3.prototype.getPoint = function ( t ) {\n\n\t\tvar points = this.points;\n\t\tvar l = points.length;\n\n\t\tvar point = ( l - ( this.closed ? 0 : 1 ) ) * t;\n\t\tvar intPoint = Math.floor( point );\n\t\tvar weight = point - intPoint;\n\n\t\tif ( this.closed ) {\n\n\t\t\tintPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length;\n\n\t\t} else if ( weight === 0 && intPoint === l - 1 ) {\n\n\t\t\tintPoint = l - 2;\n\t\t\tweight = 1;\n\n\t\t}\n\n\t\tvar p0, p1, p2, p3; // 4 points\n\n\t\tif ( this.closed || intPoint > 0 ) {\n\n\t\t\tp0 = points[ ( intPoint - 1 ) % l ];\n\n\t\t} else {\n\n\t\t\t// extrapolate first point\n\t\t\ttmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );\n\t\t\tp0 = tmp;\n\n\t\t}\n\n\t\tp1 = points[ intPoint % l ];\n\t\tp2 = points[ ( intPoint + 1 ) % l ];\n\n\t\tif ( this.closed || intPoint + 2 < l ) {\n\n\t\t\tp3 = points[ ( intPoint + 2 ) % l ];\n\n\t\t} else {\n\n\t\t\t// extrapolate last point\n\t\t\ttmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );\n\t\t\tp3 = tmp;\n\n\t\t}\n\n\t\tif ( this.type === undefined || this.type === 'centripetal' || this.type === 'chordal' ) {\n\n\t\t\t// init Centripetal / Chordal Catmull-Rom\n\t\t\tvar pow = this.type === 'chordal' ? 0.5 : 0.25;\n\t\t\tvar dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );\n\t\t\tvar dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );\n\t\t\tvar dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );\n\n\t\t\t// safety check for repeated points\n\t\t\tif ( dt1 < 1e-4 ) dt1 = 1.0;\n\t\t\tif ( dt0 < 1e-4 ) dt0 = dt1;\n\t\t\tif ( dt2 < 1e-4 ) dt2 = dt1;\n\n\t\t\tpx.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );\n\t\t\tpy.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );\n\t\t\tpz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );\n\n\t\t} else if ( this.type === 'catmullrom' ) {\n\n\t\t\tvar tension = this.tension !== undefined ? this.tension : 0.5;\n\t\t\tpx.initCatmullRom( p0.x, p1.x, p2.x, p3.x, tension );\n\t\t\tpy.initCatmullRom( p0.y, p1.y, p2.y, p3.y, tension );\n\t\t\tpz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, tension );\n\n\t\t}\n\n\t\treturn new Vector3( px.calc( weight ), py.calc( weight ), pz.calc( weight ) );\n\n\t};\n\n\tfunction CubicBezierCurve3( v0, v1, v2, v3 ) {\n\n\t\tCurve.call( this );\n\n\t\tthis.v0 = v0;\n\t\tthis.v1 = v1;\n\t\tthis.v2 = v2;\n\t\tthis.v3 = v3;\n\n\t}\n\n\tCubicBezierCurve3.prototype = Object.create( Curve.prototype );\n\tCubicBezierCurve3.prototype.constructor = CubicBezierCurve3;\n\n\tCubicBezierCurve3.prototype.getPoint = function ( t ) {\n\n\t\tvar v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;\n\n\t\treturn new Vector3(\n\t\t\tCubicBezier( t, v0.x, v1.x, v2.x, v3.x ),\n\t\t\tCubicBezier( t, v0.y, v1.y, v2.y, v3.y ),\n\t\t\tCubicBezier( t, v0.z, v1.z, v2.z, v3.z )\n\t\t);\n\n\t};\n\n\tfunction QuadraticBezierCurve3( v0, v1, v2 ) {\n\n\t\tCurve.call( this );\n\n\t\tthis.v0 = v0;\n\t\tthis.v1 = v1;\n\t\tthis.v2 = v2;\n\n\t}\n\n\tQuadraticBezierCurve3.prototype = Object.create( Curve.prototype );\n\tQuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3;\n\n\tQuadraticBezierCurve3.prototype.getPoint = function ( t ) {\n\n\t\tvar v0 = this.v0, v1 = this.v1, v2 = this.v2;\n\n\t\treturn new Vector3(\n\t\t\tQuadraticBezier( t, v0.x, v1.x, v2.x ),\n\t\t\tQuadraticBezier( t, v0.y, v1.y, v2.y ),\n\t\t\tQuadraticBezier( t, v0.z, v1.z, v2.z )\n\t\t);\n\n\t};\n\n\tfunction LineCurve3( v1, v2 ) {\n\n\t\tCurve.call( this );\n\n\t\tthis.v1 = v1;\n\t\tthis.v2 = v2;\n\n\t}\n\n\tLineCurve3.prototype = Object.create( Curve.prototype );\n\tLineCurve3.prototype.constructor = LineCurve3;\n\n\tLineCurve3.prototype.getPoint = function ( t ) {\n\n\t\tif ( t === 1 ) {\n\n\t\t\treturn this.v2.clone();\n\n\t\t}\n\n\t\tvar vector = new Vector3();\n\n\t\tvector.subVectors( this.v2, this.v1 ); // diff\n\t\tvector.multiplyScalar( t );\n\t\tvector.add( this.v1 );\n\n\t\treturn vector;\n\n\t};\n\n\tfunction ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {\n\n\t\tEllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );\n\n\t}\n\n\tArcCurve.prototype = Object.create( EllipseCurve.prototype );\n\tArcCurve.prototype.constructor = ArcCurve;\n\n\t/**\n\t * @author alteredq / http://alteredqualia.com/\n\t */\n\n\tvar SceneUtils = {\n\n\t\tcreateMultiMaterialObject: function ( geometry, materials ) {\n\n\t\t\tvar group = new Group();\n\n\t\t\tfor ( var i = 0, l = materials.length; i < l; i ++ ) {\n\n\t\t\t\tgroup.add( new Mesh( geometry, materials[ i ] ) );\n\n\t\t\t}\n\n\t\t\treturn group;\n\n\t\t},\n\n\t\tdetach: function ( child, parent, scene ) {\n\n\t\t\tchild.applyMatrix( parent.matrixWorld );\n\t\t\tparent.remove( child );\n\t\t\tscene.add( child );\n\n\t\t},\n\n\t\tattach: function ( child, scene, parent ) {\n\n\t\t\tchild.applyMatrix( new Matrix4().getInverse( parent.matrixWorld ) );\n\n\t\t\tscene.remove( child );\n\t\t\tparent.add( child );\n\n\t\t}\n\n\t};\n\n\t/**\n\t * @author mrdoob / http://mrdoob.com/\n\t */\n\n\tfunction Face4( a, b, c, d, normal, color, materialIndex ) {\n\n\t\tconsole.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' );\n\t\treturn new Face3( a, b, c, normal, color, materialIndex );\n\n\t}\n\n\tvar LineStrip = 0;\n\n\tvar LinePieces = 1;\n\n\tfunction MeshFaceMaterial( materials ) {\n\n\t\tconsole.warn( 'THREE.MeshFaceMaterial has been removed. Use an Array instead.' );\n\t\treturn materials;\n\n\t}\n\n\tfunction MultiMaterial( materials ) {\n\n\t\tif ( materials === undefined ) materials = [];\n\n\t\tconsole.warn( 'THREE.MultiMaterial has been removed. Use an Array instead.' );\n\t\tmaterials.isMultiMaterial = true;\n\t\tmaterials.materials = materials;\n\t\tmaterials.clone = function () {\n\n\t\t\treturn materials.slice();\n\n\t\t};\n\t\treturn materials;\n\n\t}\n\n\tfunction PointCloud( geometry, material ) {\n\n\t\tconsole.warn( 'THREE.PointCloud has been renamed to THREE.Points.' );\n\t\treturn new Points( geometry, material );\n\n\t}\n\n\tfunction Particle( material ) {\n\n\t\tconsole.warn( 'THREE.Particle has been renamed to THREE.Sprite.' );\n\t\treturn new Sprite( material );\n\n\t}\n\n\tfunction ParticleSystem( geometry, material ) {\n\n\t\tconsole.warn( 'THREE.ParticleSystem has been renamed to THREE.Points.' );\n\t\treturn new Points( geometry, material );\n\n\t}\n\n\tfunction PointCloudMaterial( parameters ) {\n\n\t\tconsole.warn( 'THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial.' );\n\t\treturn new PointsMaterial( parameters );\n\n\t}\n\n\tfunction ParticleBasicMaterial( parameters ) {\n\n\t\tconsole.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial.' );\n\t\treturn new PointsMaterial( parameters );\n\n\t}\n\n\tfunction ParticleSystemMaterial( parameters ) {\n\n\t\tconsole.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial.' );\n\t\treturn new PointsMaterial( parameters );\n\n\t}\n\n\tfunction Vertex( x, y, z ) {\n\n\t\tconsole.warn( 'THREE.Vertex has been removed. Use THREE.Vector3 instead.' );\n\t\treturn new Vector3( x, y, z );\n\n\t}\n\n\t//\n\n\tfunction DynamicBufferAttribute( array, itemSize ) {\n\n\t\tconsole.warn( 'THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setDynamic( true ) instead.' );\n\t\treturn new BufferAttribute( array, itemSize ).setDynamic( true );\n\n\t}\n\n\tfunction Int8Attribute( array, itemSize ) {\n\n\t\tconsole.warn( 'THREE.Int8Attribute has been removed. Use new THREE.Int8BufferAttribute() instead.' );\n\t\treturn new Int8BufferAttribute( array, itemSize );\n\n\t}\n\n\tfunction Uint8Attribute( array, itemSize ) {\n\n\t\tconsole.warn( 'THREE.Uint8Attribute has been removed. Use new THREE.Uint8BufferAttribute() instead.' );\n\t\treturn new Uint8BufferAttribute( array, itemSize );\n\n\t}\n\n\tfunction Uint8ClampedAttribute( array, itemSize ) {\n\n\t\tconsole.warn( 'THREE.Uint8ClampedAttribute has been removed. Use new THREE.Uint8ClampedBufferAttribute() instead.' );\n\t\treturn new Uint8ClampedBufferAttribute( array, itemSize );\n\n\t}\n\n\tfunction Int16Attribute( array, itemSize ) {\n\n\t\tconsole.warn( 'THREE.Int16Attribute has been removed. Use new THREE.Int16BufferAttribute() instead.' );\n\t\treturn new Int16BufferAttribute( array, itemSize );\n\n\t}\n\n\tfunction Uint16Attribute( array, itemSize ) {\n\n\t\tconsole.warn( 'THREE.Uint16Attribute has been removed. Use new THREE.Uint16BufferAttribute() instead.' );\n\t\treturn new Uint16BufferAttribute( array, itemSize );\n\n\t}\n\n\tfunction Int32Attribute( array, itemSize ) {\n\n\t\tconsole.warn( 'THREE.Int32Attribute has been removed. Use new THREE.Int32BufferAttribute() instead.' );\n\t\treturn new Int32BufferAttribute( array, itemSize );\n\n\t}\n\n\tfunction Uint32Attribute( array, itemSize ) {\n\n\t\tconsole.warn( 'THREE.Uint32Attribute has been removed. Use new THREE.Uint32BufferAttribute() instead.' );\n\t\treturn new Uint32BufferAttribute( array, itemSize );\n\n\t}\n\n\tfunction Float32Attribute( array, itemSize ) {\n\n\t\tconsole.warn( 'THREE.Float32Attribute has been removed. Use new THREE.Float32BufferAttribute() instead.' );\n\t\treturn new Float32BufferAttribute( array, itemSize );\n\n\t}\n\n\tfunction Float64Attribute( array, itemSize ) {\n\n\t\tconsole.warn( 'THREE.Float64Attribute has been removed. Use new THREE.Float64BufferAttribute() instead.' );\n\t\treturn new Float64BufferAttribute( array, itemSize );\n\n\t}\n\n\t//\n\n\tCurve.create = function ( construct, getPoint ) {\n\n\t\tconsole.log( 'THREE.Curve.create() has been deprecated' );\n\n\t\tconstruct.prototype = Object.create( Curve.prototype );\n\t\tconstruct.prototype.constructor = construct;\n\t\tconstruct.prototype.getPoint = getPoint;\n\n\t\treturn construct;\n\n\t};\n\n\t//\n\n\tfunction ClosedSplineCurve3( points ) {\n\n\t\tconsole.warn( 'THREE.ClosedSplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' );\n\n\t\tCatmullRomCurve3.call( this, points );\n\t\tthis.type = 'catmullrom';\n\t\tthis.closed = true;\n\n\t}\n\n\tClosedSplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype );\n\n\t//\n\n\tfunction SplineCurve3( points ) {\n\n\t\tconsole.warn( 'THREE.SplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' );\n\n\t\tCatmullRomCurve3.call( this, points );\n\t\tthis.type = 'catmullrom';\n\n\t}\n\n\tSplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype );\n\n\t//\n\n\tfunction Spline( points ) {\n\n\t\tconsole.warn( 'THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.' );\n\n\t\tCatmullRomCurve3.call( this, points );\n\t\tthis.type = 'catmullrom';\n\n\t}\n\n\tSpline.prototype = Object.create( CatmullRomCurve3.prototype );\n\n\tObject.assign( Spline.prototype, {\n\n\t\tinitFromArray: function ( a ) {\n\n\t\t\tconsole.error( 'THREE.Spline: .initFromArray() has been removed.' );\n\n\t\t},\n\t\tgetControlPointsArray: function ( optionalTarget ) {\n\n\t\t\tconsole.error( 'THREE.Spline: .getControlPointsArray() has been removed.' );\n\n\t\t},\n\t\treparametrizeByArcLength: function ( samplingCoef ) {\n\n\t\t\tconsole.error( 'THREE.Spline: .reparametrizeByArcLength() has been removed.' );\n\n\t\t}\n\n\t} );\n\n\t//\n\tfunction BoundingBoxHelper( object, color ) {\n\n\t\tconsole.warn( 'THREE.BoundingBoxHelper has been deprecated. Creating a THREE.BoxHelper instead.' );\n\t\treturn new BoxHelper( object, color );\n\n\t}\n\n\tfunction EdgesHelper( object, hex ) {\n\n\t\tconsole.warn( 'THREE.EdgesHelper has been removed. Use THREE.EdgesGeometry instead.' );\n\t\treturn new LineSegments( new EdgesGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) );\n\n\t}\n\n\tGridHelper.prototype.setColors = function () {\n\n\t\tconsole.error( 'THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead.' );\n\n\t};\n\n\tSkeletonHelper.prototype.update = function () {\n\n\t\tconsole.error( 'THREE.SkeletonHelper: update() no longer needs to be called.' );\n\n\t};\n\n\tfunction WireframeHelper( object, hex ) {\n\n\t\tconsole.warn( 'THREE.WireframeHelper has been removed. Use THREE.WireframeGeometry instead.' );\n\t\treturn new LineSegments( new WireframeGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) );\n\n\t}\n\n\t//\n\n\tfunction XHRLoader( manager ) {\n\n\t\tconsole.warn( 'THREE.XHRLoader has been renamed to THREE.FileLoader.' );\n\t\treturn new FileLoader( manager );\n\n\t}\n\n\tfunction BinaryTextureLoader( manager ) {\n\n\t\tconsole.warn( 'THREE.BinaryTextureLoader has been renamed to THREE.DataTextureLoader.' );\n\t\treturn new DataTextureLoader( manager );\n\n\t}\n\n\t//\n\n\tObject.assign( Box2.prototype, {\n\n\t\tcenter: function ( optionalTarget ) {\n\n\t\t\tconsole.warn( 'THREE.Box2: .center() has been renamed to .getCenter().' );\n\t\t\treturn this.getCenter( optionalTarget );\n\n\t\t},\n\t\tempty: function () {\n\n\t\t\tconsole.warn( 'THREE.Box2: .empty() has been renamed to .isEmpty().' );\n\t\t\treturn this.isEmpty();\n\n\t\t},\n\t\tisIntersectionBox: function ( box ) {\n\n\t\t\tconsole.warn( 'THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().' );\n\t\t\treturn this.intersectsBox( box );\n\n\t\t},\n\t\tsize: function ( optionalTarget ) {\n\n\t\t\tconsole.warn( 'THREE.Box2: .size() has been renamed to .getSize().' );\n\t\t\treturn this.getSize( optionalTarget );\n\n\t\t}\n\t} );\n\n\tObject.assign( Box3.prototype, {\n\n\t\tcenter: function ( optionalTarget ) {\n\n\t\t\tconsole.warn( 'THREE.Box3: .center() has been renamed to .getCenter().' );\n\t\t\treturn this.getCenter( optionalTarget );\n\n\t\t},\n\t\tempty: function () {\n\n\t\t\tconsole.warn( 'THREE.Box3: .empty() has been renamed to .isEmpty().' );\n\t\t\treturn this.isEmpty();\n\n\t\t},\n\t\tisIntersectionBox: function ( box ) {\n\n\t\t\tconsole.warn( 'THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().' );\n\t\t\treturn this.intersectsBox( box );\n\n\t\t},\n\t\tisIntersectionSphere: function ( sphere ) {\n\n\t\t\tconsole.warn( 'THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().' );\n\t\t\treturn this.intersectsSphere( sphere );\n\n\t\t},\n\t\tsize: function ( optionalTarget ) {\n\n\t\t\tconsole.warn( 'THREE.Box3: .size() has been renamed to .getSize().' );\n\t\t\treturn this.getSize( optionalTarget );\n\n\t\t}\n\t} );\n\n\tLine3.prototype.center = function ( optionalTarget ) {\n\n\t\tconsole.warn( 'THREE.Line3: .center() has been renamed to .getCenter().' );\n\t\treturn this.getCenter( optionalTarget );\n\n\t};\n\n\t_Math.random16 = function () {\n\n\t\tconsole.warn( 'THREE.Math.random16() has been deprecated. Use Math.random() instead.' );\n\t\treturn Math.random();\n\n\t};\n\n\tObject.assign( Matrix3.prototype, {\n\n\t\tflattenToArrayOffset: function ( array, offset ) {\n\n\t\t\tconsole.warn( \"THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead.\" );\n\t\t\treturn this.toArray( array, offset );\n\n\t\t},\n\t\tmultiplyVector3: function ( vector ) {\n\n\t\t\tconsole.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' );\n\t\t\treturn vector.applyMatrix3( this );\n\n\t\t},\n\t\tmultiplyVector3Array: function ( a ) {\n\n\t\t\tconsole.error( 'THREE.Matrix3: .multiplyVector3Array() has been removed.'  );\n\n\t\t},\n\t\tapplyToBuffer: function( buffer, offset, length ) {\n\n\t\t\tconsole.warn( 'THREE.Matrix3: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' );\n\t\t\treturn this.applyToBufferAttribute( buffer );\n\n\t\t},\n\t\tapplyToVector3Array: function( array, offset, length ) {\n\n\t\t\tconsole.error( 'THREE.Matrix3: .applyToVector3Array() has been removed.' );\n\n\t\t}\n\n\t} );\n\n\tObject.assign( Matrix4.prototype, {\n\n\t\textractPosition: function ( m ) {\n\n\t\t\tconsole.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' );\n\t\t\treturn this.copyPosition( m );\n\n\t\t},\n\t\tflattenToArrayOffset: function ( array, offset ) {\n\n\t\t\tconsole.warn( \"THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead.\" );\n\t\t\treturn this.toArray( array, offset );\n\n\t\t},\n\t\tgetPosition: function () {\n\n\t\t\tvar v1;\n\n\t\t\treturn function getPosition() {\n\n\t\t\t\tif ( v1 === undefined ) v1 = new Vector3();\n\t\t\t\tconsole.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' );\n\t\t\t\treturn v1.setFromMatrixColumn( this, 3 );\n\n\t\t\t};\n\n\t\t}(),\n\t\tsetRotationFromQuaternion: function ( q ) {\n\n\t\t\tconsole.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' );\n\t\t\treturn this.makeRotationFromQuaternion( q );\n\n\t\t},\n\t\tmultiplyToArray: function () {\n\n\t\t\tconsole.warn( 'THREE.Matrix4: .multiplyToArray() has been removed.' );\n\n\t\t},\n\t\tmultiplyVector3: function ( vector ) {\n\n\t\t\tconsole.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.' );\n\t\t\treturn vector.applyMatrix4( this );\n\n\t\t},\n\t\tmultiplyVector4: function ( vector ) {\n\n\t\t\tconsole.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' );\n\t\t\treturn vector.applyMatrix4( this );\n\n\t\t},\n\t\tmultiplyVector3Array: function ( a ) {\n\n\t\t\tconsole.error( 'THREE.Matrix4: .multiplyVector3Array() has been removed.'  );\n\n\t\t},\n\t\trotateAxis: function ( v ) {\n\n\t\t\tconsole.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' );\n\t\t\tv.transformDirection( this );\n\n\t\t},\n\t\tcrossVector: function ( vector ) {\n\n\t\t\tconsole.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' );\n\t\t\treturn vector.applyMatrix4( this );\n\n\t\t},\n\t\ttranslate: function () {\n\n\t\t\tconsole.error( 'THREE.Matrix4: .translate() has been removed.' );\n\n\t\t},\n\t\trotateX: function () {\n\n\t\t\tconsole.error( 'THREE.Matrix4: .rotateX() has been removed.' );\n\n\t\t},\n\t\trotateY: function () {\n\n\t\t\tconsole.error( 'THREE.Matrix4: .rotateY() has been removed.' );\n\n\t\t},\n\t\trotateZ: function () {\n\n\t\t\tconsole.error( 'THREE.Matrix4: .rotateZ() has been removed.' );\n\n\t\t},\n\t\trotateByAxis: function () {\n\n\t\t\tconsole.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' );\n\n\t\t},\n\t\tapplyToBuffer: function( buffer, offset, length ) {\n\n\t\t\tconsole.warn( 'THREE.Matrix4: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' );\n\t\t\treturn this.applyToBufferAttribute( buffer );\n\n\t\t},\n\t\tapplyToVector3Array: function( array, offset, length ) {\n\n\t\t\tconsole.error( 'THREE.Matrix4: .applyToVector3Array() has been removed.' );\n\n\t\t},\n\t\tmakeFrustum: function( left, right, bottom, top, near, far ) {\n\n\t\t\tconsole.warn( 'THREE.Matrix4: .makeFrustum() has been removed. Use .makePerspective( left, right, top, bottom, near, far ) instead.' );\n\t\t\treturn this.makePerspective( left, right, top, bottom, near, far );\n\n\t\t}\n\n\t} );\n\n\tPlane.prototype.isIntersectionLine = function ( line ) {\n\n\t\tconsole.warn( 'THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().' );\n\t\treturn this.intersectsLine( line );\n\n\t};\n\n\tQuaternion.prototype.multiplyVector3 = function ( vector ) {\n\n\t\tconsole.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' );\n\t\treturn vector.applyQuaternion( this );\n\n\t};\n\n\tObject.assign( Ray.prototype, {\n\n\t\tisIntersectionBox: function ( box ) {\n\n\t\t\tconsole.warn( 'THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().' );\n\t\t\treturn this.intersectsBox( box );\n\n\t\t},\n\t\tisIntersectionPlane: function ( plane ) {\n\n\t\t\tconsole.warn( 'THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().' );\n\t\t\treturn this.intersectsPlane( plane );\n\n\t\t},\n\t\tisIntersectionSphere: function ( sphere ) {\n\n\t\t\tconsole.warn( 'THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().' );\n\t\t\treturn this.intersectsSphere( sphere );\n\n\t\t}\n\n\t} );\n\n\tObject.assign( Shape.prototype, {\n\n\t\textrude: function ( options ) {\n\n\t\t\tconsole.warn( 'THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.' );\n\t\t\treturn new ExtrudeGeometry( this, options );\n\n\t\t},\n\t\tmakeGeometry: function ( options ) {\n\n\t\t\tconsole.warn( 'THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.' );\n\t\t\treturn new ShapeGeometry( this, options );\n\n\t\t}\n\n\t} );\n\n\tObject.assign( Vector2.prototype, {\n\n\t\tfromAttribute: function ( attribute, index, offset ) {\n\n\t\t\tconsole.error( 'THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().' );\n\t\t\treturn this.fromBufferAttribute( attribute, index, offset );\n\n\t\t}\n\n\t} );\n\n\tObject.assign( Vector3.prototype, {\n\n\t\tsetEulerFromRotationMatrix: function () {\n\n\t\t\tconsole.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' );\n\n\t\t},\n\t\tsetEulerFromQuaternion: function () {\n\n\t\t\tconsole.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' );\n\n\t\t},\n\t\tgetPositionFromMatrix: function ( m ) {\n\n\t\t\tconsole.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' );\n\t\t\treturn this.setFromMatrixPosition( m );\n\n\t\t},\n\t\tgetScaleFromMatrix: function ( m ) {\n\n\t\t\tconsole.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' );\n\t\t\treturn this.setFromMatrixScale( m );\n\n\t\t},\n\t\tgetColumnFromMatrix: function ( index, matrix ) {\n\n\t\t\tconsole.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' );\n\t\t\treturn this.setFromMatrixColumn( matrix, index );\n\n\t\t},\n\t\tapplyProjection: function ( m ) {\n\n\t\t\tconsole.warn( 'THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.' );\n\t\t\treturn this.applyMatrix4( m );\n\n\t\t},\n\t\tfromAttribute: function ( attribute, index, offset ) {\n\n\t\t\tconsole.error( 'THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().' );\n\t\t\treturn this.fromBufferAttribute( attribute, index, offset );\n\n\t\t}\n\n\t} );\n\n\tObject.assign( Vector4.prototype, {\n\n\t\tfromAttribute: function ( attribute, index, offset ) {\n\n\t\t\tconsole.error( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' );\n\t\t\treturn this.fromBufferAttribute( attribute, index, offset );\n\n\t\t}\n\n\t} );\n\n\t//\n\n\tGeometry.prototype.computeTangents = function () {\n\n\t\tconsole.warn( 'THREE.Geometry: .computeTangents() has been removed.' );\n\n\t};\n\n\tObject.assign( Object3D.prototype, {\n\n\t\tgetChildByName: function ( name ) {\n\n\t\t\tconsole.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' );\n\t\t\treturn this.getObjectByName( name );\n\n\t\t},\n\t\trenderDepth: function () {\n\n\t\t\tconsole.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' );\n\n\t\t},\n\t\ttranslate: function ( distance, axis ) {\n\n\t\t\tconsole.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' );\n\t\t\treturn this.translateOnAxis( axis, distance );\n\n\t\t}\n\n\t} );\n\n\tObject.defineProperties( Object3D.prototype, {\n\n\t\teulerOrder: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );\n\t\t\t\treturn this.rotation.order;\n\n\t\t\t},\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' );\n\t\t\t\tthis.rotation.order = value;\n\n\t\t\t}\n\t\t},\n\t\tuseQuaternion: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );\n\n\t\t\t},\n\t\t\tset: function () {\n\n\t\t\t\tconsole.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' );\n\n\t\t\t}\n\t\t}\n\n\t} );\n\n\tObject.defineProperties( LOD.prototype, {\n\n\t\tobjects: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.LOD: .objects has been renamed to .levels.' );\n\t\t\t\treturn this.levels;\n\n\t\t\t}\n\t\t}\n\n\t} );\n\n\tObject.defineProperty( Skeleton.prototype, 'useVertexTexture', {\n\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.Skeleton: useVertexTexture has been removed.' );\n\n\t\t},\n\t\tset: function () {\n\n\t\t\tconsole.warn( 'THREE.Skeleton: useVertexTexture has been removed.' );\n\n\t\t}\n\n\t} );\n\n\tObject.defineProperty( Curve.prototype, '__arcLengthDivisions', {\n\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' );\n\t\t\treturn this.arcLengthDivisions;\n\n\t\t},\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' );\n\t\t\tthis.arcLengthDivisions = value;\n\n\t\t}\n\n\t} );\n\n\t//\n\n\tPerspectiveCamera.prototype.setLens = function ( focalLength, filmGauge ) {\n\n\t\tconsole.warn( \"THREE.PerspectiveCamera.setLens is deprecated. \" +\n\t\t\t\t\"Use .setFocalLength and .filmGauge for a photographic setup.\" );\n\n\t\tif ( filmGauge !== undefined ) this.filmGauge = filmGauge;\n\t\tthis.setFocalLength( focalLength );\n\n\t};\n\n\t//\n\n\tObject.defineProperties( Light.prototype, {\n\t\tonlyShadow: {\n\t\t\tset: function () {\n\n\t\t\t\tconsole.warn( 'THREE.Light: .onlyShadow has been removed.' );\n\n\t\t\t}\n\t\t},\n\t\tshadowCameraFov: {\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.Light: .shadowCameraFov is now .shadow.camera.fov.' );\n\t\t\t\tthis.shadow.camera.fov = value;\n\n\t\t\t}\n\t\t},\n\t\tshadowCameraLeft: {\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.Light: .shadowCameraLeft is now .shadow.camera.left.' );\n\t\t\t\tthis.shadow.camera.left = value;\n\n\t\t\t}\n\t\t},\n\t\tshadowCameraRight: {\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.Light: .shadowCameraRight is now .shadow.camera.right.' );\n\t\t\t\tthis.shadow.camera.right = value;\n\n\t\t\t}\n\t\t},\n\t\tshadowCameraTop: {\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.Light: .shadowCameraTop is now .shadow.camera.top.' );\n\t\t\t\tthis.shadow.camera.top = value;\n\n\t\t\t}\n\t\t},\n\t\tshadowCameraBottom: {\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom.' );\n\t\t\t\tthis.shadow.camera.bottom = value;\n\n\t\t\t}\n\t\t},\n\t\tshadowCameraNear: {\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.Light: .shadowCameraNear is now .shadow.camera.near.' );\n\t\t\t\tthis.shadow.camera.near = value;\n\n\t\t\t}\n\t\t},\n\t\tshadowCameraFar: {\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.Light: .shadowCameraFar is now .shadow.camera.far.' );\n\t\t\t\tthis.shadow.camera.far = value;\n\n\t\t\t}\n\t\t},\n\t\tshadowCameraVisible: {\n\t\t\tset: function () {\n\n\t\t\t\tconsole.warn( 'THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.' );\n\n\t\t\t}\n\t\t},\n\t\tshadowBias: {\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.Light: .shadowBias is now .shadow.bias.' );\n\t\t\t\tthis.shadow.bias = value;\n\n\t\t\t}\n\t\t},\n\t\tshadowDarkness: {\n\t\t\tset: function () {\n\n\t\t\t\tconsole.warn( 'THREE.Light: .shadowDarkness has been removed.' );\n\n\t\t\t}\n\t\t},\n\t\tshadowMapWidth: {\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.' );\n\t\t\t\tthis.shadow.mapSize.width = value;\n\n\t\t\t}\n\t\t},\n\t\tshadowMapHeight: {\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.' );\n\t\t\t\tthis.shadow.mapSize.height = value;\n\n\t\t\t}\n\t\t}\n\t} );\n\n\t//\n\n\tObject.defineProperties( BufferAttribute.prototype, {\n\n\t\tlength: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.BufferAttribute: .length has been deprecated. Use .count instead.' );\n\t\t\t\treturn this.array.length;\n\n\t\t\t}\n\t\t}\n\n\t} );\n\n\tObject.assign( BufferGeometry.prototype, {\n\n\t\taddIndex: function ( index ) {\n\n\t\t\tconsole.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' );\n\t\t\tthis.setIndex( index );\n\n\t\t},\n\t\taddDrawCall: function ( start, count, indexOffset ) {\n\n\t\t\tif ( indexOffset !== undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' );\n\n\t\t\t}\n\t\t\tconsole.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' );\n\t\t\tthis.addGroup( start, count );\n\n\t\t},\n\t\tclearDrawCalls: function () {\n\n\t\t\tconsole.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' );\n\t\t\tthis.clearGroups();\n\n\t\t},\n\t\tcomputeTangents: function () {\n\n\t\t\tconsole.warn( 'THREE.BufferGeometry: .computeTangents() has been removed.' );\n\n\t\t},\n\t\tcomputeOffsets: function () {\n\n\t\t\tconsole.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.' );\n\n\t\t}\n\n\t} );\n\n\tObject.defineProperties( BufferGeometry.prototype, {\n\n\t\tdrawcalls: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.error( 'THREE.BufferGeometry: .drawcalls has been renamed to .groups.' );\n\t\t\t\treturn this.groups;\n\n\t\t\t}\n\t\t},\n\t\toffsets: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.BufferGeometry: .offsets has been renamed to .groups.' );\n\t\t\t\treturn this.groups;\n\n\t\t\t}\n\t\t}\n\n\t} );\n\n\t//\n\n\tObject.defineProperties( Uniform.prototype, {\n\n\t\tdynamic: {\n\t\t\tset: function () {\n\n\t\t\t\tconsole.warn( 'THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.' );\n\n\t\t\t}\n\t\t},\n\t\tonUpdate: {\n\t\t\tvalue: function () {\n\n\t\t\t\tconsole.warn( 'THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.' );\n\t\t\t\treturn this;\n\n\t\t\t}\n\t\t}\n\n\t} );\n\n\t//\n\n\tObject.defineProperties( Material.prototype, {\n\n\t\twrapAround: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.Material: .wrapAround has been removed.' );\n\n\t\t\t},\n\t\t\tset: function () {\n\n\t\t\t\tconsole.warn( 'THREE.Material: .wrapAround has been removed.' );\n\n\t\t\t}\n\t\t},\n\t\twrapRGB: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.Material: .wrapRGB has been removed.' );\n\t\t\t\treturn new Color();\n\n\t\t\t}\n\t\t},\n\n\t\tshading: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.error( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );\n\n\t\t\t},\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );\n\t\t\t\tthis.flatShading = ( value === FlatShading );\n\n\t\t\t}\n\t\t}\n\n\t} );\n\n\tObject.defineProperties( MeshPhongMaterial.prototype, {\n\n\t\tmetal: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.' );\n\t\t\t\treturn false;\n\n\t\t\t},\n\t\t\tset: function () {\n\n\t\t\t\tconsole.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead' );\n\n\t\t\t}\n\t\t}\n\n\t} );\n\n\tObject.defineProperties( ShaderMaterial.prototype, {\n\n\t\tderivatives: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );\n\t\t\t\treturn this.extensions.derivatives;\n\n\t\t\t},\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' );\n\t\t\t\tthis.extensions.derivatives = value;\n\n\t\t\t}\n\t\t}\n\n\t} );\n\n\t//\n\n\tObject.assign( WebGLRenderer.prototype, {\n\n\t\tgetCurrentRenderTarget: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().' );\n\t\t\treturn this.getRenderTarget();\n\n\t\t},\n\n\t\tgetMaxAnisotropy: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: .getMaxAnisotropy() is now .capabilities.getMaxAnisotropy().' );\n\t\t\treturn this.capabilities.getMaxAnisotropy();\n\n\t\t},\n\n\t\tgetPrecision: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: .getPrecision() is now .capabilities.precision.' );\n\t\t\treturn this.capabilities.precision;\n\n\t\t},\n\n\t\tsupportsFloatTextures: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \\'OES_texture_float\\' ).' );\n\t\t\treturn this.extensions.get( 'OES_texture_float' );\n\n\t\t},\n\t\tsupportsHalfFloatTextures: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \\'OES_texture_half_float\\' ).' );\n\t\t\treturn this.extensions.get( 'OES_texture_half_float' );\n\n\t\t},\n\t\tsupportsStandardDerivatives: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \\'OES_standard_derivatives\\' ).' );\n\t\t\treturn this.extensions.get( 'OES_standard_derivatives' );\n\n\t\t},\n\t\tsupportsCompressedTextureS3TC: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \\'WEBGL_compressed_texture_s3tc\\' ).' );\n\t\t\treturn this.extensions.get( 'WEBGL_compressed_texture_s3tc' );\n\n\t\t},\n\t\tsupportsCompressedTexturePVRTC: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \\'WEBGL_compressed_texture_pvrtc\\' ).' );\n\t\t\treturn this.extensions.get( 'WEBGL_compressed_texture_pvrtc' );\n\n\t\t},\n\t\tsupportsBlendMinMax: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \\'EXT_blend_minmax\\' ).' );\n\t\t\treturn this.extensions.get( 'EXT_blend_minmax' );\n\n\t\t},\n\t\tsupportsVertexTextures: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.' );\n\t\t\treturn this.capabilities.vertexTextures;\n\n\t\t},\n\t\tsupportsInstancedArrays: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \\'ANGLE_instanced_arrays\\' ).' );\n\t\t\treturn this.extensions.get( 'ANGLE_instanced_arrays' );\n\n\t\t},\n\t\tenableScissorTest: function ( boolean ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().' );\n\t\t\tthis.setScissorTest( boolean );\n\n\t\t},\n\t\tinitMaterial: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' );\n\n\t\t},\n\t\taddPrePlugin: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' );\n\n\t\t},\n\t\taddPostPlugin: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' );\n\n\t\t},\n\t\tupdateShadowMap: function () {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' );\n\n\t\t}\n\n\t} );\n\n\tObject.defineProperties( WebGLRenderer.prototype, {\n\n\t\tshadowMapEnabled: {\n\t\t\tget: function () {\n\n\t\t\t\treturn this.shadowMap.enabled;\n\n\t\t\t},\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' );\n\t\t\t\tthis.shadowMap.enabled = value;\n\n\t\t\t}\n\t\t},\n\t\tshadowMapType: {\n\t\t\tget: function () {\n\n\t\t\t\treturn this.shadowMap.type;\n\n\t\t\t},\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' );\n\t\t\t\tthis.shadowMap.type = value;\n\n\t\t\t}\n\t\t},\n\t\tshadowMapCullFace: {\n\t\t\tget: function () {\n\n\t\t\t\treturn this.shadowMap.cullFace;\n\n\t\t\t},\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: .shadowMapCullFace is now .shadowMap.cullFace.' );\n\t\t\t\tthis.shadowMap.cullFace = value;\n\n\t\t\t}\n\t\t}\n\t} );\n\n\tObject.defineProperties( WebGLShadowMap.prototype, {\n\n\t\tcullFace: {\n\t\t\tget: function () {\n\n\t\t\t\treturn this.renderReverseSided ? CullFaceFront : CullFaceBack;\n\n\t\t\t},\n\t\t\tset: function ( cullFace ) {\n\n\t\t\t\tvar value = ( cullFace !== CullFaceBack );\n\t\t\t\tconsole.warn( \"WebGLRenderer: .shadowMap.cullFace is deprecated. Set .shadowMap.renderReverseSided to \" + value + \".\" );\n\t\t\t\tthis.renderReverseSided = value;\n\n\t\t\t}\n\t\t}\n\n\t} );\n\n\t//\n\n\tObject.defineProperties( WebGLRenderTarget.prototype, {\n\n\t\twrapS: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );\n\t\t\t\treturn this.texture.wrapS;\n\n\t\t\t},\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' );\n\t\t\t\tthis.texture.wrapS = value;\n\n\t\t\t}\n\t\t},\n\t\twrapT: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );\n\t\t\t\treturn this.texture.wrapT;\n\n\t\t\t},\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' );\n\t\t\t\tthis.texture.wrapT = value;\n\n\t\t\t}\n\t\t},\n\t\tmagFilter: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );\n\t\t\t\treturn this.texture.magFilter;\n\n\t\t\t},\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' );\n\t\t\t\tthis.texture.magFilter = value;\n\n\t\t\t}\n\t\t},\n\t\tminFilter: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );\n\t\t\t\treturn this.texture.minFilter;\n\n\t\t\t},\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' );\n\t\t\t\tthis.texture.minFilter = value;\n\n\t\t\t}\n\t\t},\n\t\tanisotropy: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );\n\t\t\t\treturn this.texture.anisotropy;\n\n\t\t\t},\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' );\n\t\t\t\tthis.texture.anisotropy = value;\n\n\t\t\t}\n\t\t},\n\t\toffset: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );\n\t\t\t\treturn this.texture.offset;\n\n\t\t\t},\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' );\n\t\t\t\tthis.texture.offset = value;\n\n\t\t\t}\n\t\t},\n\t\trepeat: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );\n\t\t\t\treturn this.texture.repeat;\n\n\t\t\t},\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' );\n\t\t\t\tthis.texture.repeat = value;\n\n\t\t\t}\n\t\t},\n\t\tformat: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );\n\t\t\t\treturn this.texture.format;\n\n\t\t\t},\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' );\n\t\t\t\tthis.texture.format = value;\n\n\t\t\t}\n\t\t},\n\t\ttype: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );\n\t\t\t\treturn this.texture.type;\n\n\t\t\t},\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' );\n\t\t\t\tthis.texture.type = value;\n\n\t\t\t}\n\t\t},\n\t\tgenerateMipmaps: {\n\t\t\tget: function () {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );\n\t\t\t\treturn this.texture.generateMipmaps;\n\n\t\t\t},\n\t\t\tset: function ( value ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' );\n\t\t\t\tthis.texture.generateMipmaps = value;\n\n\t\t\t}\n\t\t}\n\n\t} );\n\n\t//\n\n\tAudio.prototype.load = function ( file ) {\n\n\t\tconsole.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' );\n\t\tvar scope = this;\n\t\tvar audioLoader = new AudioLoader();\n\t\taudioLoader.load( file, function ( buffer ) {\n\n\t\t\tscope.setBuffer( buffer );\n\n\t\t} );\n\t\treturn this;\n\n\t};\n\n\tAudioAnalyser.prototype.getData = function () {\n\n\t\tconsole.warn( 'THREE.AudioAnalyser: .getData() is now .getFrequencyData().' );\n\t\treturn this.getFrequencyData();\n\n\t};\n\n\t//\n\n\tCubeCamera.prototype.updateCubeMap = function ( renderer, scene ) {\n\n\t\tconsole.warn( 'THREE.CubeCamera: .updateCubeMap() is now .update().' );\n\t\treturn this.update( renderer, scene );\n\n\t};\n\n\t//\n\n\tvar GeometryUtils = {\n\n\t\tmerge: function ( geometry1, geometry2, materialIndexOffset ) {\n\n\t\t\tconsole.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' );\n\t\t\tvar matrix;\n\n\t\t\tif ( geometry2.isMesh ) {\n\n\t\t\t\tgeometry2.matrixAutoUpdate && geometry2.updateMatrix();\n\n\t\t\t\tmatrix = geometry2.matrix;\n\t\t\t\tgeometry2 = geometry2.geometry;\n\n\t\t\t}\n\n\t\t\tgeometry1.merge( geometry2, matrix, materialIndexOffset );\n\n\t\t},\n\n\t\tcenter: function ( geometry ) {\n\n\t\t\tconsole.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' );\n\t\t\treturn geometry.center();\n\n\t\t}\n\n\t};\n\n\tvar ImageUtils = {\n\n\t\tcrossOrigin: undefined,\n\n\t\tloadTexture: function ( url, mapping, onLoad, onError ) {\n\n\t\t\tconsole.warn( 'THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead.' );\n\n\t\t\tvar loader = new TextureLoader();\n\t\t\tloader.setCrossOrigin( this.crossOrigin );\n\n\t\t\tvar texture = loader.load( url, onLoad, undefined, onError );\n\n\t\t\tif ( mapping ) texture.mapping = mapping;\n\n\t\t\treturn texture;\n\n\t\t},\n\n\t\tloadTextureCube: function ( urls, mapping, onLoad, onError ) {\n\n\t\t\tconsole.warn( 'THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead.' );\n\n\t\t\tvar loader = new CubeTextureLoader();\n\t\t\tloader.setCrossOrigin( this.crossOrigin );\n\n\t\t\tvar texture = loader.load( urls, onLoad, undefined, onError );\n\n\t\t\tif ( mapping ) texture.mapping = mapping;\n\n\t\t\treturn texture;\n\n\t\t},\n\n\t\tloadCompressedTexture: function () {\n\n\t\t\tconsole.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' );\n\n\t\t},\n\n\t\tloadCompressedTextureCube: function () {\n\n\t\t\tconsole.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' );\n\n\t\t}\n\n\t};\n\n\t//\n\n\tfunction Projector() {\n\n\t\tconsole.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' );\n\n\t\tthis.projectVector = function ( vector, camera ) {\n\n\t\t\tconsole.warn( 'THREE.Projector: .projectVector() is now vector.project().' );\n\t\t\tvector.project( camera );\n\n\t\t};\n\n\t\tthis.unprojectVector = function ( vector, camera ) {\n\n\t\t\tconsole.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' );\n\t\t\tvector.unproject( camera );\n\n\t\t};\n\n\t\tthis.pickingRay = function () {\n\n\t\t\tconsole.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' );\n\n\t\t};\n\n\t}\n\n\t//\n\n\tfunction CanvasRenderer() {\n\n\t\tconsole.error( 'THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js' );\n\n\t\tthis.domElement = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );\n\t\tthis.clear = function () {};\n\t\tthis.render = function () {};\n\t\tthis.setClearColor = function () {};\n\t\tthis.setSize = function () {};\n\n\t}\n\n\texports.WebGLRenderTargetCube = WebGLRenderTargetCube;\n\texports.WebGLRenderTarget = WebGLRenderTarget;\n\texports.WebGLRenderer = WebGLRenderer;\n\texports.ShaderLib = ShaderLib;\n\texports.UniformsLib = UniformsLib;\n\texports.UniformsUtils = UniformsUtils;\n\texports.ShaderChunk = ShaderChunk;\n\texports.FogExp2 = FogExp2;\n\texports.Fog = Fog;\n\texports.Scene = Scene;\n\texports.LensFlare = LensFlare;\n\texports.Sprite = Sprite;\n\texports.LOD = LOD;\n\texports.SkinnedMesh = SkinnedMesh;\n\texports.Skeleton = Skeleton;\n\texports.Bone = Bone;\n\texports.Mesh = Mesh;\n\texports.LineSegments = LineSegments;\n\texports.LineLoop = LineLoop;\n\texports.Line = Line;\n\texports.Points = Points;\n\texports.Group = Group;\n\texports.VideoTexture = VideoTexture;\n\texports.DataTexture = DataTexture;\n\texports.CompressedTexture = CompressedTexture;\n\texports.CubeTexture = CubeTexture;\n\texports.CanvasTexture = CanvasTexture;\n\texports.DepthTexture = DepthTexture;\n\texports.Texture = Texture;\n\texports.CompressedTextureLoader = CompressedTextureLoader;\n\texports.DataTextureLoader = DataTextureLoader;\n\texports.CubeTextureLoader = CubeTextureLoader;\n\texports.TextureLoader = TextureLoader;\n\texports.ObjectLoader = ObjectLoader;\n\texports.MaterialLoader = MaterialLoader;\n\texports.BufferGeometryLoader = BufferGeometryLoader;\n\texports.DefaultLoadingManager = DefaultLoadingManager;\n\texports.LoadingManager = LoadingManager;\n\texports.JSONLoader = JSONLoader;\n\texports.ImageLoader = ImageLoader;\n\texports.FontLoader = FontLoader;\n\texports.FileLoader = FileLoader;\n\texports.Loader = Loader;\n\texports.Cache = Cache;\n\texports.AudioLoader = AudioLoader;\n\texports.SpotLightShadow = SpotLightShadow;\n\texports.SpotLight = SpotLight;\n\texports.PointLight = PointLight;\n\texports.RectAreaLight = RectAreaLight;\n\texports.HemisphereLight = HemisphereLight;\n\texports.DirectionalLightShadow = DirectionalLightShadow;\n\texports.DirectionalLight = DirectionalLight;\n\texports.AmbientLight = AmbientLight;\n\texports.LightShadow = LightShadow;\n\texports.Light = Light;\n\texports.StereoCamera = StereoCamera;\n\texports.PerspectiveCamera = PerspectiveCamera;\n\texports.OrthographicCamera = OrthographicCamera;\n\texports.CubeCamera = CubeCamera;\n\texports.ArrayCamera = ArrayCamera;\n\texports.Camera = Camera;\n\texports.AudioListener = AudioListener;\n\texports.PositionalAudio = PositionalAudio;\n\texports.AudioContext = AudioContext;\n\texports.AudioAnalyser = AudioAnalyser;\n\texports.Audio = Audio;\n\texports.VectorKeyframeTrack = VectorKeyframeTrack;\n\texports.StringKeyframeTrack = StringKeyframeTrack;\n\texports.QuaternionKeyframeTrack = QuaternionKeyframeTrack;\n\texports.NumberKeyframeTrack = NumberKeyframeTrack;\n\texports.ColorKeyframeTrack = ColorKeyframeTrack;\n\texports.BooleanKeyframeTrack = BooleanKeyframeTrack;\n\texports.PropertyMixer = PropertyMixer;\n\texports.PropertyBinding = PropertyBinding;\n\texports.KeyframeTrack = KeyframeTrack;\n\texports.AnimationUtils = AnimationUtils;\n\texports.AnimationObjectGroup = AnimationObjectGroup;\n\texports.AnimationMixer = AnimationMixer;\n\texports.AnimationClip = AnimationClip;\n\texports.Uniform = Uniform;\n\texports.InstancedBufferGeometry = InstancedBufferGeometry;\n\texports.BufferGeometry = BufferGeometry;\n\texports.GeometryIdCount = GeometryIdCount;\n\texports.Geometry = Geometry;\n\texports.InterleavedBufferAttribute = InterleavedBufferAttribute;\n\texports.InstancedInterleavedBuffer = InstancedInterleavedBuffer;\n\texports.InterleavedBuffer = InterleavedBuffer;\n\texports.InstancedBufferAttribute = InstancedBufferAttribute;\n\texports.Face3 = Face3;\n\texports.Object3D = Object3D;\n\texports.Raycaster = Raycaster;\n\texports.Layers = Layers;\n\texports.EventDispatcher = EventDispatcher;\n\texports.Clock = Clock;\n\texports.QuaternionLinearInterpolant = QuaternionLinearInterpolant;\n\texports.LinearInterpolant = LinearInterpolant;\n\texports.DiscreteInterpolant = DiscreteInterpolant;\n\texports.CubicInterpolant = CubicInterpolant;\n\texports.Interpolant = Interpolant;\n\texports.Triangle = Triangle;\n\texports.Math = _Math;\n\texports.Spherical = Spherical;\n\texports.Cylindrical = Cylindrical;\n\texports.Plane = Plane;\n\texports.Frustum = Frustum;\n\texports.Sphere = Sphere;\n\texports.Ray = Ray;\n\texports.Matrix4 = Matrix4;\n\texports.Matrix3 = Matrix3;\n\texports.Box3 = Box3;\n\texports.Box2 = Box2;\n\texports.Line3 = Line3;\n\texports.Euler = Euler;\n\texports.Vector4 = Vector4;\n\texports.Vector3 = Vector3;\n\texports.Vector2 = Vector2;\n\texports.Quaternion = Quaternion;\n\texports.Color = Color;\n\texports.ImmediateRenderObject = ImmediateRenderObject;\n\texports.VertexNormalsHelper = VertexNormalsHelper;\n\texports.SpotLightHelper = SpotLightHelper;\n\texports.SkeletonHelper = SkeletonHelper;\n\texports.PointLightHelper = PointLightHelper;\n\texports.RectAreaLightHelper = RectAreaLightHelper;\n\texports.HemisphereLightHelper = HemisphereLightHelper;\n\texports.GridHelper = GridHelper;\n\texports.PolarGridHelper = PolarGridHelper;\n\texports.FaceNormalsHelper = FaceNormalsHelper;\n\texports.DirectionalLightHelper = DirectionalLightHelper;\n\texports.CameraHelper = CameraHelper;\n\texports.BoxHelper = BoxHelper;\n\texports.Box3Helper = Box3Helper;\n\texports.PlaneHelper = PlaneHelper;\n\texports.ArrowHelper = ArrowHelper;\n\texports.AxisHelper = AxisHelper;\n\texports.CatmullRomCurve3 = CatmullRomCurve3;\n\texports.CubicBezierCurve3 = CubicBezierCurve3;\n\texports.QuadraticBezierCurve3 = QuadraticBezierCurve3;\n\texports.LineCurve3 = LineCurve3;\n\texports.ArcCurve = ArcCurve;\n\texports.EllipseCurve = EllipseCurve;\n\texports.SplineCurve = SplineCurve;\n\texports.CubicBezierCurve = CubicBezierCurve;\n\texports.QuadraticBezierCurve = QuadraticBezierCurve;\n\texports.LineCurve = LineCurve;\n\texports.Shape = Shape;\n\texports.Path = Path;\n\texports.ShapePath = ShapePath;\n\texports.Font = Font;\n\texports.CurvePath = CurvePath;\n\texports.Curve = Curve;\n\texports.ShapeUtils = ShapeUtils;\n\texports.SceneUtils = SceneUtils;\n\texports.WebGLUtils = WebGLUtils;\n\texports.WireframeGeometry = WireframeGeometry;\n\texports.ParametricGeometry = ParametricGeometry;\n\texports.ParametricBufferGeometry = ParametricBufferGeometry;\n\texports.TetrahedronGeometry = TetrahedronGeometry;\n\texports.TetrahedronBufferGeometry = TetrahedronBufferGeometry;\n\texports.OctahedronGeometry = OctahedronGeometry;\n\texports.OctahedronBufferGeometry = OctahedronBufferGeometry;\n\texports.IcosahedronGeometry = IcosahedronGeometry;\n\texports.IcosahedronBufferGeometry = IcosahedronBufferGeometry;\n\texports.DodecahedronGeometry = DodecahedronGeometry;\n\texports.DodecahedronBufferGeometry = DodecahedronBufferGeometry;\n\texports.PolyhedronGeometry = PolyhedronGeometry;\n\texports.PolyhedronBufferGeometry = PolyhedronBufferGeometry;\n\texports.TubeGeometry = TubeGeometry;\n\texports.TubeBufferGeometry = TubeBufferGeometry;\n\texports.TorusKnotGeometry = TorusKnotGeometry;\n\texports.TorusKnotBufferGeometry = TorusKnotBufferGeometry;\n\texports.TorusGeometry = TorusGeometry;\n\texports.TorusBufferGeometry = TorusBufferGeometry;\n\texports.TextGeometry = TextGeometry;\n\texports.TextBufferGeometry = TextBufferGeometry;\n\texports.SphereGeometry = SphereGeometry;\n\texports.SphereBufferGeometry = SphereBufferGeometry;\n\texports.RingGeometry = RingGeometry;\n\texports.RingBufferGeometry = RingBufferGeometry;\n\texports.PlaneGeometry = PlaneGeometry;\n\texports.PlaneBufferGeometry = PlaneBufferGeometry;\n\texports.LatheGeometry = LatheGeometry;\n\texports.LatheBufferGeometry = LatheBufferGeometry;\n\texports.ShapeGeometry = ShapeGeometry;\n\texports.ShapeBufferGeometry = ShapeBufferGeometry;\n\texports.ExtrudeGeometry = ExtrudeGeometry;\n\texports.ExtrudeBufferGeometry = ExtrudeBufferGeometry;\n\texports.EdgesGeometry = EdgesGeometry;\n\texports.ConeGeometry = ConeGeometry;\n\texports.ConeBufferGeometry = ConeBufferGeometry;\n\texports.CylinderGeometry = CylinderGeometry;\n\texports.CylinderBufferGeometry = CylinderBufferGeometry;\n\texports.CircleGeometry = CircleGeometry;\n\texports.CircleBufferGeometry = CircleBufferGeometry;\n\texports.BoxGeometry = BoxGeometry;\n\texports.BoxBufferGeometry = BoxBufferGeometry;\n\texports.ShadowMaterial = ShadowMaterial;\n\texports.SpriteMaterial = SpriteMaterial;\n\texports.RawShaderMaterial = RawShaderMaterial;\n\texports.ShaderMaterial = ShaderMaterial;\n\texports.PointsMaterial = PointsMaterial;\n\texports.MeshPhysicalMaterial = MeshPhysicalMaterial;\n\texports.MeshStandardMaterial = MeshStandardMaterial;\n\texports.MeshPhongMaterial = MeshPhongMaterial;\n\texports.MeshToonMaterial = MeshToonMaterial;\n\texports.MeshNormalMaterial = MeshNormalMaterial;\n\texports.MeshLambertMaterial = MeshLambertMaterial;\n\texports.MeshDepthMaterial = MeshDepthMaterial;\n\texports.MeshDistanceMaterial = MeshDistanceMaterial;\n\texports.MeshBasicMaterial = MeshBasicMaterial;\n\texports.LineDashedMaterial = LineDashedMaterial;\n\texports.LineBasicMaterial = LineBasicMaterial;\n\texports.Material = Material;\n\texports.Float64BufferAttribute = Float64BufferAttribute;\n\texports.Float32BufferAttribute = Float32BufferAttribute;\n\texports.Uint32BufferAttribute = Uint32BufferAttribute;\n\texports.Int32BufferAttribute = Int32BufferAttribute;\n\texports.Uint16BufferAttribute = Uint16BufferAttribute;\n\texports.Int16BufferAttribute = Int16BufferAttribute;\n\texports.Uint8ClampedBufferAttribute = Uint8ClampedBufferAttribute;\n\texports.Uint8BufferAttribute = Uint8BufferAttribute;\n\texports.Int8BufferAttribute = Int8BufferAttribute;\n\texports.BufferAttribute = BufferAttribute;\n\texports.REVISION = REVISION;\n\texports.MOUSE = MOUSE;\n\texports.CullFaceNone = CullFaceNone;\n\texports.CullFaceBack = CullFaceBack;\n\texports.CullFaceFront = CullFaceFront;\n\texports.CullFaceFrontBack = CullFaceFrontBack;\n\texports.FrontFaceDirectionCW = FrontFaceDirectionCW;\n\texports.FrontFaceDirectionCCW = FrontFaceDirectionCCW;\n\texports.BasicShadowMap = BasicShadowMap;\n\texports.PCFShadowMap = PCFShadowMap;\n\texports.PCFSoftShadowMap = PCFSoftShadowMap;\n\texports.FrontSide = FrontSide;\n\texports.BackSide = BackSide;\n\texports.DoubleSide = DoubleSide;\n\texports.FlatShading = FlatShading;\n\texports.SmoothShading = SmoothShading;\n\texports.NoColors = NoColors;\n\texports.FaceColors = FaceColors;\n\texports.VertexColors = VertexColors;\n\texports.NoBlending = NoBlending;\n\texports.NormalBlending = NormalBlending;\n\texports.AdditiveBlending = AdditiveBlending;\n\texports.SubtractiveBlending = SubtractiveBlending;\n\texports.MultiplyBlending = MultiplyBlending;\n\texports.CustomBlending = CustomBlending;\n\texports.AddEquation = AddEquation;\n\texports.SubtractEquation = SubtractEquation;\n\texports.ReverseSubtractEquation = ReverseSubtractEquation;\n\texports.MinEquation = MinEquation;\n\texports.MaxEquation = MaxEquation;\n\texports.ZeroFactor = ZeroFactor;\n\texports.OneFactor = OneFactor;\n\texports.SrcColorFactor = SrcColorFactor;\n\texports.OneMinusSrcColorFactor = OneMinusSrcColorFactor;\n\texports.SrcAlphaFactor = SrcAlphaFactor;\n\texports.OneMinusSrcAlphaFactor = OneMinusSrcAlphaFactor;\n\texports.DstAlphaFactor = DstAlphaFactor;\n\texports.OneMinusDstAlphaFactor = OneMinusDstAlphaFactor;\n\texports.DstColorFactor = DstColorFactor;\n\texports.OneMinusDstColorFactor = OneMinusDstColorFactor;\n\texports.SrcAlphaSaturateFactor = SrcAlphaSaturateFactor;\n\texports.NeverDepth = NeverDepth;\n\texports.AlwaysDepth = AlwaysDepth;\n\texports.LessDepth = LessDepth;\n\texports.LessEqualDepth = LessEqualDepth;\n\texports.EqualDepth = EqualDepth;\n\texports.GreaterEqualDepth = GreaterEqualDepth;\n\texports.GreaterDepth = GreaterDepth;\n\texports.NotEqualDepth = NotEqualDepth;\n\texports.MultiplyOperation = MultiplyOperation;\n\texports.MixOperation = MixOperation;\n\texports.AddOperation = AddOperation;\n\texports.NoToneMapping = NoToneMapping;\n\texports.LinearToneMapping = LinearToneMapping;\n\texports.ReinhardToneMapping = ReinhardToneMapping;\n\texports.Uncharted2ToneMapping = Uncharted2ToneMapping;\n\texports.CineonToneMapping = CineonToneMapping;\n\texports.UVMapping = UVMapping;\n\texports.CubeReflectionMapping = CubeReflectionMapping;\n\texports.CubeRefractionMapping = CubeRefractionMapping;\n\texports.EquirectangularReflectionMapping = EquirectangularReflectionMapping;\n\texports.EquirectangularRefractionMapping = EquirectangularRefractionMapping;\n\texports.SphericalReflectionMapping = SphericalReflectionMapping;\n\texports.CubeUVReflectionMapping = CubeUVReflectionMapping;\n\texports.CubeUVRefractionMapping = CubeUVRefractionMapping;\n\texports.RepeatWrapping = RepeatWrapping;\n\texports.ClampToEdgeWrapping = ClampToEdgeWrapping;\n\texports.MirroredRepeatWrapping = MirroredRepeatWrapping;\n\texports.NearestFilter = NearestFilter;\n\texports.NearestMipMapNearestFilter = NearestMipMapNearestFilter;\n\texports.NearestMipMapLinearFilter = NearestMipMapLinearFilter;\n\texports.LinearFilter = LinearFilter;\n\texports.LinearMipMapNearestFilter = LinearMipMapNearestFilter;\n\texports.LinearMipMapLinearFilter = LinearMipMapLinearFilter;\n\texports.UnsignedByteType = UnsignedByteType;\n\texports.ByteType = ByteType;\n\texports.ShortType = ShortType;\n\texports.UnsignedShortType = UnsignedShortType;\n\texports.IntType = IntType;\n\texports.UnsignedIntType = UnsignedIntType;\n\texports.FloatType = FloatType;\n\texports.HalfFloatType = HalfFloatType;\n\texports.UnsignedShort4444Type = UnsignedShort4444Type;\n\texports.UnsignedShort5551Type = UnsignedShort5551Type;\n\texports.UnsignedShort565Type = UnsignedShort565Type;\n\texports.UnsignedInt248Type = UnsignedInt248Type;\n\texports.AlphaFormat = AlphaFormat;\n\texports.RGBFormat = RGBFormat;\n\texports.RGBAFormat = RGBAFormat;\n\texports.LuminanceFormat = LuminanceFormat;\n\texports.LuminanceAlphaFormat = LuminanceAlphaFormat;\n\texports.RGBEFormat = RGBEFormat;\n\texports.DepthFormat = DepthFormat;\n\texports.DepthStencilFormat = DepthStencilFormat;\n\texports.RGB_S3TC_DXT1_Format = RGB_S3TC_DXT1_Format;\n\texports.RGBA_S3TC_DXT1_Format = RGBA_S3TC_DXT1_Format;\n\texports.RGBA_S3TC_DXT3_Format = RGBA_S3TC_DXT3_Format;\n\texports.RGBA_S3TC_DXT5_Format = RGBA_S3TC_DXT5_Format;\n\texports.RGB_PVRTC_4BPPV1_Format = RGB_PVRTC_4BPPV1_Format;\n\texports.RGB_PVRTC_2BPPV1_Format = RGB_PVRTC_2BPPV1_Format;\n\texports.RGBA_PVRTC_4BPPV1_Format = RGBA_PVRTC_4BPPV1_Format;\n\texports.RGBA_PVRTC_2BPPV1_Format = RGBA_PVRTC_2BPPV1_Format;\n\texports.RGB_ETC1_Format = RGB_ETC1_Format;\n\texports.LoopOnce = LoopOnce;\n\texports.LoopRepeat = LoopRepeat;\n\texports.LoopPingPong = LoopPingPong;\n\texports.InterpolateDiscrete = InterpolateDiscrete;\n\texports.InterpolateLinear = InterpolateLinear;\n\texports.InterpolateSmooth = InterpolateSmooth;\n\texports.ZeroCurvatureEnding = ZeroCurvatureEnding;\n\texports.ZeroSlopeEnding = ZeroSlopeEnding;\n\texports.WrapAroundEnding = WrapAroundEnding;\n\texports.TrianglesDrawMode = TrianglesDrawMode;\n\texports.TriangleStripDrawMode = TriangleStripDrawMode;\n\texports.TriangleFanDrawMode = TriangleFanDrawMode;\n\texports.LinearEncoding = LinearEncoding;\n\texports.sRGBEncoding = sRGBEncoding;\n\texports.GammaEncoding = GammaEncoding;\n\texports.RGBEEncoding = RGBEEncoding;\n\texports.LogLuvEncoding = LogLuvEncoding;\n\texports.RGBM7Encoding = RGBM7Encoding;\n\texports.RGBM16Encoding = RGBM16Encoding;\n\texports.RGBDEncoding = RGBDEncoding;\n\texports.BasicDepthPacking = BasicDepthPacking;\n\texports.RGBADepthPacking = RGBADepthPacking;\n\texports.CubeGeometry = BoxGeometry;\n\texports.Face4 = Face4;\n\texports.LineStrip = LineStrip;\n\texports.LinePieces = LinePieces;\n\texports.MeshFaceMaterial = MeshFaceMaterial;\n\texports.MultiMaterial = MultiMaterial;\n\texports.PointCloud = PointCloud;\n\texports.Particle = Particle;\n\texports.ParticleSystem = ParticleSystem;\n\texports.PointCloudMaterial = PointCloudMaterial;\n\texports.ParticleBasicMaterial = ParticleBasicMaterial;\n\texports.ParticleSystemMaterial = ParticleSystemMaterial;\n\texports.Vertex = Vertex;\n\texports.DynamicBufferAttribute = DynamicBufferAttribute;\n\texports.Int8Attribute = Int8Attribute;\n\texports.Uint8Attribute = Uint8Attribute;\n\texports.Uint8ClampedAttribute = Uint8ClampedAttribute;\n\texports.Int16Attribute = Int16Attribute;\n\texports.Uint16Attribute = Uint16Attribute;\n\texports.Int32Attribute = Int32Attribute;\n\texports.Uint32Attribute = Uint32Attribute;\n\texports.Float32Attribute = Float32Attribute;\n\texports.Float64Attribute = Float64Attribute;\n\texports.ClosedSplineCurve3 = ClosedSplineCurve3;\n\texports.SplineCurve3 = SplineCurve3;\n\texports.Spline = Spline;\n\texports.BoundingBoxHelper = BoundingBoxHelper;\n\texports.EdgesHelper = EdgesHelper;\n\texports.WireframeHelper = WireframeHelper;\n\texports.XHRLoader = XHRLoader;\n\texports.BinaryTextureLoader = BinaryTextureLoader;\n\texports.GeometryUtils = GeometryUtils;\n\texports.ImageUtils = ImageUtils;\n\texports.Projector = Projector;\n\texports.CanvasRenderer = CanvasRenderer;\n\n\tObject.defineProperty(exports, '__esModule', { value: true });\n\n})));\n\n},{}],42:[function(_dereq_,module,exports){\n/**\n* @author Tim Knip / http://www.floorplanner.com/ / tim at floorplanner.com\n* @author Tony Parisi / http://www.tonyparisi.com/\n*/\n\nTHREE.ColladaLoader = function () {\n\n\tvar COLLADA = null;\n\tvar scene = null;\n\tvar visualScene;\n\tvar kinematicsModel;\n\n\tvar readyCallbackFunc = null;\n\n\tvar sources = {};\n\tvar images = {};\n\tvar animations = {};\n\tvar controllers = {};\n\tvar geometries = {};\n\tvar materials = {};\n\tvar effects = {};\n\tvar cameras = {};\n\tvar lights = {};\n\n\tvar animData;\n\tvar kinematics;\n\tvar visualScenes;\n\tvar kinematicsModels;\n\tvar baseUrl;\n\tvar morphs;\n\tvar skins;\n\n\tvar flip_uv = true;\n\n\tvar options = {\n\t\t// Force Geometry to always be centered at the local origin of the\n\t\t// containing Mesh.\n\t\tcenterGeometry: false,\n\n\t\t// Axis conversion is done for geometries, animations, and controllers.\n\t\t// If we ever pull cameras or lights out of the COLLADA file, they'll\n\t\t// need extra work.\n\t\tconvertUpAxis: false,\n\n\t\tsubdivideFaces: true,\n\n\t\tupAxis: 'Y',\n\n\t\t// For reflective or refractive materials we'll use this cubemap\n\t\tdefaultEnvMap: null\n\n\t};\n\n\tvar colladaUnit = 1.0;\n\tvar colladaUp = 'Y';\n\tvar upConversion = null;\n\n\tfunction load ( url, readyCallback, progressCallback, failCallback ) {\n\n\t\tvar length = 0;\n\n\t\tif ( document.implementation && document.implementation.createDocument ) {\n\n\t\t\tvar request = new XMLHttpRequest();\n\n\t\t\trequest.onreadystatechange = function() {\n\n\t\t\t\tif ( request.readyState === 4 ) {\n\n\t\t\t\t\tif ( request.status === 0 || request.status === 200 ) {\n\n\t\t\t\t\t\tif ( request.response ) {\n\n\t\t\t\t\t\t\treadyCallbackFunc = readyCallback;\n\t\t\t\t\t\t\tparse( request.response, undefined, url );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tif ( failCallback ) {\n\n\t\t\t\t\t\t\t\tfailCallback( { type: 'error', url: url } );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tconsole.error( \"ColladaLoader: Empty or non-existing file (\" + url + \")\" );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}else{\n\n\t\t\t\t\t\tif( failCallback ){\n\n\t\t\t\t\t\t\tfailCallback( { type: 'error', url: url } );\n\n\t\t\t\t\t\t}else{\n\n\t\t\t\t\t\t\tconsole.error( 'ColladaLoader: Couldn\\'t load \"' + url + '\" (' + request.status + ')' );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( request.readyState === 3 ) {\n\n\t\t\t\t\tif ( progressCallback ) {\n\n\t\t\t\t\t\tif ( length === 0 ) {\n\n\t\t\t\t\t\t\tlength = request.getResponseHeader( \"Content-Length\" );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tprogressCallback( { total: length, loaded: request.responseText.length } );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t\trequest.open( \"GET\", url, true );\n\t\t\trequest.send( null );\n\n\t\t} else {\n\n\t\t\talert( \"Don't know how to parse XML!\" );\n\n\t\t}\n\n\t}\n\n\tfunction parse( text, callBack, url ) {\n\n\t\tCOLLADA = new DOMParser().parseFromString( text, 'text/xml' );\n\t\tcallBack = callBack || readyCallbackFunc;\n\n\t\tif ( url !== undefined ) {\n\n\t\t\tvar parts = url.split( '/' );\n\t\t\tparts.pop();\n\t\t\tbaseUrl = ( parts.length < 1 ? '.' : parts.join( '/' ) ) + '/';\n\n\t\t}\n\n\t\tparseAsset();\n\t\tsetUpConversion();\n\t\timages = parseLib( \"library_images image\", _Image, \"image\" );\n\t\tmaterials = parseLib( \"library_materials material\", Material, \"material\" );\n\t\teffects = parseLib( \"library_effects effect\", Effect, \"effect\" );\n\t\tgeometries = parseLib( \"library_geometries geometry\", Geometry, \"geometry\" );\n\t\tcameras = parseLib( \"library_cameras camera\", Camera, \"camera\" );\n\t\tlights = parseLib( \"library_lights light\", Light, \"light\" );\n\t\tcontrollers = parseLib( \"library_controllers controller\", Controller, \"controller\" );\n\t\tanimations = parseLib( \"library_animations animation\", Animation, \"animation\" );\n\t\tvisualScenes = parseLib( \"library_visual_scenes visual_scene\", VisualScene, \"visual_scene\" );\n\t\tkinematicsModels = parseLib( \"library_kinematics_models kinematics_model\", KinematicsModel, \"kinematics_model\" );\n\n\t\tmorphs = [];\n\t\tskins = [];\n\n\t\tvisualScene = parseScene();\n\t\tscene = new THREE.Group();\n\n\t\tfor ( var i = 0; i < visualScene.nodes.length; i ++ ) {\n\n\t\t\tscene.add( createSceneGraph( visualScene.nodes[ i ] ) );\n\n\t\t}\n\n\t\t// unit conversion\n\t\tscene.scale.multiplyScalar( colladaUnit );\n\n\t\tcreateAnimations();\n\n\t\tkinematicsModel = parseKinematicsModel();\n\t\tcreateKinematics();\n\n\t\tvar result = {\n\n\t\t\tscene: scene,\n\t\t\tmorphs: morphs,\n\t\t\tskins: skins,\n\t\t\tanimations: animData,\n\t\t\tkinematics: kinematics,\n\t\t\tdae: {\n\t\t\t\timages: images,\n\t\t\t\tmaterials: materials,\n\t\t\t\tcameras: cameras,\n\t\t\t\tlights: lights,\n\t\t\t\teffects: effects,\n\t\t\t\tgeometries: geometries,\n\t\t\t\tcontrollers: controllers,\n\t\t\t\tanimations: animations,\n\t\t\t\tvisualScenes: visualScenes,\n\t\t\t\tvisualScene: visualScene,\n\t\t\t\tscene: visualScene,\n\t\t\t\tkinematicsModels: kinematicsModels,\n\t\t\t\tkinematicsModel: kinematicsModel\n\t\t\t}\n\n\t\t};\n\n\t\tif ( callBack ) {\n\n\t\t\tcallBack( result );\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n\tfunction parseAsset () {\n\n\t\tvar elements = COLLADA.querySelectorAll('asset');\n\n\t\tvar element = elements[0];\n\n\t\tif ( element && element.childNodes ) {\n\n\t\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\t\tvar child = element.childNodes[ i ];\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'unit':\n\n\t\t\t\t\t\tvar meter = child.getAttribute( 'meter' );\n\n\t\t\t\t\t\tif ( meter ) {\n\n\t\t\t\t\t\t\tcolladaUnit = parseFloat( meter );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'up_axis':\n\n\t\t\t\t\t\tcolladaUp = child.textContent.charAt(0);\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction parseLib ( q, classSpec, prefix ) {\n\n\t\tvar elements = COLLADA.querySelectorAll(q);\n\n\t\tvar lib = {};\n\n\t\tvar i = 0;\n\n\t\tvar elementsLength = elements.length;\n\n\t\tfor ( var j = 0; j < elementsLength; j ++ ) {\n\n\t\t\tvar element = elements[j];\n\t\t\tvar daeElement = ( new classSpec() ).parse( element );\n\n\t\t\tif ( !daeElement.id || daeElement.id.length === 0 ) daeElement.id = prefix + ( i ++ );\n\t\t\tlib[ daeElement.id ] = daeElement;\n\n\t\t}\n\n\t\treturn lib;\n\n\t}\n\n\tfunction parseScene() {\n\n\t\tvar sceneElement = COLLADA.querySelectorAll('scene instance_visual_scene')[0];\n\n\t\tif ( sceneElement ) {\n\n\t\t\tvar url = sceneElement.getAttribute( 'url' ).replace( /^#/, '' );\n\t\t\treturn visualScenes[ url.length > 0 ? url : 'visual_scene0' ];\n\n\t\t} else {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t}\n\n\tfunction parseKinematicsModel() {\n\n\t\tvar kinematicsModelElement = COLLADA.querySelectorAll('instance_kinematics_model')[0];\n\n\t\tif ( kinematicsModelElement ) {\n\n\t\t\tvar url = kinematicsModelElement.getAttribute( 'url' ).replace(/^#/, '');\n\t\t\treturn kinematicsModels[ url.length > 0 ? url : 'kinematics_model0' ];\n\n\t\t} else {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t}\n\n\tfunction createAnimations() {\n\n\t\tanimData = [];\n\n\t\t// fill in the keys\n\t\trecurseHierarchy( scene );\n\n\t}\n\n\tfunction recurseHierarchy( node ) {\n\n\t\tvar n = visualScene.getChildById( node.colladaId, true ),\n\t\t\tnewData = null;\n\n\t\tif ( n && n.keys ) {\n\n\t\t\tnewData = {\n\t\t\t\tfps: 60,\n\t\t\t\thierarchy: [ {\n\t\t\t\t\tnode: n,\n\t\t\t\t\tkeys: n.keys,\n\t\t\t\t\tsids: n.sids\n\t\t\t\t} ],\n\t\t\t\tnode: node,\n\t\t\t\tname: 'animation_' + node.name,\n\t\t\t\tlength: 0\n\t\t\t};\n\n\t\t\tanimData.push(newData);\n\n\t\t\tfor ( var i = 0, il = n.keys.length; i < il; i ++ ) {\n\n\t\t\t\tnewData.length = Math.max( newData.length, n.keys[i].time );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tnewData = {\n\t\t\t\thierarchy: [ {\n\t\t\t\t\tkeys: [],\n\t\t\t\t\tsids: []\n\t\t\t\t} ]\n\t\t\t}\n\n\t\t}\n\n\t\tfor ( var i = 0, il = node.children.length; i < il; i ++ ) {\n\n\t\t\tvar d = recurseHierarchy( node.children[i] );\n\n\t\t\tfor ( var j = 0, jl = d.hierarchy.length; j < jl; j ++ ) {\n\n\t\t\t\tnewData.hierarchy.push( {\n\t\t\t\t\tkeys: [],\n\t\t\t\t\tsids: []\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn newData;\n\n\t}\n\n\tfunction calcAnimationBounds () {\n\n\t\tvar start = 1000000;\n\t\tvar end = -start;\n\t\tvar frames = 0;\n\t\tvar ID;\n\t\tfor ( var id in animations ) {\n\n\t\t\tvar animation = animations[ id ];\n\t\t\tID = ID || animation.id;\n\t\t\tfor ( var i = 0; i < animation.sampler.length; i ++ ) {\n\n\t\t\t\tvar sampler = animation.sampler[ i ];\n\n\t\t\t\tsampler.create();\n\n\t\t\t\tstart = Math.min( start, sampler.startTime );\n\t\t\t\tend = Math.max( end, sampler.endTime );\n\t\t\t\tframes = Math.max( frames, sampler.input.length );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn { start:start, end:end, frames:frames,ID:ID };\n\n\t}\n\n\tfunction createMorph ( geometry, ctrl ) {\n\n\t\tvar morphCtrl = ctrl instanceof InstanceController ? controllers[ ctrl.url ] : ctrl;\n\n\t\tif ( !morphCtrl || !morphCtrl.morph ) {\n\n\t\t\tconsole.log(\"could not find morph controller!\");\n\t\t\treturn;\n\n\t\t}\n\n\t\tvar morph = morphCtrl.morph;\n\n\t\tfor ( var i = 0; i < morph.targets.length; i ++ ) {\n\n\t\t\tvar target_id = morph.targets[ i ];\n\t\t\tvar daeGeometry = geometries[ target_id ];\n\n\t\t\tif ( !daeGeometry.mesh ||\n\t\t\t\t !daeGeometry.mesh.primitives ||\n\t\t\t\t !daeGeometry.mesh.primitives.length ) {\n\t\t\t\t continue;\n\t\t\t}\n\n\t\t\tvar target = daeGeometry.mesh.primitives[ 0 ].geometry;\n\n\t\t\tif ( target.vertices.length === geometry.vertices.length ) {\n\n\t\t\t\tgeometry.morphTargets.push( { name: \"target_1\", vertices: target.vertices } );\n\n\t\t\t}\n\n\t\t}\n\n\t\tgeometry.morphTargets.push( { name: \"target_Z\", vertices: geometry.vertices } );\n\n\t}\n\n\tfunction createSkin ( geometry, ctrl, applyBindShape ) {\n\n\t\tvar skinCtrl = controllers[ ctrl.url ];\n\n\t\tif ( !skinCtrl || !skinCtrl.skin ) {\n\n\t\t\tconsole.log( \"could not find skin controller!\" );\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( !ctrl.skeleton || !ctrl.skeleton.length ) {\n\n\t\t\tconsole.log( \"could not find the skeleton for the skin!\" );\n\t\t\treturn;\n\n\t\t}\n\n\t\tvar skin = skinCtrl.skin;\n\t\tvar skeleton = visualScene.getChildById( ctrl.skeleton[ 0 ] );\n\t\tvar hierarchy = [];\n\n\t\tapplyBindShape = applyBindShape !== undefined ? applyBindShape : true;\n\n\t\tvar bones = [];\n\t\tgeometry.skinWeights = [];\n\t\tgeometry.skinIndices = [];\n\n\t\t//createBones( geometry.bones, skin, hierarchy, skeleton, null, -1 );\n\t\t//createWeights( skin, geometry.bones, geometry.skinIndices, geometry.skinWeights );\n\n\t\t/*\n\t\tgeometry.animation = {\n\t\t\tname: 'take_001',\n\t\t\tfps: 30,\n\t\t\tlength: 2,\n\t\t\tJIT: true,\n\t\t\thierarchy: hierarchy\n\t\t};\n\t\t*/\n\n\t\tif ( applyBindShape ) {\n\n\t\t\tfor ( var i = 0; i < geometry.vertices.length; i ++ ) {\n\n\t\t\t\tgeometry.vertices[ i ].applyMatrix4( skin.bindShapeMatrix );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction setupSkeleton ( node, bones, frame, parent ) {\n\n\t\tnode.world = node.world || new THREE.Matrix4();\n\t\tnode.localworld = node.localworld || new THREE.Matrix4();\n\t\tnode.world.copy( node.matrix );\n\t\tnode.localworld.copy( node.matrix );\n\n\t\tif ( node.channels && node.channels.length ) {\n\n\t\t\tvar channel = node.channels[ 0 ];\n\t\t\tvar m = channel.sampler.output[ frame ];\n\n\t\t\tif ( m instanceof THREE.Matrix4 ) {\n\n\t\t\t\tnode.world.copy( m );\n\t\t\t\tnode.localworld.copy(m);\n\t\t\t\tif (frame === 0)\n\t\t\t\t\tnode.matrix.copy(m);\n\t\t\t}\n\n\t\t}\n\n\t\tif ( parent ) {\n\n\t\t\tnode.world.multiplyMatrices( parent, node.world );\n\n\t\t}\n\n\t\tbones.push( node );\n\n\t\tfor ( var i = 0; i < node.nodes.length; i ++ ) {\n\n\t\t\tsetupSkeleton( node.nodes[ i ], bones, frame, node.world );\n\n\t\t}\n\n\t}\n\n\tfunction setupSkinningMatrices ( bones, skin ) {\n\n\t\t// FIXME: this is dumb...\n\n\t\tfor ( var i = 0; i < bones.length; i ++ ) {\n\n\t\t\tvar bone = bones[ i ];\n\t\t\tvar found = -1;\n\n\t\t\tif ( bone.type != 'JOINT' ) continue;\n\n\t\t\tfor ( var j = 0; j < skin.joints.length; j ++ ) {\n\n\t\t\t\tif ( bone.sid === skin.joints[ j ] ) {\n\n\t\t\t\t\tfound = j;\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( found >= 0 ) {\n\n\t\t\t\tvar inv = skin.invBindMatrices[ found ];\n\n\t\t\t\tbone.invBindMatrix = inv;\n\t\t\t\tbone.skinningMatrix = new THREE.Matrix4();\n\t\t\t\tbone.skinningMatrix.multiplyMatrices(bone.world, inv); // (IBMi * JMi)\n\t\t\t\tbone.animatrix = new THREE.Matrix4();\n\n\t\t\t\tbone.animatrix.copy(bone.localworld);\n\t\t\t\tbone.weights = [];\n\n\t\t\t\tfor ( var j = 0; j < skin.weights.length; j ++ ) {\n\n\t\t\t\t\tfor (var k = 0; k < skin.weights[ j ].length; k ++ ) {\n\n\t\t\t\t\t\tvar w = skin.weights[ j ][ k ];\n\n\t\t\t\t\t\tif ( w.joint === found ) {\n\n\t\t\t\t\t\t\tbone.weights.push( w );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( \"ColladaLoader: Could not find joint '\" + bone.sid + \"'.\" );\n\n\t\t\t\tbone.skinningMatrix = new THREE.Matrix4();\n\t\t\t\tbone.weights = [];\n\n\t\t\t}\n\t\t}\n\n\t}\n\n\t//Walk the Collada tree and flatten the bones into a list, extract the position, quat and scale from the matrix\n\tfunction flattenSkeleton(skeleton) {\n\n\t\tvar list = [];\n\t\tvar walk = function(parentid, node, list) {\n\n\t\t\tvar bone = {};\n\t\t\tbone.name = node.sid;\n\t\t\tbone.parent = parentid;\n\t\t\tbone.matrix = node.matrix;\n\t\t\tvar data = [ new THREE.Vector3(),new THREE.Quaternion(),new THREE.Vector3() ];\n\t\t\tbone.matrix.decompose(data[0], data[1], data[2]);\n\n\t\t\tbone.pos = [ data[0].x,data[0].y,data[0].z ];\n\n\t\t\tbone.scl = [ data[2].x,data[2].y,data[2].z ];\n\t\t\tbone.rotq = [ data[1].x,data[1].y,data[1].z,data[1].w ];\n\t\t\tlist.push(bone);\n\n\t\t\tfor (var i in node.nodes) {\n\n\t\t\t\twalk(node.sid, node.nodes[i], list);\n\n\t\t\t}\n\n\t\t};\n\n\t\twalk(-1, skeleton, list);\n\t\treturn list;\n\n\t}\n\n\t//Move the vertices into the pose that is proper for the start of the animation\n\tfunction skinToBindPose(geometry,skeleton,skinController) {\n\n\t\tvar bones = [];\n\t\tsetupSkeleton( skeleton, bones, -1 );\n\t\tsetupSkinningMatrices( bones, skinController.skin );\n\t\tvar v = new THREE.Vector3();\n\t\tvar skinned = [];\n\n\t\tfor (var i = 0; i < geometry.vertices.length; i ++) {\n\n\t\t\tskinned.push(new THREE.Vector3());\n\n\t\t}\n\n\t\tfor ( i = 0; i < bones.length; i ++ ) {\n\n\t\t\tif ( bones[ i ].type != 'JOINT' ) continue;\n\n\t\t\tfor ( var j = 0; j < bones[ i ].weights.length; j ++ ) {\n\n\t\t\t\tvar w = bones[ i ].weights[ j ];\n\t\t\t\tvar vidx = w.index;\n\t\t\t\tvar weight = w.weight;\n\n\t\t\t\tvar o = geometry.vertices[vidx];\n\t\t\t\tvar s = skinned[vidx];\n\n\t\t\t\tv.x = o.x;\n\t\t\t\tv.y = o.y;\n\t\t\t\tv.z = o.z;\n\n\t\t\t\tv.applyMatrix4( bones[i].skinningMatrix );\n\n\t\t\t\ts.x += (v.x * weight);\n\t\t\t\ts.y += (v.y * weight);\n\t\t\t\ts.z += (v.z * weight);\n\t\t\t}\n\n\t\t}\n\n\t\tfor (var i = 0; i < geometry.vertices.length; i ++) {\n\n\t\t\tgeometry.vertices[i] = skinned[i];\n\n\t\t}\n\n\t}\n\n\tfunction applySkin( geometry, instanceCtrl, frame ) {\n\n\t\tif ( frame === undefined ) frame = 40;\n\n\t\tvar skinController = controllers[ instanceCtrl.url ];\n\n\t\tif ( !skinController || !skinController.skin ) {\n\n\t\t\tconsole.log( 'ColladaLoader: Could not find skin controller.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( !instanceCtrl.skeleton || !instanceCtrl.skeleton.length ) {\n\n\t\t\tconsole.log( 'ColladaLoader: Could not find the skeleton for the skin. ' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tvar animationBounds = calcAnimationBounds();\n\t\tvar skeleton = visualScene.getChildById( instanceCtrl.skeleton[0], true ) || visualScene.getChildBySid( instanceCtrl.skeleton[0], true );\n\n\t\t//flatten the skeleton into a list of bones\n\t\tvar bonelist = flattenSkeleton(skeleton);\n\t\tvar joints = skinController.skin.joints;\n\n\t\t//sort that list so that the order reflects the order in the joint list\n\t\tvar sortedbones = [];\n\t\tfor (var i = 0; i < joints.length; i ++) {\n\n\t\t\tfor (var j = 0; j < bonelist.length; j ++) {\n\n\t\t\t\tif (bonelist[j].name === joints[i]) {\n\n\t\t\t\t\tsortedbones[i] = bonelist[j];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t//hook up the parents by index instead of name\n\t\tfor (var i = 0; i < sortedbones.length; i ++) {\n\n\t\t\tfor (var j = 0; j < sortedbones.length; j ++) {\n\n\t\t\t\tif (sortedbones[i].parent === sortedbones[j].name) {\n\n\t\t\t\t\tsortedbones[i].parent = j;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\n\t\tvar i, j, w, vidx, weight;\n\t\tvar v = new THREE.Vector3(), o, s;\n\n\t\t// move vertices to bind shape\n\t\tfor ( i = 0; i < geometry.vertices.length; i ++ ) {\n\t\t\tgeometry.vertices[i].applyMatrix4( skinController.skin.bindShapeMatrix );\n\t\t}\n\n\t\tvar skinIndices = [];\n\t\tvar skinWeights = [];\n\t\tvar weights = skinController.skin.weights;\n\n\t\t// hook up the skin weights\n\t\t// TODO - this might be a good place to choose greatest 4 weights\n\t\tfor ( var i =0; i < weights.length; i ++ ) {\n\n\t\t\tvar indicies = new THREE.Vector4(weights[i][0] ? weights[i][0].joint : 0,weights[i][1] ? weights[i][1].joint : 0,weights[i][2] ? weights[i][2].joint : 0,weights[i][3] ? weights[i][3].joint : 0);\n\t\t\tvar weight = new THREE.Vector4(weights[i][0] ? weights[i][0].weight : 0,weights[i][1] ? weights[i][1].weight : 0,weights[i][2] ? weights[i][2].weight : 0,weights[i][3] ? weights[i][3].weight : 0);\n\n\t\t\tskinIndices.push(indicies);\n\t\t\tskinWeights.push(weight);\n\n\t\t}\n\n\t\tgeometry.skinIndices = skinIndices;\n\t\tgeometry.skinWeights = skinWeights;\n\t\tgeometry.bones = sortedbones;\n\t\t// process animation, or simply pose the rig if no animation\n\n\t\t//create an animation for the animated bones\n\t\t//NOTE: this has no effect when using morphtargets\n\t\tvar animationdata = { \"name\":animationBounds.ID,\"fps\":30,\"length\":animationBounds.frames / 30,\"hierarchy\":[] };\n\n\t\tfor (var j = 0; j < sortedbones.length; j ++) {\n\n\t\t\tanimationdata.hierarchy.push({ parent:sortedbones[j].parent, name:sortedbones[j].name, keys:[] });\n\n\t\t}\n\n\t\tconsole.log( 'ColladaLoader:', animationBounds.ID + ' has ' + sortedbones.length + ' bones.' );\n\n\n\n\t\tskinToBindPose(geometry, skeleton, skinController);\n\n\n\t\tfor ( frame = 0; frame < animationBounds.frames; frame ++ ) {\n\n\t\t\tvar bones = [];\n\t\t\tvar skinned = [];\n\t\t\t// process the frame and setup the rig with a fresh\n\t\t\t// transform, possibly from the bone's animation channel(s)\n\n\t\t\tsetupSkeleton( skeleton, bones, frame );\n\t\t\tsetupSkinningMatrices( bones, skinController.skin );\n\n\t\t\tfor (var i = 0; i < bones.length; i ++) {\n\n\t\t\t\tfor (var j = 0; j < animationdata.hierarchy.length; j ++) {\n\n\t\t\t\t\tif (animationdata.hierarchy[j].name === bones[i].sid) {\n\n\t\t\t\t\t\tvar key = {};\n\t\t\t\t\t\tkey.time = (frame / 30);\n\t\t\t\t\t\tkey.matrix = bones[i].animatrix;\n\n\t\t\t\t\t\tif (frame === 0)\n\t\t\t\t\t\t\tbones[i].matrix = key.matrix;\n\n\t\t\t\t\t\tvar data = [ new THREE.Vector3(),new THREE.Quaternion(),new THREE.Vector3() ];\n\t\t\t\t\t\tkey.matrix.decompose(data[0], data[1], data[2]);\n\n\t\t\t\t\t\tkey.pos = [ data[0].x,data[0].y,data[0].z ];\n\n\t\t\t\t\t\tkey.scl = [ data[2].x,data[2].y,data[2].z ];\n\t\t\t\t\t\tkey.rot = data[1];\n\n\t\t\t\t\t\tanimationdata.hierarchy[j].keys.push(key);\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tgeometry.animation = animationdata;\n\n\t\t}\n\n\t}\n\n\tfunction createKinematics() {\n\n\t\tif ( kinematicsModel && kinematicsModel.joints.length === 0 ) {\n\t\t\tkinematics = undefined;\n\t\t\treturn;\n\t\t}\n\n\t\tvar jointMap = {};\n\n\t\tvar _addToMap = function( jointIndex, parentVisualElement ) {\n\n\t\t\tvar parentVisualElementId = parentVisualElement.getAttribute( 'id' );\n\t\t\tvar colladaNode = visualScene.getChildById( parentVisualElementId, true );\n\t\t\tvar joint = kinematicsModel.joints[ jointIndex ];\n\n\t\t\tscene.traverse(function( node ) {\n\n\t\t\t\tif ( node.colladaId == parentVisualElementId ) {\n\n\t\t\t\t\tjointMap[ jointIndex ] = {\n\t\t\t\t\t\tnode: node,\n\t\t\t\t\t\ttransforms: colladaNode.transforms,\n\t\t\t\t\t\tjoint: joint,\n\t\t\t\t\t\tposition: joint.zeroPosition\n\t\t\t\t\t};\n\n\t\t\t\t}\n\n\t\t\t});\n\n\t\t};\n\n\t\tkinematics = {\n\n\t\t\tjoints: kinematicsModel && kinematicsModel.joints,\n\n\t\t\tgetJointValue: function( jointIndex ) {\n\n\t\t\t\tvar jointData = jointMap[ jointIndex ];\n\n\t\t\t\tif ( jointData ) {\n\n\t\t\t\t\treturn jointData.position;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.log( 'getJointValue: joint ' + jointIndex + ' doesn\\'t exist' );\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetJointValue: function( jointIndex, value ) {\n\n\t\t\t\tvar jointData = jointMap[ jointIndex ];\n\n\t\t\t\tif ( jointData ) {\n\n\t\t\t\t\tvar joint = jointData.joint;\n\n\t\t\t\t\tif ( value > joint.limits.max || value < joint.limits.min ) {\n\n\t\t\t\t\t\tconsole.log( 'setJointValue: joint ' + jointIndex + ' value ' + value + ' outside of limits (min: ' + joint.limits.min + ', max: ' + joint.limits.max + ')' );\n\n\t\t\t\t\t} else if ( joint.static ) {\n\n\t\t\t\t\t\tconsole.log( 'setJointValue: joint ' + jointIndex + ' is static' );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tvar threejsNode = jointData.node;\n\t\t\t\t\t\tvar axis = joint.axis;\n\t\t\t\t\t\tvar transforms = jointData.transforms;\n\n\t\t\t\t\t\tvar matrix = new THREE.Matrix4();\n\t\t\t\t\t\tvar m1 = new THREE.Matrix4();\n\n\t\t\t\t\t\tfor (i = 0; i < transforms.length; i ++ ) {\n\n\t\t\t\t\t\t\tvar transform = transforms[ i ];\n\n\t\t\t\t\t\t\t// kinda ghetto joint detection\n\n\t\t\t\t\t\t\tif ( transform.sid && transform.sid.indexOf( 'joint' + jointIndex ) !== -1 ) {\n\n\t\t\t\t\t\t\t\t// apply actual joint value here\n\t\t\t\t\t\t\t\tswitch ( joint.type ) {\n\n\t\t\t\t\t\t\t\t\tcase 'revolute':\n\n\t\t\t\t\t\t\t\t\t\tmatrix.multiply( m1.makeRotationAxis( axis, THREE.Math.degToRad(value) ) );\n\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\tcase 'prismatic':\n\n\t\t\t\t\t\t\t\t\t\tmatrix.multiply( m1.makeTranslation(axis.x * value, axis.y * value, axis.z * value ) );\n\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\tdefault:\n\n\t\t\t\t\t\t\t\t\t\tconsole.warn( 'setJointValue: unknown joint type: ' + joint.type );\n\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tswitch ( transform.type ) {\n\n\t\t\t\t\t\t\t\t\tcase 'matrix':\n\n\t\t\t\t\t\t\t\t\t\tmatrix.multiply( transform.obj );\n\n\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\tcase 'translate':\n\n\t\t\t\t\t\t\t\t\t\tmatrix.multiply( m1.makeTranslation( transform.obj.x, transform.obj.y, transform.obj.z ) );\n\n\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\tcase 'rotate':\n\n\t\t\t\t\t\t\t\t\t\tmatrix.multiply( m1.makeRotationAxis( transform.obj, transform.angle ) );\n\n\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// apply the matrix to the threejs node\n\t\t\t\t\t\tvar elementsFloat32Arr = matrix.elements;\n\t\t\t\t\t\tvar elements = Array.prototype.slice.call( elementsFloat32Arr );\n\n\t\t\t\t\t\tvar elementsRowMajor = [\n\t\t\t\t\t\t\telements[ 0 ],\n\t\t\t\t\t\t\telements[ 4 ],\n\t\t\t\t\t\t\telements[ 8 ],\n\t\t\t\t\t\t\telements[ 12 ],\n\t\t\t\t\t\t\telements[ 1 ],\n\t\t\t\t\t\t\telements[ 5 ],\n\t\t\t\t\t\t\telements[ 9 ],\n\t\t\t\t\t\t\telements[ 13 ],\n\t\t\t\t\t\t\telements[ 2 ],\n\t\t\t\t\t\t\telements[ 6 ],\n\t\t\t\t\t\t\telements[ 10 ],\n\t\t\t\t\t\t\telements[ 14 ],\n\t\t\t\t\t\t\telements[ 3 ],\n\t\t\t\t\t\t\telements[ 7 ],\n\t\t\t\t\t\t\telements[ 11 ],\n\t\t\t\t\t\t\telements[ 15 ]\n\t\t\t\t\t\t];\n\n\t\t\t\t\t\tthreejsNode.matrix.set.apply( threejsNode.matrix, elementsRowMajor );\n\t\t\t\t\t\tthreejsNode.matrix.decompose( threejsNode.position, threejsNode.quaternion, threejsNode.scale );\n\n\t\t\t\t\t\tjointMap[ jointIndex ].position = value;\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.log( 'setJointValue: joint ' + jointIndex + ' doesn\\'t exist' );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t\tvar element = COLLADA.querySelector('scene instance_kinematics_scene');\n\n\t\tif ( element ) {\n\n\t\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\t\tvar child = element.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'bind_joint_axis':\n\n\t\t\t\t\t\tvar visualTarget = child.getAttribute( 'target' ).split( '/' ).pop();\n\t\t\t\t\t\tvar axis = child.querySelector('axis param').textContent;\n\t\t\t\t\t\tvar jointIndex = parseInt( axis.split( 'joint' ).pop().split( '.' )[0] );\n\t\t\t\t\t\tvar visualTargetElement = COLLADA.querySelector( '[sid=\"' + visualTarget + '\"]' );\n\n\t\t\t\t\t\tif ( visualTargetElement ) {\n\t\t\t\t\t\t\tvar parentVisualElement = visualTargetElement.parentElement;\n\t\t\t\t\t\t\t_addToMap(jointIndex, parentVisualElement);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\n\t}\n\n\tfunction createSceneGraph ( node, parent ) {\n\n\t\tvar obj = new THREE.Object3D();\n\t\tvar skinned = false;\n\t\tvar skinController;\n\t\tvar morphController;\n\t\tvar i, j;\n\n\t\t// FIXME: controllers\n\n\t\tfor ( i = 0; i < node.controllers.length; i ++ ) {\n\n\t\t\tvar controller = controllers[ node.controllers[ i ].url ];\n\n\t\t\tswitch ( controller.type ) {\n\n\t\t\t\tcase 'skin':\n\n\t\t\t\t\tif ( geometries[ controller.skin.source ] ) {\n\n\t\t\t\t\t\tvar inst_geom = new InstanceGeometry();\n\n\t\t\t\t\t\tinst_geom.url = controller.skin.source;\n\t\t\t\t\t\tinst_geom.instance_material = node.controllers[ i ].instance_material;\n\n\t\t\t\t\t\tnode.geometries.push( inst_geom );\n\t\t\t\t\t\tskinned = true;\n\t\t\t\t\t\tskinController = node.controllers[ i ];\n\n\t\t\t\t\t} else if ( controllers[ controller.skin.source ] ) {\n\n\t\t\t\t\t\t// urgh: controller can be chained\n\t\t\t\t\t\t// handle the most basic case...\n\n\t\t\t\t\t\tvar second = controllers[ controller.skin.source ];\n\t\t\t\t\t\tmorphController = second;\n\t\t\t\t\t//\tskinController = node.controllers[i];\n\n\t\t\t\t\t\tif ( second.morph && geometries[ second.morph.source ] ) {\n\n\t\t\t\t\t\t\tvar inst_geom = new InstanceGeometry();\n\n\t\t\t\t\t\t\tinst_geom.url = second.morph.source;\n\t\t\t\t\t\t\tinst_geom.instance_material = node.controllers[ i ].instance_material;\n\n\t\t\t\t\t\t\tnode.geometries.push( inst_geom );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'morph':\n\n\t\t\t\t\tif ( geometries[ controller.morph.source ] ) {\n\n\t\t\t\t\t\tvar inst_geom = new InstanceGeometry();\n\n\t\t\t\t\t\tinst_geom.url = controller.morph.source;\n\t\t\t\t\t\tinst_geom.instance_material = node.controllers[ i ].instance_material;\n\n\t\t\t\t\t\tnode.geometries.push( inst_geom );\n\t\t\t\t\t\tmorphController = node.controllers[ i ];\n\n\t\t\t\t\t}\n\n\t\t\t\t\tconsole.log( 'ColladaLoader: Morph-controller partially supported.' );\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// geometries\n\n\t\tvar double_sided_materials = {};\n\n\t\tfor ( i = 0; i < node.geometries.length; i ++ ) {\n\n\t\t\tvar instance_geometry = node.geometries[i];\n\t\t\tvar instance_materials = instance_geometry.instance_material;\n\t\t\tvar geometry = geometries[ instance_geometry.url ];\n\t\t\tvar used_materials = {};\n\t\t\tvar used_materials_array = [];\n\t\t\tvar num_materials = 0;\n\t\t\tvar first_material;\n\n\t\t\tif ( geometry ) {\n\n\t\t\t\tif ( !geometry.mesh || !geometry.mesh.primitives )\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif ( obj.name.length === 0 ) {\n\n\t\t\t\t\tobj.name = geometry.id;\n\n\t\t\t\t}\n\n\t\t\t\t// collect used fx for this geometry-instance\n\n\t\t\t\tif ( instance_materials ) {\n\n\t\t\t\t\tfor ( j = 0; j < instance_materials.length; j ++ ) {\n\n\t\t\t\t\t\tvar instance_material = instance_materials[ j ];\n\t\t\t\t\t\tvar mat = materials[ instance_material.target ];\n\t\t\t\t\t\tvar effect_id = mat.instance_effect.url;\n\t\t\t\t\t\tvar shader = effects[ effect_id ].shader;\n\t\t\t\t\t\tvar material3js = shader.material;\n\n\t\t\t\t\t\tif ( geometry.doubleSided ) {\n\n\t\t\t\t\t\t\tif ( !( instance_material.symbol in double_sided_materials ) ) {\n\n\t\t\t\t\t\t\t\tvar _copied_material = material3js.clone();\n\t\t\t\t\t\t\t\t_copied_material.side = THREE.DoubleSide;\n\t\t\t\t\t\t\t\tdouble_sided_materials[ instance_material.symbol ] = _copied_material;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tmaterial3js = double_sided_materials[ instance_material.symbol ];\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tmaterial3js.opacity = !material3js.opacity ? 1 : material3js.opacity;\n\t\t\t\t\t\tused_materials[ instance_material.symbol ] = num_materials;\n\t\t\t\t\t\tused_materials_array.push( material3js );\n\t\t\t\t\t\tfirst_material = material3js;\n\t\t\t\t\t\tfirst_material.name = mat.name === null || mat.name === '' ? mat.id : mat.name;\n\t\t\t\t\t\tnum_materials ++;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tvar mesh;\n\t\t\t\tvar material = first_material || new THREE.MeshLambertMaterial( { color: 0xdddddd, side: geometry.doubleSided ? THREE.DoubleSide : THREE.FrontSide } );\n\t\t\t\tvar geom = geometry.mesh.geometry3js;\n\n\t\t\t\tif ( num_materials > 1 ) {\n\n\t\t\t\t\tmaterial = new THREE.MultiMaterial( used_materials_array );\n\n\t\t\t\t\tfor ( j = 0; j < geom.faces.length; j ++ ) {\n\n\t\t\t\t\t\tvar face = geom.faces[ j ];\n\t\t\t\t\t\tface.materialIndex = used_materials[ face.daeMaterial ]\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( skinController !== undefined ) {\n\n\n\t\t\t\t\tapplySkin( geom, skinController );\n\n\t\t\t\t\tif ( geom.morphTargets.length > 0 ) {\n\n\t\t\t\t\t\tmaterial.morphTargets = true;\n\t\t\t\t\t\tmaterial.skinning = false;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tmaterial.morphTargets = false;\n\t\t\t\t\t\tmaterial.skinning = true;\n\n\t\t\t\t\t}\n\n\n\t\t\t\t\tmesh = new THREE.SkinnedMesh( geom, material, false );\n\n\n\t\t\t\t\t//mesh.skeleton = skinController.skeleton;\n\t\t\t\t\t//mesh.skinController = controllers[ skinController.url ];\n\t\t\t\t\t//mesh.skinInstanceController = skinController;\n\t\t\t\t\tmesh.name = 'skin_' + skins.length;\n\n\n\n\t\t\t\t\t//mesh.animationHandle.setKey(0);\n\t\t\t\t\tskins.push( mesh );\n\n\t\t\t\t} else if ( morphController !== undefined ) {\n\n\t\t\t\t\tcreateMorph( geom, morphController );\n\n\t\t\t\t\tmaterial.morphTargets = true;\n\n\t\t\t\t\tmesh = new THREE.Mesh( geom, material );\n\t\t\t\t\tmesh.name = 'morph_' + morphs.length;\n\n\t\t\t\t\tmorphs.push( mesh );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( geom.isLineStrip === true ) {\n\n\t\t\t\t\t\tmesh = new THREE.Line( geom );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tmesh = new THREE.Mesh( geom, material );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tobj.add(mesh);\n\n\t\t\t}\n\n\t\t}\n\n\t\tfor ( i = 0; i < node.cameras.length; i ++ ) {\n\n\t\t\tvar instance_camera = node.cameras[i];\n\t\t\tvar cparams = cameras[instance_camera.url];\n\n\t\t\tvar cam = new THREE.PerspectiveCamera(cparams.yfov, parseFloat(cparams.aspect_ratio),\n\t\t\t\t\tparseFloat(cparams.znear), parseFloat(cparams.zfar));\n\n\t\t\tobj.add(cam);\n\t\t}\n\n\t\tfor ( i = 0; i < node.lights.length; i ++ ) {\n\n\t\t\tvar light = null;\n\t\t\tvar instance_light = node.lights[i];\n\t\t\tvar lparams = lights[instance_light.url];\n\n\t\t\tif ( lparams && lparams.technique ) {\n\n\t\t\t\tvar color = lparams.color.getHex();\n\t\t\t\tvar intensity = lparams.intensity;\n\t\t\t\tvar distance = lparams.distance;\n\t\t\t\tvar angle = lparams.falloff_angle;\n\n\t\t\t\tswitch ( lparams.technique ) {\n\n\t\t\t\t\tcase 'directional':\n\n\t\t\t\t\t\tlight = new THREE.DirectionalLight( color, intensity, distance );\n\t\t\t\t\t\tlight.position.set(0, 0, 1);\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'point':\n\n\t\t\t\t\t\tlight = new THREE.PointLight( color, intensity, distance );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'spot':\n\n\t\t\t\t\t\tlight = new THREE.SpotLight( color, intensity, distance, angle );\n\t\t\t\t\t\tlight.position.set(0, 0, 1);\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'ambient':\n\n\t\t\t\t\t\tlight = new THREE.AmbientLight( color );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif (light) {\n\t\t\t\tobj.add(light);\n\t\t\t}\n\t\t}\n\n\t\tobj.name = node.name || node.id || \"\";\n\t\tobj.colladaId = node.id || \"\";\n\t\tobj.layer = node.layer || \"\";\n\t\tobj.matrix = node.matrix;\n\t\tobj.matrix.decompose( obj.position, obj.quaternion, obj.scale );\n\n\t\tif ( options.centerGeometry && obj.geometry ) {\n\n\t\t\tvar delta = obj.geometry.center();\n\t\t\tdelta.multiply( obj.scale );\n\t\t\tdelta.applyQuaternion( obj.quaternion );\n\n\t\t\tobj.position.sub( delta );\n\n\t\t}\n\n\t\tfor ( i = 0; i < node.nodes.length; i ++ ) {\n\n\t\t\tobj.add( createSceneGraph( node.nodes[i], node ) );\n\n\t\t}\n\n\t\treturn obj;\n\n\t}\n\n\tfunction getJointId( skin, id ) {\n\n\t\tfor ( var i = 0; i < skin.joints.length; i ++ ) {\n\n\t\t\tif ( skin.joints[ i ] === id ) {\n\n\t\t\t\treturn i;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction getLibraryNode( id ) {\n\n\t\tvar nodes = COLLADA.querySelectorAll('library_nodes node');\n\n\t\tfor ( var i = 0; i < nodes.length; i++ ) {\n\n\t\t\tvar attObj = nodes[i].attributes.getNamedItem('id');\n\n\t\t\tif ( attObj && attObj.value === id ) {\n\n\t\t\t\treturn nodes[i];\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn undefined;\n\n\t}\n\n\tfunction getChannelsForNode ( node ) {\n\n\t\tvar channels = [];\n\t\tvar startTime = 1000000;\n\t\tvar endTime = -1000000;\n\n\t\tfor ( var id in animations ) {\n\n\t\t\tvar animation = animations[id];\n\n\t\t\tfor ( var i = 0; i < animation.channel.length; i ++ ) {\n\n\t\t\t\tvar channel = animation.channel[i];\n\t\t\t\tvar sampler = animation.sampler[i];\n\t\t\t\tvar id = channel.target.split('/')[0];\n\n\t\t\t\tif ( id == node.id ) {\n\n\t\t\t\t\tsampler.create();\n\t\t\t\t\tchannel.sampler = sampler;\n\t\t\t\t\tstartTime = Math.min(startTime, sampler.startTime);\n\t\t\t\t\tendTime = Math.max(endTime, sampler.endTime);\n\t\t\t\t\tchannels.push(channel);\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( channels.length ) {\n\n\t\t\tnode.startTime = startTime;\n\t\t\tnode.endTime = endTime;\n\n\t\t}\n\n\t\treturn channels;\n\n\t}\n\n\tfunction calcFrameDuration( node ) {\n\n\t\tvar minT = 10000000;\n\n\t\tfor ( var i = 0; i < node.channels.length; i ++ ) {\n\n\t\t\tvar sampler = node.channels[i].sampler;\n\n\t\t\tfor ( var j = 0; j < sampler.input.length - 1; j ++ ) {\n\n\t\t\t\tvar t0 = sampler.input[ j ];\n\t\t\t\tvar t1 = sampler.input[ j + 1 ];\n\t\t\t\tminT = Math.min( minT, t1 - t0 );\n\n\t\t\t}\n\t\t}\n\n\t\treturn minT;\n\n\t}\n\n\tfunction calcMatrixAt( node, t ) {\n\n\t\tvar animated = {};\n\n\t\tvar i, j;\n\n\t\tfor ( i = 0; i < node.channels.length; i ++ ) {\n\n\t\t\tvar channel = node.channels[ i ];\n\t\t\tanimated[ channel.sid ] = channel;\n\n\t\t}\n\n\t\tvar matrix = new THREE.Matrix4();\n\n\t\tfor ( i = 0; i < node.transforms.length; i ++ ) {\n\n\t\t\tvar transform = node.transforms[ i ];\n\t\t\tvar channel = animated[ transform.sid ];\n\n\t\t\tif ( channel !== undefined ) {\n\n\t\t\t\tvar sampler = channel.sampler;\n\t\t\t\tvar value;\n\n\t\t\t\tfor ( j = 0; j < sampler.input.length - 1; j ++ ) {\n\n\t\t\t\t\tif ( sampler.input[ j + 1 ] > t ) {\n\n\t\t\t\t\t\tvalue = sampler.output[ j ];\n\t\t\t\t\t\t//console.log(value.flatten)\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( value !== undefined ) {\n\n\t\t\t\t\tif ( value instanceof THREE.Matrix4 ) {\n\n\t\t\t\t\t\tmatrix.multiplyMatrices( matrix, value );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// FIXME: handle other types\n\n\t\t\t\t\t\tmatrix.multiplyMatrices( matrix, transform.matrix );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tmatrix.multiplyMatrices( matrix, transform.matrix );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tmatrix.multiplyMatrices( matrix, transform.matrix );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn matrix;\n\n\t}\n\n\tfunction bakeAnimations ( node ) {\n\n\t\tif ( node.channels && node.channels.length ) {\n\n\t\t\tvar keys = [],\n\t\t\t\tsids = [];\n\n\t\t\tfor ( var i = 0, il = node.channels.length; i < il; i ++ ) {\n\n\t\t\t\tvar channel = node.channels[i],\n\t\t\t\t\tfullSid = channel.fullSid,\n\t\t\t\t\tsampler = channel.sampler,\n\t\t\t\t\tinput = sampler.input,\n\t\t\t\t\ttransform = node.getTransformBySid( channel.sid ),\n\t\t\t\t\tmember;\n\n\t\t\t\tif ( channel.arrIndices ) {\n\n\t\t\t\t\tmember = [];\n\n\t\t\t\t\tfor ( var j = 0, jl = channel.arrIndices.length; j < jl; j ++ ) {\n\n\t\t\t\t\t\tmember[ j ] = getConvertedIndex( channel.arrIndices[ j ] );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tmember = getConvertedMember( channel.member );\n\n\t\t\t\t}\n\n\t\t\t\tif ( transform ) {\n\n\t\t\t\t\tif ( sids.indexOf( fullSid ) === -1 ) {\n\n\t\t\t\t\t\tsids.push( fullSid );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfor ( var j = 0, jl = input.length; j < jl; j ++ ) {\n\n\t\t\t\t\t\tvar time = input[j],\n\t\t\t\t\t\t\tdata = sampler.getData( transform.type, j, member ),\n\t\t\t\t\t\t\tkey = findKey( keys, time );\n\n\t\t\t\t\t\tif ( !key ) {\n\n\t\t\t\t\t\t\tkey = new Key( time );\n\t\t\t\t\t\t\tvar timeNdx = findTimeNdx( keys, time );\n\t\t\t\t\t\t\tkeys.splice( timeNdx === -1 ? keys.length : timeNdx, 0, key );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tkey.addTarget( fullSid, transform, member, data );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.log( 'Could not find transform \"' + channel.sid + '\" in node ' + node.id );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// post process\n\t\t\tfor ( var i = 0; i < sids.length; i ++ ) {\n\n\t\t\t\tvar sid = sids[ i ];\n\n\t\t\t\tfor ( var j = 0; j < keys.length; j ++ ) {\n\n\t\t\t\t\tvar key = keys[ j ];\n\n\t\t\t\t\tif ( !key.hasTarget( sid ) ) {\n\n\t\t\t\t\t\tinterpolateKeys( keys, key, j, sid );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tnode.keys = keys;\n\t\t\tnode.sids = sids;\n\n\t\t}\n\n\t}\n\n\tfunction findKey ( keys, time) {\n\n\t\tvar retVal = null;\n\n\t\tfor ( var i = 0, il = keys.length; i < il && retVal === null; i ++ ) {\n\n\t\t\tvar key = keys[i];\n\n\t\t\tif ( key.time === time ) {\n\n\t\t\t\tretVal = key;\n\n\t\t\t} else if ( key.time > time ) {\n\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn retVal;\n\n\t}\n\n\tfunction findTimeNdx ( keys, time) {\n\n\t\tvar ndx = -1;\n\n\t\tfor ( var i = 0, il = keys.length; i < il && ndx === -1; i ++ ) {\n\n\t\t\tvar key = keys[i];\n\n\t\t\tif ( key.time >= time ) {\n\n\t\t\t\tndx = i;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn ndx;\n\n\t}\n\n\tfunction interpolateKeys ( keys, key, ndx, fullSid ) {\n\n\t\tvar prevKey = getPrevKeyWith( keys, fullSid, ndx ? ndx - 1 : 0 ),\n\t\t\tnextKey = getNextKeyWith( keys, fullSid, ndx + 1 );\n\n\t\tif ( prevKey && nextKey ) {\n\n\t\t\tvar scale = (key.time - prevKey.time) / (nextKey.time - prevKey.time),\n\t\t\t\tprevTarget = prevKey.getTarget( fullSid ),\n\t\t\t\tnextData = nextKey.getTarget( fullSid ).data,\n\t\t\t\tprevData = prevTarget.data,\n\t\t\t\tdata;\n\n\t\t\tif ( prevTarget.type === 'matrix' ) {\n\n\t\t\t\tdata = prevData;\n\n\t\t\t} else if ( prevData.length ) {\n\n\t\t\t\tdata = [];\n\n\t\t\t\tfor ( var i = 0; i < prevData.length; ++ i ) {\n\n\t\t\t\t\tdata[ i ] = prevData[ i ] + ( nextData[ i ] - prevData[ i ] ) * scale;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tdata = prevData + ( nextData - prevData ) * scale;\n\n\t\t\t}\n\n\t\t\tkey.addTarget( fullSid, prevTarget.transform, prevTarget.member, data );\n\n\t\t}\n\n\t}\n\n\t// Get next key with given sid\n\n\tfunction getNextKeyWith( keys, fullSid, ndx ) {\n\n\t\tfor ( ; ndx < keys.length; ndx ++ ) {\n\n\t\t\tvar key = keys[ ndx ];\n\n\t\t\tif ( key.hasTarget( fullSid ) ) {\n\n\t\t\t\treturn key;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn null;\n\n\t}\n\n\t// Get previous key with given sid\n\n\tfunction getPrevKeyWith( keys, fullSid, ndx ) {\n\n\t\tndx = ndx >= 0 ? ndx : ndx + keys.length;\n\n\t\tfor ( ; ndx >= 0; ndx -- ) {\n\n\t\t\tvar key = keys[ ndx ];\n\n\t\t\tif ( key.hasTarget( fullSid ) ) {\n\n\t\t\t\treturn key;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn null;\n\n\t}\n\n\tfunction _Image() {\n\n\t\tthis.id = \"\";\n\t\tthis.init_from = \"\";\n\n\t}\n\n\t_Image.prototype.parse = function(element) {\n\n\t\tthis.id = element.getAttribute('id');\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\n\t\t\tif ( child.nodeName === 'init_from' ) {\n\n\t\t\t\tthis.init_from = child.textContent;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction Controller() {\n\n\t\tthis.id = \"\";\n\t\tthis.name = \"\";\n\t\tthis.type = \"\";\n\t\tthis.skin = null;\n\t\tthis.morph = null;\n\n\t}\n\n\tController.prototype.parse = function( element ) {\n\n\t\tthis.id = element.getAttribute('id');\n\t\tthis.name = element.getAttribute('name');\n\t\tthis.type = \"none\";\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'skin':\n\n\t\t\t\t\tthis.skin = (new Skin()).parse(child);\n\t\t\t\t\tthis.type = child.nodeName;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'morph':\n\n\t\t\t\t\tthis.morph = (new Morph()).parse(child);\n\t\t\t\t\tthis.type = child.nodeName;\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction Morph() {\n\n\t\tthis.method = null;\n\t\tthis.source = null;\n\t\tthis.targets = null;\n\t\tthis.weights = null;\n\n\t}\n\n\tMorph.prototype.parse = function( element ) {\n\n\t\tvar sources = {};\n\t\tvar inputs = [];\n\t\tvar i;\n\n\t\tthis.method = element.getAttribute( 'method' );\n\t\tthis.source = element.getAttribute( 'source' ).replace( /^#/, '' );\n\n\t\tfor ( i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'source':\n\n\t\t\t\t\tvar source = ( new Source() ).parse( child );\n\t\t\t\t\tsources[ source.id ] = source;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'targets':\n\n\t\t\t\t\tinputs = this.parseInputs( child );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tconsole.log( child.nodeName );\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfor ( i = 0; i < inputs.length; i ++ ) {\n\n\t\t\tvar input = inputs[ i ];\n\t\t\tvar source = sources[ input.source ];\n\n\t\t\tswitch ( input.semantic ) {\n\n\t\t\t\tcase 'MORPH_TARGET':\n\n\t\t\t\t\tthis.targets = source.read();\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'MORPH_WEIGHT':\n\n\t\t\t\t\tthis.weights = source.read();\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tMorph.prototype.parseInputs = function(element) {\n\n\t\tvar inputs = [];\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[i];\n\t\t\tif ( child.nodeType != 1) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'input':\n\n\t\t\t\t\tinputs.push( (new Input()).parse(child) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn inputs;\n\n\t};\n\n\tfunction Skin() {\n\n\t\tthis.source = \"\";\n\t\tthis.bindShapeMatrix = null;\n\t\tthis.invBindMatrices = [];\n\t\tthis.joints = [];\n\t\tthis.weights = [];\n\n\t}\n\n\tSkin.prototype.parse = function( element ) {\n\n\t\tvar sources = {};\n\t\tvar joints, weights;\n\n\t\tthis.source = element.getAttribute( 'source' ).replace( /^#/, '' );\n\t\tthis.invBindMatrices = [];\n\t\tthis.joints = [];\n\t\tthis.weights = [];\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[i];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'bind_shape_matrix':\n\n\t\t\t\t\tvar f = _floats(child.textContent);\n\t\t\t\t\tthis.bindShapeMatrix = getConvertedMat4( f );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'source':\n\n\t\t\t\t\tvar src = new Source().parse(child);\n\t\t\t\t\tsources[ src.id ] = src;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'joints':\n\n\t\t\t\t\tjoints = child;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'vertex_weights':\n\n\t\t\t\t\tweights = child;\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tconsole.log( child.nodeName );\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\t\t}\n\n\t\tthis.parseJoints( joints, sources );\n\t\tthis.parseWeights( weights, sources );\n\n\t\treturn this;\n\n\t};\n\n\tSkin.prototype.parseJoints = function ( element, sources ) {\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'input':\n\n\t\t\t\t\tvar input = ( new Input() ).parse( child );\n\t\t\t\t\tvar source = sources[ input.source ];\n\n\t\t\t\t\tif ( input.semantic === 'JOINT' ) {\n\n\t\t\t\t\t\tthis.joints = source.read();\n\n\t\t\t\t\t} else if ( input.semantic === 'INV_BIND_MATRIX' ) {\n\n\t\t\t\t\t\tthis.invBindMatrices = source.read();\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t}\n\n\t};\n\n\tSkin.prototype.parseWeights = function ( element, sources ) {\n\n\t\tvar v, vcount, inputs = [];\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'input':\n\n\t\t\t\t\tinputs.push( ( new Input() ).parse( child ) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'v':\n\n\t\t\t\t\tv = _ints( child.textContent );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'vcount':\n\n\t\t\t\t\tvcount = _ints( child.textContent );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tvar index = 0;\n\n\t\tfor ( var i = 0; i < vcount.length; i ++ ) {\n\n\t\t\tvar numBones = vcount[i];\n\t\t\tvar vertex_weights = [];\n\n\t\t\tfor ( var j = 0; j < numBones; j ++ ) {\n\n\t\t\t\tvar influence = {};\n\n\t\t\t\tfor ( var k = 0; k < inputs.length; k ++ ) {\n\n\t\t\t\t\tvar input = inputs[ k ];\n\t\t\t\t\tvar value = v[ index + input.offset ];\n\n\t\t\t\t\tswitch ( input.semantic ) {\n\n\t\t\t\t\t\tcase 'JOINT':\n\n\t\t\t\t\t\t\tinfluence.joint = value;//this.joints[value];\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'WEIGHT':\n\n\t\t\t\t\t\t\tinfluence.weight = sources[ input.source ].data[ value ];\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tvertex_weights.push( influence );\n\t\t\t\tindex += inputs.length;\n\t\t\t}\n\n\t\t\tfor ( var j = 0; j < vertex_weights.length; j ++ ) {\n\n\t\t\t\tvertex_weights[ j ].index = i;\n\n\t\t\t}\n\n\t\t\tthis.weights.push( vertex_weights );\n\n\t\t}\n\n\t};\n\n\tfunction VisualScene () {\n\n\t\tthis.id = \"\";\n\t\tthis.name = \"\";\n\t\tthis.nodes = [];\n\t\tthis.scene = new THREE.Group();\n\n\t}\n\n\tVisualScene.prototype.getChildById = function( id, recursive ) {\n\n\t\tfor ( var i = 0; i < this.nodes.length; i ++ ) {\n\n\t\t\tvar node = this.nodes[ i ].getChildById( id, recursive );\n\n\t\t\tif ( node ) {\n\n\t\t\t\treturn node;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn null;\n\n\t};\n\n\tVisualScene.prototype.getChildBySid = function( sid, recursive ) {\n\n\t\tfor ( var i = 0; i < this.nodes.length; i ++ ) {\n\n\t\t\tvar node = this.nodes[ i ].getChildBySid( sid, recursive );\n\n\t\t\tif ( node ) {\n\n\t\t\t\treturn node;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn null;\n\n\t};\n\n\tVisualScene.prototype.parse = function( element ) {\n\n\t\tthis.id = element.getAttribute( 'id' );\n\t\tthis.name = element.getAttribute( 'name' );\n\t\tthis.nodes = [];\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'node':\n\n\t\t\t\t\tthis.nodes.push( ( new Node() ).parse( child ) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction Node() {\n\n\t\tthis.id = \"\";\n\t\tthis.name = \"\";\n\t\tthis.sid = \"\";\n\t\tthis.nodes = [];\n\t\tthis.controllers = [];\n\t\tthis.transforms = [];\n\t\tthis.geometries = [];\n\t\tthis.channels = [];\n\t\tthis.matrix = new THREE.Matrix4();\n\n\t}\n\n\tNode.prototype.getChannelForTransform = function( transformSid ) {\n\n\t\tfor ( var i = 0; i < this.channels.length; i ++ ) {\n\n\t\t\tvar channel = this.channels[i];\n\t\t\tvar parts = channel.target.split('/');\n\t\t\tvar id = parts.shift();\n\t\t\tvar sid = parts.shift();\n\t\t\tvar dotSyntax = (sid.indexOf(\".\") >= 0);\n\t\t\tvar arrSyntax = (sid.indexOf(\"(\") >= 0);\n\t\t\tvar arrIndices;\n\n\t\t\tif ( dotSyntax ) {\n\n\t\t\t\tparts = sid.split(\".\");\n\t\t\t\tsid = parts.shift();\n\n\t\t\t} else if ( arrSyntax ) {\n\n\t\t\t\tarrIndices = sid.split(\"(\");\n\t\t\t\tsid = arrIndices.shift();\n\n\t\t\t\tfor ( var j = 0; j < arrIndices.length; j ++ ) {\n\n\t\t\t\t\tarrIndices[ j ] = parseInt( arrIndices[ j ].replace( /\\)/, '' ) );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( sid === transformSid ) {\n\n\t\t\t\tchannel.info = { sid: sid, dotSyntax: dotSyntax, arrSyntax: arrSyntax, arrIndices: arrIndices };\n\t\t\t\treturn channel;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn null;\n\n\t};\n\n\tNode.prototype.getChildById = function ( id, recursive ) {\n\n\t\tif ( this.id === id ) {\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tif ( recursive ) {\n\n\t\t\tfor ( var i = 0; i < this.nodes.length; i ++ ) {\n\n\t\t\t\tvar n = this.nodes[ i ].getChildById( id, recursive );\n\n\t\t\t\tif ( n ) {\n\n\t\t\t\t\treturn n;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn null;\n\n\t};\n\n\tNode.prototype.getChildBySid = function ( sid, recursive ) {\n\n\t\tif ( this.sid === sid ) {\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tif ( recursive ) {\n\n\t\t\tfor ( var i = 0; i < this.nodes.length; i ++ ) {\n\n\t\t\t\tvar n = this.nodes[ i ].getChildBySid( sid, recursive );\n\n\t\t\t\tif ( n ) {\n\n\t\t\t\t\treturn n;\n\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\n\t};\n\n\tNode.prototype.getTransformBySid = function ( sid ) {\n\n\t\tfor ( var i = 0; i < this.transforms.length; i ++ ) {\n\n\t\t\tif ( this.transforms[ i ].sid === sid ) return this.transforms[ i ];\n\n\t\t}\n\n\t\treturn null;\n\n\t};\n\n\tNode.prototype.parse = function( element ) {\n\n\t\tvar url;\n\n\t\tthis.id = element.getAttribute('id');\n\t\tthis.sid = element.getAttribute('sid');\n\t\tthis.name = element.getAttribute('name');\n\t\tthis.type = element.getAttribute('type');\n\t\tthis.layer = element.getAttribute('layer');\n\n\t\tthis.type = this.type === 'JOINT' ? this.type : 'NODE';\n\n\t\tthis.nodes = [];\n\t\tthis.transforms = [];\n\t\tthis.geometries = [];\n\t\tthis.cameras = [];\n\t\tthis.lights = [];\n\t\tthis.controllers = [];\n\t\tthis.matrix = new THREE.Matrix4();\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'node':\n\n\t\t\t\t\tthis.nodes.push( ( new Node() ).parse( child ) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'instance_camera':\n\n\t\t\t\t\tthis.cameras.push( ( new InstanceCamera() ).parse( child ) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'instance_controller':\n\n\t\t\t\t\tthis.controllers.push( ( new InstanceController() ).parse( child ) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'instance_geometry':\n\n\t\t\t\t\tthis.geometries.push( ( new InstanceGeometry() ).parse( child ) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'instance_light':\n\n\t\t\t\t\tthis.lights.push( ( new InstanceLight() ).parse( child ) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'instance_node':\n\n\t\t\t\t\turl = child.getAttribute( 'url' ).replace( /^#/, '' );\n\t\t\t\t\tvar iNode = getLibraryNode( url );\n\n\t\t\t\t\tif ( iNode ) {\n\n\t\t\t\t\t\tthis.nodes.push( ( new Node() ).parse( iNode )) ;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'rotate':\n\t\t\t\tcase 'translate':\n\t\t\t\tcase 'scale':\n\t\t\t\tcase 'matrix':\n\t\t\t\tcase 'lookat':\n\t\t\t\tcase 'skew':\n\n\t\t\t\t\tthis.transforms.push( ( new Transform() ).parse( child ) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'extra':\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tconsole.log( child.nodeName );\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.channels = getChannelsForNode( this );\n\t\tbakeAnimations( this );\n\n\t\tthis.updateMatrix();\n\n\t\treturn this;\n\n\t};\n\n\tNode.prototype.updateMatrix = function () {\n\n\t\tthis.matrix.identity();\n\n\t\tfor ( var i = 0; i < this.transforms.length; i ++ ) {\n\n\t\t\tthis.transforms[ i ].apply( this.matrix );\n\n\t\t}\n\n\t};\n\n\tfunction Transform () {\n\n\t\tthis.sid = \"\";\n\t\tthis.type = \"\";\n\t\tthis.data = [];\n\t\tthis.obj = null;\n\n\t}\n\n\tTransform.prototype.parse = function ( element ) {\n\n\t\tthis.sid = element.getAttribute( 'sid' );\n\t\tthis.type = element.nodeName;\n\t\tthis.data = _floats( element.textContent );\n\t\tthis.convert();\n\n\t\treturn this;\n\n\t};\n\n\tTransform.prototype.convert = function () {\n\n\t\tswitch ( this.type ) {\n\n\t\t\tcase 'matrix':\n\n\t\t\t\tthis.obj = getConvertedMat4( this.data );\n\t\t\t\tbreak;\n\n\t\t\tcase 'rotate':\n\n\t\t\t\tthis.angle = THREE.Math.degToRad( this.data[3] );\n\n\t\t\tcase 'translate':\n\n\t\t\t\tfixCoords( this.data, -1 );\n\t\t\t\tthis.obj = new THREE.Vector3( this.data[ 0 ], this.data[ 1 ], this.data[ 2 ] );\n\t\t\t\tbreak;\n\n\t\t\tcase 'scale':\n\n\t\t\t\tfixCoords( this.data, 1 );\n\t\t\t\tthis.obj = new THREE.Vector3( this.data[ 0 ], this.data[ 1 ], this.data[ 2 ] );\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tconsole.log( 'Can not convert Transform of type ' + this.type );\n\t\t\t\tbreak;\n\n\t\t}\n\n\t};\n\n\tTransform.prototype.apply = function () {\n\n\t\tvar m1 = new THREE.Matrix4();\n\n\t\treturn function ( matrix ) {\n\n\t\t\tswitch ( this.type ) {\n\n\t\t\t\tcase 'matrix':\n\n\t\t\t\t\tmatrix.multiply( this.obj );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'translate':\n\n\t\t\t\t\tmatrix.multiply( m1.makeTranslation( this.obj.x, this.obj.y, this.obj.z ) );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'rotate':\n\n\t\t\t\t\tmatrix.multiply( m1.makeRotationAxis( this.obj, this.angle ) );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'scale':\n\n\t\t\t\t\tmatrix.scale( this.obj );\n\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t};\n\n\t}();\n\n\tTransform.prototype.update = function ( data, member ) {\n\n\t\tvar members = [ 'X', 'Y', 'Z', 'ANGLE' ];\n\n\t\tswitch ( this.type ) {\n\n\t\t\tcase 'matrix':\n\n\t\t\t\tif ( ! member ) {\n\n\t\t\t\t\tthis.obj.copy( data );\n\n\t\t\t\t} else if ( member.length === 1 ) {\n\n\t\t\t\t\tswitch ( member[ 0 ] ) {\n\n\t\t\t\t\t\tcase 0:\n\n\t\t\t\t\t\t\tthis.obj.n11 = data[ 0 ];\n\t\t\t\t\t\t\tthis.obj.n21 = data[ 1 ];\n\t\t\t\t\t\t\tthis.obj.n31 = data[ 2 ];\n\t\t\t\t\t\t\tthis.obj.n41 = data[ 3 ];\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 1:\n\n\t\t\t\t\t\t\tthis.obj.n12 = data[ 0 ];\n\t\t\t\t\t\t\tthis.obj.n22 = data[ 1 ];\n\t\t\t\t\t\t\tthis.obj.n32 = data[ 2 ];\n\t\t\t\t\t\t\tthis.obj.n42 = data[ 3 ];\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 2:\n\n\t\t\t\t\t\t\tthis.obj.n13 = data[ 0 ];\n\t\t\t\t\t\t\tthis.obj.n23 = data[ 1 ];\n\t\t\t\t\t\t\tthis.obj.n33 = data[ 2 ];\n\t\t\t\t\t\t\tthis.obj.n43 = data[ 3 ];\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 3:\n\n\t\t\t\t\t\t\tthis.obj.n14 = data[ 0 ];\n\t\t\t\t\t\t\tthis.obj.n24 = data[ 1 ];\n\t\t\t\t\t\t\tthis.obj.n34 = data[ 2 ];\n\t\t\t\t\t\t\tthis.obj.n44 = data[ 3 ];\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( member.length === 2 ) {\n\n\t\t\t\t\tvar propName = 'n' + ( member[ 0 ] + 1 ) + ( member[ 1 ] + 1 );\n\t\t\t\t\tthis.obj[ propName ] = data;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.log('Incorrect addressing of matrix in transform.');\n\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'translate':\n\t\t\tcase 'scale':\n\n\t\t\t\tif ( Object.prototype.toString.call( member ) === '[object Array]' ) {\n\n\t\t\t\t\tmember = members[ member[ 0 ] ];\n\n\t\t\t\t}\n\n\t\t\t\tswitch ( member ) {\n\n\t\t\t\t\tcase 'X':\n\n\t\t\t\t\t\tthis.obj.x = data;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'Y':\n\n\t\t\t\t\t\tthis.obj.y = data;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'Z':\n\n\t\t\t\t\t\tthis.obj.z = data;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\n\t\t\t\t\t\tthis.obj.x = data[ 0 ];\n\t\t\t\t\t\tthis.obj.y = data[ 1 ];\n\t\t\t\t\t\tthis.obj.z = data[ 2 ];\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'rotate':\n\n\t\t\t\tif ( Object.prototype.toString.call( member ) === '[object Array]' ) {\n\n\t\t\t\t\tmember = members[ member[ 0 ] ];\n\n\t\t\t\t}\n\n\t\t\t\tswitch ( member ) {\n\n\t\t\t\t\tcase 'X':\n\n\t\t\t\t\t\tthis.obj.x = data;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'Y':\n\n\t\t\t\t\t\tthis.obj.y = data;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'Z':\n\n\t\t\t\t\t\tthis.obj.z = data;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'ANGLE':\n\n\t\t\t\t\t\tthis.angle = THREE.Math.degToRad( data );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\n\t\t\t\t\t\tthis.obj.x = data[ 0 ];\n\t\t\t\t\t\tthis.obj.y = data[ 1 ];\n\t\t\t\t\t\tthis.obj.z = data[ 2 ];\n\t\t\t\t\t\tthis.angle = THREE.Math.degToRad( data[ 3 ] );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t}\n\n\t};\n\n\tfunction InstanceController() {\n\n\t\tthis.url = \"\";\n\t\tthis.skeleton = [];\n\t\tthis.instance_material = [];\n\n\t}\n\n\tInstanceController.prototype.parse = function ( element ) {\n\n\t\tthis.url = element.getAttribute('url').replace(/^#/, '');\n\t\tthis.skeleton = [];\n\t\tthis.instance_material = [];\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'skeleton':\n\n\t\t\t\t\tthis.skeleton.push( child.textContent.replace(/^#/, '') );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'bind_material':\n\n\t\t\t\t\tvar instances = child.querySelectorAll('instance_material');\n\n\t\t\t\t\tfor ( var j = 0; j < instances.length; j ++ ) {\n\n\t\t\t\t\t\tvar instance = instances[j];\n\t\t\t\t\t\tthis.instance_material.push( (new InstanceMaterial()).parse(instance) );\n\n\t\t\t\t\t}\n\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'extra':\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction InstanceMaterial () {\n\n\t\tthis.symbol = \"\";\n\t\tthis.target = \"\";\n\n\t}\n\n\tInstanceMaterial.prototype.parse = function ( element ) {\n\n\t\tthis.symbol = element.getAttribute('symbol');\n\t\tthis.target = element.getAttribute('target').replace(/^#/, '');\n\t\treturn this;\n\n\t};\n\n\tfunction InstanceGeometry() {\n\n\t\tthis.url = \"\";\n\t\tthis.instance_material = [];\n\n\t}\n\n\tInstanceGeometry.prototype.parse = function ( element ) {\n\n\t\tthis.url = element.getAttribute('url').replace(/^#/, '');\n\t\tthis.instance_material = [];\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[i];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tif ( child.nodeName === 'bind_material' ) {\n\n\t\t\t\tvar instances = child.querySelectorAll('instance_material');\n\n\t\t\t\tfor ( var j = 0; j < instances.length; j ++ ) {\n\n\t\t\t\t\tvar instance = instances[j];\n\t\t\t\t\tthis.instance_material.push( (new InstanceMaterial()).parse(instance) );\n\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction Geometry() {\n\n\t\tthis.id = \"\";\n\t\tthis.mesh = null;\n\n\t}\n\n\tGeometry.prototype.parse = function ( element ) {\n\n\t\tthis.id = element.getAttribute('id');\n\n\t\textractDoubleSided( this, element );\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[i];\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'mesh':\n\n\t\t\t\t\tthis.mesh = (new Mesh(this)).parse(child);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'extra':\n\n\t\t\t\t\t// console.log( child );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction Mesh( geometry ) {\n\n\t\tthis.geometry = geometry.id;\n\t\tthis.primitives = [];\n\t\tthis.vertices = null;\n\t\tthis.geometry3js = null;\n\n\t}\n\n\tMesh.prototype.parse = function ( element ) {\n\n\t\tthis.primitives = [];\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'source':\n\n\t\t\t\t\t_source( child );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'vertices':\n\n\t\t\t\t\tthis.vertices = ( new Vertices() ).parse( child );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'linestrips':\n\n\t\t\t\t\tthis.primitives.push( ( new LineStrips().parse( child ) ) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'triangles':\n\n\t\t\t\t\tthis.primitives.push( ( new Triangles().parse( child ) ) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'polygons':\n\n\t\t\t\t\tthis.primitives.push( ( new Polygons().parse( child ) ) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'polylist':\n\n\t\t\t\t\tthis.primitives.push( ( new Polylist().parse( child ) ) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.geometry3js = new THREE.Geometry();\n\n\t\tif ( this.vertices === null ) {\n\n\t\t\t// TODO (mrdoob): Study case when this is null (carrier.dae)\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tvar vertexData = sources[ this.vertices.input['POSITION'].source ].data;\n\n\t\tfor ( var i = 0; i < vertexData.length; i += 3 ) {\n\n\t\t\tthis.geometry3js.vertices.push( getConvertedVec3( vertexData, i ).clone() );\n\n\t\t}\n\n\t\tfor ( var i = 0; i < this.primitives.length; i ++ ) {\n\n\t\t\tvar primitive = this.primitives[ i ];\n\t\t\tprimitive.setVertices( this.vertices );\n\t\t\tthis.handlePrimitive( primitive, this.geometry3js );\n\n\t\t}\n\n\t\tif ( this.geometry3js.calcNormals ) {\n\n\t\t\tthis.geometry3js.computeVertexNormals();\n\t\t\tdelete this.geometry3js.calcNormals;\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tMesh.prototype.handlePrimitive = function ( primitive, geom ) {\n\n\t\tif ( primitive instanceof LineStrips ) {\n\n\t\t\t// TODO: Handle indices. Maybe easier with BufferGeometry?\n\n\t\t\tgeom.isLineStrip = true;\n\t\t\treturn;\n\n\t\t}\n\n\t\tvar j, k, pList = primitive.p, inputs = primitive.inputs;\n\t\tvar input, index, idx32;\n\t\tvar source, numParams;\n\t\tvar vcount, vcIndex = 0, maxOffset = 0;\n\t\tvar texture_sets = [];\n\n\t\tfor ( j = 0; j < inputs.length; j ++ ) {\n\n\t\t\tinput = inputs[ j ];\n\n\t\t\tvar offset = input.offset + 1;\n\t\t\tmaxOffset = (maxOffset < offset) ? offset : maxOffset;\n\n\t\t\tswitch ( input.semantic ) {\n\n\t\t\t\tcase 'TEXCOORD':\n\t\t\t\t\ttexture_sets.push( input.set );\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfor ( var pCount = 0; pCount < pList.length; ++ pCount ) {\n\n\t\t\tvar p = pList[ pCount ], i = 0;\n\n\t\t\twhile ( i < p.length ) {\n\n\t\t\t\tvar vs = [];\n\t\t\t\tvar ns = [];\n\t\t\t\tvar ts = null;\n\t\t\t\tvar cs = [];\n\n\t\t\t\tif ( primitive.vcount ) {\n\n\t\t\t\t\tvcount = primitive.vcount.length ? primitive.vcount[ vcIndex ++ ] : primitive.vcount;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tvcount = p.length / maxOffset;\n\n\t\t\t\t}\n\n\n\t\t\t\tfor ( j = 0; j < vcount; j ++ ) {\n\n\t\t\t\t\tfor ( k = 0; k < inputs.length; k ++ ) {\n\n\t\t\t\t\t\tinput = inputs[ k ];\n\t\t\t\t\t\tsource = sources[ input.source ];\n\n\t\t\t\t\t\tindex = p[ i + ( j * maxOffset ) + input.offset ];\n\t\t\t\t\t\tnumParams = source.accessor.params.length;\n\t\t\t\t\t\tidx32 = index * numParams;\n\n\t\t\t\t\t\tswitch ( input.semantic ) {\n\n\t\t\t\t\t\t\tcase 'VERTEX':\n\n\t\t\t\t\t\t\t\tvs.push( index );\n\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase 'NORMAL':\n\n\t\t\t\t\t\t\t\tns.push( getConvertedVec3( source.data, idx32 ) );\n\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase 'TEXCOORD':\n\n\t\t\t\t\t\t\t\tts = ts || { };\n\t\t\t\t\t\t\t\tif ( ts[ input.set ] === undefined ) ts[ input.set ] = [];\n\t\t\t\t\t\t\t\t// invert the V\n\t\t\t\t\t\t\t\tts[ input.set ].push( new THREE.Vector2( source.data[ idx32 ], source.data[ idx32 + 1 ] ) );\n\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase 'COLOR':\n\n\t\t\t\t\t\t\t\tcs.push( new THREE.Color().setRGB( source.data[ idx32 ], source.data[ idx32 + 1 ], source.data[ idx32 + 2 ] ) );\n\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tdefault:\n\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( ns.length === 0 ) {\n\n\t\t\t\t\t// check the vertices inputs\n\t\t\t\t\tinput = this.vertices.input.NORMAL;\n\n\t\t\t\t\tif ( input ) {\n\n\t\t\t\t\t\tsource = sources[ input.source ];\n\t\t\t\t\t\tnumParams = source.accessor.params.length;\n\n\t\t\t\t\t\tfor ( var ndx = 0, len = vs.length; ndx < len; ndx ++ ) {\n\n\t\t\t\t\t\t\tns.push( getConvertedVec3( source.data, vs[ ndx ] * numParams ) );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tgeom.calcNormals = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( !ts ) {\n\n\t\t\t\t\tts = { };\n\t\t\t\t\t// check the vertices inputs\n\t\t\t\t\tinput = this.vertices.input.TEXCOORD;\n\n\t\t\t\t\tif ( input ) {\n\n\t\t\t\t\t\ttexture_sets.push( input.set );\n\t\t\t\t\t\tsource = sources[ input.source ];\n\t\t\t\t\t\tnumParams = source.accessor.params.length;\n\n\t\t\t\t\t\tfor ( var ndx = 0, len = vs.length; ndx < len; ndx ++ ) {\n\n\t\t\t\t\t\t\tidx32 = vs[ ndx ] * numParams;\n\t\t\t\t\t\t\tif ( ts[ input.set ] === undefined ) ts[ input.set ] = [ ];\n\t\t\t\t\t\t\t// invert the V\n\t\t\t\t\t\t\tts[ input.set ].push( new THREE.Vector2( source.data[ idx32 ], 1.0 - source.data[ idx32 + 1 ] ) );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( cs.length === 0 ) {\n\n\t\t\t\t\t// check the vertices inputs\n\t\t\t\t\tinput = this.vertices.input.COLOR;\n\n\t\t\t\t\tif ( input ) {\n\n\t\t\t\t\t\tsource = sources[ input.source ];\n\t\t\t\t\t\tnumParams = source.accessor.params.length;\n\n\t\t\t\t\t\tfor ( var ndx = 0, len = vs.length; ndx < len; ndx ++ ) {\n\n\t\t\t\t\t\t\tidx32 = vs[ ndx ] * numParams;\n\t\t\t\t\t\t\tcs.push( new THREE.Color().setRGB( source.data[ idx32 ], source.data[ idx32 + 1 ], source.data[ idx32 + 2 ] ) );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tvar face = null, faces = [], uv, uvArr;\n\n\t\t\t\tif ( vcount === 3 ) {\n\n\t\t\t\t\tfaces.push( new THREE.Face3( vs[0], vs[1], vs[2], ns, cs.length ? cs : new THREE.Color() ) );\n\n\t\t\t\t} else if ( vcount === 4 ) {\n\n\t\t\t\t\tfaces.push( new THREE.Face3( vs[0], vs[1], vs[3], ns.length ? [ ns[0].clone(), ns[1].clone(), ns[3].clone() ] : [], cs.length ? [ cs[0], cs[1], cs[3] ] : new THREE.Color() ) );\n\n\t\t\t\t\tfaces.push( new THREE.Face3( vs[1], vs[2], vs[3], ns.length ? [ ns[1].clone(), ns[2].clone(), ns[3].clone() ] : [], cs.length ? [ cs[1], cs[2], cs[3] ] : new THREE.Color() ) );\n\n\t\t\t\t} else if ( vcount > 4 && options.subdivideFaces ) {\n\n\t\t\t\t\tvar clr = cs.length ? cs : new THREE.Color(),\n\t\t\t\t\t\tvec1, vec2, vec3, v1, v2, norm;\n\n\t\t\t\t\t// subdivide into multiple Face3s\n\n\t\t\t\t\tfor ( k = 1; k < vcount - 1; ) {\n\n\t\t\t\t\t\tfaces.push( new THREE.Face3( vs[0], vs[k], vs[k + 1], ns.length ? [ ns[0].clone(), ns[k ++].clone(), ns[k].clone() ] : [], clr ) );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( faces.length ) {\n\n\t\t\t\t\tfor ( var ndx = 0, len = faces.length; ndx < len; ndx ++ ) {\n\n\t\t\t\t\t\tface = faces[ndx];\n\t\t\t\t\t\tface.daeMaterial = primitive.material;\n\t\t\t\t\t\tgeom.faces.push( face );\n\n\t\t\t\t\t\tfor ( k = 0; k < texture_sets.length; k ++ ) {\n\n\t\t\t\t\t\t\tuv = ts[ texture_sets[k] ];\n\n\t\t\t\t\t\t\tif ( vcount > 4 ) {\n\n\t\t\t\t\t\t\t\t// Grab the right UVs for the vertices in this face\n\t\t\t\t\t\t\t\tuvArr = [ uv[0], uv[ndx + 1], uv[ndx + 2] ];\n\n\t\t\t\t\t\t\t} else if ( vcount === 4 ) {\n\n\t\t\t\t\t\t\t\tif ( ndx === 0 ) {\n\n\t\t\t\t\t\t\t\t\tuvArr = [ uv[0], uv[1], uv[3] ];\n\n\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\tuvArr = [ uv[1].clone(), uv[2], uv[3].clone() ];\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tuvArr = [ uv[0], uv[1], uv[2] ];\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif ( geom.faceVertexUvs[k] === undefined ) {\n\n\t\t\t\t\t\t\t\tgeom.faceVertexUvs[k] = [];\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tgeom.faceVertexUvs[k].push( uvArr );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.log( 'dropped face with vcount ' + vcount + ' for geometry with id: ' + geom.id );\n\n\t\t\t\t}\n\n\t\t\t\ti += maxOffset * vcount;\n\n\t\t\t}\n\n\t\t}\n\n\t};\n\n\tfunction Polygons () {\n\n\t\tthis.material = \"\";\n\t\tthis.count = 0;\n\t\tthis.inputs = [];\n\t\tthis.vcount = null;\n\t\tthis.p = [];\n\t\tthis.geometry = new THREE.Geometry();\n\n\t}\n\n\tPolygons.prototype.setVertices = function ( vertices ) {\n\n\t\tfor ( var i = 0; i < this.inputs.length; i ++ ) {\n\n\t\t\tif ( this.inputs[ i ].source === vertices.id ) {\n\n\t\t\t\tthis.inputs[ i ].source = vertices.input[ 'POSITION' ].source;\n\n\t\t\t}\n\n\t\t}\n\n\t};\n\n\tPolygons.prototype.parse = function ( element ) {\n\n\t\tthis.material = element.getAttribute( 'material' );\n\t\tthis.count = _attr_as_int( element, 'count', 0 );\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'input':\n\n\t\t\t\t\tthis.inputs.push( ( new Input() ).parse( element.childNodes[ i ] ) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'vcount':\n\n\t\t\t\t\tthis.vcount = _ints( child.textContent );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'p':\n\n\t\t\t\t\tthis.p.push( _ints( child.textContent ) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'ph':\n\n\t\t\t\t\tconsole.warn( 'polygon holes not yet supported!' );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction Polylist () {\n\n\t\tPolygons.call( this );\n\n\t\tthis.vcount = [];\n\n\t}\n\n\tPolylist.prototype = Object.create( Polygons.prototype );\n\tPolylist.prototype.constructor = Polylist;\n\n\tfunction LineStrips() {\n\n\t\tPolygons.call( this );\n\n\t\tthis.vcount = 1;\n\n\t}\n\n\tLineStrips.prototype = Object.create( Polygons.prototype );\n\tLineStrips.prototype.constructor = LineStrips;\n\n\tfunction Triangles () {\n\n\t\tPolygons.call( this );\n\n\t\tthis.vcount = 3;\n\n\t}\n\n\tTriangles.prototype = Object.create( Polygons.prototype );\n\tTriangles.prototype.constructor = Triangles;\n\n\tfunction Accessor() {\n\n\t\tthis.source = \"\";\n\t\tthis.count = 0;\n\t\tthis.stride = 0;\n\t\tthis.params = [];\n\n\t}\n\n\tAccessor.prototype.parse = function ( element ) {\n\n\t\tthis.params = [];\n\t\tthis.source = element.getAttribute( 'source' );\n\t\tthis.count = _attr_as_int( element, 'count', 0 );\n\t\tthis.stride = _attr_as_int( element, 'stride', 0 );\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\n\t\t\tif ( child.nodeName === 'param' ) {\n\n\t\t\t\tvar param = {};\n\t\t\t\tparam[ 'name' ] = child.getAttribute( 'name' );\n\t\t\t\tparam[ 'type' ] = child.getAttribute( 'type' );\n\t\t\t\tthis.params.push( param );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction Vertices() {\n\n\t\tthis.input = {};\n\n\t}\n\n\tVertices.prototype.parse = function ( element ) {\n\n\t\tthis.id = element.getAttribute('id');\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tif ( element.childNodes[i].nodeName === 'input' ) {\n\n\t\t\t\tvar input = ( new Input() ).parse( element.childNodes[ i ] );\n\t\t\t\tthis.input[ input.semantic ] = input;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction Input () {\n\n\t\tthis.semantic = \"\";\n\t\tthis.offset = 0;\n\t\tthis.source = \"\";\n\t\tthis.set = 0;\n\n\t}\n\n\tInput.prototype.parse = function ( element ) {\n\n\t\tthis.semantic = element.getAttribute('semantic');\n\t\tthis.source = element.getAttribute('source').replace(/^#/, '');\n\t\tthis.set = _attr_as_int(element, 'set', -1);\n\t\tthis.offset = _attr_as_int(element, 'offset', 0);\n\n\t\tif ( this.semantic === 'TEXCOORD' && this.set < 0 ) {\n\n\t\t\tthis.set = 0;\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction Source ( id ) {\n\n\t\tthis.id = id;\n\t\tthis.type = null;\n\n\t}\n\n\tSource.prototype.parse = function ( element ) {\n\n\t\tthis.id = element.getAttribute( 'id' );\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[i];\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'bool_array':\n\n\t\t\t\t\tthis.data = _bools( child.textContent );\n\t\t\t\t\tthis.type = child.nodeName;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'float_array':\n\n\t\t\t\t\tthis.data = _floats( child.textContent );\n\t\t\t\t\tthis.type = child.nodeName;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'int_array':\n\n\t\t\t\t\tthis.data = _ints( child.textContent );\n\t\t\t\t\tthis.type = child.nodeName;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'IDREF_array':\n\t\t\t\tcase 'Name_array':\n\n\t\t\t\t\tthis.data = _strings( child.textContent );\n\t\t\t\t\tthis.type = child.nodeName;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'technique_common':\n\n\t\t\t\t\tfor ( var j = 0; j < child.childNodes.length; j ++ ) {\n\n\t\t\t\t\t\tif ( child.childNodes[ j ].nodeName === 'accessor' ) {\n\n\t\t\t\t\t\t\tthis.accessor = ( new Accessor() ).parse( child.childNodes[ j ] );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\t// console.log(child.nodeName);\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tSource.prototype.read = function () {\n\n\t\tvar result = [];\n\n\t\t//for (var i = 0; i < this.accessor.params.length; i++) {\n\n\t\tvar param = this.accessor.params[ 0 ];\n\n\t\t\t//console.log(param.name + \" \" + param.type);\n\n\t\tswitch ( param.type ) {\n\n\t\t\tcase 'IDREF':\n\t\t\tcase 'Name': case 'name':\n\t\t\tcase 'float':\n\n\t\t\t\treturn this.data;\n\n\t\t\tcase 'float4x4':\n\n\t\t\t\tfor ( var j = 0; j < this.data.length; j += 16 ) {\n\n\t\t\t\t\tvar s = this.data.slice( j, j + 16 );\n\t\t\t\t\tvar m = getConvertedMat4( s );\n\t\t\t\t\tresult.push( m );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\n\t\t\t\tconsole.log( 'ColladaLoader: Source: Read dont know how to read ' + param.type + '.' );\n\t\t\t\tbreak;\n\n\t\t}\n\n\t\t//}\n\n\t\treturn result;\n\n\t};\n\n\tfunction Material () {\n\n\t\tthis.id = \"\";\n\t\tthis.name = \"\";\n\t\tthis.instance_effect = null;\n\n\t}\n\n\tMaterial.prototype.parse = function ( element ) {\n\n\t\tthis.id = element.getAttribute( 'id' );\n\t\tthis.name = element.getAttribute( 'name' );\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tif ( element.childNodes[ i ].nodeName === 'instance_effect' ) {\n\n\t\t\t\tthis.instance_effect = ( new InstanceEffect() ).parse( element.childNodes[ i ] );\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction ColorOrTexture () {\n\n\t\tthis.color = new THREE.Color();\n\t\tthis.color.setRGB( Math.random(), Math.random(), Math.random() );\n\t\tthis.color.a = 1.0;\n\n\t\tthis.texture = null;\n\t\tthis.texcoord = null;\n\t\tthis.texOpts = null;\n\n\t}\n\n\tColorOrTexture.prototype.isColor = function () {\n\n\t\treturn ( this.texture === null );\n\n\t};\n\n\tColorOrTexture.prototype.isTexture = function () {\n\n\t\treturn ( this.texture != null );\n\n\t};\n\n\tColorOrTexture.prototype.parse = function ( element ) {\n\n\t\tif (element.nodeName === 'transparent') {\n\n\t\t\tthis.opaque = element.getAttribute('opaque');\n\n\t\t}\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'color':\n\n\t\t\t\t\tvar rgba = _floats( child.textContent );\n\t\t\t\t\tthis.color = new THREE.Color();\n\t\t\t\t\tthis.color.setRGB( rgba[0], rgba[1], rgba[2] );\n\t\t\t\t\tthis.color.a = rgba[3];\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'texture':\n\n\t\t\t\t\tthis.texture = child.getAttribute('texture');\n\t\t\t\t\tthis.texcoord = child.getAttribute('texcoord');\n\t\t\t\t\t// Defaults from:\n\t\t\t\t\t// https://collada.org/mediawiki/index.php/Maya_texture_placement_MAYA_extension\n\t\t\t\t\tthis.texOpts = {\n\t\t\t\t\t\toffsetU: 0,\n\t\t\t\t\t\toffsetV: 0,\n\t\t\t\t\t\trepeatU: 1,\n\t\t\t\t\t\trepeatV: 1,\n\t\t\t\t\t\twrapU: 1,\n\t\t\t\t\t\twrapV: 1\n\t\t\t\t\t};\n\t\t\t\t\tthis.parseTexture( child );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tColorOrTexture.prototype.parseTexture = function ( element ) {\n\n\t\tif ( ! element.childNodes ) return this;\n\n\t\t// This should be supported by Maya, 3dsMax, and MotionBuilder\n\n\t\tif ( element.childNodes[1] && element.childNodes[1].nodeName === 'extra' ) {\n\n\t\t\telement = element.childNodes[1];\n\n\t\t\tif ( element.childNodes[1] && element.childNodes[1].nodeName === 'technique' ) {\n\n\t\t\t\telement = element.childNodes[1];\n\n\t\t\t}\n\n\t\t}\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'offsetU':\n\t\t\t\tcase 'offsetV':\n\t\t\t\tcase 'repeatU':\n\t\t\t\tcase 'repeatV':\n\n\t\t\t\t\tthis.texOpts[ child.nodeName ] = parseFloat( child.textContent );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'wrapU':\n\t\t\t\tcase 'wrapV':\n\n\t\t\t\t\t// some dae have a value of true which becomes NaN via parseInt\n\n\t\t\t\t\tif ( child.textContent.toUpperCase() === 'TRUE' ) {\n\n\t\t\t\t\t\tthis.texOpts[ child.nodeName ] = 1;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tthis.texOpts[ child.nodeName ] = parseInt( child.textContent );\n\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tthis.texOpts[ child.nodeName ] = child.textContent;\n\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction Shader ( type, effect ) {\n\n\t\tthis.type = type;\n\t\tthis.effect = effect;\n\t\tthis.material = null;\n\n\t}\n\n\tShader.prototype.parse = function ( element ) {\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'emission':\n\t\t\t\tcase 'diffuse':\n\t\t\t\tcase 'specular':\n\t\t\t\tcase 'transparent':\n\n\t\t\t\t\tthis[ child.nodeName ] = ( new ColorOrTexture() ).parse( child );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'bump':\n\n\t\t\t\t\t// If 'bumptype' is 'heightfield', create a 'bump' property\n\t\t\t\t\t// Else if 'bumptype' is 'normalmap', create a 'normal' property\n\t\t\t\t\t// (Default to 'bump')\n\t\t\t\t\tvar bumpType = child.getAttribute( 'bumptype' );\n\t\t\t\t\tif ( bumpType ) {\n\t\t\t\t\t\tif ( bumpType.toLowerCase() === \"heightfield\" ) {\n\t\t\t\t\t\t\tthis[ 'bump' ] = ( new ColorOrTexture() ).parse( child );\n\t\t\t\t\t\t} else if ( bumpType.toLowerCase() === \"normalmap\" ) {\n\t\t\t\t\t\t\tthis[ 'normal' ] = ( new ColorOrTexture() ).parse( child );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconsole.error( \"Shader.prototype.parse: Invalid value for attribute 'bumptype' (\" + bumpType + \") - valid bumptypes are 'HEIGHTFIELD' and 'NORMALMAP' - defaulting to 'HEIGHTFIELD'\" );\n\t\t\t\t\t\t\tthis[ 'bump' ] = ( new ColorOrTexture() ).parse( child );\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconsole.warn( \"Shader.prototype.parse: Attribute 'bumptype' missing from bump node - defaulting to 'HEIGHTFIELD'\" );\n\t\t\t\t\t\tthis[ 'bump' ] = ( new ColorOrTexture() ).parse( child );\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'shininess':\n\t\t\t\tcase 'reflectivity':\n\t\t\t\tcase 'index_of_refraction':\n\t\t\t\tcase 'transparency':\n\n\t\t\t\t\tvar f = child.querySelectorAll('float');\n\n\t\t\t\t\tif ( f.length > 0 )\n\t\t\t\t\t\tthis[ child.nodeName ] = parseFloat( f[ 0 ].textContent );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.create();\n\t\treturn this;\n\n\t};\n\n\tShader.prototype.create = function() {\n\n\t\tvar props = {};\n\n\t\tvar transparent = false;\n\n\t\tif (this['transparency'] !== undefined && this['transparent'] !== undefined) {\n\t\t\t// convert transparent color RBG to average value\n\t\t\tvar transparentColor = this['transparent'];\n\t\t\tvar transparencyLevel = (this.transparent.color.r + this.transparent.color.g + this.transparent.color.b) / 3 * this.transparency;\n\n\t\t\tif (transparencyLevel > 0) {\n\t\t\t\ttransparent = true;\n\t\t\t\tprops[ 'transparent' ] = true;\n\t\t\t\tprops[ 'opacity' ] = 1 - transparencyLevel;\n\n\t\t\t}\n\n\t\t}\n\n\t\tvar keys = {\n\t\t\t'diffuse':'map',\n\t\t\t'ambient':'lightMap',\n\t\t\t'specular':'specularMap',\n\t\t\t'emission':'emissionMap',\n\t\t\t'bump':'bumpMap',\n\t\t\t'normal':'normalMap'\n\t\t\t};\n\n\t\tfor ( var prop in this ) {\n\n\t\t\tswitch ( prop ) {\n\n\t\t\t\tcase 'ambient':\n\t\t\t\tcase 'emission':\n\t\t\t\tcase 'diffuse':\n\t\t\t\tcase 'specular':\n\t\t\t\tcase 'bump':\n\t\t\t\tcase 'normal':\n\n\t\t\t\t\tvar cot = this[ prop ];\n\n\t\t\t\t\tif ( cot instanceof ColorOrTexture ) {\n\n\t\t\t\t\t\tif ( cot.isTexture() ) {\n\n\t\t\t\t\t\t\tvar samplerId = cot.texture;\n\t\t\t\t\t\t\tvar sampler = this.effect.sampler[samplerId];\n\n\t\t\t\t\t\t\tif ( sampler !== undefined && sampler.source !== undefined ) {\n\n\t\t\t\t\t\t\t\tvar surface = this.effect.surface[sampler.source];\n\n\t\t\t\t\t\t\t\tif ( surface !== undefined ) {\n\n\t\t\t\t\t\t\t\t\tvar image = images[ surface.init_from ];\n\n\t\t\t\t\t\t\t\t\tif ( image ) {\n\n\t\t\t\t\t\t\t\t\t\tvar url = baseUrl + image.init_from;\n\n\t\t\t\t\t\t\t\t\t\tvar texture;\n\t\t\t\t\t\t\t\t\t\tvar loader = THREE.Loader.Handlers.get( url );\n\n\t\t\t\t\t\t\t\t\t\tif ( loader !== null ) {\n\n\t\t\t\t\t\t\t\t\t\t\ttexture = loader.load( url );\n\n\t\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t\ttexture = new THREE.Texture();\n\n\t\t\t\t\t\t\t\t\t\t\tloadTextureImage( texture, url );\n\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif ( sampler.wrap_s === \"MIRROR\" ) {\n\n\t\t\t\t\t\t\t\t\t\t\ttexture.wrapS = THREE.MirroredRepeatWrapping;\n\n\t\t\t\t\t\t\t\t\t\t} else if ( sampler.wrap_s === \"WRAP\" || cot.texOpts.wrapU ) {\n\n\t\t\t\t\t\t\t\t\t\t\ttexture.wrapS = THREE.RepeatWrapping;\n\n\t\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t\ttexture.wrapS = THREE.ClampToEdgeWrapping;\n\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif ( sampler.wrap_t === \"MIRROR\" ) {\n\n\t\t\t\t\t\t\t\t\t\t\ttexture.wrapT = THREE.MirroredRepeatWrapping;\n\n\t\t\t\t\t\t\t\t\t\t} else if ( sampler.wrap_t === \"WRAP\" || cot.texOpts.wrapV ) {\n\n\t\t\t\t\t\t\t\t\t\t\ttexture.wrapT = THREE.RepeatWrapping;\n\n\t\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t\ttexture.wrapT = THREE.ClampToEdgeWrapping;\n\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\ttexture.offset.x = cot.texOpts.offsetU;\n\t\t\t\t\t\t\t\t\t\ttexture.offset.y = cot.texOpts.offsetV;\n\t\t\t\t\t\t\t\t\t\ttexture.repeat.x = cot.texOpts.repeatU;\n\t\t\t\t\t\t\t\t\t\ttexture.repeat.y = cot.texOpts.repeatV;\n\t\t\t\t\t\t\t\t\t\tprops[keys[prop]] = texture;\n\n\t\t\t\t\t\t\t\t\t\t// Texture with baked lighting?\n\t\t\t\t\t\t\t\t\t\tif (prop === 'emission') props['emissive'] = 0xffffff;\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else if ( prop === 'diffuse' || !transparent ) {\n\n\t\t\t\t\t\t\tif ( prop === 'emission' ) {\n\n\t\t\t\t\t\t\t\tprops[ 'emissive' ] = cot.color.getHex();\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tprops[ prop ] = cot.color.getHex();\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'shininess':\n\n\t\t\t\t\tprops[ prop ] = this[ prop ];\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'reflectivity':\n\n\t\t\t\t\tprops[ prop ] = this[ prop ];\n\t\t\t\t\tif ( props[ prop ] > 0.0 ) props['envMap'] = options.defaultEnvMap;\n\t\t\t\t\tprops['combine'] = THREE.MixOperation;\t//mix regular shading with reflective component\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'index_of_refraction':\n\n\t\t\t\t\tprops[ 'refractionRatio' ] = this[ prop ]; //TODO: \"index_of_refraction\" becomes \"refractionRatio\" in shader, but I'm not sure if the two are actually comparable\n\t\t\t\t\tif ( this[ prop ] !== 1.0 ) props['envMap'] = options.defaultEnvMap;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'transparency':\n\t\t\t\t\t// gets figured out up top\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tprops[ 'side' ] = this.effect.doubleSided ? THREE.DoubleSide : THREE.FrontSide;\n\n\t\tif ( props.diffuse !== undefined ) {\n\n\t\t\tprops.color = props.diffuse;\n\t\t\tdelete props.diffuse;\n\n\t\t}\n\n\t\tswitch ( this.type ) {\n\n\t\t\tcase 'constant':\n\n\t\t\t\tif (props.emissive != undefined) props.color = props.emissive;\n\t\t\t\tthis.material = new THREE.MeshBasicMaterial( props );\n\t\t\t\tbreak;\n\n\t\t\tcase 'phong':\n\t\t\tcase 'blinn':\n\n\t\t\t\tthis.material = new THREE.MeshPhongMaterial( props );\n\t\t\t\tbreak;\n\n\t\t\tcase 'lambert':\n\t\t\tdefault:\n\n\t\t\t\tthis.material = new THREE.MeshLambertMaterial( props );\n\t\t\t\tbreak;\n\n\t\t}\n\n\t\treturn this.material;\n\n\t};\n\n\tfunction Surface ( effect ) {\n\n\t\tthis.effect = effect;\n\t\tthis.init_from = null;\n\t\tthis.format = null;\n\n\t}\n\n\tSurface.prototype.parse = function ( element ) {\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'init_from':\n\n\t\t\t\t\tthis.init_from = child.textContent;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'format':\n\n\t\t\t\t\tthis.format = child.textContent;\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tconsole.log( \"unhandled Surface prop: \" + child.nodeName );\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction Sampler2D ( effect ) {\n\n\t\tthis.effect = effect;\n\t\tthis.source = null;\n\t\tthis.wrap_s = null;\n\t\tthis.wrap_t = null;\n\t\tthis.minfilter = null;\n\t\tthis.magfilter = null;\n\t\tthis.mipfilter = null;\n\n\t}\n\n\tSampler2D.prototype.parse = function ( element ) {\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'source':\n\n\t\t\t\t\tthis.source = child.textContent;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'minfilter':\n\n\t\t\t\t\tthis.minfilter = child.textContent;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'magfilter':\n\n\t\t\t\t\tthis.magfilter = child.textContent;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'mipfilter':\n\n\t\t\t\t\tthis.mipfilter = child.textContent;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'wrap_s':\n\n\t\t\t\t\tthis.wrap_s = child.textContent;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'wrap_t':\n\n\t\t\t\t\tthis.wrap_t = child.textContent;\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tconsole.log( \"unhandled Sampler2D prop: \" + child.nodeName );\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction Effect () {\n\n\t\tthis.id = \"\";\n\t\tthis.name = \"\";\n\t\tthis.shader = null;\n\t\tthis.surface = {};\n\t\tthis.sampler = {};\n\n\t}\n\n\tEffect.prototype.create = function () {\n\n\t\tif ( this.shader === null ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t};\n\n\tEffect.prototype.parse = function ( element ) {\n\n\t\tthis.id = element.getAttribute( 'id' );\n\t\tthis.name = element.getAttribute( 'name' );\n\n\t\textractDoubleSided( this, element );\n\n\t\tthis.shader = null;\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'profile_COMMON':\n\n\t\t\t\t\tthis.parseTechnique( this.parseProfileCOMMON( child ) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tEffect.prototype.parseNewparam = function ( element ) {\n\n\t\tvar sid = element.getAttribute( 'sid' );\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'surface':\n\n\t\t\t\t\tthis.surface[sid] = ( new Surface( this ) ).parse( child );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'sampler2D':\n\n\t\t\t\t\tthis.sampler[sid] = ( new Sampler2D( this ) ).parse( child );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'extra':\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tconsole.log( child.nodeName );\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t};\n\n\tEffect.prototype.parseProfileCOMMON = function ( element ) {\n\n\t\tvar technique;\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'profile_COMMON':\n\n\t\t\t\t\tthis.parseProfileCOMMON( child );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'technique':\n\n\t\t\t\t\ttechnique = child;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'newparam':\n\n\t\t\t\t\tthis.parseNewparam( child );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'image':\n\n\t\t\t\t\tvar _image = ( new _Image() ).parse( child );\n\t\t\t\t\timages[ _image.id ] = _image;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'extra':\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tconsole.log( child.nodeName );\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn technique;\n\n\t};\n\n\tEffect.prototype.parseTechnique = function ( element ) {\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[i];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'constant':\n\t\t\t\tcase 'lambert':\n\t\t\t\tcase 'blinn':\n\t\t\t\tcase 'phong':\n\n\t\t\t\t\tthis.shader = ( new Shader( child.nodeName, this ) ).parse( child );\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'extra':\n\t\t\t\t\tthis.parseExtra(child);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t};\n\n\tEffect.prototype.parseExtra = function ( element ) {\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[i];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'technique':\n\t\t\t\t\tthis.parseExtraTechnique( child );\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t};\n\n\tEffect.prototype.parseExtraTechnique = function ( element ) {\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[i];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'bump':\n\t\t\t\t\tthis.shader.parse( element );\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t};\n\n\tfunction InstanceEffect () {\n\n\t\tthis.url = \"\";\n\n\t}\n\n\tInstanceEffect.prototype.parse = function ( element ) {\n\n\t\tthis.url = element.getAttribute( 'url' ).replace( /^#/, '' );\n\t\treturn this;\n\n\t};\n\n\tfunction Animation() {\n\n\t\tthis.id = \"\";\n\t\tthis.name = \"\";\n\t\tthis.source = {};\n\t\tthis.sampler = [];\n\t\tthis.channel = [];\n\n\t}\n\n\tAnimation.prototype.parse = function ( element ) {\n\n\t\tthis.id = element.getAttribute( 'id' );\n\t\tthis.name = element.getAttribute( 'name' );\n\t\tthis.source = {};\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'animation':\n\n\t\t\t\t\tvar anim = ( new Animation() ).parse( child );\n\n\t\t\t\t\tfor ( var src in anim.source ) {\n\n\t\t\t\t\t\tthis.source[ src ] = anim.source[ src ];\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfor ( var j = 0; j < anim.channel.length; j ++ ) {\n\n\t\t\t\t\t\tthis.channel.push( anim.channel[ j ] );\n\t\t\t\t\t\tthis.sampler.push( anim.sampler[ j ] );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'source':\n\n\t\t\t\t\tvar src = ( new Source() ).parse( child );\n\t\t\t\t\tthis.source[ src.id ] = src;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'sampler':\n\n\t\t\t\t\tthis.sampler.push( ( new Sampler( this ) ).parse( child ) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'channel':\n\n\t\t\t\t\tthis.channel.push( ( new Channel( this ) ).parse( child ) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction Channel( animation ) {\n\n\t\tthis.animation = animation;\n\t\tthis.source = \"\";\n\t\tthis.target = \"\";\n\t\tthis.fullSid = null;\n\t\tthis.sid = null;\n\t\tthis.dotSyntax = null;\n\t\tthis.arrSyntax = null;\n\t\tthis.arrIndices = null;\n\t\tthis.member = null;\n\n\t}\n\n\tChannel.prototype.parse = function ( element ) {\n\n\t\tthis.source = element.getAttribute( 'source' ).replace( /^#/, '' );\n\t\tthis.target = element.getAttribute( 'target' );\n\n\t\tvar parts = this.target.split( '/' );\n\n\t\tvar id = parts.shift();\n\t\tvar sid = parts.shift();\n\n\t\tvar dotSyntax = ( sid.indexOf(\".\") >= 0 );\n\t\tvar arrSyntax = ( sid.indexOf(\"(\") >= 0 );\n\n\t\tif ( dotSyntax ) {\n\n\t\t\tparts = sid.split(\".\");\n\t\t\tthis.sid = parts.shift();\n\t\t\tthis.member = parts.shift();\n\n\t\t} else if ( arrSyntax ) {\n\n\t\t\tvar arrIndices = sid.split(\"(\");\n\t\t\tthis.sid = arrIndices.shift();\n\n\t\t\tfor (var j = 0; j < arrIndices.length; j ++ ) {\n\n\t\t\t\tarrIndices[j] = parseInt( arrIndices[j].replace(/\\)/, '') );\n\n\t\t\t}\n\n\t\t\tthis.arrIndices = arrIndices;\n\n\t\t} else {\n\n\t\t\tthis.sid = sid;\n\n\t\t}\n\n\t\tthis.fullSid = sid;\n\t\tthis.dotSyntax = dotSyntax;\n\t\tthis.arrSyntax = arrSyntax;\n\n\t\treturn this;\n\n\t};\n\n\tfunction Sampler ( animation ) {\n\n\t\tthis.id = \"\";\n\t\tthis.animation = animation;\n\t\tthis.inputs = [];\n\t\tthis.input = null;\n\t\tthis.output = null;\n\t\tthis.strideOut = null;\n\t\tthis.interpolation = null;\n\t\tthis.startTime = null;\n\t\tthis.endTime = null;\n\t\tthis.duration = 0;\n\n\t}\n\n\tSampler.prototype.parse = function ( element ) {\n\n\t\tthis.id = element.getAttribute( 'id' );\n\t\tthis.inputs = [];\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'input':\n\n\t\t\t\t\tthis.inputs.push( (new Input()).parse( child ) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tSampler.prototype.create = function () {\n\n\t\tfor ( var i = 0; i < this.inputs.length; i ++ ) {\n\n\t\t\tvar input = this.inputs[ i ];\n\t\t\tvar source = this.animation.source[ input.source ];\n\n\t\t\tswitch ( input.semantic ) {\n\n\t\t\t\tcase 'INPUT':\n\n\t\t\t\t\tthis.input = source.read();\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'OUTPUT':\n\n\t\t\t\t\tthis.output = source.read();\n\t\t\t\t\tthis.strideOut = source.accessor.stride;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'INTERPOLATION':\n\n\t\t\t\t\tthis.interpolation = source.read();\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'IN_TANGENT':\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'OUT_TANGENT':\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tconsole.log(input.semantic);\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.startTime = 0;\n\t\tthis.endTime = 0;\n\t\tthis.duration = 0;\n\n\t\tif ( this.input.length ) {\n\n\t\t\tthis.startTime = 100000000;\n\t\t\tthis.endTime = -100000000;\n\n\t\t\tfor ( var i = 0; i < this.input.length; i ++ ) {\n\n\t\t\t\tthis.startTime = Math.min( this.startTime, this.input[ i ] );\n\t\t\t\tthis.endTime = Math.max( this.endTime, this.input[ i ] );\n\n\t\t\t}\n\n\t\t\tthis.duration = this.endTime - this.startTime;\n\n\t\t}\n\n\t};\n\n\tSampler.prototype.getData = function ( type, ndx, member ) {\n\n\t\tvar data;\n\n\t\tif ( type === 'matrix' && this.strideOut === 16 ) {\n\n\t\t\tdata = this.output[ ndx ];\n\n\t\t} else if ( this.strideOut > 1 ) {\n\n\t\t\tdata = [];\n\t\t\tndx *= this.strideOut;\n\n\t\t\tfor ( var i = 0; i < this.strideOut; ++ i ) {\n\n\t\t\t\tdata[ i ] = this.output[ ndx + i ];\n\n\t\t\t}\n\n\t\t\tif ( this.strideOut === 3 ) {\n\n\t\t\t\tswitch ( type ) {\n\n\t\t\t\t\tcase 'rotate':\n\t\t\t\t\tcase 'translate':\n\n\t\t\t\t\t\tfixCoords( data, -1 );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'scale':\n\n\t\t\t\t\t\tfixCoords( data, 1 );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t} else if ( this.strideOut === 4 && type === 'matrix' ) {\n\n\t\t\t\tfixCoords( data, -1 );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tdata = this.output[ ndx ];\n\n\t\t\tif ( member && type === 'translate' ) {\n\t\t\t\tdata = getConvertedTranslation( member, data );\n\t\t\t}\n\n\t\t}\n\n\t\treturn data;\n\n\t};\n\n\tfunction Key ( time ) {\n\n\t\tthis.targets = [];\n\t\tthis.time = time;\n\n\t}\n\n\tKey.prototype.addTarget = function ( fullSid, transform, member, data ) {\n\n\t\tthis.targets.push( {\n\t\t\tsid: fullSid,\n\t\t\tmember: member,\n\t\t\ttransform: transform,\n\t\t\tdata: data\n\t\t} );\n\n\t};\n\n\tKey.prototype.apply = function ( opt_sid ) {\n\n\t\tfor ( var i = 0; i < this.targets.length; ++ i ) {\n\n\t\t\tvar target = this.targets[ i ];\n\n\t\t\tif ( !opt_sid || target.sid === opt_sid ) {\n\n\t\t\t\ttarget.transform.update( target.data, target.member );\n\n\t\t\t}\n\n\t\t}\n\n\t};\n\n\tKey.prototype.getTarget = function ( fullSid ) {\n\n\t\tfor ( var i = 0; i < this.targets.length; ++ i ) {\n\n\t\t\tif ( this.targets[ i ].sid === fullSid ) {\n\n\t\t\t\treturn this.targets[ i ];\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn null;\n\n\t};\n\n\tKey.prototype.hasTarget = function ( fullSid ) {\n\n\t\tfor ( var i = 0; i < this.targets.length; ++ i ) {\n\n\t\t\tif ( this.targets[ i ].sid === fullSid ) {\n\n\t\t\t\treturn true;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn false;\n\n\t};\n\n\t// TODO: Currently only doing linear interpolation. Should support full COLLADA spec.\n\tKey.prototype.interpolate = function ( nextKey, time ) {\n\n\t\tfor ( var i = 0, l = this.targets.length; i < l; i ++ ) {\n\n\t\t\tvar target = this.targets[ i ],\n\t\t\t\tnextTarget = nextKey.getTarget( target.sid ),\n\t\t\t\tdata;\n\n\t\t\tif ( target.transform.type !== 'matrix' && nextTarget ) {\n\n\t\t\t\tvar scale = ( time - this.time ) / ( nextKey.time - this.time ),\n\t\t\t\t\tnextData = nextTarget.data,\n\t\t\t\t\tprevData = target.data;\n\n\t\t\t\tif ( scale < 0 ) scale = 0;\n\t\t\t\tif ( scale > 1 ) scale = 1;\n\n\t\t\t\tif ( prevData.length ) {\n\n\t\t\t\t\tdata = [];\n\n\t\t\t\t\tfor ( var j = 0; j < prevData.length; ++ j ) {\n\n\t\t\t\t\t\tdata[ j ] = prevData[ j ] + ( nextData[ j ] - prevData[ j ] ) * scale;\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tdata = prevData + ( nextData - prevData ) * scale;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tdata = target.data;\n\n\t\t\t}\n\n\t\t\ttarget.transform.update( data, target.member );\n\n\t\t}\n\n\t};\n\n\t// Camera\n\tfunction Camera() {\n\n\t\tthis.id = \"\";\n\t\tthis.name = \"\";\n\t\tthis.technique = \"\";\n\n\t}\n\n\tCamera.prototype.parse = function ( element ) {\n\n\t\tthis.id = element.getAttribute( 'id' );\n\t\tthis.name = element.getAttribute( 'name' );\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'optics':\n\n\t\t\t\t\tthis.parseOptics( child );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tCamera.prototype.parseOptics = function ( element ) {\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tif ( element.childNodes[ i ].nodeName === 'technique_common' ) {\n\n\t\t\t\tvar technique = element.childNodes[ i ];\n\n\t\t\t\tfor ( var j = 0; j < technique.childNodes.length; j ++ ) {\n\n\t\t\t\t\tthis.technique = technique.childNodes[ j ].nodeName;\n\n\t\t\t\t\tif ( this.technique === 'perspective' ) {\n\n\t\t\t\t\t\tvar perspective = technique.childNodes[ j ];\n\n\t\t\t\t\t\tfor ( var k = 0; k < perspective.childNodes.length; k ++ ) {\n\n\t\t\t\t\t\t\tvar param = perspective.childNodes[ k ];\n\n\t\t\t\t\t\t\tswitch ( param.nodeName ) {\n\n\t\t\t\t\t\t\t\tcase 'yfov':\n\t\t\t\t\t\t\t\t\tthis.yfov = param.textContent;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase 'xfov':\n\t\t\t\t\t\t\t\t\tthis.xfov = param.textContent;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase 'znear':\n\t\t\t\t\t\t\t\t\tthis.znear = param.textContent;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase 'zfar':\n\t\t\t\t\t\t\t\t\tthis.zfar = param.textContent;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase 'aspect_ratio':\n\t\t\t\t\t\t\t\t\tthis.aspect_ratio = param.textContent;\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else if ( this.technique === 'orthographic' ) {\n\n\t\t\t\t\t\tvar orthographic = technique.childNodes[ j ];\n\n\t\t\t\t\t\tfor ( var k = 0; k < orthographic.childNodes.length; k ++ ) {\n\n\t\t\t\t\t\t\tvar param = orthographic.childNodes[ k ];\n\n\t\t\t\t\t\t\tswitch ( param.nodeName ) {\n\n\t\t\t\t\t\t\t\tcase 'xmag':\n\t\t\t\t\t\t\t\t\tthis.xmag = param.textContent;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase 'ymag':\n\t\t\t\t\t\t\t\t\tthis.ymag = param.textContent;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase 'znear':\n\t\t\t\t\t\t\t\t\tthis.znear = param.textContent;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase 'zfar':\n\t\t\t\t\t\t\t\t\tthis.zfar = param.textContent;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase 'aspect_ratio':\n\t\t\t\t\t\t\t\t\tthis.aspect_ratio = param.textContent;\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction InstanceCamera() {\n\n\t\tthis.url = \"\";\n\n\t}\n\n\tInstanceCamera.prototype.parse = function ( element ) {\n\n\t\tthis.url = element.getAttribute('url').replace(/^#/, '');\n\n\t\treturn this;\n\n\t};\n\n\t// Light\n\n\tfunction Light() {\n\n\t\tthis.id = \"\";\n\t\tthis.name = \"\";\n\t\tthis.technique = \"\";\n\n\t}\n\n\tLight.prototype.parse = function ( element ) {\n\n\t\tthis.id = element.getAttribute( 'id' );\n\t\tthis.name = element.getAttribute( 'name' );\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'technique_common':\n\n\t\t\t\t\tthis.parseCommon( child );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'technique':\n\n\t\t\t\t\tthis.parseTechnique( child );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tLight.prototype.parseCommon = function ( element ) {\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tswitch ( element.childNodes[ i ].nodeName ) {\n\n\t\t\t\tcase 'directional':\n\t\t\t\tcase 'point':\n\t\t\t\tcase 'spot':\n\t\t\t\tcase 'ambient':\n\n\t\t\t\t\tthis.technique = element.childNodes[ i ].nodeName;\n\n\t\t\t\t\tvar light = element.childNodes[ i ];\n\n\t\t\t\t\tfor ( var j = 0; j < light.childNodes.length; j ++ ) {\n\n\t\t\t\t\t\tvar child = light.childNodes[j];\n\n\t\t\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\t\t\tcase 'color':\n\n\t\t\t\t\t\t\t\tvar rgba = _floats( child.textContent );\n\t\t\t\t\t\t\t\tthis.color = new THREE.Color(0);\n\t\t\t\t\t\t\t\tthis.color.setRGB( rgba[0], rgba[1], rgba[2] );\n\t\t\t\t\t\t\t\tthis.color.a = rgba[3];\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase 'falloff_angle':\n\n\t\t\t\t\t\t\t\tthis.falloff_angle = parseFloat( child.textContent );\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase 'quadratic_attenuation':\n\t\t\t\t\t\t\t\tvar f = parseFloat( child.textContent );\n\t\t\t\t\t\t\t\tthis.distance = f ? Math.sqrt( 1 / f ) : 0;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tLight.prototype.parseTechnique = function ( element ) {\n\n\t\tthis.profile = element.getAttribute( 'profile' );\n\n\t\tfor ( var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'intensity':\n\n\t\t\t\t\tthis.intensity = parseFloat(child.textContent);\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction InstanceLight() {\n\n\t\tthis.url = \"\";\n\n\t}\n\n\tInstanceLight.prototype.parse = function ( element ) {\n\n\t\tthis.url = element.getAttribute('url').replace(/^#/, '');\n\n\t\treturn this;\n\n\t};\n\n\tfunction KinematicsModel( ) {\n\n\t\tthis.id = '';\n\t\tthis.name = '';\n\t\tthis.joints = [];\n\t\tthis.links = [];\n\n\t}\n\n\tKinematicsModel.prototype.parse = function( element ) {\n\n\t\tthis.id = element.getAttribute('id');\n\t\tthis.name = element.getAttribute('name');\n\t\tthis.joints = [];\n\t\tthis.links = [];\n\n\t\tfor (var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'technique_common':\n\n\t\t\t\t\tthis.parseCommon(child);\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tKinematicsModel.prototype.parseCommon = function( element ) {\n\n\t\tfor (var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( element.childNodes[ i ].nodeName ) {\n\n\t\t\t\tcase 'joint':\n\t\t\t\t\tthis.joints.push( (new Joint()).parse(child) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'link':\n\t\t\t\t\tthis.links.push( (new Link()).parse(child) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction Joint( ) {\n\n\t\tthis.sid = '';\n\t\tthis.name = '';\n\t\tthis.axis = new THREE.Vector3();\n\t\tthis.limits = {\n\t\t\tmin: 0,\n\t\t\tmax: 0\n\t\t};\n\t\tthis.type = '';\n\t\tthis.static = false;\n\t\tthis.zeroPosition = 0.0;\n\t\tthis.middlePosition = 0.0;\n\n\t}\n\n\tJoint.prototype.parse = function( element ) {\n\n\t\tthis.sid = element.getAttribute('sid');\n\t\tthis.name = element.getAttribute('name');\n\t\tthis.axis = new THREE.Vector3();\n\t\tthis.limits = {\n\t\t\tmin: 0,\n\t\t\tmax: 0\n\t\t};\n\t\tthis.type = '';\n\t\tthis.static = false;\n\t\tthis.zeroPosition = 0.0;\n\t\tthis.middlePosition = 0.0;\n\n\t\tvar axisElement = element.querySelector('axis');\n\t\tvar _axis = _floats(axisElement.textContent);\n\t\tthis.axis = getConvertedVec3(_axis, 0);\n\n\t\tvar min = element.querySelector('limits min') ? parseFloat(element.querySelector('limits min').textContent) : -360;\n\t\tvar max = element.querySelector('limits max') ? parseFloat(element.querySelector('limits max').textContent) : 360;\n\n\t\tthis.limits = {\n\t\t\tmin: min,\n\t\t\tmax: max\n\t\t};\n\n\t\tvar jointTypes = [ 'prismatic', 'revolute' ];\n\t\tfor (var i = 0; i < jointTypes.length; i ++ ) {\n\n\t\t\tvar type = jointTypes[ i ];\n\n\t\t\tvar jointElement = element.querySelector(type);\n\n\t\t\tif ( jointElement ) {\n\n\t\t\t\tthis.type = type;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// if the min is equal to or somehow greater than the max, consider the joint static\n\t\tif ( this.limits.min >= this.limits.max ) {\n\n\t\t\tthis.static = true;\n\n\t\t}\n\n\t\tthis.middlePosition = (this.limits.min + this.limits.max) / 2.0;\n\t\treturn this;\n\n\t};\n\n\tfunction Link( ) {\n\n\t\tthis.sid = '';\n\t\tthis.name = '';\n\t\tthis.transforms = [];\n\t\tthis.attachments = [];\n\n\t}\n\n\tLink.prototype.parse = function( element ) {\n\n\t\tthis.sid = element.getAttribute('sid');\n\t\tthis.name = element.getAttribute('name');\n\t\tthis.transforms = [];\n\t\tthis.attachments = [];\n\n\t\tfor (var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'attachment_full':\n\t\t\t\t\tthis.attachments.push( (new Attachment()).parse(child) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'rotate':\n\t\t\t\tcase 'translate':\n\t\t\t\tcase 'matrix':\n\n\t\t\t\t\tthis.transforms.push( (new Transform()).parse(child) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction Attachment( ) {\n\n\t\tthis.joint = '';\n\t\tthis.transforms = [];\n\t\tthis.links = [];\n\n\t}\n\n\tAttachment.prototype.parse = function( element ) {\n\n\t\tthis.joint = element.getAttribute('joint').split('/').pop();\n\t\tthis.links = [];\n\n\t\tfor (var i = 0; i < element.childNodes.length; i ++ ) {\n\n\t\t\tvar child = element.childNodes[ i ];\n\t\t\tif ( child.nodeType != 1 ) continue;\n\n\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\tcase 'link':\n\t\t\t\t\tthis.links.push( (new Link()).parse(child) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'rotate':\n\t\t\t\tcase 'translate':\n\t\t\t\tcase 'matrix':\n\n\t\t\t\t\tthis.transforms.push( (new Transform()).parse(child) );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t};\n\n\tfunction _source( element ) {\n\n\t\tvar id = element.getAttribute( 'id' );\n\n\t\tif ( sources[ id ] != undefined ) {\n\n\t\t\treturn sources[ id ];\n\n\t\t}\n\n\t\tsources[ id ] = ( new Source(id )).parse( element );\n\t\treturn sources[ id ];\n\n\t}\n\n\tfunction _nsResolver( nsPrefix ) {\n\n\t\tif ( nsPrefix === \"dae\" ) {\n\n\t\t\treturn \"http://www.collada.org/2005/11/COLLADASchema\";\n\n\t\t}\n\n\t\treturn null;\n\n\t}\n\n\tfunction _bools( str ) {\n\n\t\tvar raw = _strings( str );\n\t\tvar data = [];\n\n\t\tfor ( var i = 0, l = raw.length; i < l; i ++ ) {\n\n\t\t\tdata.push( (raw[i] === 'true' || raw[i] === '1') ? true : false );\n\n\t\t}\n\n\t\treturn data;\n\n\t}\n\n\tfunction _floats( str ) {\n\n\t\tvar raw = _strings(str);\n\t\tvar data = [];\n\n\t\tfor ( var i = 0, l = raw.length; i < l; i ++ ) {\n\n\t\t\tdata.push( parseFloat( raw[ i ] ) );\n\n\t\t}\n\n\t\treturn data;\n\n\t}\n\n\tfunction _ints( str ) {\n\n\t\tvar raw = _strings( str );\n\t\tvar data = [];\n\n\t\tfor ( var i = 0, l = raw.length; i < l; i ++ ) {\n\n\t\t\tdata.push( parseInt( raw[ i ], 10 ) );\n\n\t\t}\n\n\t\treturn data;\n\n\t}\n\n\tfunction _strings( str ) {\n\n\t\treturn ( str.length > 0 ) ? _trimString( str ).split( /\\s+/ ) : [];\n\n\t}\n\n\tfunction _trimString( str ) {\n\n\t\treturn str.replace( /^\\s+/, \"\" ).replace( /\\s+$/, \"\" );\n\n\t}\n\n\tfunction _attr_as_float( element, name, defaultValue ) {\n\n\t\tif ( element.hasAttribute( name ) ) {\n\n\t\t\treturn parseFloat( element.getAttribute( name ) );\n\n\t\t} else {\n\n\t\t\treturn defaultValue;\n\n\t\t}\n\n\t}\n\n\tfunction _attr_as_int( element, name, defaultValue ) {\n\n\t\tif ( element.hasAttribute( name ) ) {\n\n\t\t\treturn parseInt( element.getAttribute( name ), 10) ;\n\n\t\t} else {\n\n\t\t\treturn defaultValue;\n\n\t\t}\n\n\t}\n\n\tfunction _attr_as_string( element, name, defaultValue ) {\n\n\t\tif ( element.hasAttribute( name ) ) {\n\n\t\t\treturn element.getAttribute( name );\n\n\t\t} else {\n\n\t\t\treturn defaultValue;\n\n\t\t}\n\n\t}\n\n\tfunction _format_float( f, num ) {\n\n\t\tif ( f === undefined ) {\n\n\t\t\tvar s = '0.';\n\n\t\t\twhile ( s.length < num + 2 ) {\n\n\t\t\t\ts += '0';\n\n\t\t\t}\n\n\t\t\treturn s;\n\n\t\t}\n\n\t\tnum = num || 2;\n\n\t\tvar parts = f.toString().split( '.' );\n\t\tparts[ 1 ] = parts.length > 1 ? parts[ 1 ].substr( 0, num ) : \"0\";\n\n\t\twhile ( parts[ 1 ].length < num ) {\n\n\t\t\tparts[ 1 ] += '0';\n\n\t\t}\n\n\t\treturn parts.join( '.' );\n\n\t}\n\n\tfunction loadTextureImage ( texture, url ) {\n\n\t\tvar loader = new THREE.ImageLoader();\n\n\t\tloader.load( url, function ( image ) {\n\n\t\t\ttexture.image = image;\n\t\t\ttexture.needsUpdate = true;\n\n\t\t} );\n\n\t}\n\n\tfunction extractDoubleSided( obj, element ) {\n\n\t\tobj.doubleSided = false;\n\n\t\tvar node = element.querySelectorAll('extra double_sided')[0];\n\n\t\tif ( node ) {\n\n\t\t\tif ( node && parseInt( node.textContent, 10 ) === 1 ) {\n\n\t\t\t\tobj.doubleSided = true;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t// Up axis conversion\n\n\tfunction setUpConversion() {\n\n\t\tif ( options.convertUpAxis !== true || colladaUp === options.upAxis ) {\n\n\t\t\tupConversion = null;\n\n\t\t} else {\n\n\t\t\tswitch ( colladaUp ) {\n\n\t\t\t\tcase 'X':\n\n\t\t\t\t\tupConversion = options.upAxis === 'Y' ? 'XtoY' : 'XtoZ';\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'Y':\n\n\t\t\t\t\tupConversion = options.upAxis === 'X' ? 'YtoX' : 'YtoZ';\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'Z':\n\n\t\t\t\t\tupConversion = options.upAxis === 'X' ? 'ZtoX' : 'ZtoY';\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction fixCoords( data, sign ) {\n\n\t\tif ( options.convertUpAxis !== true || colladaUp === options.upAxis ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tswitch ( upConversion ) {\n\n\t\t\tcase 'XtoY':\n\n\t\t\t\tvar tmp = data[ 0 ];\n\t\t\t\tdata[ 0 ] = sign * data[ 1 ];\n\t\t\t\tdata[ 1 ] = tmp;\n\t\t\t\tbreak;\n\n\t\t\tcase 'XtoZ':\n\n\t\t\t\tvar tmp = data[ 2 ];\n\t\t\t\tdata[ 2 ] = data[ 1 ];\n\t\t\t\tdata[ 1 ] = data[ 0 ];\n\t\t\t\tdata[ 0 ] = tmp;\n\t\t\t\tbreak;\n\n\t\t\tcase 'YtoX':\n\n\t\t\t\tvar tmp = data[ 0 ];\n\t\t\t\tdata[ 0 ] = data[ 1 ];\n\t\t\t\tdata[ 1 ] = sign * tmp;\n\t\t\t\tbreak;\n\n\t\t\tcase 'YtoZ':\n\n\t\t\t\tvar tmp = data[ 1 ];\n\t\t\t\tdata[ 1 ] = sign * data[ 2 ];\n\t\t\t\tdata[ 2 ] = tmp;\n\t\t\t\tbreak;\n\n\t\t\tcase 'ZtoX':\n\n\t\t\t\tvar tmp = data[ 0 ];\n\t\t\t\tdata[ 0 ] = data[ 1 ];\n\t\t\t\tdata[ 1 ] = data[ 2 ];\n\t\t\t\tdata[ 2 ] = tmp;\n\t\t\t\tbreak;\n\n\t\t\tcase 'ZtoY':\n\n\t\t\t\tvar tmp = data[ 1 ];\n\t\t\t\tdata[ 1 ] = data[ 2 ];\n\t\t\t\tdata[ 2 ] = sign * tmp;\n\t\t\t\tbreak;\n\n\t\t}\n\n\t}\n\n\tfunction getConvertedTranslation( axis, data ) {\n\n\t\tif ( options.convertUpAxis !== true || colladaUp === options.upAxis ) {\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tswitch ( axis ) {\n\t\t\tcase 'X':\n\t\t\t\tdata = upConversion === 'XtoY' ? data * -1 : data;\n\t\t\t\tbreak;\n\t\t\tcase 'Y':\n\t\t\t\tdata = upConversion === 'YtoZ' || upConversion === 'YtoX' ? data * -1 : data;\n\t\t\t\tbreak;\n\t\t\tcase 'Z':\n\t\t\t\tdata = upConversion === 'ZtoY' ? data * -1 : data ;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn data;\n\t}\n\n\tfunction getConvertedVec3( data, offset ) {\n\n\t\tvar arr = [ data[ offset ], data[ offset + 1 ], data[ offset + 2 ] ];\n\t\tfixCoords( arr, -1 );\n\t\treturn new THREE.Vector3( arr[ 0 ], arr[ 1 ], arr[ 2 ] );\n\n\t}\n\n\tfunction getConvertedMat4( data ) {\n\n\t\tif ( options.convertUpAxis ) {\n\n\t\t\t// First fix rotation and scale\n\n\t\t\t// Columns first\n\t\t\tvar arr = [ data[ 0 ], data[ 4 ], data[ 8 ] ];\n\t\t\tfixCoords( arr, -1 );\n\t\t\tdata[ 0 ] = arr[ 0 ];\n\t\t\tdata[ 4 ] = arr[ 1 ];\n\t\t\tdata[ 8 ] = arr[ 2 ];\n\t\t\tarr = [ data[ 1 ], data[ 5 ], data[ 9 ] ];\n\t\t\tfixCoords( arr, -1 );\n\t\t\tdata[ 1 ] = arr[ 0 ];\n\t\t\tdata[ 5 ] = arr[ 1 ];\n\t\t\tdata[ 9 ] = arr[ 2 ];\n\t\t\tarr = [ data[ 2 ], data[ 6 ], data[ 10 ] ];\n\t\t\tfixCoords( arr, -1 );\n\t\t\tdata[ 2 ] = arr[ 0 ];\n\t\t\tdata[ 6 ] = arr[ 1 ];\n\t\t\tdata[ 10 ] = arr[ 2 ];\n\t\t\t// Rows second\n\t\t\tarr = [ data[ 0 ], data[ 1 ], data[ 2 ] ];\n\t\t\tfixCoords( arr, -1 );\n\t\t\tdata[ 0 ] = arr[ 0 ];\n\t\t\tdata[ 1 ] = arr[ 1 ];\n\t\t\tdata[ 2 ] = arr[ 2 ];\n\t\t\tarr = [ data[ 4 ], data[ 5 ], data[ 6 ] ];\n\t\t\tfixCoords( arr, -1 );\n\t\t\tdata[ 4 ] = arr[ 0 ];\n\t\t\tdata[ 5 ] = arr[ 1 ];\n\t\t\tdata[ 6 ] = arr[ 2 ];\n\t\t\tarr = [ data[ 8 ], data[ 9 ], data[ 10 ] ];\n\t\t\tfixCoords( arr, -1 );\n\t\t\tdata[ 8 ] = arr[ 0 ];\n\t\t\tdata[ 9 ] = arr[ 1 ];\n\t\t\tdata[ 10 ] = arr[ 2 ];\n\n\t\t\t// Now fix translation\n\t\t\tarr = [ data[ 3 ], data[ 7 ], data[ 11 ] ];\n\t\t\tfixCoords( arr, -1 );\n\t\t\tdata[ 3 ] = arr[ 0 ];\n\t\t\tdata[ 7 ] = arr[ 1 ];\n\t\t\tdata[ 11 ] = arr[ 2 ];\n\n\t\t}\n\n\t\treturn new THREE.Matrix4().set(\n\t\t\tdata[0], data[1], data[2], data[3],\n\t\t\tdata[4], data[5], data[6], data[7],\n\t\t\tdata[8], data[9], data[10], data[11],\n\t\t\tdata[12], data[13], data[14], data[15]\n\t\t\t);\n\n\t}\n\n\tfunction getConvertedIndex( index ) {\n\n\t\tif ( index > -1 && index < 3 ) {\n\n\t\t\tvar members = [ 'X', 'Y', 'Z' ],\n\t\t\t\tindices = { X: 0, Y: 1, Z: 2 };\n\n\t\t\tindex = getConvertedMember( members[ index ] );\n\t\t\tindex = indices[ index ];\n\n\t\t}\n\n\t\treturn index;\n\n\t}\n\n\tfunction getConvertedMember( member ) {\n\n\t\tif ( options.convertUpAxis ) {\n\n\t\t\tswitch ( member ) {\n\n\t\t\t\tcase 'X':\n\n\t\t\t\t\tswitch ( upConversion ) {\n\n\t\t\t\t\t\tcase 'XtoY':\n\t\t\t\t\t\tcase 'XtoZ':\n\t\t\t\t\t\tcase 'YtoX':\n\n\t\t\t\t\t\t\tmember = 'Y';\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'ZtoX':\n\n\t\t\t\t\t\t\tmember = 'Z';\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'Y':\n\n\t\t\t\t\tswitch ( upConversion ) {\n\n\t\t\t\t\t\tcase 'XtoY':\n\t\t\t\t\t\tcase 'YtoX':\n\t\t\t\t\t\tcase 'ZtoX':\n\n\t\t\t\t\t\t\tmember = 'X';\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'XtoZ':\n\t\t\t\t\t\tcase 'YtoZ':\n\t\t\t\t\t\tcase 'ZtoY':\n\n\t\t\t\t\t\t\tmember = 'Z';\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'Z':\n\n\t\t\t\t\tswitch ( upConversion ) {\n\n\t\t\t\t\t\tcase 'XtoZ':\n\n\t\t\t\t\t\t\tmember = 'X';\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'YtoZ':\n\t\t\t\t\t\tcase 'ZtoX':\n\t\t\t\t\t\tcase 'ZtoY':\n\n\t\t\t\t\t\t\tmember = 'Y';\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn member;\n\n\t}\n\n\treturn {\n\n\t\tload: load,\n\t\tparse: parse,\n\t\tapplySkin: applySkin,\n\t\tgeometries : geometries,\n\t\toptions: options\n\n\t};\n\n};\n\n},{}],43:[function(_dereq_,module,exports){\n/**\n * @author Rich Tibbett / https://github.com/richtr\n * @author mrdoob / http://mrdoob.com/\n * @author Tony Parisi / http://www.tonyparisi.com/\n * @author Takahiro / https://github.com/takahirox\n * @author Don McCurdy / https://www.donmccurdy.com\n */\n\nTHREE.GLTFLoader = ( function () {\n\n\tfunction GLTFLoader( manager ) {\n\n\t\tthis.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;\n\n\t}\n\n\tGLTFLoader.prototype = {\n\n\t\tconstructor: GLTFLoader,\n\n\t\tcrossOrigin: 'Anonymous',\n\n\t\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\t\tvar scope = this;\n\n\t\t\tvar path = this.path && ( typeof this.path === 'string' ) ? this.path : THREE.Loader.prototype.extractUrlBase( url );\n\n\t\t\tvar loader = new THREE.FileLoader( scope.manager );\n\n\t\t\tloader.setResponseType( 'arraybuffer' );\n\n\t\t\tloader.load( url, function ( data ) {\n\n\t\t\t\ttry {\n\n\t\t\t\t\tscope.parse( data, path, onLoad, onError );\n\n\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t// For SyntaxError or TypeError, return a generic failure message.\n\t\t\t\t\tonError( e.constructor === Error ? e : new Error( 'THREE.GLTFLoader: Unable to parse model.' ) );\n\n\t\t\t\t}\n\n\t\t\t}, onProgress, onError );\n\n\t\t},\n\n\t\tsetCrossOrigin: function ( value ) {\n\n\t\t\tthis.crossOrigin = value;\n\n\t\t},\n\n\t\tsetPath: function ( value ) {\n\n\t\t\tthis.path = value;\n\n\t\t},\n\n\t\tparse: function ( data, path, onLoad, onError ) {\n\n\t\t\tvar content;\n\t\t\tvar extensions = {};\n\n\t\t\tvar magic = convertUint8ArrayToString( new Uint8Array( data, 0, 4 ) );\n\n\t\t\tif ( magic === BINARY_EXTENSION_HEADER_MAGIC ) {\n\n\t\t\t\textensions[ EXTENSIONS.KHR_BINARY_GLTF ] = new GLTFBinaryExtension( data );\n\t\t\t\tcontent = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].content;\n\n\t\t\t} else {\n\n\t\t\t\tcontent = convertUint8ArrayToString( new Uint8Array( data ) );\n\n\t\t\t}\n\n\t\t\tvar json = JSON.parse( content );\n\n\t\t\tif ( json.asset === undefined || json.asset.version[ 0 ] < 2 ) {\n\n\t\t\t\tonError( new Error( 'THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported.' ) );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tif ( json.extensionsUsed ) {\n\n\t\t\t\tif( json.extensionsUsed.indexOf( EXTENSIONS.KHR_LIGHTS ) >= 0 ) {\n\n\t\t\t\t\textensions[ EXTENSIONS.KHR_LIGHTS ] = new GLTFLightsExtension( json );\n\n\t\t\t\t}\n\n\t\t\t\tif( json.extensionsUsed.indexOf( EXTENSIONS.KHR_MATERIALS_COMMON ) >= 0 ) {\n\n\t\t\t\t\textensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] = new GLTFMaterialsCommonExtension( json );\n\n\t\t\t\t}\n\n\t\t\t\tif( json.extensionsUsed.indexOf( EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ) >= 0 ) {\n\n\t\t\t\t\textensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ] = new GLTFMaterialsPbrSpecularGlossinessExtension();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tconsole.time( 'GLTFLoader' );\n\n\t\t\tvar parser = new GLTFParser( json, extensions, {\n\n\t\t\t\tpath: path || this.path,\n\t\t\t\tcrossOrigin: this.crossOrigin\n\n\t\t\t} );\n\n\t\t\tparser.parse( function ( scene, scenes, cameras, animations ) {\n\n\t\t\t\tconsole.timeEnd( 'GLTFLoader' );\n\n\t\t\t\tvar glTF = {\n\t\t\t\t\tscene: scene,\n\t\t\t\t\tscenes: scenes,\n\t\t\t\t\tcameras: cameras,\n\t\t\t\t\tanimations: animations\n\t\t\t\t};\n\n\t\t\t\tonLoad( glTF );\n\n\t\t\t}, onError );\n\n\t\t}\n\n\t};\n\n\t/* GLTFREGISTRY */\n\n\tfunction GLTFRegistry() {\n\n\t\tvar objects = {};\n\n\t\treturn\t{\n\n\t\t\tget: function ( key ) {\n\n\t\t\t\treturn objects[ key ];\n\n\t\t\t},\n\n\t\t\tadd: function ( key, object ) {\n\n\t\t\t\tobjects[ key ] = object;\n\n\t\t\t},\n\n\t\t\tremove: function ( key ) {\n\n\t\t\t\tdelete objects[ key ];\n\n\t\t\t},\n\n\t\t\tremoveAll: function () {\n\n\t\t\t\tobjects = {};\n\n\t\t\t},\n\n\t\t\tupdate: function ( scene, camera ) {\n\n\t\t\t\tfor ( var name in objects ) {\n\n\t\t\t\t\tvar object = objects[ name ];\n\n\t\t\t\t\tif ( object.update ) {\n\n\t\t\t\t\t\tobject.update( scene, camera );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\t/*********************************/\n\t/********** EXTENSIONS ***********/\n\t/*********************************/\n\n\tvar EXTENSIONS = {\n\t\tKHR_BINARY_GLTF: 'KHR_binary_glTF',\n\t\tKHR_LIGHTS: 'KHR_lights',\n\t\tKHR_MATERIALS_COMMON: 'KHR_materials_common',\n\t\tKHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness'\n\t};\n\n\t/**\n\t * Lights Extension\n\t *\n\t * Specification: PENDING\n\t */\n\tfunction GLTFLightsExtension( json ) {\n\n\t\tthis.name = EXTENSIONS.KHR_LIGHTS;\n\n\t\tthis.lights = {};\n\n\t\tvar extension = ( json.extensions && json.extensions[ EXTENSIONS.KHR_LIGHTS ] ) || {};\n\t\tvar lights = extension.lights || {};\n\n\t\tfor ( var lightId in lights ) {\n\n\t\t\tvar light = lights[ lightId ];\n\t\t\tvar lightNode;\n\n\t\t\tvar color = new THREE.Color().fromArray( light.color );\n\n\t\t\tswitch ( light.type ) {\n\n\t\t\t\tcase 'directional':\n\t\t\t\t\tlightNode = new THREE.DirectionalLight( color );\n\t\t\t\t\tlightNode.position.set( 0, 0, 1 );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'point':\n\t\t\t\t\tlightNode = new THREE.PointLight( color );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'spot':\n\t\t\t\t\tlightNode = new THREE.SpotLight( color );\n\t\t\t\t\tlightNode.position.set( 0, 0, 1 );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'ambient':\n\t\t\t\t\tlightNode = new THREE.AmbientLight( color );\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tif ( lightNode ) {\n\n\t\t\t\tif ( light.constantAttenuation !== undefined ) {\n\n\t\t\t\t\tlightNode.intensity = light.constantAttenuation;\n\n\t\t\t\t}\n\n\t\t\t\tif ( light.linearAttenuation !== undefined ) {\n\n\t\t\t\t\tlightNode.distance = 1 / light.linearAttenuation;\n\n\t\t\t\t}\n\n\t\t\t\tif ( light.quadraticAttenuation !== undefined ) {\n\n\t\t\t\t\tlightNode.decay = light.quadraticAttenuation;\n\n\t\t\t\t}\n\n\t\t\t\tif ( light.fallOffAngle !== undefined ) {\n\n\t\t\t\t\tlightNode.angle = light.fallOffAngle;\n\n\t\t\t\t}\n\n\t\t\t\tif ( light.fallOffExponent !== undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.GLTFLoader:: light.fallOffExponent not currently supported.' );\n\n\t\t\t\t}\n\n\t\t\t\tlightNode.name = light.name || ( 'light_' + lightId );\n\t\t\t\tthis.lights[ lightId ] = lightNode;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Common Materials Extension\n\t *\n\t * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/Khronos/KHR_materials_common\n\t */\n\tfunction GLTFMaterialsCommonExtension( json ) {\n\n\t\tthis.name = EXTENSIONS.KHR_MATERIALS_COMMON;\n\n\t}\n\n\tGLTFMaterialsCommonExtension.prototype.getMaterialType = function ( material ) {\n\n\t\tvar khrMaterial = material.extensions[ this.name ];\n\n\t\tswitch ( khrMaterial.type ) {\n\n\t\t\tcase 'commonBlinn' :\n\t\t\tcase 'commonPhong' :\n\t\t\t\treturn THREE.MeshPhongMaterial;\n\n\t\t\tcase 'commonLambert' :\n\t\t\t\treturn THREE.MeshLambertMaterial;\n\n\t\t\tcase 'commonConstant' :\n\t\t\tdefault :\n\t\t\t\treturn THREE.MeshBasicMaterial;\n\n\t\t}\n\n\t};\n\n\tGLTFMaterialsCommonExtension.prototype.extendParams = function ( materialParams, material, parser ) {\n\n\t\tvar khrMaterial = material.extensions[ this.name ];\n\n\t\tvar pending = [];\n\n\t\tvar keys = [];\n\n\t\t// TODO: Currently ignored: 'ambientFactor', 'ambientTexture'\n\t\tswitch ( khrMaterial.type ) {\n\n\t\t\tcase 'commonBlinn' :\n\t\t\tcase 'commonPhong' :\n\t\t\t\tkeys.push( 'diffuseFactor', 'diffuseTexture', 'specularFactor', 'specularTexture', 'shininessFactor' );\n\t\t\t\tbreak;\n\n\t\t\tcase 'commonLambert' :\n\t\t\t\tkeys.push( 'diffuseFactor', 'diffuseTexture' );\n\t\t\t\tbreak;\n\n\t\t\tcase 'commonConstant' :\n\t\t\tdefault :\n\t\t\t\tbreak;\n\n\t\t}\n\n\t\tvar materialValues = {};\n\n\t\tkeys.forEach( function( v ) {\n\n\t\t\tif ( khrMaterial[ v ] !== undefined ) materialValues[ v ] = khrMaterial[ v ];\n\n\t\t} );\n\n\t\tif ( materialValues.diffuseFactor !== undefined ) {\n\n\t\t\tmaterialParams.color = new THREE.Color().fromArray( materialValues.diffuseFactor );\n\t\t\tmaterialParams.opacity = materialValues.diffuseFactor[ 3 ];\n\n\t\t}\n\n\t\tif ( materialValues.diffuseTexture !== undefined ) {\n\n\t\t\tpending.push( parser.assignTexture( materialParams, 'map', materialValues.diffuseTexture.index ) );\n\n\t\t}\n\n\t\tif ( materialValues.specularFactor !== undefined ) {\n\n\t\t\tmaterialParams.specular = new THREE.Color().fromArray( materialValues.specularFactor );\n\n\t\t}\n\n\t\tif ( materialValues.specularTexture !== undefined ) {\n\n\t\t\tpending.push( parser.assignTexture( materialParams, 'specularMap', materialValues.specularTexture.index ) );\n\n\t\t}\n\n\t\tif ( materialValues.shininessFactor !== undefined ) {\n\n\t\t\tmaterialParams.shininess = materialValues.shininessFactor;\n\n\t\t}\n\n\t\treturn Promise.all( pending );\n\n\t};\n\n\t/* BINARY EXTENSION */\n\n\tvar BINARY_EXTENSION_BUFFER_NAME = 'binary_glTF';\n\tvar BINARY_EXTENSION_HEADER_MAGIC = 'glTF';\n\tvar BINARY_EXTENSION_HEADER_LENGTH = 12;\n\tvar BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4E4F534A, BIN: 0x004E4942 };\n\n\tfunction GLTFBinaryExtension( data ) {\n\n\t\tthis.name = EXTENSIONS.KHR_BINARY_GLTF;\n\t\tthis.content = null;\n\t\tthis.body = null;\n\n\t\tvar headerView = new DataView( data, 0, BINARY_EXTENSION_HEADER_LENGTH );\n\n\t\tthis.header = {\n\t\t\tmagic: convertUint8ArrayToString( new Uint8Array( data.slice( 0, 4 ) ) ),\n\t\t\tversion: headerView.getUint32( 4, true ),\n\t\t\tlength: headerView.getUint32( 8, true )\n\t\t};\n\n\t\tif ( this.header.magic !== BINARY_EXTENSION_HEADER_MAGIC ) {\n\n\t\t\tthrow new Error( 'THREE.GLTFLoader: Unsupported glTF-Binary header.' );\n\n\t\t} else if ( this.header.version < 2.0 ) {\n\n\t\t\tthrow new Error( 'THREE.GLTFLoader: Legacy binary file detected. Use GLTFLoader instead.' );\n\n\t\t}\n\n\t\tvar chunkView = new DataView( data, BINARY_EXTENSION_HEADER_LENGTH );\n\t\tvar chunkIndex = 0;\n\n\t\twhile ( chunkIndex < chunkView.byteLength ) {\n\n\t\t\tvar chunkLength = chunkView.getUint32( chunkIndex, true );\n\t\t\tchunkIndex += 4;\n\n\t\t\tvar chunkType = chunkView.getUint32( chunkIndex, true );\n\t\t\tchunkIndex += 4;\n\n\t\t\tif ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON ) {\n\n\t\t\t\tvar contentArray = new Uint8Array( data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength );\n\t\t\t\tthis.content = convertUint8ArrayToString( contentArray );\n\n\t\t\t} else if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN ) {\n\n\t\t\t\tvar byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex;\n\t\t\t\tthis.body = data.slice( byteOffset, byteOffset + chunkLength );\n\n\t\t\t}\n\n\t\t\t// Clients must ignore chunks with unknown types.\n\n\t\t\tchunkIndex += chunkLength;\n\n\t\t}\n\n\t\tif ( this.content === null ) {\n\n\t\t\tthrow new Error( 'THREE.GLTFLoader: JSON content not found.' );\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Specular-Glossiness Extension\n\t *\n\t * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/Khronos/KHR_materials_pbrSpecularGlossiness\n\t */\n\tfunction GLTFMaterialsPbrSpecularGlossinessExtension() {\n\n\t\treturn {\n\n\t\t\tname: EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS,\n\n\t\t\tgetMaterialType: function () {\n\n\t\t\t\treturn THREE.ShaderMaterial;\n\n\t\t\t},\n\n\t\t\textendParams: function ( params, material, parser ) {\n\n\t\t\t\tvar pbrSpecularGlossiness = material.extensions[ this.name ];\n\n\t\t\t\tvar shader = THREE.ShaderLib[ 'standard' ];\n\n\t\t\t\tvar uniforms = THREE.UniformsUtils.clone( shader.uniforms );\n\n\t\t\t\tvar specularMapParsFragmentChunk = [\n\t\t\t\t\t'#ifdef USE_SPECULARMAP',\n\t\t\t\t\t'\tuniform sampler2D specularMap;',\n\t\t\t\t\t'#endif'\n\t\t\t\t].join( '\\n' );\n\n\t\t\t\tvar glossinessMapParsFragmentChunk = [\n\t\t\t\t\t'#ifdef USE_GLOSSINESSMAP',\n\t\t\t\t\t'\tuniform sampler2D glossinessMap;',\n\t\t\t\t\t'#endif'\n\t\t\t\t].join( '\\n' );\n\n\t\t\t\tvar specularMapFragmentChunk = [\n\t\t\t\t\t'vec3 specularFactor = specular;',\n\t\t\t\t\t'#ifdef USE_SPECULARMAP',\n\t\t\t\t\t'\tvec4 texelSpecular = texture2D( specularMap, vUv );',\n\t\t\t\t\t'\t// reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture',\n\t\t\t\t\t'\tspecularFactor *= texelSpecular.rgb;',\n\t\t\t\t\t'#endif'\n\t\t\t\t].join( '\\n' );\n\n\t\t\t\tvar glossinessMapFragmentChunk = [\n\t\t\t\t\t'float glossinessFactor = glossiness;',\n\t\t\t\t\t'#ifdef USE_GLOSSINESSMAP',\n\t\t\t\t\t'\tvec4 texelGlossiness = texture2D( glossinessMap, vUv );',\n\t\t\t\t\t'\t// reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture',\n\t\t\t\t\t'\tglossinessFactor *= texelGlossiness.a;',\n\t\t\t\t\t'#endif'\n\t\t\t\t].join( '\\n' );\n\n\t\t\t\tvar lightPhysicalFragmentChunk = [\n\t\t\t\t\t'PhysicalMaterial material;',\n\t\t\t\t\t'material.diffuseColor = diffuseColor.rgb;',\n\t\t\t\t\t'material.specularRoughness = clamp( 1.0 - glossinessFactor, 0.04, 1.0 );',\n\t\t\t\t\t'material.specularColor = specularFactor.rgb;',\n\t\t\t\t].join( '\\n' );\n\n\t\t\t\tvar fragmentShader = shader.fragmentShader\n\t\t\t\t\t\t\t.replace( '#include <specularmap_fragment>', '' )\n\t\t\t\t\t\t\t.replace( 'uniform float roughness;', 'uniform vec3 specular;' )\n\t\t\t\t\t\t\t.replace( 'uniform float metalness;', 'uniform float glossiness;' )\n\t\t\t\t\t\t\t.replace( '#include <roughnessmap_pars_fragment>', specularMapParsFragmentChunk )\n\t\t\t\t\t\t\t.replace( '#include <metalnessmap_pars_fragment>', glossinessMapParsFragmentChunk )\n\t\t\t\t\t\t\t.replace( '#include <roughnessmap_fragment>', specularMapFragmentChunk )\n\t\t\t\t\t\t\t.replace( '#include <metalnessmap_fragment>', glossinessMapFragmentChunk )\n\t\t\t\t\t\t\t.replace( '#include <lights_physical_fragment>', lightPhysicalFragmentChunk );\n\n\t\t\t\tdelete uniforms.roughness;\n\t\t\t\tdelete uniforms.metalness;\n\t\t\t\tdelete uniforms.roughnessMap;\n\t\t\t\tdelete uniforms.metalnessMap;\n\n\t\t\t\tuniforms.specular = { value: new THREE.Color().setHex( 0x111111 ) };\n\t\t\t\tuniforms.glossiness = { value: 0.5 };\n\t\t\t\tuniforms.specularMap = { value: null };\n\t\t\t\tuniforms.glossinessMap = { value: null };\n\n\t\t\t\tparams.vertexShader = shader.vertexShader;\n\t\t\t\tparams.fragmentShader = fragmentShader;\n\t\t\t\tparams.uniforms = uniforms;\n\t\t\t\tparams.defines = { 'STANDARD': '' };\n\n\t\t\t\tparams.color = new THREE.Color( 1.0, 1.0, 1.0 );\n\t\t\t\tparams.opacity = 1.0;\n\n\t\t\t\tvar pending = [];\n\n\t\t\t\tif ( Array.isArray( pbrSpecularGlossiness.diffuseFactor ) ) {\n\n\t\t\t\t\tvar array = pbrSpecularGlossiness.diffuseFactor;\n\n\t\t\t\t\tparams.color.fromArray( array );\n\t\t\t\t\tparams.opacity = array[ 3 ];\n\n\t\t\t\t}\n\n\t\t\t\tif ( pbrSpecularGlossiness.diffuseTexture !== undefined ) {\n\n\t\t\t\t\tpending.push( parser.assignTexture( params, 'map', pbrSpecularGlossiness.diffuseTexture.index ) );\n\n\t\t\t\t}\n\n\t\t\t\tparams.emissive = new THREE.Color( 0.0, 0.0, 0.0 );\n\t\t\t\tparams.glossiness = pbrSpecularGlossiness.glossinessFactor !== undefined ? pbrSpecularGlossiness.glossinessFactor : 1.0;\n\t\t\t\tparams.specular = new THREE.Color( 1.0, 1.0, 1.0 );\n\n\t\t\t\tif ( Array.isArray( pbrSpecularGlossiness.specularFactor ) ) {\n\n\t\t\t\t\tparams.specular.fromArray( pbrSpecularGlossiness.specularFactor );\n\n\t\t\t\t}\n\n\t\t\t\tif ( pbrSpecularGlossiness.specularGlossinessTexture !== undefined ) {\n\n\t\t\t\t\tvar specGlossIndex = pbrSpecularGlossiness.specularGlossinessTexture.index;\n\t\t\t\t\tpending.push( parser.assignTexture( params, 'glossinessMap', specGlossIndex ) );\n\t\t\t\t\tpending.push( parser.assignTexture( params, 'specularMap', specGlossIndex ) );\n\n\t\t\t\t}\n\n\t\t\t\treturn Promise.all( pending );\n\n\t\t\t},\n\n\t\t\tcreateMaterial: function ( params ) {\n\n\t\t\t\t// setup material properties based on MeshStandardMaterial for Specular-Glossiness\n\n\t\t\t\tvar material = new THREE.ShaderMaterial( {\n\t\t\t\t\tdefines: params.defines,\n\t\t\t\t\tvertexShader: params.vertexShader,\n\t\t\t\t\tfragmentShader: params.fragmentShader,\n\t\t\t\t\tuniforms: params.uniforms,\n\t\t\t\t\tfog: true,\n\t\t\t\t\tlights: true,\n\t\t\t\t\topacity: params.opacity,\n\t\t\t\t\ttransparent: params.transparent\n\t\t\t\t} );\n\n\t\t\t\tmaterial.isGLTFSpecularGlossinessMaterial = true;\n\n\t\t\t\tmaterial.color = params.color;\n\n\t\t\t\tmaterial.map = params.map === undefined ? null : params.map;\n\n\t\t\t\tmaterial.lightMap = null;\n\t\t\t\tmaterial.lightMapIntensity = 1.0;\n\n\t\t\t\tmaterial.aoMap = params.aoMap === undefined ? null : params.aoMap;\n\t\t\t\tmaterial.aoMapIntensity = 1.0;\n\n\t\t\t\tmaterial.emissive = params.emissive;\n\t\t\t\tmaterial.emissiveIntensity = 1.0;\n\t\t\t\tmaterial.emissiveMap = params.emissiveMap === undefined ? null : params.emissiveMap;\n\n\t\t\t\tmaterial.bumpMap = params.bumpMap === undefined ? null : params.bumpMap;\n\t\t\t\tmaterial.bumpScale = 1;\n\n\t\t\t\tmaterial.normalMap = params.normalMap === undefined ? null : params.normalMap;\n\t\t\t\tmaterial.normalScale = new THREE.Vector2( 1, 1 );\n\n\t\t\t\tmaterial.displacementMap = null;\n\t\t\t\tmaterial.displacementScale = 1;\n\t\t\t\tmaterial.displacementBias = 0;\n\n\t\t\t\tmaterial.specularMap = params.specularMap === undefined ? null : params.specularMap;\n\t\t\t\tmaterial.specular = params.specular;\n\n\t\t\t\tmaterial.glossinessMap = params.glossinessMap === undefined ? null : params.glossinessMap;\n\t\t\t\tmaterial.glossiness = params.glossiness;\n\n\t\t\t\tmaterial.alphaMap = null;\n\n\t\t\t\tmaterial.envMap = params.envMap === undefined ? null : params.envMap;\n\t\t\t\tmaterial.envMapIntensity = 1.0;\n\n\t\t\t\tmaterial.refractionRatio = 0.98;\n\n\t\t\t\tmaterial.extensions.derivatives = true;\n\n\t\t\t\treturn material;\n\n\t\t\t},\n\n\t\t\t// Here's based on refreshUniformsCommon() and refreshUniformsStandard() in WebGLRenderer.\n\t\t\trefreshUniforms: function ( renderer, scene, camera, geometry, material, group ) {\n\n\t\t\t\tvar uniforms = material.uniforms;\n\t\t\t\tvar defines = material.defines;\n\n\t\t\t\tuniforms.opacity.value = material.opacity;\n\n\t\t\t\tuniforms.diffuse.value.copy( material.color );\n\t\t\t\tuniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );\n\n\t\t\t\tuniforms.map.value = material.map;\n\t\t\t\tuniforms.specularMap.value = material.specularMap;\n\t\t\t\tuniforms.alphaMap.value = material.alphaMap;\n\n\t\t\t\tuniforms.lightMap.value = material.lightMap;\n\t\t\t\tuniforms.lightMapIntensity.value = material.lightMapIntensity;\n\n\t\t\t\tuniforms.aoMap.value = material.aoMap;\n\t\t\t\tuniforms.aoMapIntensity.value = material.aoMapIntensity;\n\n\t\t\t\t// uv repeat and offset setting priorities\n\t\t\t\t// 1. color map\n\t\t\t\t// 2. specular map\n\t\t\t\t// 3. normal map\n\t\t\t\t// 4. bump map\n\t\t\t\t// 5. alpha map\n\t\t\t\t// 6. emissive map\n\n\t\t\t\tvar uvScaleMap;\n\n\t\t\t\tif ( material.map ) {\n\n\t\t\t\t\tuvScaleMap = material.map;\n\n\t\t\t\t} else if ( material.specularMap ) {\n\n\t\t\t\t\tuvScaleMap = material.specularMap;\n\n\t\t\t\t} else if ( material.displacementMap ) {\n\n\t\t\t\t\tuvScaleMap = material.displacementMap;\n\n\t\t\t\t} else if ( material.normalMap ) {\n\n\t\t\t\t\tuvScaleMap = material.normalMap;\n\n\t\t\t\t} else if ( material.bumpMap ) {\n\n\t\t\t\t\tuvScaleMap = material.bumpMap;\n\n\t\t\t\t} else if ( material.glossinessMap ) {\n\n\t\t\t\t\tuvScaleMap = material.glossinessMap;\n\n\t\t\t\t} else if ( material.alphaMap ) {\n\n\t\t\t\t\tuvScaleMap = material.alphaMap;\n\n\t\t\t\t} else if ( material.emissiveMap ) {\n\n\t\t\t\t\tuvScaleMap = material.emissiveMap;\n\n\t\t\t\t}\n\n\t\t\t\tif ( uvScaleMap !== undefined ) {\n\n\t\t\t\t\t// backwards compatibility\n\t\t\t\t\tif ( uvScaleMap.isWebGLRenderTarget ) {\n\n\t\t\t\t\t\tuvScaleMap = uvScaleMap.texture;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tvar offset = uvScaleMap.offset;\n\t\t\t\t\tvar repeat = uvScaleMap.repeat;\n\n\t\t\t\t\tuniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );\n\n\t\t\t\t}\n\n\t\t\t\tuniforms.envMap.value = material.envMap;\n\t\t\t\tuniforms.envMapIntensity.value = material.envMapIntensity;\n\t\t\t\tuniforms.flipEnvMap.value = ( material.envMap && material.envMap.isCubeTexture ) ? -1 : 1;\n\n\t\t\t\tuniforms.refractionRatio.value = material.refractionRatio;\n\n\t\t\t\tuniforms.specular.value.copy( material.specular );\n\t\t\t\tuniforms.glossiness.value = material.glossiness;\n\n\t\t\t\tuniforms.glossinessMap.value = material.glossinessMap;\n\n\t\t\t\tuniforms.emissiveMap.value = material.emissiveMap;\n\t\t\t\tuniforms.bumpMap.value = material.bumpMap;\n\t\t\t\tuniforms.normalMap.value = material.normalMap;\n\n\t\t\t\tuniforms.displacementMap.value = material.displacementMap;\n\t\t\t\tuniforms.displacementScale.value = material.displacementScale;\n\t\t\t\tuniforms.displacementBias.value = material.displacementBias;\n\n\t\t\t\tif ( uniforms.glossinessMap.value !== null && defines.USE_GLOSSINESSMAP === undefined ) {\n\n\t\t\t\t\tdefines.USE_GLOSSINESSMAP = '';\n\t\t\t\t\t// set USE_ROUGHNESSMAP to enable vUv\n\t\t\t\t\tdefines.USE_ROUGHNESSMAP = '';\n\n\t\t\t\t}\n\n\t\t\t\tif ( uniforms.glossinessMap.value === null && defines.USE_GLOSSINESSMAP !== undefined ) {\n\n\t\t\t\t\tdelete defines.USE_GLOSSINESSMAP;\n\t\t\t\t\tdelete defines.USE_ROUGHNESSMAP;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\t/*********************************/\n\t/********** INTERNALS ************/\n\t/*********************************/\n\n\t/* CONSTANTS */\n\n\tvar WEBGL_CONSTANTS = {\n\t\tFLOAT: 5126,\n\t\t//FLOAT_MAT2: 35674,\n\t\tFLOAT_MAT3: 35675,\n\t\tFLOAT_MAT4: 35676,\n\t\tFLOAT_VEC2: 35664,\n\t\tFLOAT_VEC3: 35665,\n\t\tFLOAT_VEC4: 35666,\n\t\tLINEAR: 9729,\n\t\tREPEAT: 10497,\n\t\tSAMPLER_2D: 35678,\n\t\tPOINTS: 0,\n\t\tLINES: 1,\n\t\tLINE_LOOP: 2,\n\t\tLINE_STRIP: 3,\n\t\tTRIANGLES: 4,\n\t\tTRIANGLE_STRIP: 5,\n\t\tTRIANGLE_FAN: 6,\n\t\tUNSIGNED_BYTE: 5121,\n\t\tUNSIGNED_SHORT: 5123\n\t};\n\n\tvar WEBGL_TYPE = {\n\t\t5126: Number,\n\t\t//35674: THREE.Matrix2,\n\t\t35675: THREE.Matrix3,\n\t\t35676: THREE.Matrix4,\n\t\t35664: THREE.Vector2,\n\t\t35665: THREE.Vector3,\n\t\t35666: THREE.Vector4,\n\t\t35678: THREE.Texture\n\t};\n\n\tvar WEBGL_COMPONENT_TYPES = {\n\t\t5120: Int8Array,\n\t\t5121: Uint8Array,\n\t\t5122: Int16Array,\n\t\t5123: Uint16Array,\n\t\t5125: Uint32Array,\n\t\t5126: Float32Array\n\t};\n\n\tvar WEBGL_FILTERS = {\n\t\t9728: THREE.NearestFilter,\n\t\t9729: THREE.LinearFilter,\n\t\t9984: THREE.NearestMipMapNearestFilter,\n\t\t9985: THREE.LinearMipMapNearestFilter,\n\t\t9986: THREE.NearestMipMapLinearFilter,\n\t\t9987: THREE.LinearMipMapLinearFilter\n\t};\n\n\tvar WEBGL_WRAPPINGS = {\n\t\t33071: THREE.ClampToEdgeWrapping,\n\t\t33648: THREE.MirroredRepeatWrapping,\n\t\t10497: THREE.RepeatWrapping\n\t};\n\n\tvar WEBGL_TEXTURE_FORMATS = {\n\t\t6406: THREE.AlphaFormat,\n\t\t6407: THREE.RGBFormat,\n\t\t6408: THREE.RGBAFormat,\n\t\t6409: THREE.LuminanceFormat,\n\t\t6410: THREE.LuminanceAlphaFormat\n\t};\n\n\tvar WEBGL_TEXTURE_DATATYPES = {\n\t\t5121: THREE.UnsignedByteType,\n\t\t32819: THREE.UnsignedShort4444Type,\n\t\t32820: THREE.UnsignedShort5551Type,\n\t\t33635: THREE.UnsignedShort565Type\n\t};\n\n\tvar WEBGL_SIDES = {\n\t\t1028: THREE.BackSide,  // Culling front\n\t\t1029: THREE.FrontSide  // Culling back\n\t\t//1032: THREE.NoSide   // Culling front and back, what to do?\n\t};\n\n\tvar WEBGL_DEPTH_FUNCS = {\n\t\t512: THREE.NeverDepth,\n\t\t513: THREE.LessDepth,\n\t\t514: THREE.EqualDepth,\n\t\t515: THREE.LessEqualDepth,\n\t\t516: THREE.GreaterEqualDepth,\n\t\t517: THREE.NotEqualDepth,\n\t\t518: THREE.GreaterEqualDepth,\n\t\t519: THREE.AlwaysDepth\n\t};\n\n\tvar WEBGL_BLEND_EQUATIONS = {\n\t\t32774: THREE.AddEquation,\n\t\t32778: THREE.SubtractEquation,\n\t\t32779: THREE.ReverseSubtractEquation\n\t};\n\n\tvar WEBGL_BLEND_FUNCS = {\n\t\t0: THREE.ZeroFactor,\n\t\t1: THREE.OneFactor,\n\t\t768: THREE.SrcColorFactor,\n\t\t769: THREE.OneMinusSrcColorFactor,\n\t\t770: THREE.SrcAlphaFactor,\n\t\t771: THREE.OneMinusSrcAlphaFactor,\n\t\t772: THREE.DstAlphaFactor,\n\t\t773: THREE.OneMinusDstAlphaFactor,\n\t\t774: THREE.DstColorFactor,\n\t\t775: THREE.OneMinusDstColorFactor,\n\t\t776: THREE.SrcAlphaSaturateFactor\n\t\t// The followings are not supported by Three.js yet\n\t\t//32769: CONSTANT_COLOR,\n\t\t//32770: ONE_MINUS_CONSTANT_COLOR,\n\t\t//32771: CONSTANT_ALPHA,\n\t\t//32772: ONE_MINUS_CONSTANT_COLOR\n\t};\n\n\tvar WEBGL_TYPE_SIZES = {\n\t\t'SCALAR': 1,\n\t\t'VEC2': 2,\n\t\t'VEC3': 3,\n\t\t'VEC4': 4,\n\t\t'MAT2': 4,\n\t\t'MAT3': 9,\n\t\t'MAT4': 16\n\t};\n\n\tvar PATH_PROPERTIES = {\n\t\tscale: 'scale',\n\t\ttranslation: 'position',\n\t\trotation: 'quaternion',\n\t\tweights: 'morphTargetInfluences'\n\t};\n\n\tvar INTERPOLATION = {\n\t\tCATMULLROMSPLINE: THREE.InterpolateSmooth,\n\t\tCUBICSPLINE: THREE.InterpolateSmooth,\n\t\tLINEAR: THREE.InterpolateLinear,\n\t\tSTEP: THREE.InterpolateDiscrete\n\t};\n\n\tvar STATES_ENABLES = {\n\t\t2884: 'CULL_FACE',\n\t\t2929: 'DEPTH_TEST',\n\t\t3042: 'BLEND',\n\t\t3089: 'SCISSOR_TEST',\n\t\t32823: 'POLYGON_OFFSET_FILL',\n\t\t32926: 'SAMPLE_ALPHA_TO_COVERAGE'\n\t};\n\n\tvar ALPHA_MODES = {\n\t\tOPAQUE: 'OPAQUE',\n\t\tMASK: 'MASK',\n\t\tBLEND: 'BLEND'\n\t};\n\n\t/* UTILITY FUNCTIONS */\n\n\tfunction _each( object, callback, thisObj ) {\n\n\t\tif ( !object ) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\tvar results;\n\t\tvar fns = [];\n\n\t\tif ( Object.prototype.toString.call( object ) === '[object Array]' ) {\n\n\t\t\tresults = [];\n\n\t\t\tvar length = object.length;\n\n\t\t\tfor ( var idx = 0; idx < length; idx ++ ) {\n\n\t\t\t\tvar value = callback.call( thisObj || this, object[ idx ], idx );\n\n\t\t\t\tif ( value ) {\n\n\t\t\t\t\tfns.push( value );\n\n\t\t\t\t\tif ( value instanceof Promise ) {\n\n\t\t\t\t\t\tvalue.then( function( key, value ) {\n\n\t\t\t\t\t\t\tresults[ key ] = value;\n\n\t\t\t\t\t\t}.bind( this, idx ));\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tresults[ idx ] = value;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tresults = {};\n\n\t\t\tfor ( var key in object ) {\n\n\t\t\t\tif ( object.hasOwnProperty( key ) ) {\n\n\t\t\t\t\tvar value = callback.call( thisObj || this, object[ key ], key );\n\n\t\t\t\t\tif ( value ) {\n\n\t\t\t\t\t\tfns.push( value );\n\n\t\t\t\t\t\tif ( value instanceof Promise ) {\n\n\t\t\t\t\t\t\tvalue.then( function( key, value ) {\n\n\t\t\t\t\t\t\t\tresults[ key ] = value;\n\n\t\t\t\t\t\t\t}.bind( this, key ));\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tresults[ key ] = value;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn Promise.all( fns ).then( function() {\n\n\t\t\treturn results;\n\n\t\t});\n\n\t}\n\n\tfunction resolveURL( url, path ) {\n\n\t\t// Invalid URL\n\t\tif ( typeof url !== 'string' || url === '' )\n\t\t\treturn '';\n\n\t\t// Absolute URL http://,https://,//\n\t\tif ( /^(https?:)?\\/\\//i.test( url ) ) {\n\n\t\t\treturn url;\n\n\t\t}\n\n\t\t// Data URI\n\t\tif ( /^data:.*,.*$/i.test( url ) ) {\n\n\t\t\treturn url;\n\n\t\t}\n\n\t\t// Blob URL\n\t\tif ( /^blob:.*$/i.test( url ) ) {\n\n\t\t\treturn url;\n\n\t\t}\n\n\t\t// Relative URL\n\t\treturn ( path || '' ) + url;\n\n\t}\n\n\tfunction convertUint8ArrayToString( array ) {\n\n\t\tif ( window.TextDecoder !== undefined ) {\n\n\t\t\treturn new TextDecoder().decode( array );\n\n\t\t}\n\n\t\t// Avoid the String.fromCharCode.apply(null, array) shortcut, which\n\t\t// throws a \"maximum call stack size exceeded\" error for large arrays.\n\n\t\tvar s = '';\n\n\t\tfor ( var i = 0, il = array.length; i < il; i ++ ) {\n\n\t\t\ts += String.fromCharCode( array[ i ] );\n\n\t\t}\n\n\t\treturn s;\n\n\t}\n\n\t/**\n\t * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#default-material\n\t */\n\tfunction createDefaultMaterial() {\n\n\t\treturn new THREE.MeshStandardMaterial( {\n\t\t\tcolor: 0xFFFFFF,\n\t\t\temissive: 0x000000,\n\t\t\tmetalness: 1,\n\t\t\troughness: 1,\n\t\t\ttransparent: false,\n\t\t\tdepthTest: true,\n\t\t\tside: THREE.FrontSide\n\t\t} );\n\n\t}\n\n\t/**\n\t * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets\n\t * @param {THREE.Mesh} mesh\n\t * @param {GLTF.Mesh} meshDef\n\t * @param {GLTF.Primitive} primitiveDef\n\t * @param {Object} dependencies\n\t */\n\tfunction addMorphTargets ( mesh, meshDef, primitiveDef, dependencies ) {\n\n\t\tvar geometry = mesh.geometry;\n\t\tvar material = mesh.material;\n\n\t\tvar targets = primitiveDef.targets;\n\t\tvar morphAttributes = geometry.morphAttributes;\n\n\t\tmorphAttributes.position = [];\n\t\tmorphAttributes.normal = [];\n\n\t\tmaterial.morphTargets = true;\n\n\t\tfor ( var i = 0, il = targets.length; i < il; i ++ ) {\n\n\t\t\tvar target = targets[ i ];\n\t\t\tvar attributeName = 'morphTarget' + i;\n\n\t\t\tvar positionAttribute, normalAttribute;\n\n\t\t\tif ( target.POSITION !== undefined ) {\n\n\t\t\t\t// Three.js morph formula is\n\t\t\t\t//   position\n\t\t\t\t//     + weight0 * ( morphTarget0 - position )\n\t\t\t\t//     + weight1 * ( morphTarget1 - position )\n\t\t\t\t//     ...\n\t\t\t\t// while the glTF one is\n\t\t\t\t//   position\n\t\t\t\t//     + weight0 * morphTarget0\n\t\t\t\t//     + weight1 * morphTarget1\n\t\t\t\t//     ...\n\t\t\t\t// then adding position to morphTarget.\n\t\t\t\t// So morphTarget value will depend on mesh's position, then cloning attribute\n\t\t\t\t// for the case if attribute is shared among two or more meshes.\n\n\t\t\t\tpositionAttribute = dependencies.accessors[ target.POSITION ].clone();\n\t\t\t\tvar position = geometry.attributes.position;\n\n\t\t\t\tfor ( var j = 0, jl = positionAttribute.count; j < jl; j ++ ) {\n\n\t\t\t\t\tpositionAttribute.setXYZ(\n\t\t\t\t\t\tj,\n\t\t\t\t\t\tpositionAttribute.getX( j ) + position.getX( j ),\n\t\t\t\t\t\tpositionAttribute.getY( j ) + position.getY( j ),\n\t\t\t\t\t\tpositionAttribute.getZ( j ) + position.getZ( j )\n\t\t\t\t\t);\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// Copying the original position not to affect the final position.\n\t\t\t\t// See the formula above.\n\t\t\t\tpositionAttribute = geometry.attributes.position.clone();\n\n\t\t\t}\n\n\t\t\tif ( target.NORMAL !== undefined ) {\n\n\t\t\t\tmaterial.morphNormals = true;\n\n\t\t\t\t// see target.POSITION's comment\n\n\t\t\t\tnormalAttribute = dependencies.accessors[ target.NORMAL ].clone();\n\t\t\t\tvar normal = geometry.attributes.normal;\n\n\t\t\t\tfor ( var j = 0, jl = normalAttribute.count; j < jl; j ++ ) {\n\n\t\t\t\t\tnormalAttribute.setXYZ(\n\t\t\t\t\t\tj,\n\t\t\t\t\t\tnormalAttribute.getX( j ) + normal.getX( j ),\n\t\t\t\t\t\tnormalAttribute.getY( j ) + normal.getY( j ),\n\t\t\t\t\t\tnormalAttribute.getZ( j ) + normal.getZ( j )\n\t\t\t\t\t);\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tnormalAttribute = geometry.attributes.normal.clone();\n\n\t\t\t}\n\n\t\t\tif ( target.TANGENT !== undefined ) {\n\n\t\t\t\t// TODO: implement\n\n\t\t\t}\n\n\t\t\tpositionAttribute.name = attributeName;\n\t\t\tnormalAttribute.name = attributeName;\n\n\t\t\tmorphAttributes.position.push( positionAttribute );\n\t\t\tmorphAttributes.normal.push( normalAttribute );\n\n\t\t}\n\n\t\tmesh.updateMorphTargets();\n\n\t\tif ( meshDef.weights !== undefined ) {\n\n\t\t\tfor ( var i = 0, il = meshDef.weights.length; i < il; i ++ ) {\n\n\t\t\t\tmesh.morphTargetInfluences[ i ] = meshDef.weights[ i ];\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/* GLTF PARSER */\n\n\tfunction GLTFParser( json, extensions, options ) {\n\n\t\tthis.json = json || {};\n\t\tthis.extensions = extensions || {};\n\t\tthis.options = options || {};\n\n\t\t// loader object cache\n\t\tthis.cache = new GLTFRegistry();\n\n\t}\n\n\tGLTFParser.prototype._withDependencies = function ( dependencies ) {\n\n\t\tvar _dependencies = {};\n\n\t\tfor ( var i = 0; i < dependencies.length; i ++ ) {\n\n\t\t\tvar dependency = dependencies[ i ];\n\t\t\tvar fnName = 'load' + dependency.charAt( 0 ).toUpperCase() + dependency.slice( 1 );\n\n\t\t\tvar cached = this.cache.get( dependency );\n\n\t\t\tif ( cached !== undefined ) {\n\n\t\t\t\t_dependencies[ dependency ] = cached;\n\n\t\t\t} else if ( this[ fnName ] ) {\n\n\t\t\t\tvar fn = this[ fnName ]();\n\t\t\t\tthis.cache.add( dependency, fn );\n\n\t\t\t\t_dependencies[ dependency ] = fn;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn _each( _dependencies, function ( dependency ) {\n\n\t\t\treturn dependency;\n\n\t\t} );\n\n\t};\n\n\tGLTFParser.prototype.parse = function ( onLoad, onError ) {\n\n\t\tvar json = this.json;\n\n\t\t// Clear the loader cache\n\t\tthis.cache.removeAll();\n\n\t\t// Fire the callback on complete\n\t\tthis._withDependencies( [\n\n\t\t\t'scenes',\n\t\t\t'cameras',\n\t\t\t'animations'\n\n\t\t] ).then( function ( dependencies ) {\n\n\t\t\tvar scenes = [];\n\n\t\t\tfor ( var name in dependencies.scenes ) {\n\n\t\t\t\tscenes.push( dependencies.scenes[ name ] );\n\n\t\t\t}\n\n\t\t\tvar scene = json.scene !== undefined ? dependencies.scenes[ json.scene ] : scenes[ 0 ];\n\n\t\t\tvar cameras = [];\n\n\t\t\tfor ( var name in dependencies.cameras ) {\n\n\t\t\t\tvar camera = dependencies.cameras[ name ];\n\t\t\t\tcameras.push( camera );\n\n\t\t\t}\n\n\t\t\tvar animations = [];\n\n\t\t\tfor ( var name in dependencies.animations ) {\n\n\t\t\t\tanimations.push( dependencies.animations[ name ] );\n\n\t\t\t}\n\n\t\t\tonLoad( scene, scenes, cameras, animations );\n\n\t\t} ).catch( onError );\n\n\t};\n\n\t/**\n\t * Requests the specified dependency asynchronously, with caching.\n\t * @param {string} type\n\t * @param {number} index\n\t * @return {Promise<Object>}\n\t */\n\tGLTFParser.prototype.getDependency = function ( type, index ) {\n\n\t\tvar cacheKey = type + ':' + index;\n\t\tvar dependency = this.cache.get( cacheKey );\n\n\t\tif ( !dependency ) {\n\n\t\t\tvar fnName = 'load' + type.charAt( 0 ).toUpperCase() + type.slice( 1 );\n\t\t\tdependency = this[ fnName ]( index );\n\t\t\tthis.cache.add( cacheKey, dependency );\n\n\t\t}\n\n\t\treturn dependency;\n\n\t};\n\n\t/**\n\t * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views\n\t * @param {number} bufferIndex\n\t * @return {Promise<ArrayBuffer>}\n\t */\n\tGLTFParser.prototype.loadBuffer = function ( bufferIndex ) {\n\n\t\tvar bufferDef = this.json.buffers[ bufferIndex ];\n\n\t\tif ( bufferDef.type && bufferDef.type !== 'arraybuffer' ) {\n\n\t\t\tthrow new Error( 'THREE.GLTFLoader: %s buffer type is not supported.', bufferDef.type );\n\n\t\t}\n\n\t\t// If present, GLB container is required to be the first buffer.\n\t\tif ( bufferDef.uri === undefined && bufferIndex === 0 ) {\n\n\t\t\treturn Promise.resolve( this.extensions[ EXTENSIONS.KHR_BINARY_GLTF ].body );\n\n\t\t}\n\n\t\tvar options = this.options;\n\n\t\treturn new Promise( function ( resolve ) {\n\n\t\t\tvar loader = new THREE.FileLoader();\n\t\t\tloader.setResponseType( 'arraybuffer' );\n\t\t\tloader.load( resolveURL( bufferDef.uri, options.path ), resolve);\n\n\t\t} );\n\n\t};\n\n\t/**\n\t * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views\n\t * @param {number} bufferViewIndex\n\t * @return {Promise<ArrayBuffer>}\n\t */\n\tGLTFParser.prototype.loadBufferView = function ( bufferViewIndex ) {\n\n\t\tvar bufferViewDef = this.json.bufferViews[ bufferViewIndex ];\n\n\t\treturn this.getDependency( 'buffer', bufferViewDef.buffer ).then( function ( buffer ) {\n\n\t\t\tvar byteLength = bufferViewDef.byteLength || 0;\n\t\t\tvar byteOffset = bufferViewDef.byteOffset || 0;\n\t\t\treturn buffer.slice( byteOffset, byteOffset + byteLength );\n\n\t\t} );\n\n\t};\n\n\tGLTFParser.prototype.loadAccessors = function () {\n\n\t\tvar parser = this;\n\t\tvar json = this.json;\n\n\t\treturn _each( json.accessors, function ( accessor ) {\n\n\t\t\treturn parser.getDependency( 'bufferView', accessor.bufferView ).then( function ( bufferView ) {\n\n\t\t\t\tvar itemSize = WEBGL_TYPE_SIZES[ accessor.type ];\n\t\t\t\tvar TypedArray = WEBGL_COMPONENT_TYPES[ accessor.componentType ];\n\n\t\t\t\t// For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12.\n\t\t\t\tvar elementBytes = TypedArray.BYTES_PER_ELEMENT;\n\t\t\t\tvar itemBytes = elementBytes * itemSize;\n\t\t\t\tvar byteStride = json.bufferViews[ accessor.bufferView ].byteStride;\n\t\t\t\tvar array;\n\n\t\t\t\t// The buffer is not interleaved if the stride is the item size in bytes.\n\t\t\t\tif ( byteStride && byteStride !== itemBytes ) {\n\n\t\t\t\t\t// Use the full buffer if it's interleaved.\n\t\t\t\t\tarray = new TypedArray( bufferView );\n\n\t\t\t\t\t// Integer parameters to IB/IBA are in array elements, not bytes.\n\t\t\t\t\tvar ib = new THREE.InterleavedBuffer( array, byteStride / elementBytes );\n\n\t\t\t\t\treturn new THREE.InterleavedBufferAttribute( ib, itemSize, accessor.byteOffset / elementBytes );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tarray = new TypedArray( bufferView, accessor.byteOffset, accessor.count * itemSize );\n\n\t\t\t\t\treturn new THREE.BufferAttribute( array, itemSize );\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t} );\n\n\t};\n\n\t/**\n\t * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#textures\n\t * @param {number} textureIndex\n\t * @return {Promise<THREE.Texture>}\n\t */\n\tGLTFParser.prototype.loadTexture = function ( textureIndex ) {\n\n\t\tvar parser = this;\n\t\tvar json = this.json;\n\t\tvar options = this.options;\n\n\t\tvar URL = window.URL || window.webkitURL;\n\n\t\tvar textureDef = json.textures[ textureIndex ];\n\t\tvar source = json.images[ textureDef.source ];\n\t\tvar sourceURI = source.uri;\n\t\tvar isObjectURL = false;\n\n\t\tif ( source.bufferView !== undefined ) {\n\n\t\t\t// Load binary image data from bufferView, if provided.\n\n\t\t\tsourceURI = parser.getDependency( 'bufferView', source.bufferView )\n\t\t\t\t.then( function ( bufferView ) {\n\n\t\t\t\t\tisObjectURL = true;\n\t\t\t\t\tvar blob = new Blob( [ bufferView ], { type: source.mimeType } );\n\t\t\t\t\tsourceURI = URL.createObjectURL( blob );\n\t\t\t\t\treturn sourceURI;\n\n\t\t\t\t} );\n\n\t\t}\n\n\t\treturn Promise.resolve( sourceURI ).then( function ( sourceURI ) {\n\n\t\t\t// Load Texture resource.\n\n\t\t\tvar textureLoader = THREE.Loader.Handlers.get( sourceURI ) || new THREE.TextureLoader();\n\t\t\ttextureLoader.setCrossOrigin( options.crossOrigin );\n\n\t\t\treturn new Promise( function ( resolve, reject ) {\n\n\t\t\t\ttextureLoader.load( resolveURL( sourceURI, options.path ), resolve, undefined, reject );\n\n\t\t\t} );\n\n\t\t} ).then( function ( texture ) {\n\n\t\t\t// Clean up resources and configure Texture.\n\n\t\t\tif ( isObjectURL !== undefined ) {\n\n\t\t\t\tURL.revokeObjectURL( sourceURI );\n\n\t\t\t}\n\n\t\t\ttexture.flipY = false;\n\n\t\t\tif ( textureDef.name !== undefined ) texture.name = textureDef.name;\n\n\t\t\ttexture.format = textureDef.format !== undefined ? WEBGL_TEXTURE_FORMATS[ textureDef.format ] : THREE.RGBAFormat;\n\n\t\t\tif ( textureDef.internalFormat !== undefined && texture.format !== WEBGL_TEXTURE_FORMATS[ textureDef.internalFormat ] ) {\n\n\t\t\t\tconsole.warn( 'THREE.GLTFLoader: Three.js does not support texture internalFormat which is different from texture format. ' +\n\t\t\t\t\t\t\t\t\t\t\t'internalFormat will be forced to be the same value as format.' );\n\n\t\t\t}\n\n\t\t\ttexture.type = textureDef.type !== undefined ? WEBGL_TEXTURE_DATATYPES[ textureDef.type ] : THREE.UnsignedByteType;\n\n\t\t\tvar samplers = json.samplers || {};\n\t\t\tvar sampler = samplers[ textureDef.sampler ] || {};\n\n\t\t\ttexture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || THREE.LinearFilter;\n\t\t\ttexture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || THREE.LinearMipMapLinearFilter;\n\t\t\ttexture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || THREE.RepeatWrapping;\n\t\t\ttexture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || THREE.RepeatWrapping;\n\n\t\t\treturn texture;\n\n\t\t} );\n\n\t};\n\n\t/**\n\t * Asynchronously assigns a texture to the given material parameters.\n\t * @param {Object} materialParams\n\t * @param {string} textureName\n\t * @param {number} textureIndex\n\t * @return {Promise}\n\t */\n\tGLTFParser.prototype.assignTexture = function ( materialParams, textureName, textureIndex ) {\n\n\t\treturn this.getDependency( 'texture', textureIndex ).then( function ( texture ) {\n\n\t\t\tmaterialParams[ textureName ] = texture;\n\n\t\t} );\n\n\t};\n\n\t/**\n\t * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials\n\t * @return {Promise<Array<THREE.Material>>}\n\t */\n\tGLTFParser.prototype.loadMaterials = function () {\n\n\t\tvar parser = this;\n\t\tvar json = this.json;\n\t\tvar extensions = this.extensions;\n\n\t\treturn _each( json.materials, function ( material ) {\n\n\t\t\tvar materialType;\n\t\t\tvar materialParams = {};\n\t\t\tvar materialExtensions = material.extensions || {};\n\n\t\t\tvar pending = [];\n\n\t\t\tif ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] ) {\n\n\t\t\t\tvar khcExtension = extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ];\n\t\t\t\tmaterialType = khcExtension.getMaterialType( material );\n\t\t\t\tpending.push( khcExtension.extendParams( materialParams, material, parser ) );\n\n\t\t\t} else if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ] ) {\n\n\t\t\t\tvar sgExtension = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ];\n\t\t\t\tmaterialType = sgExtension.getMaterialType( material );\n\t\t\t\tpending.push( sgExtension.extendParams( materialParams, material, parser ) );\n\n\t\t\t} else if ( material.pbrMetallicRoughness !== undefined ) {\n\n\t\t\t\t// Specification:\n\t\t\t\t// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material\n\n\t\t\t\tmaterialType = THREE.MeshStandardMaterial;\n\n\t\t\t\tvar metallicRoughness = material.pbrMetallicRoughness;\n\n\t\t\t\tmaterialParams.color = new THREE.Color( 1.0, 1.0, 1.0 );\n\t\t\t\tmaterialParams.opacity = 1.0;\n\n\t\t\t\tif ( Array.isArray( metallicRoughness.baseColorFactor ) ) {\n\n\t\t\t\t\tvar array = metallicRoughness.baseColorFactor;\n\n\t\t\t\t\tmaterialParams.color.fromArray( array );\n\t\t\t\t\tmaterialParams.opacity = array[ 3 ];\n\n\t\t\t\t}\n\n\t\t\t\tif ( metallicRoughness.baseColorTexture !== undefined ) {\n\n\t\t\t\t\tpending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture.index ) );\n\n\t\t\t\t}\n\n\t\t\t\tmaterialParams.metalness = metallicRoughness.metallicFactor !== undefined ? metallicRoughness.metallicFactor : 1.0;\n\t\t\t\tmaterialParams.roughness = metallicRoughness.roughnessFactor !== undefined ? metallicRoughness.roughnessFactor : 1.0;\n\n\t\t\t\tif ( metallicRoughness.metallicRoughnessTexture !== undefined ) {\n\n\t\t\t\t\tvar textureIndex = metallicRoughness.metallicRoughnessTexture.index;\n\t\t\t\t\tpending.push( parser.assignTexture( materialParams, 'metalnessMap', textureIndex ) );\n\t\t\t\t\tpending.push( parser.assignTexture( materialParams, 'roughnessMap', textureIndex ) );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tmaterialType = THREE.MeshPhongMaterial;\n\n\t\t\t}\n\n\t\t\tif ( material.doubleSided === true ) {\n\n\t\t\t\tmaterialParams.side = THREE.DoubleSide;\n\n\t\t\t}\n\n\t\t\tvar alphaMode = material.alphaMode || ALPHA_MODES.OPAQUE;\n\n\t\t\tif ( alphaMode !== ALPHA_MODES.OPAQUE ) {\n\n\t\t\t\tmaterialParams.transparent = true;\n\n\t\t\t} else {\n\n\t\t\t\tmaterialParams.transparent = false;\n\n\t\t\t}\n\n\t\t\tif ( material.normalTexture !== undefined ) {\n\n\t\t\t\tpending.push( parser.assignTexture( materialParams, 'normalMap', material.normalTexture.index ) );\n\n\t\t\t}\n\n\t\t\tif ( material.occlusionTexture !== undefined ) {\n\n\t\t\t\tpending.push( parser.assignTexture( materialParams, 'aoMap', material.occlusionTexture.index ) );\n\n\t\t\t}\n\n\t\t\tif ( material.emissiveFactor !== undefined ) {\n\n\t\t\t\tif ( materialType === THREE.MeshBasicMaterial ) {\n\n\t\t\t\t\tmaterialParams.color = new THREE.Color().fromArray( material.emissiveFactor );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tmaterialParams.emissive = new THREE.Color().fromArray( material.emissiveFactor );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( material.emissiveTexture !== undefined ) {\n\n\t\t\t\tif ( materialType === THREE.MeshBasicMaterial ) {\n\n\t\t\t\t\tpending.push( parser.assignTexture( materialParams, 'map', material.emissiveTexture.index ) );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tpending.push( parser.assignTexture( materialParams, 'emissiveMap', material.emissiveTexture.index ) );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn Promise.all( pending ).then( function () {\n\n\t\t\t\tvar _material;\n\n\t\t\t\tif ( materialType === THREE.ShaderMaterial ) {\n\n\t\t\t\t\t_material = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].createMaterial( materialParams );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t_material = new materialType( materialParams );\n\n\t\t\t\t}\n\n\t\t\t\tif ( material.name !== undefined ) _material.name = material.name;\n\n\t\t\t\t// Normal map textures use OpenGL conventions:\n\t\t\t\t// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#materialnormaltexture\n\t\t\t\t_material.normalScale.x = -1;\n\n\t\t\t\t_material.userData = material.extras;\n\n\t\t\t\treturn _material;\n\n\t\t\t} );\n\n\t\t} );\n\n\t};\n\n\tGLTFParser.prototype.loadGeometries = function ( primitives ) {\n\n\t\treturn this._withDependencies( [\n\n\t\t\t'accessors',\n\n\t\t] ).then( function ( dependencies ) {\n\n\t\t\treturn _each( primitives, function ( primitive ) {\n\n\t\t\t\tvar geometry = new THREE.BufferGeometry();\n\n\t\t\t\tvar attributes = primitive.attributes;\n\n\t\t\t\tfor ( var attributeId in attributes ) {\n\n\t\t\t\t\tvar attributeEntry = attributes[ attributeId ];\n\n\t\t\t\t\tif ( attributeEntry === undefined ) return;\n\n\t\t\t\t\tvar bufferAttribute = dependencies.accessors[ attributeEntry ];\n\n\t\t\t\t\tswitch ( attributeId ) {\n\n\t\t\t\t\t\tcase 'POSITION':\n\n\t\t\t\t\t\t\tgeometry.addAttribute( 'position', bufferAttribute );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'NORMAL':\n\n\t\t\t\t\t\t\tgeometry.addAttribute( 'normal', bufferAttribute );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'TEXCOORD_0':\n\t\t\t\t\t\tcase 'TEXCOORD0':\n\t\t\t\t\t\tcase 'TEXCOORD':\n\n\t\t\t\t\t\t\tgeometry.addAttribute( 'uv', bufferAttribute );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'TEXCOORD_1':\n\n\t\t\t\t\t\t\tgeometry.addAttribute( 'uv2', bufferAttribute );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'COLOR_0':\n\t\t\t\t\t\tcase 'COLOR0':\n\t\t\t\t\t\tcase 'COLOR':\n\n\t\t\t\t\t\t\tgeometry.addAttribute( 'color', bufferAttribute );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'WEIGHTS_0':\n\t\t\t\t\t\tcase 'WEIGHT': // WEIGHT semantic deprecated.\n\n\t\t\t\t\t\t\tgeometry.addAttribute( 'skinWeight', bufferAttribute );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'JOINTS_0':\n\t\t\t\t\t\tcase 'JOINT': // JOINT semantic deprecated.\n\n\t\t\t\t\t\t\tgeometry.addAttribute( 'skinIndex', bufferAttribute );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( primitive.indices !== undefined ) {\n\n\t\t\t\t\tgeometry.setIndex( dependencies.accessors[ primitive.indices ] );\n\n\t\t\t\t}\n\n\t\t\t\treturn geometry;\n\n\t\t\t} );\n\n\t\t} );\n\n\t};\n\n\t/**\n\t * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#meshes\n\t */\n\tGLTFParser.prototype.loadMeshes = function () {\n\n\t\tvar scope = this;\n\t\tvar json = this.json;\n\n\t\treturn this._withDependencies( [\n\n\t\t\t'accessors',\n\t\t\t'materials'\n\n\t\t] ).then( function ( dependencies ) {\n\n\t\t\treturn _each( json.meshes, function ( meshDef ) {\n\n\t\t\t\tvar group = new THREE.Group();\n\n\t\t\t\tif ( meshDef.name !== undefined ) group.name = meshDef.name;\n\t\t\t\tif ( meshDef.extras ) group.userData = meshDef.extras;\n\n\t\t\t\tvar primitives = meshDef.primitives || [];\n\n\t\t\t\treturn scope.loadGeometries( primitives ).then( function ( geometries ) {\n\n\t\t\t\t\tfor ( var name in primitives ) {\n\n\t\t\t\t\t\tvar primitive = primitives[ name ];\n\t\t\t\t\t\tvar geometry = geometries[ name ];\n\n\t\t\t\t\t\tvar material = primitive.material === undefined\n\t\t\t\t\t\t\t? createDefaultMaterial()\n\t\t\t\t\t\t\t: dependencies.materials[ primitive.material ];\n\n\t\t\t\t\t\tif ( material.aoMap\n\t\t\t\t\t\t\t\t&& geometry.attributes.uv2 === undefined\n\t\t\t\t\t\t\t\t&& geometry.attributes.uv !== undefined ) {\n\n\t\t\t\t\t\t\tconsole.log( 'THREE.GLTFLoader: Duplicating UVs to support aoMap.' );\n\t\t\t\t\t\t\tgeometry.addAttribute( 'uv2', new THREE.BufferAttribute( geometry.attributes.uv.array, 2 ) );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( geometry.attributes.color !== undefined ) {\n\n\t\t\t\t\t\t\tmaterial.vertexColors = THREE.VertexColors;\n\t\t\t\t\t\t\tmaterial.needsUpdate = true;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( geometry.attributes.normal === undefined ) {\n\n\t\t\t\t\t\t\tif ( material.flatShading !== undefined ) {\n\n\t\t\t\t\t\t\t\tmaterial.flatShading = true;\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t// TODO: Remove this backwards-compatibility fix after r87 release.\n\t\t\t\t\t\t\t\tmaterial.shading = THREE.FlatShading;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar mesh;\n\n\t\t\t\t\t\tif ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES || primitive.mode === undefined ) {\n\n\t\t\t\t\t\t\tmesh = new THREE.Mesh( geometry, material );\n\n\t\t\t\t\t\t} else if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ) {\n\n\t\t\t\t\t\t\tmesh = new THREE.Mesh( geometry, material );\n\t\t\t\t\t\t\tmesh.drawMode = THREE.TriangleStripDrawMode;\n\n\t\t\t\t\t\t} else if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ) {\n\n\t\t\t\t\t\t\tmesh = new THREE.Mesh( geometry, material );\n\t\t\t\t\t\t\tmesh.drawMode = THREE.TriangleFanDrawMode;\n\n\t\t\t\t\t\t} else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {\n\n\t\t\t\t\t\t\tmesh = new THREE.LineSegments( geometry, material );\n\n\t\t\t\t\t\t} else if ( primitive.mode === WEBGL_CONSTANTS.LINE_STRIP ) {\n\n\t\t\t\t\t\t\tmesh = new THREE.Line( geometry, material );\n\n\t\t\t\t\t\t} else if ( primitive.mode === WEBGL_CONSTANTS.LINE_LOOP ) {\n\n\t\t\t\t\t\t\tmesh = new THREE.LineLoop( geometry, material );\n\n\t\t\t\t\t\t} else if ( primitive.mode === WEBGL_CONSTANTS.POINTS ) {\n\n\t\t\t\t\t\t\tmesh = new THREE.Points( geometry, material );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tthrow new Error( 'THREE.GLTFLoader: Primitive mode unsupported: ', primitive.mode );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tmesh.name = group.name + '_' + name;\n\n\t\t\t\t\t\tif ( primitive.targets !== undefined ) {\n\n\t\t\t\t\t\t\taddMorphTargets( mesh, meshDef, primitive, dependencies );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( primitive.extras ) mesh.userData = primitive.extras;\n\n\t\t\t\t\t\tgroup.add( mesh );\n\n\t\t\t\t\t}\n\n\t\t\t\t\treturn group;\n\n\t\t\t\t} );\n\n\t\t\t} );\n\n\t\t} );\n\n\t};\n\n\t/**\n\t * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#cameras\n\t */\n\tGLTFParser.prototype.loadCameras = function () {\n\n\t\tvar json = this.json;\n\n\t\treturn _each( json.cameras, function ( camera ) {\n\n\t\t\tvar _camera;\n\n\t\t\tvar params = camera[ camera.type ];\n\n\t\t\tif ( !params ) {\n\n\t\t\t\tconsole.warn( 'THREE.GLTFLoader: Missing camera parameters.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tif ( camera.type === 'perspective' ) {\n\n\t\t\t\tvar aspectRatio = params.aspectRatio || 1;\n\t\t\t\tvar xfov = params.yfov * aspectRatio;\n\n\t\t\t\t_camera = new THREE.PerspectiveCamera( THREE.Math.radToDeg( xfov ), aspectRatio, params.znear || 1, params.zfar || 2e6 );\n\n\t\t\t} else if ( camera.type === 'orthographic' ) {\n\n\t\t\t\t_camera = new THREE.OrthographicCamera( params.xmag / -2, params.xmag / 2, params.ymag / 2, params.ymag / -2, params.znear, params.zfar );\n\n\t\t\t}\n\n\t\t\tif ( camera.name !== undefined ) _camera.name = camera.name;\n\t\t\tif ( camera.extras ) _camera.userData = camera.extras;\n\n\t\t\treturn _camera;\n\n\t\t} );\n\n\t};\n\n\tGLTFParser.prototype.loadSkins = function () {\n\n\t\tvar json = this.json;\n\n\t\treturn this._withDependencies( [\n\n\t\t\t'accessors'\n\n\t\t] ).then( function ( dependencies ) {\n\n\t\t\treturn _each( json.skins, function ( skin ) {\n\n\t\t\t\tvar _skin = {\n\t\t\t\t\tjoints: skin.joints,\n\t\t\t\t\tinverseBindMatrices: dependencies.accessors[ skin.inverseBindMatrices ]\n\t\t\t\t};\n\n\t\t\t\treturn _skin;\n\n\t\t\t} );\n\n\t\t} );\n\n\t};\n\n\tGLTFParser.prototype.loadAnimations = function () {\n\n\t\tvar json = this.json;\n\n\t\treturn this._withDependencies( [\n\n\t\t\t'accessors',\n\t\t\t'nodes'\n\n\t\t] ).then( function ( dependencies ) {\n\n\t\t\treturn _each( json.animations, function ( animation, animationId ) {\n\n\t\t\t\tvar tracks = [];\n\n\t\t\t\tfor ( var channelId in animation.channels ) {\n\n\t\t\t\t\tvar channel = animation.channels[ channelId ];\n\t\t\t\t\tvar sampler = animation.samplers[ channel.sampler ];\n\n\t\t\t\t\tif ( sampler ) {\n\n\t\t\t\t\t\tvar target = channel.target;\n\t\t\t\t\t\tvar name = target.node !== undefined ? target.node : target.id; // NOTE: target.id is deprecated.\n\t\t\t\t\t\tvar input = animation.parameters !== undefined ? animation.parameters[ sampler.input ] : sampler.input;\n\t\t\t\t\t\tvar output = animation.parameters !== undefined ? animation.parameters[ sampler.output ] : sampler.output;\n\n\t\t\t\t\t\tvar inputAccessor = dependencies.accessors[ input ];\n\t\t\t\t\t\tvar outputAccessor = dependencies.accessors[ output ];\n\n\t\t\t\t\t\tvar node = dependencies.nodes[ name ];\n\n\t\t\t\t\t\tif ( node ) {\n\n\t\t\t\t\t\t\tnode.updateMatrix();\n\t\t\t\t\t\t\tnode.matrixAutoUpdate = true;\n\n\t\t\t\t\t\t\tvar TypedKeyframeTrack;\n\n\t\t\t\t\t\t\tswitch ( PATH_PROPERTIES[ target.path ] ) {\n\n\t\t\t\t\t\t\t\tcase PATH_PROPERTIES.weights:\n\n\t\t\t\t\t\t\t\t\tTypedKeyframeTrack = THREE.NumberKeyframeTrack;\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase PATH_PROPERTIES.rotation:\n\n\t\t\t\t\t\t\t\t\tTypedKeyframeTrack = THREE.QuaternionKeyframeTrack;\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase PATH_PROPERTIES.position:\n\t\t\t\t\t\t\t\tcase PATH_PROPERTIES.scale:\n\t\t\t\t\t\t\t\tdefault:\n\n\t\t\t\t\t\t\t\t\tTypedKeyframeTrack = THREE.VectorKeyframeTrack;\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tvar targetName = node.name ? node.name : node.uuid;\n\n\t\t\t\t\t\t\tif ( sampler.interpolation === 'CATMULLROMSPLINE' ) {\n\n\t\t\t\t\t\t\t\tconsole.warn( 'THREE.GLTFLoader: CATMULLROMSPLINE interpolation is not supported. Using CUBICSPLINE instead.' );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tvar interpolation = sampler.interpolation !== undefined ? INTERPOLATION[ sampler.interpolation ] : THREE.InterpolateLinear;\n\n\t\t\t\t\t\t\tvar targetNames = [];\n\n\t\t\t\t\t\t\tif ( PATH_PROPERTIES[ target.path ] === PATH_PROPERTIES.weights ) {\n\n\t\t\t\t\t\t\t\t// node should be THREE.Group here but\n\t\t\t\t\t\t\t\t// PATH_PROPERTIES.weights(morphTargetInfluences) should be\n\t\t\t\t\t\t\t\t// the property of a mesh object under node.\n\t\t\t\t\t\t\t\t// So finding targets here.\n\n\t\t\t\t\t\t\t\tnode.traverse( function ( object ) {\n\n\t\t\t\t\t\t\t\t\tif ( object.isMesh === true && object.material.morphTargets === true ) {\n\n\t\t\t\t\t\t\t\t\t\ttargetNames.push( object.name ? object.name : object.uuid );\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t} );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\ttargetNames.push( targetName );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// KeyframeTrack.optimize() will modify given 'times' and 'values'\n\t\t\t\t\t\t\t// buffers before creating a truncated copy to keep. Because buffers may\n\t\t\t\t\t\t\t// be reused by other tracks, make copies here.\n\t\t\t\t\t\t\tfor ( var i = 0, il = targetNames.length; i < il; i ++ ) {\n\n\t\t\t\t\t\t\t\ttracks.push( new TypedKeyframeTrack(\n\t\t\t\t\t\t\t\t\ttargetNames[ i ] + '.' + PATH_PROPERTIES[ target.path ],\n\t\t\t\t\t\t\t\t\tTHREE.AnimationUtils.arraySlice( inputAccessor.array, 0 ),\n\t\t\t\t\t\t\t\t\tTHREE.AnimationUtils.arraySlice( outputAccessor.array, 0 ),\n\t\t\t\t\t\t\t\t\tinterpolation\n\t\t\t\t\t\t\t\t) );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tvar name = animation.name !== undefined ? animation.name : 'animation_' + animationId;\n\n\t\t\t\treturn new THREE.AnimationClip( name, undefined, tracks );\n\n\t\t\t} );\n\n\t\t} );\n\n\t};\n\n\tGLTFParser.prototype.loadNodes = function () {\n\n\t\tvar json = this.json;\n\t\tvar extensions = this.extensions;\n\t\tvar scope = this;\n\n\t\tvar nodes = json.nodes || [];\n\t\tvar skins = json.skins || [];\n\n\t\t// Nothing in the node definition indicates whether it is a Bone or an\n\t\t// Object3D. Use the skins' joint references to mark bones.\n\t\tskins.forEach( function ( skin ) {\n\n\t\t\tskin.joints.forEach( function ( id ) {\n\n\t\t\t\tnodes[ id ].isBone = true;\n\n\t\t\t} );\n\n\t\t} );\n\n\t\treturn _each( json.nodes, function ( node ) {\n\n\t\t\tvar matrix = new THREE.Matrix4();\n\n\t\t\tvar _node = node.isBone === true ? new THREE.Bone() : new THREE.Object3D();\n\n\t\t\tif ( node.name !== undefined ) {\n\n\t\t\t\t_node.name = THREE.PropertyBinding.sanitizeNodeName( node.name );\n\n\t\t\t}\n\n\t\t\tif ( node.extras ) _node.userData = node.extras;\n\n\t\t\tif ( node.matrix !== undefined ) {\n\n\t\t\t\tmatrix.fromArray( node.matrix );\n\t\t\t\t_node.applyMatrix( matrix );\n\n\t\t\t} else {\n\n\t\t\t\tif ( node.translation !== undefined ) {\n\n\t\t\t\t\t_node.position.fromArray( node.translation );\n\n\t\t\t\t}\n\n\t\t\t\tif ( node.rotation !== undefined ) {\n\n\t\t\t\t\t_node.quaternion.fromArray( node.rotation );\n\n\t\t\t\t}\n\n\t\t\t\tif ( node.scale !== undefined ) {\n\n\t\t\t\t\t_node.scale.fromArray( node.scale );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn _node;\n\n\t\t} ).then( function ( __nodes ) {\n\n\t\t\treturn scope._withDependencies( [\n\n\t\t\t\t'meshes',\n\t\t\t\t'skins',\n\t\t\t\t'cameras'\n\n\t\t\t] ).then( function ( dependencies ) {\n\n\t\t\t\treturn _each( __nodes, function ( _node, nodeId ) {\n\n\t\t\t\t\tvar node = json.nodes[ nodeId ];\n\n\t\t\t\t\tvar meshes;\n\n\t\t\t\t\tif ( node.mesh !== undefined) {\n\n\t\t\t\t\t\tmeshes = [ node.mesh ];\n\n\t\t\t\t\t} else if ( node.meshes !== undefined ) {\n\n\t\t\t\t\t\tconsole.warn( 'THREE.GLTFLoader: Legacy glTF file detected. Nodes may have no more than one mesh.' );\n\n\t\t\t\t\t\tmeshes = node.meshes;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( meshes !== undefined ) {\n\n\t\t\t\t\t\tfor ( var meshId in meshes ) {\n\n\t\t\t\t\t\t\tvar mesh = meshes[ meshId ];\n\t\t\t\t\t\t\tvar group = dependencies.meshes[ mesh ];\n\n\t\t\t\t\t\t\tif ( group === undefined ) {\n\n\t\t\t\t\t\t\t\tconsole.warn( 'THREE.GLTFLoader: Could not find node \"' + mesh + '\".' );\n\t\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// do not clone children as they will be replaced anyway\n\t\t\t\t\t\t\tvar clonedgroup = group.clone( false );\n\n\t\t\t\t\t\t\tfor ( var childrenId in group.children ) {\n\n\t\t\t\t\t\t\t\tvar child = group.children[ childrenId ];\n\t\t\t\t\t\t\t\tvar originalChild = child;\n\n\t\t\t\t\t\t\t\t// clone Mesh to add to _node\n\n\t\t\t\t\t\t\t\tvar originalMaterial = child.material;\n\t\t\t\t\t\t\t\tvar originalGeometry = child.geometry;\n\t\t\t\t\t\t\t\tvar originalInfluences = child.morphTargetInfluences;\n\t\t\t\t\t\t\t\tvar originalUserData = child.userData;\n\t\t\t\t\t\t\t\tvar originalName = child.name;\n\n\t\t\t\t\t\t\t\tvar material = originalMaterial;\n\n\t\t\t\t\t\t\t\tswitch ( child.type ) {\n\n\t\t\t\t\t\t\t\t\tcase 'LineSegments':\n\t\t\t\t\t\t\t\t\t\tchild = new THREE.LineSegments( originalGeometry, material );\n\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\tcase 'LineLoop':\n\t\t\t\t\t\t\t\t\t\tchild = new THREE.LineLoop( originalGeometry, material );\n\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\tcase 'Line':\n\t\t\t\t\t\t\t\t\t\tchild = new THREE.Line( originalGeometry, material );\n\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\tcase 'Points':\n\t\t\t\t\t\t\t\t\t\tchild = new THREE.Points( originalGeometry, material );\n\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\t\tchild = new THREE.Mesh( originalGeometry, material );\n\t\t\t\t\t\t\t\t\t\tchild.drawMode = originalChild.drawMode;\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tchild.castShadow = true;\n\t\t\t\t\t\t\t\tchild.morphTargetInfluences = originalInfluences;\n\t\t\t\t\t\t\t\tchild.userData = originalUserData;\n\t\t\t\t\t\t\t\tchild.name = originalName;\n\n\t\t\t\t\t\t\t\tvar skinEntry;\n\n\t\t\t\t\t\t\t\tif ( node.skin !== undefined ) {\n\n\t\t\t\t\t\t\t\t\tskinEntry = dependencies.skins[ node.skin ];\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Replace Mesh with SkinnedMesh in library\n\t\t\t\t\t\t\t\tif ( skinEntry ) {\n\n\t\t\t\t\t\t\t\t\tvar geometry = originalGeometry;\n\t\t\t\t\t\t\t\t\tmaterial = originalMaterial;\n\t\t\t\t\t\t\t\t\tmaterial.skinning = true;\n\n\t\t\t\t\t\t\t\t\tchild = new THREE.SkinnedMesh( geometry, material );\n\t\t\t\t\t\t\t\t\tchild.castShadow = true;\n\t\t\t\t\t\t\t\t\tchild.userData = originalUserData;\n\t\t\t\t\t\t\t\t\tchild.name = originalName;\n\n\t\t\t\t\t\t\t\t\tvar bones = [];\n\t\t\t\t\t\t\t\t\tvar boneInverses = [];\n\n\t\t\t\t\t\t\t\t\tfor ( var i = 0, l = skinEntry.joints.length; i < l; i ++ ) {\n\n\t\t\t\t\t\t\t\t\t\tvar jointId = skinEntry.joints[ i ];\n\t\t\t\t\t\t\t\t\t\tvar jointNode = __nodes[ jointId ];\n\n\t\t\t\t\t\t\t\t\t\tif ( jointNode ) {\n\n\t\t\t\t\t\t\t\t\t\t\tbones.push( jointNode );\n\n\t\t\t\t\t\t\t\t\t\t\tvar m = skinEntry.inverseBindMatrices.array;\n\t\t\t\t\t\t\t\t\t\t\tvar mat = new THREE.Matrix4().fromArray( m, i * 16 );\n\t\t\t\t\t\t\t\t\t\t\tboneInverses.push( mat );\n\n\t\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t\tconsole.warn( 'THREE.GLTFLoader: Joint \"%s\" could not be found.', jointId );\n\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tchild.bind( new THREE.Skeleton( bones, boneInverses ), child.matrixWorld );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tclonedgroup.add( child );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t_node.add( clonedgroup );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( node.camera !== undefined ) {\n\n\t\t\t\t\t\tvar camera = dependencies.cameras[ node.camera ];\n\n\t\t\t\t\t\t_node.add( camera );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( node.extensions\n\t\t\t\t\t\t\t && node.extensions[ EXTENSIONS.KHR_LIGHTS ]\n\t\t\t\t\t\t\t && node.extensions[ EXTENSIONS.KHR_LIGHTS ].light !== undefined ) {\n\n\t\t\t\t\t\tvar lights = extensions[ EXTENSIONS.KHR_LIGHTS ].lights;\n\t\t\t\t\t\t_node.add( lights[ node.extensions[ EXTENSIONS.KHR_LIGHTS ].light ] );\n\n\t\t\t\t\t}\n\n\t\t\t\t\treturn _node;\n\n\t\t\t\t} );\n\n\t\t\t} );\n\n\t\t} );\n\n\t};\n\n\tGLTFParser.prototype.loadScenes = function () {\n\n\t\tvar json = this.json;\n\t\tvar extensions = this.extensions;\n\n\t\t// scene node hierachy builder\n\n\t\tfunction buildNodeHierachy( nodeId, parentObject, allNodes ) {\n\n\t\t\tvar _node = allNodes[ nodeId ];\n\t\t\tparentObject.add( _node );\n\n\t\t\tvar node = json.nodes[ nodeId ];\n\n\t\t\tif ( node.children ) {\n\n\t\t\t\tvar children = node.children;\n\n\t\t\t\tfor ( var i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\t\t\tvar child = children[ i ];\n\t\t\t\t\tbuildNodeHierachy( child, _node, allNodes );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this._withDependencies( [\n\n\t\t\t'nodes'\n\n\t\t] ).then( function ( dependencies ) {\n\n\t\t\treturn _each( json.scenes, function ( scene ) {\n\n\t\t\t\tvar _scene = new THREE.Scene();\n\t\t\t\tif ( scene.name !== undefined ) _scene.name = scene.name;\n\n\t\t\t\tif ( scene.extras ) _scene.userData = scene.extras;\n\n\t\t\t\tvar nodes = scene.nodes || [];\n\n\t\t\t\tfor ( var i = 0, l = nodes.length; i < l; i ++ ) {\n\n\t\t\t\t\tvar nodeId = nodes[ i ];\n\t\t\t\t\tbuildNodeHierachy( nodeId, _scene, dependencies.nodes );\n\n\t\t\t\t}\n\n\t\t\t\t_scene.traverse( function ( child ) {\n\n\t\t\t\t\t// for Specular-Glossiness.\n\t\t\t\t\tif ( child.material && child.material.isGLTFSpecularGlossinessMaterial ) {\n\n\t\t\t\t\t\tchild.onBeforeRender = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].refreshUniforms;\n\n\t\t\t\t\t}\n\n\t\t\t\t} );\n\n\t\t\t\t// Ambient lighting, if present, is always attached to the scene root.\n\t\t\t\tif ( scene.extensions\n\t\t\t\t\t\t\t && scene.extensions[ EXTENSIONS.KHR_LIGHTS ]\n\t\t\t\t\t\t\t && scene.extensions[ EXTENSIONS.KHR_LIGHTS ].light !== undefined ) {\n\n\t\t\t\t\tvar lights = extensions[ EXTENSIONS.KHR_LIGHTS ].lights;\n\t\t\t\t\t_scene.add( lights[ scene.extensions[ EXTENSIONS.KHR_LIGHTS ].light ] );\n\n\t\t\t\t}\n\n\t\t\t\treturn _scene;\n\n\t\t\t} );\n\n\t\t} );\n\n\t};\n\n\treturn GLTFLoader;\n\n} )();\n\n},{}],44:[function(_dereq_,module,exports){\n/**\n * Loads a Wavefront .mtl file specifying materials\n *\n * @author angelxuanchang\n */\n\nTHREE.MTLLoader = function ( manager ) {\n\n\tthis.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;\n\n};\n\nTHREE.MTLLoader.prototype = {\n\n\tconstructor: THREE.MTLLoader,\n\n\t/**\n\t * Loads and parses a MTL asset from a URL.\n\t *\n\t * @param {String} url - URL to the MTL file.\n\t * @param {Function} [onLoad] - Callback invoked with the loaded object.\n\t * @param {Function} [onProgress] - Callback for download progress.\n\t * @param {Function} [onError] - Callback for download errors.\n\t *\n\t * @see setPath setTexturePath\n\t *\n\t * @note In order for relative texture references to resolve correctly\n\t * you must call setPath and/or setTexturePath explicitly prior to load.\n\t */\n\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\tvar scope = this;\n\n\t\tvar loader = new THREE.FileLoader( this.manager );\n\t\tloader.setPath( this.path );\n\t\tloader.load( url, function ( text ) {\n\n\t\t\tonLoad( scope.parse( text ) );\n\n\t\t}, onProgress, onError );\n\n\t},\n\n\t/**\n\t * Set base path for resolving references.\n\t * If set this path will be prepended to each loaded and found reference.\n\t *\n\t * @see setTexturePath\n\t * @param {String} path\n\t *\n\t * @example\n\t *     mtlLoader.setPath( 'assets/obj/' );\n\t *     mtlLoader.load( 'my.mtl', ... );\n\t */\n\tsetPath: function ( path ) {\n\n\t\tthis.path = path;\n\n\t},\n\n\t/**\n\t * Set base path for resolving texture references.\n\t * If set this path will be prepended found texture reference.\n\t * If not set and setPath is, it will be used as texture base path.\n\t *\n\t * @see setPath\n\t * @param {String} path\n\t *\n\t * @example\n\t *     mtlLoader.setPath( 'assets/obj/' );\n\t *     mtlLoader.setTexturePath( 'assets/textures/' );\n\t *     mtlLoader.load( 'my.mtl', ... );\n\t */\n\tsetTexturePath: function ( path ) {\n\n\t\tthis.texturePath = path;\n\n\t},\n\n\tsetBaseUrl: function ( path ) {\n\n\t\tconsole.warn( 'THREE.MTLLoader: .setBaseUrl() is deprecated. Use .setTexturePath( path ) for texture path or .setPath( path ) for general base path instead.' );\n\n\t\tthis.setTexturePath( path );\n\n\t},\n\n\tsetCrossOrigin: function ( value ) {\n\n\t\tthis.crossOrigin = value;\n\n\t},\n\n\tsetMaterialOptions: function ( value ) {\n\n\t\tthis.materialOptions = value;\n\n\t},\n\n\t/**\n\t * Parses a MTL file.\n\t *\n\t * @param {String} text - Content of MTL file\n\t * @return {THREE.MTLLoader.MaterialCreator}\n\t *\n\t * @see setPath setTexturePath\n\t *\n\t * @note In order for relative texture references to resolve correctly\n\t * you must call setPath and/or setTexturePath explicitly prior to parse.\n\t */\n\tparse: function ( text ) {\n\n\t\tvar lines = text.split( '\\n' );\n\t\tvar info = {};\n\t\tvar delimiter_pattern = /\\s+/;\n\t\tvar materialsInfo = {};\n\n\t\tfor ( var i = 0; i < lines.length; i ++ ) {\n\n\t\t\tvar line = lines[ i ];\n\t\t\tline = line.trim();\n\n\t\t\tif ( line.length === 0 || line.charAt( 0 ) === '#' ) {\n\n\t\t\t\t// Blank line or comment ignore\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\tvar pos = line.indexOf( ' ' );\n\n\t\t\tvar key = ( pos >= 0 ) ? line.substring( 0, pos ) : line;\n\t\t\tkey = key.toLowerCase();\n\n\t\t\tvar value = ( pos >= 0 ) ? line.substring( pos + 1 ) : '';\n\t\t\tvalue = value.trim();\n\n\t\t\tif ( key === 'newmtl' ) {\n\n\t\t\t\t// New material\n\n\t\t\t\tinfo = { name: value };\n\t\t\t\tmaterialsInfo[ value ] = info;\n\n\t\t\t} else if ( info ) {\n\n\t\t\t\tif ( key === 'ka' || key === 'kd' || key === 'ks' ) {\n\n\t\t\t\t\tvar ss = value.split( delimiter_pattern, 3 );\n\t\t\t\t\tinfo[ key ] = [ parseFloat( ss[ 0 ] ), parseFloat( ss[ 1 ] ), parseFloat( ss[ 2 ] ) ];\n\n\t\t\t\t} else {\n\n\t\t\t\t\tinfo[ key ] = value;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tvar materialCreator = new THREE.MTLLoader.MaterialCreator( this.texturePath || this.path, this.materialOptions );\n\t\tmaterialCreator.setCrossOrigin( this.crossOrigin );\n\t\tmaterialCreator.setManager( this.manager );\n\t\tmaterialCreator.setMaterials( materialsInfo );\n\t\treturn materialCreator;\n\n\t}\n\n};\n\n/**\n * Create a new THREE-MTLLoader.MaterialCreator\n * @param baseUrl - Url relative to which textures are loaded\n * @param options - Set of options on how to construct the materials\n *                  side: Which side to apply the material\n *                        THREE.FrontSide (default), THREE.BackSide, THREE.DoubleSide\n *                  wrap: What type of wrapping to apply for textures\n *                        THREE.RepeatWrapping (default), THREE.ClampToEdgeWrapping, THREE.MirroredRepeatWrapping\n *                  normalizeRGB: RGBs need to be normalized to 0-1 from 0-255\n *                                Default: false, assumed to be already normalized\n *                  ignoreZeroRGBs: Ignore values of RGBs (Ka,Kd,Ks) that are all 0's\n *                                  Default: false\n * @constructor\n */\n\nTHREE.MTLLoader.MaterialCreator = function ( baseUrl, options ) {\n\n\tthis.baseUrl = baseUrl || '';\n\tthis.options = options;\n\tthis.materialsInfo = {};\n\tthis.materials = {};\n\tthis.materialsArray = [];\n\tthis.nameLookup = {};\n\n\tthis.side = ( this.options && this.options.side ) ? this.options.side : THREE.FrontSide;\n\tthis.wrap = ( this.options && this.options.wrap ) ? this.options.wrap : THREE.RepeatWrapping;\n\n};\n\nTHREE.MTLLoader.MaterialCreator.prototype = {\n\n\tconstructor: THREE.MTLLoader.MaterialCreator,\n\n\tcrossOrigin: 'Anonymous',\n\n\tsetCrossOrigin: function ( value ) {\n\n\t\tthis.crossOrigin = value;\n\n\t},\n\n\tsetManager: function ( value ) {\n\n\t\tthis.manager = value;\n\n\t},\n\n\tsetMaterials: function ( materialsInfo ) {\n\n\t\tthis.materialsInfo = this.convert( materialsInfo );\n\t\tthis.materials = {};\n\t\tthis.materialsArray = [];\n\t\tthis.nameLookup = {};\n\n\t},\n\n\tconvert: function ( materialsInfo ) {\n\n\t\tif ( ! this.options ) return materialsInfo;\n\n\t\tvar converted = {};\n\n\t\tfor ( var mn in materialsInfo ) {\n\n\t\t\t// Convert materials info into normalized form based on options\n\n\t\t\tvar mat = materialsInfo[ mn ];\n\n\t\t\tvar covmat = {};\n\n\t\t\tconverted[ mn ] = covmat;\n\n\t\t\tfor ( var prop in mat ) {\n\n\t\t\t\tvar save = true;\n\t\t\t\tvar value = mat[ prop ];\n\t\t\t\tvar lprop = prop.toLowerCase();\n\n\t\t\t\tswitch ( lprop ) {\n\n\t\t\t\t\tcase 'kd':\n\t\t\t\t\tcase 'ka':\n\t\t\t\t\tcase 'ks':\n\n\t\t\t\t\t\t// Diffuse color (color under white light) using RGB values\n\n\t\t\t\t\t\tif ( this.options && this.options.normalizeRGB ) {\n\n\t\t\t\t\t\t\tvalue = [ value[ 0 ] / 255, value[ 1 ] / 255, value[ 2 ] / 255 ];\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( this.options && this.options.ignoreZeroRGBs ) {\n\n\t\t\t\t\t\t\tif ( value[ 0 ] === 0 && value[ 1 ] === 0 && value[ 2 ] === 0 ) {\n\n\t\t\t\t\t\t\t\t// ignore\n\n\t\t\t\t\t\t\t\tsave = false;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t\tif ( save ) {\n\n\t\t\t\t\tcovmat[ lprop ] = value;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn converted;\n\n\t},\n\n\tpreload: function () {\n\n\t\tfor ( var mn in this.materialsInfo ) {\n\n\t\t\tthis.create( mn );\n\n\t\t}\n\n\t},\n\n\tgetIndex: function ( materialName ) {\n\n\t\treturn this.nameLookup[ materialName ];\n\n\t},\n\n\tgetAsArray: function () {\n\n\t\tvar index = 0;\n\n\t\tfor ( var mn in this.materialsInfo ) {\n\n\t\t\tthis.materialsArray[ index ] = this.create( mn );\n\t\t\tthis.nameLookup[ mn ] = index;\n\t\t\tindex ++;\n\n\t\t}\n\n\t\treturn this.materialsArray;\n\n\t},\n\n\tcreate: function ( materialName ) {\n\n\t\tif ( this.materials[ materialName ] === undefined ) {\n\n\t\t\tthis.createMaterial_( materialName );\n\n\t\t}\n\n\t\treturn this.materials[ materialName ];\n\n\t},\n\n\tcreateMaterial_: function ( materialName ) {\n\n\t\t// Create material\n\n\t\tvar scope = this;\n\t\tvar mat = this.materialsInfo[ materialName ];\n\t\tvar params = {\n\n\t\t\tname: materialName,\n\t\t\tside: this.side\n\n\t\t};\n\n\t\tfunction resolveURL( baseUrl, url ) {\n\n\t\t\tif ( typeof url !== 'string' || url === '' )\n\t\t\t\treturn '';\n\n\t\t\t// Absolute URL\n\t\t\tif ( /^https?:\\/\\//i.test( url ) ) return url;\n\n\t\t\treturn baseUrl + url;\n\n\t\t}\n\n\t\tfunction setMapForType( mapType, value ) {\n\n\t\t\tif ( params[ mapType ] ) return; // Keep the first encountered texture\n\n\t\t\tvar texParams = scope.getTextureParams( value, params );\n\t\t\tvar map = scope.loadTexture( resolveURL( scope.baseUrl, texParams.url ) );\n\n\t\t\tmap.repeat.copy( texParams.scale );\n\t\t\tmap.offset.copy( texParams.offset );\n\n\t\t\tmap.wrapS = scope.wrap;\n\t\t\tmap.wrapT = scope.wrap;\n\n\t\t\tparams[ mapType ] = map;\n\n\t\t}\n\n\t\tfor ( var prop in mat ) {\n\n\t\t\tvar value = mat[ prop ];\n\t\t\tvar n;\n\n\t\t\tif ( value === '' ) continue;\n\n\t\t\tswitch ( prop.toLowerCase() ) {\n\n\t\t\t\t// Ns is material specular exponent\n\n\t\t\t\tcase 'kd':\n\n\t\t\t\t\t// Diffuse color (color under white light) using RGB values\n\n\t\t\t\t\tparams.color = new THREE.Color().fromArray( value );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'ks':\n\n\t\t\t\t\t// Specular color (color when light is reflected from shiny surface) using RGB values\n\t\t\t\t\tparams.specular = new THREE.Color().fromArray( value );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'map_kd':\n\n\t\t\t\t\t// Diffuse texture map\n\n\t\t\t\t\tsetMapForType( \"map\", value );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'map_ks':\n\n\t\t\t\t\t// Specular map\n\n\t\t\t\t\tsetMapForType( \"specularMap\", value );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'norm':\n\n\t\t\t\t\tsetMapForType( \"normalMap\", value );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'map_bump':\n\t\t\t\tcase 'bump':\n\n\t\t\t\t\t// Bump texture map\n\n\t\t\t\t\tsetMapForType( \"bumpMap\", value );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'ns':\n\n\t\t\t\t\t// The specular exponent (defines the focus of the specular highlight)\n\t\t\t\t\t// A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000.\n\n\t\t\t\t\tparams.shininess = parseFloat( value );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'd':\n\t\t\t\t\tn = parseFloat(value);\n\n\t\t\t\t\tif ( n < 1 ) {\n\n\t\t\t\t\t\tparams.opacity = n;\n\t\t\t\t\t\tparams.transparent = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'tr':\n\t\t\t\t\tn = parseFloat(value);\n\n\t\t\t\t\tif ( n > 0 ) {\n\n\t\t\t\t\t\tparams.opacity = 1 - n;\n\t\t\t\t\t\tparams.transparent = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.materials[ materialName ] = new THREE.MeshPhongMaterial( params );\n\t\treturn this.materials[ materialName ];\n\n\t},\n\n\tgetTextureParams: function ( value, matParams ) {\n\n\t\tvar texParams = {\n\n\t\t\tscale: new THREE.Vector2( 1, 1 ),\n\t\t\toffset: new THREE.Vector2( 0, 0 )\n\n\t\t };\n\n\t\tvar items = value.split( /\\s+/ );\n\t\tvar pos;\n\n\t\tpos = items.indexOf( '-bm' );\n\n\t\tif ( pos >= 0 ) {\n\n\t\t\tmatParams.bumpScale = parseFloat( items[ pos + 1 ] );\n\t\t\titems.splice( pos, 2 );\n\n\t\t}\n\n\t\tpos = items.indexOf( '-s' );\n\n\t\tif ( pos >= 0 ) {\n\n\t\t\ttexParams.scale.set( parseFloat( items[ pos + 1 ] ), parseFloat( items[ pos + 2 ] ) );\n\t\t\titems.splice( pos, 4 ); // we expect 3 parameters here!\n\n\t\t}\n\n\t\tpos = items.indexOf( '-o' );\n\n\t\tif ( pos >= 0 ) {\n\n\t\t\ttexParams.offset.set( parseFloat( items[ pos + 1 ] ), parseFloat( items[ pos + 2 ] ) );\n\t\t\titems.splice( pos, 4 ); // we expect 3 parameters here!\n\n\t\t}\n\n\t\ttexParams.url = items.join( ' ' ).trim();\n\t\treturn texParams;\n\n\t},\n\n\tloadTexture: function ( url, mapping, onLoad, onProgress, onError ) {\n\n\t\tvar texture;\n\t\tvar loader = THREE.Loader.Handlers.get( url );\n\t\tvar manager = ( this.manager !== undefined ) ? this.manager : THREE.DefaultLoadingManager;\n\n\t\tif ( loader === null ) {\n\n\t\t\tloader = new THREE.TextureLoader( manager );\n\n\t\t}\n\n\t\tif ( loader.setCrossOrigin ) loader.setCrossOrigin( this.crossOrigin );\n\t\ttexture = loader.load( url, onLoad, onProgress, onError );\n\n\t\tif ( mapping !== undefined ) texture.mapping = mapping;\n\n\t\treturn texture;\n\n\t}\n\n};\n\n},{}],45:[function(_dereq_,module,exports){\n/**\n * @author mrdoob / http://mrdoob.com/\n */\n\nTHREE.OBJLoader = ( function () {\n\n\t// o object_name | g group_name\n\tvar object_pattern           = /^[og]\\s*(.+)?/;\n\t// mtllib file_reference\n\tvar material_library_pattern = /^mtllib /;\n\t// usemtl material_name\n\tvar material_use_pattern     = /^usemtl /;\n\n\tfunction ParserState() {\n\n\t\tvar state = {\n\t\t\tobjects  : [],\n\t\t\tobject   : {},\n\n\t\t\tvertices : [],\n\t\t\tnormals  : [],\n\t\t\tuvs      : [],\n\n\t\t\tmaterialLibraries : [],\n\n\t\t\tstartObject: function ( name, fromDeclaration ) {\n\n\t\t\t\t// If the current object (initial from reset) is not from a g/o declaration in the parsed\n\t\t\t\t// file. We need to use it for the first parsed g/o to keep things in sync.\n\t\t\t\tif ( this.object && this.object.fromDeclaration === false ) {\n\n\t\t\t\t\tthis.object.name = name;\n\t\t\t\t\tthis.object.fromDeclaration = ( fromDeclaration !== false );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\tvar previousMaterial = ( this.object && typeof this.object.currentMaterial === 'function' ? this.object.currentMaterial() : undefined );\n\n\t\t\t\tif ( this.object && typeof this.object._finalize === 'function' ) {\n\n\t\t\t\t\tthis.object._finalize( true );\n\n\t\t\t\t}\n\n\t\t\t\tthis.object = {\n\t\t\t\t\tname : name || '',\n\t\t\t\t\tfromDeclaration : ( fromDeclaration !== false ),\n\n\t\t\t\t\tgeometry : {\n\t\t\t\t\t\tvertices : [],\n\t\t\t\t\t\tnormals  : [],\n\t\t\t\t\t\tuvs      : []\n\t\t\t\t\t},\n\t\t\t\t\tmaterials : [],\n\t\t\t\t\tsmooth : true,\n\n\t\t\t\t\tstartMaterial: function ( name, libraries ) {\n\n\t\t\t\t\t\tvar previous = this._finalize( false );\n\n\t\t\t\t\t\t// New usemtl declaration overwrites an inherited material, except if faces were declared\n\t\t\t\t\t\t// after the material, then it must be preserved for proper MultiMaterial continuation.\n\t\t\t\t\t\tif ( previous && ( previous.inherited || previous.groupCount <= 0 ) ) {\n\n\t\t\t\t\t\t\tthis.materials.splice( previous.index, 1 );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar material = {\n\t\t\t\t\t\t\tindex      : this.materials.length,\n\t\t\t\t\t\t\tname       : name || '',\n\t\t\t\t\t\t\tmtllib     : ( Array.isArray( libraries ) && libraries.length > 0 ? libraries[ libraries.length - 1 ] : '' ),\n\t\t\t\t\t\t\tsmooth     : ( previous !== undefined ? previous.smooth : this.smooth ),\n\t\t\t\t\t\t\tgroupStart : ( previous !== undefined ? previous.groupEnd : 0 ),\n\t\t\t\t\t\t\tgroupEnd   : -1,\n\t\t\t\t\t\t\tgroupCount : -1,\n\t\t\t\t\t\t\tinherited  : false,\n\n\t\t\t\t\t\t\tclone: function ( index ) {\n\t\t\t\t\t\t\t\tvar cloned = {\n\t\t\t\t\t\t\t\t\tindex      : ( typeof index === 'number' ? index : this.index ),\n\t\t\t\t\t\t\t\t\tname       : this.name,\n\t\t\t\t\t\t\t\t\tmtllib     : this.mtllib,\n\t\t\t\t\t\t\t\t\tsmooth     : this.smooth,\n\t\t\t\t\t\t\t\t\tgroupStart : 0,\n\t\t\t\t\t\t\t\t\tgroupEnd   : -1,\n\t\t\t\t\t\t\t\t\tgroupCount : -1,\n\t\t\t\t\t\t\t\t\tinherited  : false\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\tcloned.clone = this.clone.bind(cloned);\n\t\t\t\t\t\t\t\treturn cloned;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tthis.materials.push( material );\n\n\t\t\t\t\t\treturn material;\n\n\t\t\t\t\t},\n\n\t\t\t\t\tcurrentMaterial: function () {\n\n\t\t\t\t\t\tif ( this.materials.length > 0 ) {\n\t\t\t\t\t\t\treturn this.materials[ this.materials.length - 1 ];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn undefined;\n\n\t\t\t\t\t},\n\n\t\t\t\t\t_finalize: function ( end ) {\n\n\t\t\t\t\t\tvar lastMultiMaterial = this.currentMaterial();\n\t\t\t\t\t\tif ( lastMultiMaterial && lastMultiMaterial.groupEnd === -1 ) {\n\n\t\t\t\t\t\t\tlastMultiMaterial.groupEnd = this.geometry.vertices.length / 3;\n\t\t\t\t\t\t\tlastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart;\n\t\t\t\t\t\t\tlastMultiMaterial.inherited = false;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Ignore objects tail materials if no face declarations followed them before a new o/g started.\n\t\t\t\t\t\tif ( end && this.materials.length > 1 ) {\n\n\t\t\t\t\t\t\tfor ( var mi = this.materials.length - 1; mi >= 0; mi-- ) {\n\t\t\t\t\t\t\t\tif ( this.materials[ mi ].groupCount <= 0 ) {\n\t\t\t\t\t\t\t\t\tthis.materials.splice( mi, 1 );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Guarantee at least one empty material, this makes the creation later more straight forward.\n\t\t\t\t\t\tif ( end && this.materials.length === 0 ) {\n\n\t\t\t\t\t\t\tthis.materials.push({\n\t\t\t\t\t\t\t\tname   : '',\n\t\t\t\t\t\t\t\tsmooth : this.smooth\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn lastMultiMaterial;\n\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t// Inherit previous objects material.\n\t\t\t\t// Spec tells us that a declared material must be set to all objects until a new material is declared.\n\t\t\t\t// If a usemtl declaration is encountered while this new object is being parsed, it will\n\t\t\t\t// overwrite the inherited material. Exception being that there was already face declarations\n\t\t\t\t// to the inherited material, then it will be preserved for proper MultiMaterial continuation.\n\n\t\t\t\tif ( previousMaterial && previousMaterial.name && typeof previousMaterial.clone === 'function' ) {\n\n\t\t\t\t\tvar declared = previousMaterial.clone( 0 );\n\t\t\t\t\tdeclared.inherited = true;\n\t\t\t\t\tthis.object.materials.push( declared );\n\n\t\t\t\t}\n\n\t\t\t\tthis.objects.push( this.object );\n\n\t\t\t},\n\n\t\t\tfinalize: function () {\n\n\t\t\t\tif ( this.object && typeof this.object._finalize === 'function' ) {\n\n\t\t\t\t\tthis.object._finalize( true );\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tparseVertexIndex: function ( value, len ) {\n\n\t\t\t\tvar index = parseInt( value, 10 );\n\t\t\t\treturn ( index >= 0 ? index - 1 : index + len / 3 ) * 3;\n\n\t\t\t},\n\n\t\t\tparseNormalIndex: function ( value, len ) {\n\n\t\t\t\tvar index = parseInt( value, 10 );\n\t\t\t\treturn ( index >= 0 ? index - 1 : index + len / 3 ) * 3;\n\n\t\t\t},\n\n\t\t\tparseUVIndex: function ( value, len ) {\n\n\t\t\t\tvar index = parseInt( value, 10 );\n\t\t\t\treturn ( index >= 0 ? index - 1 : index + len / 2 ) * 2;\n\n\t\t\t},\n\n\t\t\taddVertex: function ( a, b, c ) {\n\n\t\t\t\tvar src = this.vertices;\n\t\t\t\tvar dst = this.object.geometry.vertices;\n\n\t\t\t\tdst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );\n\t\t\t\tdst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );\n\t\t\t\tdst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );\n\n\t\t\t},\n\n\t\t\taddVertexLine: function ( a ) {\n\n\t\t\t\tvar src = this.vertices;\n\t\t\t\tvar dst = this.object.geometry.vertices;\n\n\t\t\t\tdst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );\n\n\t\t\t},\n\n\t\t\taddNormal: function ( a, b, c ) {\n\n\t\t\t\tvar src = this.normals;\n\t\t\t\tvar dst = this.object.geometry.normals;\n\n\t\t\t\tdst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );\n\t\t\t\tdst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );\n\t\t\t\tdst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );\n\n\t\t\t},\n\n\t\t\taddUV: function ( a, b, c ) {\n\n\t\t\t\tvar src = this.uvs;\n\t\t\t\tvar dst = this.object.geometry.uvs;\n\n\t\t\t\tdst.push( src[ a + 0 ], src[ a + 1 ] );\n\t\t\t\tdst.push( src[ b + 0 ], src[ b + 1 ] );\n\t\t\t\tdst.push( src[ c + 0 ], src[ c + 1 ] );\n\n\t\t\t},\n\n\t\t\taddUVLine: function ( a ) {\n\n\t\t\t\tvar src = this.uvs;\n\t\t\t\tvar dst = this.object.geometry.uvs;\n\n\t\t\t\tdst.push( src[ a + 0 ], src[ a + 1 ] );\n\n\t\t\t},\n\n\t\t\taddFace: function ( a, b, c, ua, ub, uc, na, nb, nc ) {\n\n\t\t\t\tvar vLen = this.vertices.length;\n\n\t\t\t\tvar ia = this.parseVertexIndex( a, vLen );\n\t\t\t\tvar ib = this.parseVertexIndex( b, vLen );\n\t\t\t\tvar ic = this.parseVertexIndex( c, vLen );\n\n\t\t\t\tthis.addVertex( ia, ib, ic );\n\n\t\t\t\tif ( ua !== undefined ) {\n\n\t\t\t\t\tvar uvLen = this.uvs.length;\n\n\t\t\t\t\tia = this.parseUVIndex( ua, uvLen );\n\t\t\t\t\tib = this.parseUVIndex( ub, uvLen );\n\t\t\t\t\tic = this.parseUVIndex( uc, uvLen );\n\n\t\t\t\t\tthis.addUV( ia, ib, ic );\n\n\t\t\t\t}\n\n\t\t\t\tif ( na !== undefined ) {\n\n\t\t\t\t\t// Normals are many times the same. If so, skip function call and parseInt.\n\t\t\t\t\tvar nLen = this.normals.length;\n\t\t\t\t\tia = this.parseNormalIndex( na, nLen );\n\n\t\t\t\t\tib = na === nb ? ia : this.parseNormalIndex( nb, nLen );\n\t\t\t\t\tic = na === nc ? ia : this.parseNormalIndex( nc, nLen );\n\n\t\t\t\t\tthis.addNormal( ia, ib, ic );\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\taddLineGeometry: function ( vertices, uvs ) {\n\n\t\t\t\tthis.object.geometry.type = 'Line';\n\n\t\t\t\tvar vLen = this.vertices.length;\n\t\t\t\tvar uvLen = this.uvs.length;\n\n\t\t\t\tfor ( var vi = 0, l = vertices.length; vi < l; vi ++ ) {\n\n\t\t\t\t\tthis.addVertexLine( this.parseVertexIndex( vertices[ vi ], vLen ) );\n\n\t\t\t\t}\n\n\t\t\t\tfor ( var uvi = 0, l = uvs.length; uvi < l; uvi ++ ) {\n\n\t\t\t\t\tthis.addUVLine( this.parseUVIndex( uvs[ uvi ], uvLen ) );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t\tstate.startObject( '', false );\n\n\t\treturn state;\n\n\t}\n\n\t//\n\n\tfunction OBJLoader( manager ) {\n\n\t\tthis.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;\n\n\t\tthis.materials = null;\n\n\t};\n\n\tOBJLoader.prototype = {\n\n\t\tconstructor: OBJLoader,\n\n\t\tload: function ( url, onLoad, onProgress, onError ) {\n\n\t\t\tvar scope = this;\n\n\t\t\tvar loader = new THREE.FileLoader( scope.manager );\n\t\t\tloader.setPath( this.path );\n\t\t\tloader.load( url, function ( text ) {\n\n\t\t\t\tonLoad( scope.parse( text ) );\n\n\t\t\t}, onProgress, onError );\n\n\t\t},\n\n\t\tsetPath: function ( value ) {\n\n\t\t\tthis.path = value;\n\n\t\t},\n\n\t\tsetMaterials: function ( materials ) {\n\n\t\t\tthis.materials = materials;\n\n\t\t\treturn this;\n\n\t\t},\n\n\t\tparse: function ( text ) {\n\n\t\t\tconsole.time( 'OBJLoader' );\n\n\t\t\tvar state = new ParserState();\n\n\t\t\tif ( text.indexOf( '\\r\\n' ) !== - 1 ) {\n\n\t\t\t\t// This is faster than String.split with regex that splits on both\n\t\t\t\ttext = text.replace( /\\r\\n/g, '\\n' );\n\n\t\t\t}\n\n\t\t\tif ( text.indexOf( '\\\\\\n' ) !== - 1) {\n\n\t\t\t\t// join lines separated by a line continuation character (\\)\n\t\t\t\ttext = text.replace( /\\\\\\n/g, '' );\n\n\t\t\t}\n\n\t\t\tvar lines = text.split( '\\n' );\n\t\t\tvar line = '', lineFirstChar = '';\n\t\t\tvar lineLength = 0;\n\t\t\tvar result = [];\n\n\t\t\t// Faster to just trim left side of the line. Use if available.\n\t\t\tvar trimLeft = ( typeof ''.trimLeft === 'function' );\n\n\t\t\tfor ( var i = 0, l = lines.length; i < l; i ++ ) {\n\n\t\t\t\tline = lines[ i ];\n\n\t\t\t\tline = trimLeft ? line.trimLeft() : line.trim();\n\n\t\t\t\tlineLength = line.length;\n\n\t\t\t\tif ( lineLength === 0 ) continue;\n\n\t\t\t\tlineFirstChar = line.charAt( 0 );\n\n\t\t\t\t// @todo invoke passed in handler if any\n\t\t\t\tif ( lineFirstChar === '#' ) continue;\n\n\t\t\t\tif ( lineFirstChar === 'v' ) {\n\n\t\t\t\t\tvar data = line.split( /\\s+/ );\n\n\t\t\t\t\tswitch ( data[ 0 ] ) {\n\n\t\t\t\t\t\tcase 'v':\n\t\t\t\t\t\t\tstate.vertices.push(\n\t\t\t\t\t\t\t\tparseFloat( data[ 1 ] ),\n\t\t\t\t\t\t\t\tparseFloat( data[ 2 ] ),\n\t\t\t\t\t\t\t\tparseFloat( data[ 3 ] )\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'vn':\n\t\t\t\t\t\t\tstate.normals.push(\n\t\t\t\t\t\t\t\tparseFloat( data[ 1 ] ),\n\t\t\t\t\t\t\t\tparseFloat( data[ 2 ] ),\n\t\t\t\t\t\t\t\tparseFloat( data[ 3 ] )\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'vt':\n\t\t\t\t\t\t\tstate.uvs.push(\n\t\t\t\t\t\t\t\tparseFloat( data[ 1 ] ),\n\t\t\t\t\t\t\t\tparseFloat( data[ 2 ] )\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( lineFirstChar === 'f' ) {\n\n\t\t\t\t\tvar lineData = line.substr( 1 ).trim();\n\t\t\t\t\tvar vertexData = lineData.split( /\\s+/ );\n\t\t\t\t\tvar faceVertices = [];\n\n\t\t\t\t\t// Parse the face vertex data into an easy to work with format\n\n\t\t\t\t\tfor ( var j = 0, jl = vertexData.length; j < jl; j ++ ) {\n\n\t\t\t\t\t\tvar vertex = vertexData[ j ];\n\n\t\t\t\t\t\tif ( vertex.length > 0 ) {\n\n\t\t\t\t\t\t\tvar vertexParts = vertex.split( '/' );\n\t\t\t\t\t\t\tfaceVertices.push( vertexParts );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// Draw an edge between the first vertex and all subsequent vertices to form an n-gon\n\n\t\t\t\t\tvar v1 = faceVertices[ 0 ];\n\n\t\t\t\t\tfor ( var j = 1, jl = faceVertices.length - 1; j < jl; j ++ ) {\n\n\t\t\t\t\t\tvar v2 = faceVertices[ j ];\n\t\t\t\t\t\tvar v3 = faceVertices[ j + 1 ];\n\n\t\t\t\t\t\tstate.addFace(\n\t\t\t\t\t\t\tv1[ 0 ], v2[ 0 ], v3[ 0 ],\n\t\t\t\t\t\t\tv1[ 1 ], v2[ 1 ], v3[ 1 ],\n\t\t\t\t\t\t\tv1[ 2 ], v2[ 2 ], v3[ 2 ]\n\t\t\t\t\t\t);\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( lineFirstChar === 'l' ) {\n\n\t\t\t\t\tvar lineParts = line.substring( 1 ).trim().split( \" \" );\n\t\t\t\t\tvar lineVertices = [], lineUVs = [];\n\n\t\t\t\t\tif ( line.indexOf( \"/\" ) === - 1 ) {\n\n\t\t\t\t\t\tlineVertices = lineParts;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tfor ( var li = 0, llen = lineParts.length; li < llen; li ++ ) {\n\n\t\t\t\t\t\t\tvar parts = lineParts[ li ].split( \"/\" );\n\n\t\t\t\t\t\t\tif ( parts[ 0 ] !== \"\" ) lineVertices.push( parts[ 0 ] );\n\t\t\t\t\t\t\tif ( parts[ 1 ] !== \"\" ) lineUVs.push( parts[ 1 ] );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\t\t\t\t\tstate.addLineGeometry( lineVertices, lineUVs );\n\n\t\t\t\t} else if ( ( result = object_pattern.exec( line ) ) !== null ) {\n\n\t\t\t\t\t// o object_name\n\t\t\t\t\t// or\n\t\t\t\t\t// g group_name\n\n\t\t\t\t\t// WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869\n\t\t\t\t\t// var name = result[ 0 ].substr( 1 ).trim();\n\t\t\t\t\tvar name = ( \" \" + result[ 0 ].substr( 1 ).trim() ).substr( 1 );\n\n\t\t\t\t\tstate.startObject( name );\n\n\t\t\t\t} else if ( material_use_pattern.test( line ) ) {\n\n\t\t\t\t\t// material\n\n\t\t\t\t\tstate.object.startMaterial( line.substring( 7 ).trim(), state.materialLibraries );\n\n\t\t\t\t} else if ( material_library_pattern.test( line ) ) {\n\n\t\t\t\t\t// mtl file\n\n\t\t\t\t\tstate.materialLibraries.push( line.substring( 7 ).trim() );\n\n\t\t\t\t} else if ( lineFirstChar === 's' ) {\n\n\t\t\t\t\tresult = line.split( ' ' );\n\n\t\t\t\t\t// smooth shading\n\n\t\t\t\t\t// @todo Handle files that have varying smooth values for a set of faces inside one geometry,\n\t\t\t\t\t// but does not define a usemtl for each face set.\n\t\t\t\t\t// This should be detected and a dummy material created (later MultiMaterial and geometry groups).\n\t\t\t\t\t// This requires some care to not create extra material on each smooth value for \"normal\" obj files.\n\t\t\t\t\t// where explicit usemtl defines geometry groups.\n\t\t\t\t\t// Example asset: examples/models/obj/cerberus/Cerberus.obj\n\n\t\t\t\t\t/*\n\t\t\t\t\t * http://paulbourke.net/dataformats/obj/\n\t\t\t\t\t * or\n\t\t\t\t\t * http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf\n\t\t\t\t\t *\n\t\t\t\t\t * From chapter \"Grouping\" Syntax explanation \"s group_number\":\n\t\t\t\t\t * \"group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off.\n\t\t\t\t\t * Polygonal elements use group numbers to put elements in different smoothing groups. For free-form\n\t\t\t\t\t * surfaces, smoothing groups are either turned on or off; there is no difference between values greater\n\t\t\t\t\t * than 0.\"\n\t\t\t\t\t */\n\t\t\t\t\tif ( result.length > 1 ) {\n\n\t\t\t\t\t\tvar value = result[ 1 ].trim().toLowerCase();\n\t\t\t\t\t\tstate.object.smooth = ( value !== '0' && value !== 'off' );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// ZBrush can produce \"s\" lines #11707\n\t\t\t\t\t\tstate.object.smooth = true;\n\n\t\t\t\t\t}\n\t\t\t\t\tvar material = state.object.currentMaterial();\n\t\t\t\t\tif ( material ) material.smooth = state.object.smooth;\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// Handle null terminated files without exception\n\t\t\t\t\tif ( line === '\\0' ) continue;\n\n\t\t\t\t\tthrow new Error( \"Unexpected line: '\" + line  + \"'\" );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tstate.finalize();\n\n\t\t\tvar container = new THREE.Group();\n\t\t\tcontainer.materialLibraries = [].concat( state.materialLibraries );\n\n\t\t\tfor ( var i = 0, l = state.objects.length; i < l; i ++ ) {\n\n\t\t\t\tvar object = state.objects[ i ];\n\t\t\t\tvar geometry = object.geometry;\n\t\t\t\tvar materials = object.materials;\n\t\t\t\tvar isLine = ( geometry.type === 'Line' );\n\n\t\t\t\t// Skip o/g line declarations that did not follow with any faces\n\t\t\t\tif ( geometry.vertices.length === 0 ) continue;\n\n\t\t\t\tvar buffergeometry = new THREE.BufferGeometry();\n\n\t\t\t\tbuffergeometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( geometry.vertices ), 3 ) );\n\n\t\t\t\tif ( geometry.normals.length > 0 ) {\n\n\t\t\t\t\tbuffergeometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( geometry.normals ), 3 ) );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tbuffergeometry.computeVertexNormals();\n\n\t\t\t\t}\n\n\t\t\t\tif ( geometry.uvs.length > 0 ) {\n\n\t\t\t\t\tbuffergeometry.addAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( geometry.uvs ), 2 ) );\n\n\t\t\t\t}\n\n\t\t\t\t// Create materials\n\n\t\t\t\tvar createdMaterials = [];\n\n\t\t\t\tfor ( var mi = 0, miLen = materials.length; mi < miLen ; mi++ ) {\n\n\t\t\t\t\tvar sourceMaterial = materials[ mi ];\n\t\t\t\t\tvar material = undefined;\n\n\t\t\t\t\tif ( this.materials !== null ) {\n\n\t\t\t\t\t\tmaterial = this.materials.create( sourceMaterial.name );\n\n\t\t\t\t\t\t// mtl etc. loaders probably can't create line materials correctly, copy properties to a line material.\n\t\t\t\t\t\tif ( isLine && material && ! ( material instanceof THREE.LineBasicMaterial ) ) {\n\n\t\t\t\t\t\t\tvar materialLine = new THREE.LineBasicMaterial();\n\t\t\t\t\t\t\tmaterialLine.copy( material );\n\t\t\t\t\t\t\tmaterial = materialLine;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( ! material ) {\n\n\t\t\t\t\t\tmaterial = ( ! isLine ? new THREE.MeshPhongMaterial() : new THREE.LineBasicMaterial() );\n\t\t\t\t\t\tmaterial.name = sourceMaterial.name;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tmaterial.flatShading = sourceMaterial.smooth ? false : true;\n\n\t\t\t\t\tcreatedMaterials.push(material);\n\n\t\t\t\t}\n\n\t\t\t\t// Create mesh\n\n\t\t\t\tvar mesh;\n\n\t\t\t\tif ( createdMaterials.length > 1 ) {\n\n\t\t\t\t\tfor ( var mi = 0, miLen = materials.length; mi < miLen ; mi++ ) {\n\n\t\t\t\t\t\tvar sourceMaterial = materials[ mi ];\n\t\t\t\t\t\tbuffergeometry.addGroup( sourceMaterial.groupStart, sourceMaterial.groupCount, mi );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tmesh = ( ! isLine ? new THREE.Mesh( buffergeometry, createdMaterials ) : new THREE.LineSegments( buffergeometry, createdMaterials ) );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tmesh = ( ! isLine ? new THREE.Mesh( buffergeometry, createdMaterials[ 0 ] ) : new THREE.LineSegments( buffergeometry, createdMaterials[ 0 ] ) );\n\t\t\t\t}\n\n\t\t\t\tmesh.name = object.name;\n\n\t\t\t\tcontainer.add( mesh );\n\n\t\t\t}\n\n\t\t\tconsole.timeEnd( 'OBJLoader' );\n\n\t\t\treturn container;\n\n\t\t}\n\n\t};\n\n\treturn OBJLoader;\n\n} )();\n\n},{}],46:[function(_dereq_,module,exports){\n\nexports = module.exports = trim;\n\nfunction trim(str){\n  return str.replace(/^\\s*|\\s*$/g, '');\n}\n\nexports.left = function(str){\n  return str.replace(/^\\s*/, '');\n};\n\nexports.right = function(str){\n  return str.replace(/\\s*$/, '');\n};\n\n},{}],47:[function(_dereq_,module,exports){\nmodule.exports={\n  \"_args\": [\n    [\n      {\n        \"raw\": \"webvr-polyfill@^0.9.36\",\n        \"scope\": null,\n        \"escapedName\": \"webvr-polyfill\",\n        \"name\": \"webvr-polyfill\",\n        \"rawSpec\": \"^0.9.36\",\n        \"spec\": \">=0.9.36 <0.10.0\",\n        \"type\": \"range\"\n      },\n      \"X:\\\\Development\\\\aframe\"\n    ]\n  ],\n  \"_from\": \"webvr-polyfill@>=0.9.36 <0.10.0\",\n  \"_id\": \"webvr-polyfill@0.9.38\",\n  \"_inCache\": true,\n  \"_location\": \"/webvr-polyfill\",\n  \"_nodeVersion\": \"8.1.4\",\n  \"_npmOperationalInternal\": {\n    \"host\": \"s3://npm-registry-packages\",\n    \"tmp\": \"tmp/webvr-polyfill-0.9.38.tgz_1505328121599_0.8887633208651096\"\n  },\n  \"_npmUser\": {\n    \"name\": \"jsantell\",\n    \"email\": \"jsantell@gmail.com\"\n  },\n  \"_npmVersion\": \"5.4.1\",\n  \"_phantomChildren\": {},\n  \"_requested\": {\n    \"raw\": \"webvr-polyfill@^0.9.36\",\n    \"scope\": null,\n    \"escapedName\": \"webvr-polyfill\",\n    \"name\": \"webvr-polyfill\",\n    \"rawSpec\": \"^0.9.36\",\n    \"spec\": \">=0.9.36 <0.10.0\",\n    \"type\": \"range\"\n  },\n  \"_requiredBy\": [\n    \"/\"\n  ],\n  \"_resolved\": \"https://registry.npmjs.org/webvr-polyfill/-/webvr-polyfill-0.9.38.tgz\",\n  \"_shasum\": \"740099a2f268a56a0bf18181fb57395efad70712\",\n  \"_shrinkwrap\": null,\n  \"_spec\": \"webvr-polyfill@^0.9.36\",\n  \"_where\": \"X:\\\\Development\\\\aframe\",\n  \"authors\": [\n    \"Boris Smus <boris@smus.com>\",\n    \"Brandon Jones <tojiro@gmail.com>\",\n    \"Jordan Santell <jordan@jsantell.com>\"\n  ],\n  \"bugs\": {\n    \"url\": \"https://github.com/googlevr/webvr-polyfill/issues\"\n  },\n  \"dependencies\": {},\n  \"description\": \"Use WebVR today, on mobile or desktop, without requiring a special browser build.\",\n  \"devDependencies\": {\n    \"chai\": \"^3.5.0\",\n    \"jsdom\": \"^9.12.0\",\n    \"mocha\": \"^3.2.0\",\n    \"semver\": \"^5.3.0\",\n    \"webpack\": \"^2.6.1\",\n    \"webpack-dev-server\": \"^2.4.5\"\n  },\n  \"directories\": {},\n  \"dist\": {\n    \"integrity\": \"sha512-HABweqWYE0suk6P5TdHlagJK56HSecB5xKj6ZshocrxSj9UmNOCjCRv4vFYHCaFZKtuKWa8niRHVbJ3Vo7JYDg==\",\n    \"shasum\": \"740099a2f268a56a0bf18181fb57395efad70712\",\n    \"tarball\": \"https://registry.npmjs.org/webvr-polyfill/-/webvr-polyfill-0.9.38.tgz\"\n  },\n  \"gitHead\": \"8063169c6fc52342ebe5524d7f217987f9aa9cab\",\n  \"homepage\": \"https://github.com/googlevr/webvr-polyfill\",\n  \"keywords\": [\n    \"vr\",\n    \"webvr\"\n  ],\n  \"license\": \"Apache-2.0\",\n  \"main\": \"src/node-entry\",\n  \"maintainers\": [\n    {\n      \"name\": \"jsantell\",\n      \"email\": \"jsantell@gmail.com\"\n    },\n    {\n      \"name\": \"toji\",\n      \"email\": \"tojiro@gmail.com\"\n    },\n    {\n      \"name\": \"smus\",\n      \"email\": \"boris@smus.com\"\n    }\n  ],\n  \"name\": \"webvr-polyfill\",\n  \"optionalDependencies\": {},\n  \"readme\": \"ERROR: No README data found!\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/googlevr/webvr-polyfill.git\"\n  },\n  \"scripts\": {\n    \"build\": \"webpack\",\n    \"start\": \"npm run watch\",\n    \"test\": \"mocha\",\n    \"watch\": \"webpack-dev-server\"\n  },\n  \"version\": \"0.9.38\"\n}\n\n},{}],48:[function(_dereq_,module,exports){\n/*\n * Copyright 2015 Google Inc. All Rights Reserved.\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\nvar Util = _dereq_('./util.js');\nvar WakeLock = _dereq_('./wakelock.js');\n\n// Start at a higher number to reduce chance of conflict.\nvar nextDisplayId = 1000;\nvar hasShowDeprecationWarning = false;\n\nvar defaultLeftBounds = [0, 0, 0.5, 1];\nvar defaultRightBounds = [0.5, 0, 0.5, 1];\n\n/**\n * The base class for all VR frame data.\n */\n\nfunction 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\n/**\n * The base class for all VR displays.\n */\nfunction VRDisplay() {\n  this.isPolyfilled = true;\n  this.displayId = nextDisplayId++;\n  this.displayName = 'webvr-polyfill displayName';\n\n  this.depthNear = 0.01;\n  this.depthFar = 10000.0;\n\n  this.isConnected = true;\n  this.isPresenting = false;\n  this.capabilities = {\n    hasPosition: false,\n    hasOrientation: false,\n    hasExternalDisplay: false,\n    canPresent: false,\n    maxLayers: 1\n  };\n  this.stageParameters = null;\n\n  // \"Private\" members.\n  this.waitingForPresent_ = false;\n  this.layer_ = null;\n\n  this.fullscreenElement_ = null;\n  this.fullscreenWrapper_ = null;\n  this.fullscreenElementCachedStyle_ = null;\n\n  this.fullscreenEventTarget_ = null;\n  this.fullscreenChangeHandler_ = null;\n  this.fullscreenErrorHandler_ = null;\n\n  this.wakelock_ = new WakeLock();\n}\n\nVRDisplay.prototype.getFrameData = function(frameData) {\n  // TODO: Technically this should retain it's value for the duration of a frame\n  // but I doubt that's practical to do in javascript.\n  return Util.frameDataFromPose(frameData, this.getPose(), this);\n};\n\nVRDisplay.prototype.getPose = function() {\n  // TODO: Technically this should retain it's value for the duration of a frame\n  // but I doubt that's practical to do in javascript.\n  return this.getImmediatePose();\n};\n\nVRDisplay.prototype.requestAnimationFrame = function(callback) {\n  return window.requestAnimationFrame(callback);\n};\n\nVRDisplay.prototype.cancelAnimationFrame = function(id) {\n  return window.cancelAnimationFrame(id);\n};\n\nVRDisplay.prototype.wrapForFullscreen = function(element) {\n  // Don't wrap in iOS.\n  if (Util.isIOS()) {\n    return element;\n  }\n  if (!this.fullscreenWrapper_) {\n    this.fullscreenWrapper_ = document.createElement('div');\n    var cssProperties = [\n      'height: ' + Math.min(screen.height, screen.width) + 'px !important',\n      'top: 0 !important',\n      'left: 0 !important',\n      'right: 0 !important',\n      'border: 0',\n      'margin: 0',\n      'padding: 0',\n      'z-index: 999999 !important',\n      'position: fixed',\n    ];\n    this.fullscreenWrapper_.setAttribute('style', cssProperties.join('; ') + ';');\n    this.fullscreenWrapper_.classList.add('webvr-polyfill-fullscreen-wrapper');\n  }\n\n  if (this.fullscreenElement_ == element) {\n    return this.fullscreenWrapper_;\n  }\n\n  // Remove any previously applied wrappers\n  this.removeFullscreenWrapper();\n\n  this.fullscreenElement_ = element;\n  var parent = this.fullscreenElement_.parentElement;\n  parent.insertBefore(this.fullscreenWrapper_, this.fullscreenElement_);\n  parent.removeChild(this.fullscreenElement_);\n  this.fullscreenWrapper_.insertBefore(this.fullscreenElement_, this.fullscreenWrapper_.firstChild);\n  this.fullscreenElementCachedStyle_ = this.fullscreenElement_.getAttribute('style');\n\n  var self = this;\n  function applyFullscreenElementStyle() {\n    if (!self.fullscreenElement_) {\n      return;\n    }\n\n    var cssProperties = [\n      'position: absolute',\n      'top: 0',\n      'left: 0',\n      'width: ' + Math.max(screen.width, screen.height) + 'px',\n      'height: ' + Math.min(screen.height, screen.width) + 'px',\n      'border: 0',\n      'margin: 0',\n      'padding: 0',\n    ];\n    self.fullscreenElement_.setAttribute('style', cssProperties.join('; ') + ';');\n  }\n\n  applyFullscreenElementStyle();\n\n  return this.fullscreenWrapper_;\n};\n\nVRDisplay.prototype.removeFullscreenWrapper = function() {\n  if (!this.fullscreenElement_) {\n    return;\n  }\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\n  var parent = this.fullscreenWrapper_.parentElement;\n  this.fullscreenWrapper_.removeChild(element);\n  parent.insertBefore(element, this.fullscreenWrapper_);\n  parent.removeChild(this.fullscreenWrapper_);\n\n  return element;\n};\n\nVRDisplay.prototype.requestPresent = function(layers) {\n  var wasPresenting = this.isPresenting;\n  var self = this;\n\n  if (!(layers instanceof Array)) {\n    if (!hasShowDeprecationWarning) {\n      console.warn(\"Using a deprecated form of requestPresent. Should pass in an array of VRLayers.\");\n      hasShowDeprecationWarning = true;\n    }\n    layers = [layers];\n  }\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\n    if (layers.length == 0 || layers.length > self.capabilities.maxLayers) {\n      reject(new Error('Invalid number of layers.'));\n      return;\n    }\n\n    var incomingLayer = layers[0];\n    if (!incomingLayer.source) {\n      /*\n      todo: figure out the correct behavior if the source is not provided.\n      see https://github.com/w3c/webvr/issues/58\n      */\n      resolve();\n      return;\n    }\n\n    var leftBounds = incomingLayer.leftBounds || defaultLeftBounds;\n    var rightBounds = incomingLayer.rightBounds || defaultRightBounds;\n    if (wasPresenting) {\n      // Already presenting, just changing configuration\n      var layer = self.layer_;\n      if (layer.source !== incomingLayer.source) {\n        layer.source = incomingLayer.source;\n      }\n\n      for (var i = 0; i < 4; i++) {\n        layer.leftBounds[i] = leftBounds[i];\n        layer.rightBounds[i] = rightBounds[i];\n      }\n\n      resolve();\n      return;\n    }\n\n    // Was not already presenting.\n    self.layer_ = {\n      predistorted: incomingLayer.predistorted,\n      source: incomingLayer.source,\n      leftBounds: leftBounds.slice(0),\n      rightBounds: rightBounds.slice(0)\n    };\n\n    self.waitingForPresent_ = false;\n    if (self.layer_ && self.layer_.source) {\n      var fullscreenElement = self.wrapForFullscreen(self.layer_.source);\n\n      var onFullscreenChange = function() {\n        var actualFullscreenElement = Util.getFullscreenElement();\n\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.wakelock_.release();\n          self.endPresent_();\n          self.removeFullscreenListeners_();\n        }\n        self.fireVRDisplayPresentChange_();\n      }\n      var onFullscreenError = function() {\n        if (!self.waitingForPresent_) {\n          return;\n        }\n\n        self.removeFullscreenWrapper();\n        self.removeFullscreenListeners_();\n\n        self.wakelock_.release();\n        self.waitingForPresent_ = false;\n        self.isPresenting = false;\n\n        reject(new Error('Unable to present.'));\n      }\n\n      self.addFullscreenListeners_(fullscreenElement,\n          onFullscreenChange, onFullscreenError);\n\n      if (Util.requestFullscreen(fullscreenElement)) {\n        self.wakelock_.request();\n        self.waitingForPresent_ = true;\n      } else if (Util.isIOS() || Util.isWebViewAndroid()) {\n        // *sigh* Just fake it.\n        self.wakelock_.request();\n        self.isPresenting = true;\n        self.beginPresent_();\n        self.fireVRDisplayPresentChange_();\n        resolve();\n      }\n    }\n\n    if (!self.waitingForPresent_ && !Util.isIOS()) {\n      Util.exitFullscreen();\n      reject(new Error('Unable to present.'));\n    }\n  });\n};\n\nVRDisplay.prototype.exitPresent = function() {\n  var wasPresenting = this.isPresenting;\n  var self = this;\n  this.isPresenting = false;\n  this.layer_ = null;\n  this.wakelock_.release();\n\n  return new Promise(function(resolve, reject) {\n    if (wasPresenting) {\n      if (!Util.exitFullscreen() && Util.isIOS()) {\n        self.endPresent_();\n        self.fireVRDisplayPresentChange_();\n      }\n\n      if (Util.isWebViewAndroid()) {\n        self.removeFullscreenWrapper();\n        self.removeFullscreenListeners_();\n        self.endPresent_();\n        self.fireVRDisplayPresentChange_();\n      }\n\n      resolve();\n    } else {\n      reject(new Error('Was not presenting to VRDisplay.'));\n    }\n  });\n};\n\nVRDisplay.prototype.getLayers = function() {\n  if (this.layer_) {\n    return [this.layer_];\n  }\n  return [];\n};\n\nVRDisplay.prototype.fireVRDisplayPresentChange_ = function() {\n  // Important: unfortunately we cannot have full spec compliance here.\n  // CustomEvent custom fields all go under e.detail (so the VRDisplay ends up\n  // being e.detail.display, instead of e.display as per WebVR spec).\n  var event = new CustomEvent('vrdisplaypresentchange', {detail: {display: this}});\n  window.dispatchEvent(event);\n};\n\nVRDisplay.prototype.fireVRDisplayConnect_ = function() {\n  // Important: unfortunately we cannot have full spec compliance here.\n  // CustomEvent custom fields all go under e.detail (so the VRDisplay ends up\n  // being e.detail.display, instead of e.display as per WebVR spec).\n  var event = new CustomEvent('vrdisplayconnect', {detail: {display: this}});\n  window.dispatchEvent(event);\n};\n\nVRDisplay.prototype.addFullscreenListeners_ = function(element, changeHandler, errorHandler) {\n  this.removeFullscreenListeners_();\n\n  this.fullscreenEventTarget_ = element;\n  this.fullscreenChangeHandler_ = changeHandler;\n  this.fullscreenErrorHandler_ = errorHandler;\n\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\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\nVRDisplay.prototype.removeFullscreenListeners_ = function() {\n  if (!this.fullscreenEventTarget_)\n    return;\n\n  var element = this.fullscreenEventTarget_;\n\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\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\n  this.fullscreenEventTarget_ = null;\n  this.fullscreenChangeHandler_ = null;\n  this.fullscreenErrorHandler_ = null;\n};\n\nVRDisplay.prototype.beginPresent_ = function() {\n  // Override to add custom behavior when presentation begins.\n};\n\nVRDisplay.prototype.endPresent_ = function() {\n  // Override to add custom behavior when presentation ends.\n};\n\nVRDisplay.prototype.submitFrame = function(pose) {\n  // Override to add custom behavior for frame submission.\n};\n\nVRDisplay.prototype.getEyeParameters = function(whichEye) {\n  // Override to return accurate eye parameters if canPresent is true.\n  return null;\n};\n\n/*\n * Deprecated classes\n */\n\n/**\n * The base class for all VR devices. (Deprecated)\n */\nfunction VRDevice() {\n  this.isPolyfilled = true;\n  this.hardwareUnitId = 'webvr-polyfill hardwareUnitId';\n  this.deviceId = 'webvr-polyfill deviceId';\n  this.deviceName = 'webvr-polyfill deviceName';\n}\n\n/**\n * The base class for all VR HMD devices. (Deprecated)\n */\nfunction HMDVRDevice() {\n}\nHMDVRDevice.prototype = new VRDevice();\n\n/**\n * The base class for all VR position sensor devices. (Deprecated)\n */\nfunction PositionSensorVRDevice() {\n}\nPositionSensorVRDevice.prototype = new VRDevice();\n\nmodule.exports.VRFrameData = VRFrameData;\nmodule.exports.VRDisplay = VRDisplay;\nmodule.exports.VRDevice = VRDevice;\nmodule.exports.HMDVRDevice = HMDVRDevice;\nmodule.exports.PositionSensorVRDevice = PositionSensorVRDevice;\n\n},{\"./util.js\":68,\"./wakelock.js\":70}],49:[function(_dereq_,module,exports){\n/*\n * Copyright 2016 Google Inc. All Rights Reserved.\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\nvar CardboardUI = _dereq_('./cardboard-ui.js');\nvar Util = _dereq_('./util.js');\nvar WGLUPreserveGLState = _dereq_('./deps/wglu-preserve-state.js');\n\nvar distortionVS = [\n  'attribute vec2 position;',\n  'attribute vec3 texCoord;',\n\n  'varying vec2 vTexCoord;',\n\n  'uniform vec4 viewportOffsetScale[2];',\n\n  'void main() {',\n  '  vec4 viewport = viewportOffsetScale[int(texCoord.z)];',\n  '  vTexCoord = (texCoord.xy * viewport.zw) + viewport.xy;',\n  '  gl_Position = vec4( position, 1.0, 1.0 );',\n  '}',\n].join('\\n');\n\nvar distortionFS = [\n  'precision mediump float;',\n  'uniform sampler2D diffuse;',\n\n  'varying vec2 vTexCoord;',\n\n  'void main() {',\n  '  gl_FragColor = texture2D(diffuse, vTexCoord);',\n  '}',\n].join('\\n');\n\n/**\n * A mesh-based distorter.\n */\nfunction CardboardDistorter(gl) {\n  this.gl = gl;\n  this.ctxAttribs = gl.getContextAttributes();\n\n  this.meshWidth = 20;\n  this.meshHeight = 20;\n\n  this.bufferScale = window.WebVRConfig.BUFFER_SCALE;\n\n  this.bufferWidth = gl.drawingBufferWidth;\n  this.bufferHeight = gl.drawingBufferHeight;\n\n  // Patching support\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\n  if (!Util.isIOS()) {\n    this.realCanvasWidth = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'width');\n    this.realCanvasHeight = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'height');\n  }\n\n  this.isPatched = false;\n\n  // State tracking\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\n  this.attribs = {\n    position: 0,\n    texCoord: 1\n  };\n  this.program = Util.linkProgram(gl, distortionVS, distortionFS, this.attribs);\n  this.uniforms = Util.getProgramUniforms(gl, this.program);\n\n  this.viewportOffsetScale = new Float32Array(8);\n  this.setTextureBounds();\n\n  this.vertexBuffer = gl.createBuffer();\n  this.indexBuffer = gl.createBuffer();\n  this.indexCount = 0;\n\n  this.renderTarget = gl.createTexture();\n  this.framebuffer = gl.createFramebuffer();\n\n  this.depthStencilBuffer = null;\n  this.depthBuffer = null;\n  this.stencilBuffer = null;\n\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\n  this.patch();\n\n  this.onResize();\n\n  if (!window.WebVRConfig.CARDBOARD_UI_DISABLED) {\n    this.cardboardUI = new CardboardUI(gl);\n  }\n};\n\n/**\n * Tears down all the resources created by the distorter and removes any\n * patches.\n */\nCardboardDistorter.prototype.destroy = function() {\n  var gl = this.gl;\n\n  this.unpatch();\n\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\n  if (this.cardboardUI) {\n    this.cardboardUI.destroy();\n  }\n};\n\n\n/**\n * Resizes the backbuffer to match the canvas width and height.\n */\nCardboardDistorter.prototype.onResize = function() {\n  var gl = this.gl;\n  var self = this;\n\n  var glState = [\n    gl.RENDERBUFFER_BINDING,\n    gl.TEXTURE_BINDING_2D, gl.TEXTURE0\n  ];\n\n  WGLUPreserveGLState(gl, glState, function(gl) {\n    // Bind real backbuffer and clear it once. We don't need to clear it again\n    // after that because we're overwriting the same area every frame.\n    self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null);\n\n    // Put things in a good state\n    if (self.scissorTest) { self.realDisable.call(gl, gl.SCISSOR_TEST); }\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\n    gl.clear(gl.COLOR_BUFFER_BIT);\n\n    // Now bind and resize the fake backbuffer\n    self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.framebuffer);\n\n    gl.bindTexture(gl.TEXTURE_2D, self.renderTarget);\n    gl.texImage2D(gl.TEXTURE_2D, 0, self.ctxAttribs.alpha ? gl.RGBA : gl.RGB,\n        self.bufferWidth, self.bufferHeight, 0,\n        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\n    if (self.ctxAttribs.depth && self.ctxAttribs.stencil) {\n      gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthStencilBuffer);\n      gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL,\n          self.bufferWidth, self.bufferHeight);\n      gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT,\n          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,\n          self.bufferWidth, self.bufferHeight);\n      gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT,\n          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,\n          self.bufferWidth, self.bufferHeight);\n      gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT,\n          gl.RENDERBUFFER, self.stencilBuffer);\n    }\n\n    if (!gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE) {\n      console.error('Framebuffer incomplete!');\n    }\n\n    self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer);\n\n    if (self.scissorTest) { 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\n  if (this.cardboardUI) {\n    this.cardboardUI.onResize();\n  }\n};\n\nCardboardDistorter.prototype.patch = function() {\n  if (this.isPatched) {\n    return;\n  }\n\n  var self = this;\n  var canvas = this.gl.canvas;\n  var gl = this.gl;\n\n  if (!Util.isIOS()) {\n    canvas.width = Util.getScreenWidth() * this.bufferScale;\n    canvas.height = Util.getScreenHeight() * this.bufferScale;\n\n    Object.defineProperty(canvas, 'width', {\n      configurable: true,\n      enumerable: true,\n      get: function() {\n        return self.bufferWidth;\n      },\n      set: function(value) {\n        self.bufferWidth = value;\n        self.realCanvasWidth.set.call(canvas, value);\n        self.onResize();\n      }\n    });\n\n    Object.defineProperty(canvas, 'height', {\n      configurable: true,\n      enumerable: true,\n      get: function() {\n        return self.bufferHeight;\n      },\n      set: function(value) {\n        self.bufferHeight = value;\n        self.realCanvasHeight.set.call(canvas, value);\n        self.onResize();\n      }\n    });\n  }\n\n  this.lastBoundFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);\n\n  if (this.lastBoundFramebuffer == null) {\n    this.lastBoundFramebuffer = this.framebuffer;\n    this.gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);\n  }\n\n  this.gl.bindFramebuffer = function(target, framebuffer) {\n    self.lastBoundFramebuffer = framebuffer ? framebuffer : self.framebuffer;\n    // Silently make calls to bind the default framebuffer bind ours instead.\n    self.realBindFramebuffer.call(gl, target, self.lastBoundFramebuffer);\n  };\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\n  gl.enable = function(pname) {\n    switch (pname) {\n      case gl.CULL_FACE: self.cullFace = true; break;\n      case gl.DEPTH_TEST: self.depthTest = true; break;\n      case gl.BLEND: self.blend = true; break;\n      case gl.SCISSOR_TEST: self.scissorTest = true; break;\n      case gl.STENCIL_TEST: self.stencilTest = true; break;\n    }\n    self.realEnable.call(gl, pname);\n  };\n\n  gl.disable = function(pname) {\n    switch (pname) {\n      case gl.CULL_FACE: self.cullFace = false; break;\n      case gl.DEPTH_TEST: self.depthTest = false; break;\n      case gl.BLEND: self.blend = false; break;\n      case gl.SCISSOR_TEST: self.scissorTest = false; break;\n      case gl.STENCIL_TEST: self.stencilTest = false; break;\n    }\n    self.realDisable.call(gl, pname);\n  };\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\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\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\n  this.isPatched = true;\n  Util.safariCssSizeWorkaround(canvas);\n};\n\nCardboardDistorter.prototype.unpatch = function() {\n  if (!this.isPatched) {\n    return;\n  }\n\n  var gl = this.gl;\n  var canvas = this.gl.canvas;\n\n  if (!Util.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\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\n  // Check to see if our fake backbuffer is bound and bind the real backbuffer\n  // if that's the case.\n  if (this.lastBoundFramebuffer == this.framebuffer) {\n    gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n  }\n\n  this.isPatched = false;\n\n  setTimeout(function() {\n    Util.safariCssSizeWorkaround(canvas);\n  }, 1);\n};\n\nCardboardDistorter.prototype.setTextureBounds = function(leftBounds, rightBounds) {\n  if (!leftBounds) {\n    leftBounds = [0, 0, 0.5, 1];\n  }\n\n  if (!rightBounds) {\n    rightBounds = [0.5, 0, 0.5, 1];\n  }\n\n  // Left eye\n  this.viewportOffsetScale[0] = leftBounds[0]; // X\n  this.viewportOffsetScale[1] = leftBounds[1]; // Y\n  this.viewportOffsetScale[2] = leftBounds[2]; // Width\n  this.viewportOffsetScale[3] = leftBounds[3]; // Height\n\n  // Right eye\n  this.viewportOffsetScale[4] = rightBounds[0]; // X\n  this.viewportOffsetScale[5] = rightBounds[1]; // Y\n  this.viewportOffsetScale[6] = rightBounds[2]; // Width\n  this.viewportOffsetScale[7] = rightBounds[3]; // Height\n};\n\n/**\n * Performs distortion pass on the injected backbuffer, rendering it to the real\n * backbuffer.\n */\nCardboardDistorter.prototype.submitFrame = function() {\n  var gl = this.gl;\n  var self = this;\n\n  var glState = [];\n\n  if (!window.WebVRConfig.DIRTY_SUBMIT_FRAME_BINDINGS) {\n    glState.push(\n      gl.CURRENT_PROGRAM,\n      gl.ARRAY_BUFFER_BINDING,\n      gl.ELEMENT_ARRAY_BUFFER_BINDING,\n      gl.TEXTURE_BINDING_2D, gl.TEXTURE0\n    );\n  }\n\n  WGLUPreserveGLState(gl, glState, function(gl) {\n    // Bind the real default framebuffer\n    self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null);\n\n    // Make sure the GL state is in a good place\n    if (self.cullFace) { self.realDisable.call(gl, gl.CULL_FACE); }\n    if (self.depthTest) { self.realDisable.call(gl, gl.DEPTH_TEST); }\n    if (self.blend) { self.realDisable.call(gl, gl.BLEND); }\n    if (self.scissorTest) { self.realDisable.call(gl, gl.SCISSOR_TEST); }\n    if (self.stencilTest) { self.realDisable.call(gl, gl.STENCIL_TEST); }\n    self.realColorMask.call(gl, true, true, true, true);\n    self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);\n\n    // If the backbuffer has an alpha channel clear every frame so the page\n    // doesn't show through.\n    if (self.ctxAttribs.alpha || Util.isIOS()) {\n      self.realClearColor.call(gl, 0, 0, 0, 1);\n      gl.clear(gl.COLOR_BUFFER_BIT);\n    }\n\n    // Bind distortion program and mesh\n    gl.useProgram(self.program);\n\n    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer);\n\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\n    gl.activeTexture(gl.TEXTURE0);\n    gl.uniform1i(self.uniforms.diffuse, 0);\n    gl.bindTexture(gl.TEXTURE_2D, self.renderTarget);\n\n    gl.uniform4fv(self.uniforms.viewportOffsetScale, self.viewportOffsetScale);\n\n    // Draws both eyes\n    gl.drawElements(gl.TRIANGLES, self.indexCount, gl.UNSIGNED_SHORT, 0);\n\n    if (self.cardboardUI) {\n      self.cardboardUI.renderNoState();\n    }\n\n    // Bind the fake default framebuffer again\n    self.realBindFramebuffer.call(self.gl, gl.FRAMEBUFFER, self.framebuffer);\n\n    // If preserveDrawingBuffer == false clear the framebuffer\n    if (!self.ctxAttribs.preserveDrawingBuffer) {\n      self.realClearColor.call(gl, 0, 0, 0, 0);\n      gl.clear(gl.COLOR_BUFFER_BIT);\n    }\n\n    if (!window.WebVRConfig.DIRTY_SUBMIT_FRAME_BINDINGS) {\n      self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer);\n    }\n\n    // Restore state\n    if (self.cullFace) { self.realEnable.call(gl, gl.CULL_FACE); }\n    if (self.depthTest) { self.realEnable.call(gl, gl.DEPTH_TEST); }\n    if (self.blend) { self.realEnable.call(gl, gl.BLEND); }\n    if (self.scissorTest) { self.realEnable.call(gl, gl.SCISSOR_TEST); }\n    if (self.stencilTest) { 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  });\n\n  // Workaround for the fact that Safari doesn't allow us to patch the canvas\n  // width and height correctly. After each submit frame check to see what the\n  // real backbuffer size has been set to and resize the fake backbuffer size\n  // to match.\n  if (Util.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\n/**\n * Call when the deviceInfo has changed. At this point we need\n * to re-calculate the distortion mesh.\n */\nCardboardDistorter.prototype.updateDeviceInfo = function(deviceInfo) {\n  var gl = this.gl;\n  var self = this;\n\n  var glState = [gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING];\n  WGLUPreserveGLState(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\n    // Indices don't change based on device parameters, so only compute once.\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\n/**\n * Build the distortion mesh vertices.\n * Based on code from the Unity cardboard plugin.\n */\nCardboardDistorter.prototype.computeMeshVertices_ = function(width, height, deviceInfo) {\n  var vertices = new Float32Array(2 * width * height * 5);\n\n  var lensFrustum = deviceInfo.getLeftEyeVisibleTanAngles();\n  var noLensFrustum = deviceInfo.getLeftEyeNoLensTanAngles();\n  var viewport = deviceInfo.getLeftEyeVisibleScreenRect(noLensFrustum);\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        var u = i / (width - 1);\n        var v = j / (height - 1);\n\n        // Grid points regularly spaced in StreoScreen, and barrel distorted in\n        // the mesh.\n        var s = u;\n        var t = v;\n        var x = Util.lerp(lensFrustum[0], lensFrustum[2], u);\n        var y = Util.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\n        // Convert u,v to mesh screen coordinates.\n        var aspect = deviceInfo.device.widthMeters / deviceInfo.device.heightMeters;\n\n        // FIXME: The original Unity plugin multiplied U by the aspect ratio\n        // and didn't multiply either value by 2, but that seems to get it\n        // really close to correct looking for me. I hate this kind of \"Don't\n        // know why it works\" code though, and wold love a more logical\n        // explanation of what needs to happen here.\n        u = (viewport.x + u * viewport.width - 0.5) * 2.0; //* aspect;\n        v = (viewport.y + v * viewport.height - 0.5) * 2.0;\n\n        vertices[(vidx * 5) + 0] = u; // position.x\n        vertices[(vidx * 5) + 1] = v; // position.y\n        vertices[(vidx * 5) + 2] = s; // texCoord.x\n        vertices[(vidx * 5) + 3] = t; // texCoord.y\n        vertices[(vidx * 5) + 4] = e; // texCoord.z (viewport index)\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\n/**\n * Build the distortion mesh indices.\n * Based on code from the Unity cardboard plugin.\n */\nCardboardDistorter.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)\n          continue;\n        // Build a quad.  Lower right and upper left quadrants have quads with\n        // the triangle diagonal flipped to get the vignette to interpolate\n        // correctly.\n        if ((i <= halfwidth) == (j <= halfheight)) {\n          // Quad diagonal lower left to upper right.\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          // Quad diagonal upper left to lower right.\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\nCardboardDistorter.prototype.getOwnPropertyDescriptor_ = function(proto, attrName) {\n  var descriptor = Object.getOwnPropertyDescriptor(proto, attrName);\n  // In some cases (ahem... Safari), the descriptor returns undefined get and\n  // set fields. In this case, we need to create a synthetic property\n  // descriptor. This works around some of the issues in\n  // https://github.com/borismus/webvr-polyfill/issues/46\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\nmodule.exports = CardboardDistorter;\n\n},{\"./cardboard-ui.js\":50,\"./deps/wglu-preserve-state.js\":52,\"./util.js\":68}],50:[function(_dereq_,module,exports){\n/*\n * Copyright 2016 Google Inc. All Rights Reserved.\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\nvar Util = _dereq_('./util.js');\nvar WGLUPreserveGLState = _dereq_('./deps/wglu-preserve-state.js');\n\nvar uiVS = [\n  'attribute vec2 position;',\n\n  'uniform mat4 projectionMat;',\n\n  'void main() {',\n  '  gl_Position = projectionMat * vec4( position, -1.0, 1.0 );',\n  '}',\n].join('\\n');\n\nvar uiFS = [\n  'precision mediump float;',\n\n  'uniform vec4 color;',\n\n  'void main() {',\n  '  gl_FragColor = color;',\n  '}',\n].join('\\n');\n\nvar DEG2RAD = Math.PI/180.0;\n\n// The gear has 6 identical sections, each spanning 60 degrees.\nvar kAnglePerGearSection = 60;\n\n// Half-angle of the span of the outer rim.\nvar kOuterRimEndAngle = 12;\n\n// Angle between the middle of the outer rim and the start of the inner rim.\nvar kInnerRimBeginAngle = 20;\n\n// Distance from center to outer rim, normalized so that the entire model\n// fits in a [-1, 1] x [-1, 1] square.\nvar kOuterRadius = 1;\n\n// Distance from center to depressed rim, in model units.\nvar kMiddleRadius = 0.75;\n\n// Radius of the inner hollow circle, in model units.\nvar kInnerRadius = 0.3125;\n\n// Center line thickness in DP.\nvar kCenterLineThicknessDp = 4;\n\n// Button width in DP.\nvar kButtonWidthDp = 28;\n\n// Factor to scale the touch area that responds to the touch.\nvar kTouchSlopFactor = 1.5;\n\nvar Angles = [\n  0, kOuterRimEndAngle, kInnerRimBeginAngle,\n  kAnglePerGearSection - kInnerRimBeginAngle,\n  kAnglePerGearSection - kOuterRimEndAngle\n];\n\n/**\n * Renders the alignment line and \"options\" gear. It is assumed that the canvas\n * this is rendered into covers the entire screen (or close to it.)\n */\nfunction CardboardUI(gl) {\n  this.gl = gl;\n\n  this.attribs = {\n    position: 0\n  };\n  this.program = Util.linkProgram(gl, uiVS, uiFS, this.attribs);\n  this.uniforms = Util.getProgramUniforms(gl, this.program);\n\n  this.vertexBuffer = gl.createBuffer();\n  this.gearOffset = 0;\n  this.gearVertexCount = 0;\n  this.arrowOffset = 0;\n  this.arrowVertexCount = 0;\n\n  this.projMat = new Float32Array(16);\n\n  this.listener = null;\n\n  this.onResize();\n};\n\n/**\n * Tears down all the resources created by the UI renderer.\n */\nCardboardUI.prototype.destroy = function() {\n  var gl = this.gl;\n\n  if (this.listener) {\n    gl.canvas.removeEventListener('click', this.listener, false);\n  }\n\n  gl.deleteProgram(this.program);\n  gl.deleteBuffer(this.vertexBuffer);\n};\n\n/**\n * Adds a listener to clicks on the gear and back icons\n */\nCardboardUI.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    // Check to see if the user clicked on (or around) the gear icon\n    if (event.clientX > midline - buttonSize &&\n        event.clientX < midline + buttonSize &&\n        event.clientY > canvas.clientHeight - buttonSize) {\n      optionsCallback(event);\n    }\n    // Check to see if the user clicked on (or around) the back icon\n    else if (event.clientX < buttonSize && event.clientY < buttonSize) {\n      backCallback(event);\n    }\n  };\n  canvas.addEventListener('click', this.listener, false);\n};\n\n/**\n * Builds the UI mesh.\n */\nCardboardUI.prototype.onResize = function() {\n  var gl = this.gl;\n  var self = this;\n\n  var glState = [\n    gl.ARRAY_BUFFER_BINDING\n  ];\n\n  WGLUPreserveGLState(gl, glState, function(gl) {\n    var vertices = [];\n\n    var midline = gl.drawingBufferWidth / 2;\n\n    // The gl buffer size will likely be smaller than the physical pixel count.\n    // So we need to scale the dps down based on the actual buffer size vs physical pixel count.\n    // This will properly size the ui elements no matter what the gl buffer resolution is\n    var physicalPixels = Math.max(screen.width, screen.height) * window.devicePixelRatio;\n    var scalingRatio = gl.drawingBufferWidth / physicalPixels;\n    var dps = scalingRatio *  window.devicePixelRatio;\n\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\n    // Build centerline\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\n    // Build gear\n    self.gearOffset = (vertices.length / 2);\n\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\n    for (var i = 0; i <= 6; i++) {\n      var segmentTheta = i * kAnglePerGearSection;\n\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\n    self.gearVertexCount = (vertices.length / 2) - self.gearOffset;\n\n    // Build back arrow\n    self.arrowOffset = (vertices.length / 2);\n\n    function addArrowVertex(x, y) {\n      vertices.push(buttonBorder + x, gl.drawingBufferHeight - buttonBorder - y);\n    }\n\n    var angledLineWidth = lineWidth / Math.sin(45 * DEG2RAD);\n\n    addArrowVertex(0, buttonScale);\n    addArrowVertex(buttonScale, 0);\n    addArrowVertex(buttonScale + angledLineWidth, angledLineWidth);\n    addArrowVertex(angledLineWidth, buttonScale + angledLineWidth);\n\n    addArrowVertex(angledLineWidth, buttonScale - angledLineWidth);\n    addArrowVertex(0, buttonScale);\n    addArrowVertex(buttonScale, buttonScale * 2);\n    addArrowVertex(buttonScale + angledLineWidth, (buttonScale * 2) - angledLineWidth);\n\n    addArrowVertex(angledLineWidth, buttonScale - angledLineWidth);\n    addArrowVertex(0, buttonScale);\n\n    addArrowVertex(angledLineWidth, buttonScale - lineWidth);\n    addArrowVertex(kButtonWidthDp * dps, buttonScale - lineWidth);\n    addArrowVertex(angledLineWidth, buttonScale + lineWidth);\n    addArrowVertex(kButtonWidthDp * dps, buttonScale + lineWidth);\n\n    self.arrowVertexCount = (vertices.length / 2) - self.arrowOffset;\n\n    // Buffer data\n    gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);\n    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);\n  });\n};\n\n/**\n * Performs distortion pass on the injected backbuffer, rendering it to the real\n * backbuffer.\n */\nCardboardUI.prototype.render = function() {\n  var gl = this.gl;\n  var self = this;\n\n  var glState = [\n    gl.CULL_FACE,\n    gl.DEPTH_TEST,\n    gl.BLEND,\n    gl.SCISSOR_TEST,\n    gl.STENCIL_TEST,\n    gl.COLOR_WRITEMASK,\n    gl.VIEWPORT,\n\n    gl.CURRENT_PROGRAM,\n    gl.ARRAY_BUFFER_BINDING\n  ];\n\n  WGLUPreserveGLState(gl, glState, function(gl) {\n    // Make sure the GL state is in a good place\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\n    self.renderNoState();\n  });\n};\n\nCardboardUI.prototype.renderNoState = function() {\n  var gl = this.gl;\n\n  // Bind distortion program and mesh\n  gl.useProgram(this.program);\n\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\n  gl.uniform4f(this.uniforms.color, 1.0, 1.0, 1.0, 1.0);\n\n  Util.orthoMatrix(this.projMat, 0, gl.drawingBufferWidth, 0, gl.drawingBufferHeight, 0.1, 1024.0);\n  gl.uniformMatrix4fv(this.uniforms.projectionMat, false, this.projMat);\n\n  // Draws UI element\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\nmodule.exports = CardboardUI;\n\n},{\"./deps/wglu-preserve-state.js\":52,\"./util.js\":68}],51:[function(_dereq_,module,exports){\n/*\n * Copyright 2016 Google Inc. All Rights Reserved.\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\nvar CardboardDistorter = _dereq_('./cardboard-distorter.js');\nvar CardboardUI = _dereq_('./cardboard-ui.js');\nvar DeviceInfo = _dereq_('./device-info.js');\nvar Dpdb = _dereq_('./dpdb/dpdb.js');\nvar FusionPoseSensor = _dereq_('./sensor-fusion/fusion-pose-sensor.js');\nvar RotateInstructions = _dereq_('./rotate-instructions.js');\nvar ViewerSelector = _dereq_('./viewer-selector.js');\nvar VRDisplay = _dereq_('./base.js').VRDisplay;\nvar Util = _dereq_('./util.js');\n\nvar Eye = {\n  LEFT: 'left',\n  RIGHT: 'right'\n};\n\n/**\n * VRDisplay based on mobile device parameters and DeviceMotion APIs.\n */\nfunction CardboardVRDisplay() {\n  this.displayName = 'Cardboard VRDisplay (webvr-polyfill)';\n\n  this.capabilities.hasOrientation = true;\n  this.capabilities.canPresent = true;\n\n  // \"Private\" members.\n  this.bufferScale_ = window.WebVRConfig.BUFFER_SCALE;\n  this.poseSensor_ = new FusionPoseSensor();\n  this.distorter_ = null;\n  this.cardboardUI_ = null;\n\n  this.dpdb_ = new Dpdb(true, this.onDeviceParamsUpdated_.bind(this));\n  this.deviceInfo_ = new DeviceInfo(this.dpdb_.getDeviceParams());\n\n  this.viewerSelector_ = new ViewerSelector();\n  this.viewerSelector_.onChange(this.onViewerChanged_.bind(this));\n\n  // Set the correct initial viewer.\n  this.deviceInfo_.setViewer(this.viewerSelector_.getCurrentViewer());\n\n  if (!window.WebVRConfig.ROTATE_INSTRUCTIONS_DISABLED) {\n    this.rotateInstructions_ = new RotateInstructions();\n  }\n\n  if (Util.isIOS()) {\n    // Listen for resize events to workaround this awful Safari bug.\n    window.addEventListener('resize', this.onResize_.bind(this));\n  }\n}\nCardboardVRDisplay.prototype = new VRDisplay();\n\nCardboardVRDisplay.prototype.getImmediatePose = function() {\n  return {\n    position: this.poseSensor_.getPosition(),\n    orientation: this.poseSensor_.getOrientation(),\n    linearVelocity: null,\n    linearAcceleration: null,\n    angularVelocity: null,\n    angularAcceleration: null\n  };\n};\n\nCardboardVRDisplay.prototype.resetPose = function() {\n  this.poseSensor_.resetPose();\n};\n\nCardboardVRDisplay.prototype.getEyeParameters = function(whichEye) {\n  var offset = [this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0];\n  var fieldOfView;\n\n  // TODO: FoV can be a little expensive to compute. Cache when device params change.\n  if (whichEye == Eye.LEFT) {\n    offset[0] *= -1.0;\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\n  return {\n    fieldOfView: fieldOfView,\n    offset: offset,\n    // TODO: Should be able to provide better values than these.\n    renderWidth: this.deviceInfo_.device.width * 0.5 * this.bufferScale_,\n    renderHeight: this.deviceInfo_.device.height * this.bufferScale_,\n  };\n};\n\nCardboardVRDisplay.prototype.onDeviceParamsUpdated_ = function(newParams) {\n  if (Util.isDebug()) {\n    console.log('DPDB reported that device params were updated.');\n  }\n  this.deviceInfo_.updateDeviceParams(newParams);\n\n  if (this.distorter_) {\n    this.distorter_.updateDeviceInfo(this.deviceInfo_);\n  }\n};\n\nCardboardVRDisplay.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\nCardboardVRDisplay.prototype.beginPresent_ = function() {\n  var gl = this.layer_.source.getContext('webgl');\n  if (!gl)\n    gl = this.layer_.source.getContext('experimental-webgl');\n  if (!gl)\n    gl = this.layer_.source.getContext('webgl2');\n\n  if (!gl)\n    return; // Can't do distortion without a WebGL context.\n\n  // Provides a way to opt out of distortion\n  if (this.layer_.predistorted) {\n    if (!window.WebVRConfig.CARDBOARD_UI_DISABLED) {\n      gl.canvas.width = Util.getScreenWidth() * this.bufferScale_;\n      gl.canvas.height = Util.getScreenHeight() * this.bufferScale_;\n      this.cardboardUI_ = new CardboardUI(gl);\n    }\n  } else {\n    // Create a new distorter for the target context\n    this.distorter_ = new CardboardDistorter(gl);\n    this.distorter_.updateDeviceInfo(this.deviceInfo_);\n    this.cardboardUI_ = this.distorter_.cardboardUI;\n  }\n\n  if (this.cardboardUI_) {\n    this.cardboardUI_.listen(function(e) {\n      // Options clicked.\n      this.viewerSelector_.show(this.layer_.source.parentElement);\n      e.stopPropagation();\n      e.preventDefault();\n    }.bind(this), function(e) {\n      // Back clicked.\n      this.exitPresent();\n      e.stopPropagation();\n      e.preventDefault();\n    }.bind(this));\n  }\n\n  if (this.rotateInstructions_) {\n    if (Util.isLandscapeMode() && Util.isMobile()) {\n      // In landscape mode, temporarily show the \"put into Cardboard\"\n      // interstitial. Otherwise, do the default thing.\n      this.rotateInstructions_.showTemporarily(3000, this.layer_.source.parentElement);\n    } else {\n      this.rotateInstructions_.update();\n    }\n  }\n\n  // Listen for orientation change events in order to show interstitial.\n  this.orientationHandler = this.onOrientationChange_.bind(this);\n  window.addEventListener('orientationchange', this.orientationHandler);\n\n  // Listen for present display change events in order to update distorter dimensions\n  this.vrdisplaypresentchangeHandler = this.updateBounds_.bind(this);\n  window.addEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler);\n\n  // Fire this event initially, to give geometry-distortion clients the chance\n  // to do something custom.\n  this.fireVRDisplayDeviceParamsChange_();\n};\n\nCardboardVRDisplay.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\n  if (this.rotateInstructions_) {\n    this.rotateInstructions_.hide();\n  }\n  this.viewerSelector_.hide();\n\n  window.removeEventListener('orientationchange', this.orientationHandler);\n  window.removeEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler);\n};\n\nCardboardVRDisplay.prototype.submitFrame = function(pose) {\n  if (this.distorter_) {\n    this.updateBounds_();\n    this.distorter_.submitFrame();\n  } else if (this.cardboardUI_ && this.layer_) {\n    // Hack for predistorted: true.\n    var canvas = this.layer_.source.getContext('webgl').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\n    // Render the Cardboard UI.\n    this.cardboardUI_.render();\n  }\n};\n\nCardboardVRDisplay.prototype.onOrientationChange_ = function(e) {\n  // Hide the viewer selector.\n  this.viewerSelector_.hide();\n\n  // Update the rotate instructions.\n  if (this.rotateInstructions_) {\n    this.rotateInstructions_.update();\n  }\n\n  this.onResize_();\n};\n\nCardboardVRDisplay.prototype.onResize_ = function(e) {\n  if (this.layer_) {\n    var gl = this.layer_.source.getContext('webgl');\n    // Size the CSS canvas.\n    // Added padding on right and bottom because iPhone 5 will not\n    // hide the URL bar unless content is bigger than the screen.\n    // This will not be visible as long as the container element (e.g. body)\n    // is set to 'overflow: hidden'.\n    // Additionally, 'box-sizing: content-box' ensures renderWidth = width + padding.\n    // This is required when 'box-sizing: border-box' is used elsewhere in the page.\n    var cssProperties = [\n      'position: absolute',\n      'top: 0',\n      'left: 0',\n      'width: ' + Math.max(screen.width, screen.height) + 'px',\n      'height: ' + Math.min(screen.height, screen.width) + 'px',\n      'border: 0',\n      'margin: 0',\n      'padding: 0 10px 10px 0',\n      'box-sizing: content-box',\n    ];\n    gl.canvas.setAttribute('style', cssProperties.join('; ') + ';');\n\n    Util.safariCssSizeWorkaround(gl.canvas);\n  }\n};\n\nCardboardVRDisplay.prototype.onViewerChanged_ = function(viewer) {\n  this.deviceInfo_.setViewer(viewer);\n\n  if (this.distorter_) {\n    // Update the distortion appropriately.\n    this.distorter_.updateDeviceInfo(this.deviceInfo_);\n  }\n\n  // Fire a new event containing viewer and device parameters for clients that\n  // want to implement their own geometry-based distortion.\n  this.fireVRDisplayDeviceParamsChange_();\n};\n\nCardboardVRDisplay.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\nmodule.exports = CardboardVRDisplay;\n\n},{\"./base.js\":48,\"./cardboard-distorter.js\":49,\"./cardboard-ui.js\":50,\"./device-info.js\":53,\"./dpdb/dpdb.js\":57,\"./rotate-instructions.js\":62,\"./sensor-fusion/fusion-pose-sensor.js\":64,\"./util.js\":68,\"./viewer-selector.js\":69}],52:[function(_dereq_,module,exports){\n/**\n * Copyright (c) 2016, Brandon Jones.\n * https://github.com/toji/webgl-utils/blob/master/src/wglu-preserve-state.js\n * LICENSE: https://github.com/toji/webgl-utils/blob/master/LICENSE.md\n */\n\nfunction WGLUPreserveGLState(gl, bindings, callback) {\n  if (!bindings) {\n    callback(gl);\n    return;\n  }\n\n  var boundValues = [];\n\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\n  callback(gl);\n\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; // Ignore this binding, since we special-case it to happen last.\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)\n          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)\n          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\n    if (activeTexture) {\n      gl.activeTexture(activeTexture);\n    }\n  }\n}\n\nmodule.exports = WGLUPreserveGLState;\n\n},{}],53:[function(_dereq_,module,exports){\n/*\n * Copyright 2015 Google Inc. All Rights Reserved.\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\nvar Distortion = _dereq_('./distortion/distortion.js');\nvar MathUtil = _dereq_('./math-util.js');\nvar Util = _dereq_('./util.js');\n\nfunction Device(params) {\n  this.width = params.width || Util.getScreenWidth();\n  this.height = params.height || Util.getScreenHeight();\n  this.widthMeters = params.widthMeters;\n  this.heightMeters = params.heightMeters;\n  this.bevelMeters = params.bevelMeters;\n}\n\n\n// Fallback Android device (based on Nexus 5 measurements) for use when\n// we can't recognize an Android device.\nvar DEFAULT_ANDROID = new Device({\n  widthMeters: 0.110,\n  heightMeters: 0.062,\n  bevelMeters: 0.004\n});\n\n// Fallback iOS device (based on iPhone6) for use when\n// we can't recognize an Android device.\nvar DEFAULT_IOS = new Device({\n  widthMeters: 0.1038,\n  heightMeters: 0.0584,\n  bevelMeters: 0.004\n});\n\n\nvar 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,\n      -0.58821183, 0.5733938, -0.48303202, 0.33299083, -0.17573841,\n      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,\n      1.0560602, -0.58208317, 0.21609078, -0.05444823, 0.009177956,\n      -9.904169E-4, 6.183535E-5, -1.6981803E-6]\n  })\n};\n\n\nvar DEFAULT_LEFT_CENTER = {x: 0.5, y: 0.5};\nvar DEFAULT_RIGHT_CENTER = {x: 0.5, y: 0.5};\n\n/**\n * Manages information about the device and the viewer.\n *\n * deviceParams indicates the parameters of the device to use (generally\n * obtained from dpdb.getDeviceParams()). Can be null to mean no device\n * params were found.\n */\nfunction DeviceInfo(deviceParams) {\n  this.viewer = Viewers.CardboardV2;\n  this.updateDeviceParams(deviceParams);\n  this.distortion = new Distortion(this.viewer.distortionCoefficients);\n}\n\nDeviceInfo.prototype.updateDeviceParams = function(deviceParams) {\n  this.device = this.determineDevice_(deviceParams) || this.device;\n};\n\nDeviceInfo.prototype.getDevice = function() {\n  return this.device;\n};\n\nDeviceInfo.prototype.setViewer = function(viewer) {\n  this.viewer = viewer;\n  this.distortion = new Distortion(this.viewer.distortionCoefficients);\n};\n\nDeviceInfo.prototype.determineDevice_ = function(deviceParams) {\n  if (!deviceParams) {\n    // No parameters, so use a default.\n    if (Util.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\n  // Compute device screen dimensions based on deviceParams.\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 = Util.getScreenWidth();\n  var height = Util.getScreenHeight();\n  return new Device({\n    widthMeters: metersPerPixelX * width,\n    heightMeters: metersPerPixelY * height,\n    bevelMeters: deviceParams.bevelMm * 0.001,\n  });\n};\n\n/**\n * Calculates field of view for the left eye.\n */\nDeviceInfo.prototype.getDistortedFieldOfViewLeftEye = function() {\n  var viewer = this.viewer;\n  var device = this.device;\n  var distortion = this.distortion;\n\n  // Device.height and device.width for device in portrait mode, so transpose.\n  var eyeToScreenDistance = viewer.screenLensDistance;\n\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\n  var outerAngle = MathUtil.radToDeg * Math.atan(\n      distortion.distort(outerDist / eyeToScreenDistance));\n  var innerAngle = MathUtil.radToDeg * Math.atan(\n      distortion.distort(innerDist / eyeToScreenDistance));\n  var bottomAngle = MathUtil.radToDeg * Math.atan(\n      distortion.distort(bottomDist / eyeToScreenDistance));\n  var topAngle = MathUtil.radToDeg * Math.atan(\n      distortion.distort(topDist / eyeToScreenDistance));\n\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\n/**\n * Calculates the tan-angles from the maximum FOV for the left eye for the\n * current device and screen parameters.\n */\nDeviceInfo.prototype.getLeftEyeVisibleTanAngles = function() {\n  var viewer = this.viewer;\n  var device = this.device;\n  var distortion = this.distortion;\n\n  // Tan-angles from the max FOV.\n  var fovLeft = Math.tan(-MathUtil.degToRad * viewer.fov);\n  var fovTop = Math.tan(MathUtil.degToRad * viewer.fov);\n  var fovRight = Math.tan(MathUtil.degToRad * viewer.fov);\n  var fovBottom = Math.tan(-MathUtil.degToRad * viewer.fov);\n  // Viewport size.\n  var halfWidth = device.widthMeters / 4;\n  var halfHeight = device.heightMeters / 2;\n  // Viewport center, measured from left lens position.\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  // Tan-angles of the viewport edges, as seen through the lens.\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  // Compare the two sets of tan-angles and take the value closer to zero on each side.\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\n/**\n * Calculates the tan-angles from the maximum FOV for the left eye for the\n * current device and screen parameters, assuming no lenses.\n */\nDeviceInfo.prototype.getLeftEyeNoLensTanAngles = function() {\n  var viewer = this.viewer;\n  var device = this.device;\n  var distortion = this.distortion;\n\n  var result = new Float32Array(4);\n  // Tan-angles from the max FOV.\n  var fovLeft = distortion.distortInverse(Math.tan(-MathUtil.degToRad * viewer.fov));\n  var fovTop = distortion.distortInverse(Math.tan(MathUtil.degToRad * viewer.fov));\n  var fovRight = distortion.distortInverse(Math.tan(MathUtil.degToRad * viewer.fov));\n  var fovBottom = distortion.distortInverse(Math.tan(-MathUtil.degToRad * viewer.fov));\n  // Viewport size.\n  var halfWidth = device.widthMeters / 4;\n  var halfHeight = device.heightMeters / 2;\n  // Viewport center, measured from left lens position.\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  // Tan-angles of the viewport edges, as seen through the lens.\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  // Compare the two sets of tan-angles and take the value closer to zero on each side.\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\n/**\n * Calculates the screen rectangle visible from the left eye for the\n * current device and screen parameters.\n */\nDeviceInfo.prototype.getLeftEyeVisibleScreenRect = function(undistortedFrustum) {\n  var viewer = this.viewer;\n  var device = this.device;\n\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\nDeviceInfo.prototype.getFieldOfViewLeftEye = function(opt_isUndistorted) {\n  return opt_isUndistorted ? this.getUndistortedFieldOfViewLeftEye() :\n      this.getDistortedFieldOfViewLeftEye();\n};\n\nDeviceInfo.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\n/**\n * Calculates undistorted field of view for the left eye.\n */\nDeviceInfo.prototype.getUndistortedFieldOfViewLeftEye = function() {\n  var p = this.getUndistortedParams_();\n\n  return {\n    leftDegrees: MathUtil.radToDeg * Math.atan(p.outerDist),\n    rightDegrees: MathUtil.radToDeg * Math.atan(p.innerDist),\n    downDegrees: MathUtil.radToDeg * Math.atan(p.bottomDist),\n    upDegrees: MathUtil.radToDeg * Math.atan(p.topDist)\n  };\n};\n\nDeviceInfo.prototype.getUndistortedViewportLeftEye = function() {\n  var p = this.getUndistortedParams_();\n  var viewer = this.viewer;\n  var device = this.device;\n\n  // Distances stored in local variables are in tan-angle units unless otherwise\n  // noted.\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\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\nDeviceInfo.prototype.getUndistortedParams_ = function() {\n  var viewer = this.viewer;\n  var device = this.device;\n  var distortion = this.distortion;\n\n  // Most of these variables in tan-angle units.\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\n  var eyePosX = screenWidth / 2 - halfLensDistance;\n  var eyePosY = (viewer.baselineLensDistance - device.bevelMeters) / eyeToScreenDistance;\n\n  var maxFov = viewer.fov;\n  var viewerMax = distortion.distortInverse(Math.tan(MathUtil.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\n  return {\n    outerDist: outerDist,\n    innerDist: innerDist,\n    topDist: topDist,\n    bottomDist: bottomDist,\n    eyePosX: eyePosX,\n    eyePosY: eyePosY\n  };\n};\n\n\nfunction CardboardViewer(params) {\n  // A machine readable ID.\n  this.id = params.id;\n  // A human readable label.\n  this.label = params.label;\n\n  // Field of view in degrees (per side).\n  this.fov = params.fov;\n\n  // Distance between lens centers in meters.\n  this.interLensDistance = params.interLensDistance;\n  // Distance between viewer baseline and lens center in meters.\n  this.baselineLensDistance = params.baselineLensDistance;\n  // Screen-to-lens distance in meters.\n  this.screenLensDistance = params.screenLensDistance;\n\n  // Distortion coefficients.\n  this.distortionCoefficients = params.distortionCoefficients;\n  // Inverse distortion coefficients.\n  // TODO: Calculate these from distortionCoefficients in the future.\n  this.inverseCoefficients = params.inverseCoefficients;\n}\n\n// Export viewer information.\nDeviceInfo.Viewers = Viewers;\nmodule.exports = DeviceInfo;\n\n},{\"./distortion/distortion.js\":55,\"./math-util.js\":59,\"./util.js\":68}],54:[function(_dereq_,module,exports){\n/*\n * Copyright 2016 Google Inc. All Rights Reserved.\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 */\nvar VRDisplay = _dereq_('./base.js').VRDisplay;\nvar HMDVRDevice = _dereq_('./base.js').HMDVRDevice;\nvar PositionSensorVRDevice = _dereq_('./base.js').PositionSensorVRDevice;\n\n/**\n * Wraps a VRDisplay and exposes it as a HMDVRDevice\n */\nfunction VRDisplayHMDDevice(display) {\n  this.display = display;\n\n  this.hardwareUnitId = display.displayId;\n  this.deviceId = 'webvr-polyfill:HMD:' + display.displayId;\n  this.deviceName = display.displayName + ' (HMD)';\n}\nVRDisplayHMDDevice.prototype = new HMDVRDevice();\n\nVRDisplayHMDDevice.prototype.getEyeParameters = function(whichEye) {\n  var eyeParameters = this.display.getEyeParameters(whichEye);\n\n  return {\n    currentFieldOfView: eyeParameters.fieldOfView,\n    maximumFieldOfView: eyeParameters.fieldOfView,\n    minimumFieldOfView: eyeParameters.fieldOfView,\n    recommendedFieldOfView: eyeParameters.fieldOfView,\n    eyeTranslation: { x: eyeParameters.offset[0], y: eyeParameters.offset[1], z: eyeParameters.offset[2] },\n    renderRect: {\n      x: (whichEye == 'right') ? eyeParameters.renderWidth : 0,\n      y: 0,\n      width: eyeParameters.renderWidth,\n      height: eyeParameters.renderHeight\n    }\n  };\n};\n\nVRDisplayHMDDevice.prototype.setFieldOfView =\n    function(opt_fovLeft, opt_fovRight, opt_zNear, opt_zFar) {\n  // Not supported. getEyeParameters reports that the min, max, and recommended\n  // FoV is all the same, so no adjustment can be made.\n};\n\n// TODO: Need to hook requestFullscreen to see if a wrapped VRDisplay was passed\n// in as an option. If so we should prevent the default fullscreen behavior and\n// call VRDisplay.requestPresent instead.\n\n/**\n * Wraps a VRDisplay and exposes it as a PositionSensorVRDevice\n */\nfunction VRDisplayPositionSensorDevice(display) {\n  this.display = display;\n\n  this.hardwareUnitId = display.displayId;\n  this.deviceId = 'webvr-polyfill:PositionSensor: ' + display.displayId;\n  this.deviceName = display.displayName + ' (PositionSensor)';\n}\nVRDisplayPositionSensorDevice.prototype = new PositionSensorVRDevice();\n\nVRDisplayPositionSensorDevice.prototype.getState = function() {\n  var pose = this.display.getPose();\n  return {\n    position: pose.position ? { x: pose.position[0], y: pose.position[1], z: pose.position[2] } : null,\n    orientation: pose.orientation ? { x: pose.orientation[0], y: pose.orientation[1], z: pose.orientation[2], w: pose.orientation[3] } : null,\n    linearVelocity: null,\n    linearAcceleration: null,\n    angularVelocity: null,\n    angularAcceleration: null\n  };\n};\n\nVRDisplayPositionSensorDevice.prototype.resetState = function() {\n  return this.positionDevice.resetPose();\n};\n\n\nmodule.exports.VRDisplayHMDDevice = VRDisplayHMDDevice;\nmodule.exports.VRDisplayPositionSensorDevice = VRDisplayPositionSensorDevice;\n\n\n},{\"./base.js\":48}],55:[function(_dereq_,module,exports){\n/**\n * TODO(smus): Implement coefficient inversion.\n */\nfunction Distortion(coefficients) {\n  this.coefficients = coefficients;\n}\n\n/**\n * Calculates the inverse distortion for a radius.\n * </p><p>\n * Allows to compute the original undistorted radius from a distorted one.\n * See also getApproximateInverseDistortion() for a faster but potentially\n * less accurate method.\n *\n * @param {Number} radius Distorted radius from the lens center in tan-angle units.\n * @return {Number} The undistorted radius in tan-angle units.\n */\nDistortion.prototype.distortInverse = function(radius) {\n  // Secant method.\n  var r0 = 0;\n  var r1 = 1;\n  var dr0 = radius - this.distort(r0);\n  while (Math.abs(r1 - r0) > 0.0001 /** 0.1mm */) {\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\n/**\n * Distorts a radius by its distortion factor from the center of the lenses.\n *\n * @param {Number} radius Radius from the lens center in tan-angle units.\n * @return {Number} The distorted radius in tan-angle units.\n */\nDistortion.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\nmodule.exports = Distortion;\n\n},{}],56:[function(_dereq_,module,exports){\nmodule.exports={\n  \"format\": 1,\n  \"last_updated\": \"2017-08-27T14:39:31Z\",\n  \"devices\": [\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"asus/*/Nexus 7/*\"\n        },\n        {\n          \"ua\": \"Nexus 7\"\n        }\n      ],\n      \"dpi\": [\n        320.8,\n        323\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"asus/*/ASUS_Z00AD/*\"\n        },\n        {\n          \"ua\": \"ASUS_Z00AD\"\n        }\n      ],\n      \"dpi\": [\n        403,\n        404.6\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"Google/*/Pixel XL/*\"\n        },\n        {\n          \"ua\": \"Pixel XL\"\n        }\n      ],\n      \"dpi\": [\n        537.9,\n        533\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"Google/*/Pixel/*\"\n        },\n        {\n          \"ua\": \"Pixel\"\n        }\n      ],\n      \"dpi\": [\n        432.6,\n        436.7\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"HTC/*/HTC6435LVW/*\"\n        },\n        {\n          \"ua\": \"HTC6435LVW\"\n        }\n      ],\n      \"dpi\": [\n        449.7,\n        443.3\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"HTC/*/HTC One XL/*\"\n        },\n        {\n          \"ua\": \"HTC One XL\"\n        }\n      ],\n      \"dpi\": [\n        315.3,\n        314.6\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"htc/*/Nexus 9/*\"\n        },\n        {\n          \"ua\": \"Nexus 9\"\n        }\n      ],\n      \"dpi\": 289,\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"HTC/*/HTC One M9/*\"\n        },\n        {\n          \"ua\": \"HTC One M9\"\n        }\n      ],\n      \"dpi\": [\n        442.5,\n        443.3\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"HTC/*/HTC One_M8/*\"\n        },\n        {\n          \"ua\": \"HTC One_M8\"\n        }\n      ],\n      \"dpi\": [\n        449.7,\n        447.4\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"HTC/*/HTC One/*\"\n        },\n        {\n          \"ua\": \"HTC One\"\n        }\n      ],\n      \"dpi\": 472.8,\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"Huawei/*/Nexus 6P/*\"\n        },\n        {\n          \"ua\": \"Nexus 6P\"\n        }\n      ],\n      \"dpi\": [\n        515.1,\n        518\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"LENOVO/*/Lenovo PB2-690Y/*\"\n        },\n        {\n          \"ua\": \"Lenovo PB2-690Y\"\n        }\n      ],\n      \"dpi\": [\n        457.2,\n        454.713\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"LGE/*/Nexus 5X/*\"\n        },\n        {\n          \"ua\": \"Nexus 5X\"\n        }\n      ],\n      \"dpi\": [\n        422,\n        419.9\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"LGE/*/LGMS345/*\"\n        },\n        {\n          \"ua\": \"LGMS345\"\n        }\n      ],\n      \"dpi\": [\n        221.7,\n        219.1\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"LGE/*/LG-D800/*\"\n        },\n        {\n          \"ua\": \"LG-D800\"\n        }\n      ],\n      \"dpi\": [\n        422,\n        424.1\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"LGE/*/LG-D850/*\"\n        },\n        {\n          \"ua\": \"LG-D850\"\n        }\n      ],\n      \"dpi\": [\n        537.9,\n        541.9\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"LGE/*/VS985 4G/*\"\n        },\n        {\n          \"ua\": \"VS985 4G\"\n        }\n      ],\n      \"dpi\": [\n        537.9,\n        535.6\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"LGE/*/Nexus 5/*\"\n        },\n        {\n          \"ua\": \"Nexus 5 B\"\n        }\n      ],\n      \"dpi\": [\n        442.4,\n        444.8\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"LGE/*/Nexus 4/*\"\n        },\n        {\n          \"ua\": \"Nexus 4\"\n        }\n      ],\n      \"dpi\": [\n        319.8,\n        318.4\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"LGE/*/LG-P769/*\"\n        },\n        {\n          \"ua\": \"LG-P769\"\n        }\n      ],\n      \"dpi\": [\n        240.6,\n        247.5\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"LGE/*/LGMS323/*\"\n        },\n        {\n          \"ua\": \"LGMS323\"\n        }\n      ],\n      \"dpi\": [\n        206.6,\n        204.6\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"LGE/*/LGLS996/*\"\n        },\n        {\n          \"ua\": \"LGLS996\"\n        }\n      ],\n      \"dpi\": [\n        403.4,\n        401.5\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"Micromax/*/4560MMX/*\"\n        },\n        {\n          \"ua\": \"4560MMX\"\n        }\n      ],\n      \"dpi\": [\n        240,\n        219.4\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"Micromax/*/A250/*\"\n        },\n        {\n          \"ua\": \"Micromax A250\"\n        }\n      ],\n      \"dpi\": [\n        480,\n        446.4\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"Micromax/*/Micromax AQ4501/*\"\n        },\n        {\n          \"ua\": \"Micromax AQ4501\"\n        }\n      ],\n      \"dpi\": 240,\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"motorola/*/DROID RAZR/*\"\n        },\n        {\n          \"ua\": \"DROID RAZR\"\n        }\n      ],\n      \"dpi\": [\n        368.1,\n        256.7\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"motorola/*/XT830C/*\"\n        },\n        {\n          \"ua\": \"XT830C\"\n        }\n      ],\n      \"dpi\": [\n        254,\n        255.9\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"motorola/*/XT1021/*\"\n        },\n        {\n          \"ua\": \"XT1021\"\n        }\n      ],\n      \"dpi\": [\n        254,\n        256.7\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"motorola/*/XT1023/*\"\n        },\n        {\n          \"ua\": \"XT1023\"\n        }\n      ],\n      \"dpi\": [\n        254,\n        256.7\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"motorola/*/XT1028/*\"\n        },\n        {\n          \"ua\": \"XT1028\"\n        }\n      ],\n      \"dpi\": [\n        326.6,\n        327.6\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"motorola/*/XT1034/*\"\n        },\n        {\n          \"ua\": \"XT1034\"\n        }\n      ],\n      \"dpi\": [\n        326.6,\n        328.4\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"motorola/*/XT1053/*\"\n        },\n        {\n          \"ua\": \"XT1053\"\n        }\n      ],\n      \"dpi\": [\n        315.3,\n        316.1\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"motorola/*/XT1562/*\"\n        },\n        {\n          \"ua\": \"XT1562\"\n        }\n      ],\n      \"dpi\": [\n        403.4,\n        402.7\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"motorola/*/Nexus 6/*\"\n        },\n        {\n          \"ua\": \"Nexus 6 B\"\n        }\n      ],\n      \"dpi\": [\n        494.3,\n        489.7\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"motorola/*/XT1063/*\"\n        },\n        {\n          \"ua\": \"XT1063\"\n        }\n      ],\n      \"dpi\": [\n        295,\n        296.6\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"motorola/*/XT1064/*\"\n        },\n        {\n          \"ua\": \"XT1064\"\n        }\n      ],\n      \"dpi\": [\n        295,\n        295.6\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"motorola/*/XT1092/*\"\n        },\n        {\n          \"ua\": \"XT1092\"\n        }\n      ],\n      \"dpi\": [\n        422,\n        424.1\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"motorola/*/XT1095/*\"\n        },\n        {\n          \"ua\": \"XT1095\"\n        }\n      ],\n      \"dpi\": [\n        422,\n        423.4\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"motorola/*/G4/*\"\n        },\n        {\n          \"ua\": \"Moto G (4)\"\n        }\n      ],\n      \"dpi\": 401,\n      \"bw\": 4,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"OnePlus/*/A0001/*\"\n        },\n        {\n          \"ua\": \"A0001\"\n        }\n      ],\n      \"dpi\": [\n        403.4,\n        401\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"OnePlus/*/ONE E1005/*\"\n        },\n        {\n          \"ua\": \"ONE E1005\"\n        }\n      ],\n      \"dpi\": [\n        442.4,\n        441.4\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"OnePlus/*/ONE A2005/*\"\n        },\n        {\n          \"ua\": \"ONE A2005\"\n        }\n      ],\n      \"dpi\": [\n        391.9,\n        405.4\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"OPPO/*/X909/*\"\n        },\n        {\n          \"ua\": \"X909\"\n        }\n      ],\n      \"dpi\": [\n        442.4,\n        444.1\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/GT-I9082/*\"\n        },\n        {\n          \"ua\": \"GT-I9082\"\n        }\n      ],\n      \"dpi\": [\n        184.7,\n        185.4\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-G360P/*\"\n        },\n        {\n          \"ua\": \"SM-G360P\"\n        }\n      ],\n      \"dpi\": [\n        196.7,\n        205.4\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/Nexus S/*\"\n        },\n        {\n          \"ua\": \"Nexus S\"\n        }\n      ],\n      \"dpi\": [\n        234.5,\n        229.8\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/GT-I9300/*\"\n        },\n        {\n          \"ua\": \"GT-I9300\"\n        }\n      ],\n      \"dpi\": [\n        304.8,\n        303.9\n      ],\n      \"bw\": 5,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-T230NU/*\"\n        },\n        {\n          \"ua\": \"SM-T230NU\"\n        }\n      ],\n      \"dpi\": 216,\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SGH-T399/*\"\n        },\n        {\n          \"ua\": \"SGH-T399\"\n        }\n      ],\n      \"dpi\": [\n        217.7,\n        231.4\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SGH-M919/*\"\n        },\n        {\n          \"ua\": \"SGH-M919\"\n        }\n      ],\n      \"dpi\": [\n        440.8,\n        437.7\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-N9005/*\"\n        },\n        {\n          \"ua\": \"SM-N9005\"\n        }\n      ],\n      \"dpi\": [\n        386.4,\n        387\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SAMSUNG-SM-N900A/*\"\n        },\n        {\n          \"ua\": \"SAMSUNG-SM-N900A\"\n        }\n      ],\n      \"dpi\": [\n        386.4,\n        387.7\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/GT-I9500/*\"\n        },\n        {\n          \"ua\": \"GT-I9500\"\n        }\n      ],\n      \"dpi\": [\n        442.5,\n        443.3\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/GT-I9505/*\"\n        },\n        {\n          \"ua\": \"GT-I9505\"\n        }\n      ],\n      \"dpi\": 439.4,\n      \"bw\": 4,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-G900F/*\"\n        },\n        {\n          \"ua\": \"SM-G900F\"\n        }\n      ],\n      \"dpi\": [\n        415.6,\n        431.6\n      ],\n      \"bw\": 5,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-G900M/*\"\n        },\n        {\n          \"ua\": \"SM-G900M\"\n        }\n      ],\n      \"dpi\": [\n        415.6,\n        431.6\n      ],\n      \"bw\": 5,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-G800F/*\"\n        },\n        {\n          \"ua\": \"SM-G800F\"\n        }\n      ],\n      \"dpi\": 326.8,\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-G906S/*\"\n        },\n        {\n          \"ua\": \"SM-G906S\"\n        }\n      ],\n      \"dpi\": [\n        562.7,\n        572.4\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/GT-I9300/*\"\n        },\n        {\n          \"ua\": \"GT-I9300\"\n        }\n      ],\n      \"dpi\": [\n        306.7,\n        304.8\n      ],\n      \"bw\": 5,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-T535/*\"\n        },\n        {\n          \"ua\": \"SM-T535\"\n        }\n      ],\n      \"dpi\": [\n        142.6,\n        136.4\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-N920C/*\"\n        },\n        {\n          \"ua\": \"SM-N920C\"\n        }\n      ],\n      \"dpi\": [\n        515.1,\n        518.4\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-N920W8/*\"\n        },\n        {\n          \"ua\": \"SM-N920W8\"\n        }\n      ],\n      \"dpi\": [\n        515.1,\n        518.4\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/GT-I9300I/*\"\n        },\n        {\n          \"ua\": \"GT-I9300I\"\n        }\n      ],\n      \"dpi\": [\n        304.8,\n        305.8\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/GT-I9195/*\"\n        },\n        {\n          \"ua\": \"GT-I9195\"\n        }\n      ],\n      \"dpi\": [\n        249.4,\n        256.7\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SPH-L520/*\"\n        },\n        {\n          \"ua\": \"SPH-L520\"\n        }\n      ],\n      \"dpi\": [\n        249.4,\n        255.9\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SAMSUNG-SGH-I717/*\"\n        },\n        {\n          \"ua\": \"SAMSUNG-SGH-I717\"\n        }\n      ],\n      \"dpi\": 285.8,\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SPH-D710/*\"\n        },\n        {\n          \"ua\": \"SPH-D710\"\n        }\n      ],\n      \"dpi\": [\n        217.7,\n        204.2\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/GT-N7100/*\"\n        },\n        {\n          \"ua\": \"GT-N7100\"\n        }\n      ],\n      \"dpi\": 265.1,\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SCH-I605/*\"\n        },\n        {\n          \"ua\": \"SCH-I605\"\n        }\n      ],\n      \"dpi\": 265.1,\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/Galaxy Nexus/*\"\n        },\n        {\n          \"ua\": \"Galaxy Nexus\"\n        }\n      ],\n      \"dpi\": [\n        315.3,\n        314.2\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-N910H/*\"\n        },\n        {\n          \"ua\": \"SM-N910H\"\n        }\n      ],\n      \"dpi\": [\n        515.1,\n        518\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-N910C/*\"\n        },\n        {\n          \"ua\": \"SM-N910C\"\n        }\n      ],\n      \"dpi\": [\n        515.2,\n        520.2\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-G130M/*\"\n        },\n        {\n          \"ua\": \"SM-G130M\"\n        }\n      ],\n      \"dpi\": [\n        165.9,\n        164.8\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-G928I/*\"\n        },\n        {\n          \"ua\": \"SM-G928I\"\n        }\n      ],\n      \"dpi\": [\n        515.1,\n        518.4\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-G920F/*\"\n        },\n        {\n          \"ua\": \"SM-G920F\"\n        }\n      ],\n      \"dpi\": 580.6,\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-G920P/*\"\n        },\n        {\n          \"ua\": \"SM-G920P\"\n        }\n      ],\n      \"dpi\": [\n        522.5,\n        577\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-G925F/*\"\n        },\n        {\n          \"ua\": \"SM-G925F\"\n        }\n      ],\n      \"dpi\": 580.6,\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-G925V/*\"\n        },\n        {\n          \"ua\": \"SM-G925V\"\n        }\n      ],\n      \"dpi\": [\n        522.5,\n        576.6\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-G930F/*\"\n        },\n        {\n          \"ua\": \"SM-G930F\"\n        }\n      ],\n      \"dpi\": 576.6,\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-G935F/*\"\n        },\n        {\n          \"ua\": \"SM-G935F\"\n        }\n      ],\n      \"dpi\": 533,\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-G950F/*\"\n        },\n        {\n          \"ua\": \"SM-G950F\"\n        }\n      ],\n      \"dpi\": [\n        562.707,\n        565.293\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"samsung/*/SM-G955U/*\"\n        },\n        {\n          \"ua\": \"SM-G955U\"\n        }\n      ],\n      \"dpi\": [\n        522.514,\n        525.762\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"Sony/*/C6903/*\"\n        },\n        {\n          \"ua\": \"C6903\"\n        }\n      ],\n      \"dpi\": [\n        442.5,\n        443.3\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"Sony/*/D6653/*\"\n        },\n        {\n          \"ua\": \"D6653\"\n        }\n      ],\n      \"dpi\": [\n        428.6,\n        427.6\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"Sony/*/E6653/*\"\n        },\n        {\n          \"ua\": \"E6653\"\n        }\n      ],\n      \"dpi\": [\n        428.6,\n        425.7\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"Sony/*/E6853/*\"\n        },\n        {\n          \"ua\": \"E6853\"\n        }\n      ],\n      \"dpi\": [\n        403.4,\n        401.9\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"Sony/*/SGP321/*\"\n        },\n        {\n          \"ua\": \"SGP321\"\n        }\n      ],\n      \"dpi\": [\n        224.7,\n        224.1\n      ],\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"TCT/*/ALCATEL ONE TOUCH Fierce/*\"\n        },\n        {\n          \"ua\": \"ALCATEL ONE TOUCH Fierce\"\n        }\n      ],\n      \"dpi\": [\n        240,\n        247.5\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"THL/*/thl 5000/*\"\n        },\n        {\n          \"ua\": \"thl 5000\"\n        }\n      ],\n      \"dpi\": [\n        480,\n        443.3\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"android\",\n      \"rules\": [\n        {\n          \"mdmh\": \"ZTE/*/ZTE Blade L2/*\"\n        },\n        {\n          \"ua\": \"ZTE Blade L2\"\n        }\n      ],\n      \"dpi\": 240,\n      \"bw\": 3,\n      \"ac\": 500\n    },\n    {\n      \"type\": \"ios\",\n      \"rules\": [\n        {\n          \"res\": [\n            640,\n            960\n          ]\n        }\n      ],\n      \"dpi\": [\n        325.1,\n        328.4\n      ],\n      \"bw\": 4,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"ios\",\n      \"rules\": [\n        {\n          \"res\": [\n            640,\n            1136\n          ]\n        }\n      ],\n      \"dpi\": [\n        317.1,\n        320.2\n      ],\n      \"bw\": 3,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"ios\",\n      \"rules\": [\n        {\n          \"res\": [\n            750,\n            1334\n          ]\n        }\n      ],\n      \"dpi\": 326.4,\n      \"bw\": 4,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"ios\",\n      \"rules\": [\n        {\n          \"res\": [\n            1242,\n            2208\n          ]\n        }\n      ],\n      \"dpi\": [\n        453.6,\n        458.4\n      ],\n      \"bw\": 4,\n      \"ac\": 1000\n    },\n    {\n      \"type\": \"ios\",\n      \"rules\": [\n        {\n          \"res\": [\n            1125,\n            2001\n          ]\n        }\n      ],\n      \"dpi\": [\n        410.9,\n        415.4\n      ],\n      \"bw\": 4,\n      \"ac\": 1000\n    }\n  ]\n}\n},{}],57:[function(_dereq_,module,exports){\n/*\n * Copyright 2015 Google Inc. All Rights Reserved.\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// Offline cache of the DPDB, to be used until we load the online one (and\n// as a fallback in case we can't load the online one).\nvar DPDB_CACHE = _dereq_('./dpdb.json');\nvar Util = _dereq_('../util.js');\n\n// Online DPDB URL.\nvar ONLINE_DPDB_URL =\n  'https://dpdb.webvr.rocks/dpdb.json';\n\n/**\n * Calculates device parameters based on the DPDB (Device Parameter Database).\n * Initially, uses the cached DPDB values.\n *\n * If fetchOnline == true, then this object tries to fetch the online version\n * of the DPDB and updates the device info if a better match is found.\n * Calls the onDeviceParamsUpdated callback when there is an update to the\n * device information.\n */\nfunction Dpdb(fetchOnline, onDeviceParamsUpdated) {\n  // Start with the offline DPDB cache while we are loading the real one.\n  this.dpdb = DPDB_CACHE;\n\n  // Calculate device params based on the offline version of the DPDB.\n  this.recalculateDeviceParams_();\n\n  // XHR to fetch online DPDB file, if requested.\n  if (fetchOnline) {\n    // Set the callback.\n    this.onDeviceParamsUpdated = onDeviceParamsUpdated;\n\n    var xhr = new XMLHttpRequest();\n    var obj = this;\n    xhr.open('GET', ONLINE_DPDB_URL, true);\n    xhr.addEventListener('load', function() {\n      obj.loading = false;\n      if (xhr.status >= 200 && xhr.status <= 299) {\n        // Success.\n        obj.dpdb = JSON.parse(xhr.response);\n        obj.recalculateDeviceParams_();\n      } else {\n        // Error loading the DPDB.\n        console.error('Error loading online DPDB!');\n      }\n    });\n    xhr.send();\n  }\n}\n\n// Returns the current device parameters.\nDpdb.prototype.getDeviceParams = function() {\n  return this.deviceParams;\n};\n\n// Recalculates this device's parameters based on the DPDB.\nDpdb.prototype.recalculateDeviceParams_ = function() {\n  var newDeviceParams = this.calcDeviceParams_();\n  if (newDeviceParams) {\n    this.deviceParams = newDeviceParams;\n    // Invoke callback, if it is set.\n    if (this.onDeviceParamsUpdated) {\n      this.onDeviceParamsUpdated(this.deviceParams);\n    }\n  } else {\n    console.error('Failed to recalculate device parameters.');\n  }\n};\n\n// Returns a DeviceParams object that represents the best guess as to this\n// device's parameters. Can return null if the device does not match any\n// known devices.\nDpdb.prototype.calcDeviceParams_ = function() {\n  var db = this.dpdb; // shorthand\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\n  // Get the actual user agent and screen dimensions in pixels.\n  var userAgent = navigator.userAgent || navigator.vendor || window.opera;\n  var width = Util.getScreenWidth();\n  var height = Util.getScreenHeight();\n\n  if (!db.devices) {\n    console.error('DPDB has no devices section.');\n    return null;\n  }\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\n    if (device.type != 'ios' && device.type != 'android') {\n      console.warn('Device[' + i + '] has invalid type.');\n      continue;\n    }\n\n    // See if this device is of the appropriate type.\n    if (Util.isIOS() != (device.type == 'ios')) continue;\n\n    // See if this device matches any of the rules:\n    var matched = false;\n    for (var j = 0; j < device.rules.length; j++) {\n      var rule = device.rules[j];\n      if (this.matchRule_(rule, userAgent, width, height)) {\n        matched = true;\n        break;\n      }\n    }\n    if (!matched) continue;\n\n    // device.dpi might be an array of [ xdpi, ydpi] or just a scalar.\n    var xdpi = device.dpi[0] || device.dpi;\n    var ydpi = device.dpi[1] || device.dpi;\n\n    return new DeviceParams({ xdpi: xdpi, ydpi: ydpi, bevelMm: device.bw });\n  }\n\n  console.warn('No DPDB device match.');\n  return null;\n};\n\nDpdb.prototype.matchRule_ = function(rule, ua, screenWidth, screenHeight) {\n  // We can only match 'ua' and 'res' rules, not other types like 'mdmh'\n  // (which are meant for native platforms).\n  if (!rule.ua && !rule.res) return false;\n\n  // If our user agent string doesn't contain the indicated user agent string,\n  // the match fails.\n  if (rule.ua && ua.indexOf(rule.ua) < 0) return false;\n\n  // If the rule specifies screen dimensions that don't correspond to ours,\n  // the match fails.\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    // Compare min and max so as to make the order not matter, i.e., it should\n    // be true that 640x480 == 480x640.\n    if (Math.min(screenWidth, screenHeight) != Math.min(resX, resY) ||\n        (Math.max(screenWidth, screenHeight) != Math.max(resX, resY))) {\n      return false;\n    }\n  }\n\n  return true;\n}\n\nfunction DeviceParams(params) {\n  this.xdpi = params.xdpi;\n  this.ydpi = params.ydpi;\n  this.bevelMm = params.bevelMm;\n}\n\nmodule.exports = Dpdb;\n\n},{\"../util.js\":68,\"./dpdb.json\":56}],58:[function(_dereq_,module,exports){\n/*\n * Copyright 2015 Google Inc. All Rights Reserved.\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 */\nvar Util = _dereq_('./util.js');\nvar WebVRPolyfill = _dereq_('./webvr-polyfill.js').WebVRPolyfill;\n\n// Initialize a WebVRConfig just in case.\nwindow.WebVRConfig = Util.extend({\n  // Forces availability of VR mode, even for non-mobile devices.\n  FORCE_ENABLE_VR: false,\n\n  // Complementary filter coefficient. 0 for accelerometer, 1 for gyro.\n  K_FILTER: 0.98,\n\n  // How far into the future to predict during fast motion (in seconds).\n  PREDICTION_TIME_S: 0.040,\n\n  // Flag to enable touch panner. In case you have your own touch controls.\n  TOUCH_PANNER_DISABLED: true,\n\n  // Flag to disabled the UI in VR Mode.\n  CARDBOARD_UI_DISABLED: false, // Default: false\n\n  // Flag to disable the instructions to rotate your device.\n  ROTATE_INSTRUCTIONS_DISABLED: false, // Default: false.\n\n  // Enable yaw panning only, disabling roll and pitch. This can be useful\n  // for panoramas with nothing interesting above or below.\n  YAW_ONLY: false,\n\n  // To disable keyboard and mouse controls, if you want to use your own\n  // implementation.\n  MOUSE_KEYBOARD_CONTROLS_DISABLED: false,\n\n  // Prevent the polyfill from initializing immediately. Requires the app\n  // to call InitializeWebVRPolyfill() before it can be used.\n  DEFER_INITIALIZATION: false,\n\n  // Enable the deprecated version of the API (navigator.getVRDevices).\n  ENABLE_DEPRECATED_API: false,\n\n  // Scales the recommended buffer size reported by WebVR, which can improve\n  // performance.\n  // UPDATE(2016-05-03): Setting this to 0.5 by default since 1.0 does not\n  // perform well on many mobile devices.\n  BUFFER_SCALE: 0.5,\n\n  // Allow VRDisplay.submitFrame to change gl bindings, which is more\n  // efficient if the application code will re-bind its resources on the\n  // next frame anyway. This has been seen to cause rendering glitches with\n  // THREE.js.\n  // Dirty bindings include: gl.FRAMEBUFFER_BINDING, gl.CURRENT_PROGRAM,\n  // gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING,\n  // and gl.TEXTURE_BINDING_2D for texture unit 0.\n  DIRTY_SUBMIT_FRAME_BINDINGS: false,\n\n  // When set to true, this will cause a polyfilled VRDisplay to always be\n  // appended to the list returned by navigator.getVRDisplays(), even if that\n  // list includes a native VRDisplay.\n  ALWAYS_APPEND_POLYFILL_DISPLAY: false,\n\n  // There are versions of Chrome (M58-M60?) where the native WebVR API exists,\n  // and instead of returning 0 VR displays when none are detected,\n  // `navigator.getVRDisplays()`'s promise never resolves. This results\n  // in the polyfill hanging and not being able to provide fallback\n  // displays, so set a timeout in milliseconds to stop waiting for a response\n  // and just use polyfilled displays.\n  // https://bugs.chromium.org/p/chromium/issues/detail?id=727969\n  GET_VR_DISPLAYS_TIMEOUT: 1000,\n}, window.WebVRConfig);\n\nif (!window.WebVRConfig.DEFER_INITIALIZATION) {\n  new WebVRPolyfill();\n} else {\n  window.InitializeWebVRPolyfill = function() {\n    new WebVRPolyfill();\n  }\n}\n\nwindow.WebVRPolyfill = WebVRPolyfill;\n\n},{\"./util.js\":68,\"./webvr-polyfill.js\":71}],59:[function(_dereq_,module,exports){\n/*\n * Copyright 2016 Google Inc. All Rights Reserved.\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\nvar MathUtil = window.MathUtil || {};\n\nMathUtil.degToRad = Math.PI / 180;\nMathUtil.radToDeg = 180 / Math.PI;\n\n// Some minimal math functionality borrowed from THREE.Math and stripped down\n// for the purposes of this library.\n\n\nMathUtil.Vector2 = function ( x, y ) {\n  this.x = x || 0;\n  this.y = y || 0;\n};\n\nMathUtil.Vector2.prototype = {\n  constructor: MathUtil.Vector2,\n\n  set: function ( x, y ) {\n    this.x = x;\n    this.y = y;\n\n    return this;\n  },\n\n  copy: function ( v ) {\n    this.x = v.x;\n    this.y = v.y;\n\n    return this;\n  },\n\n  subVectors: function ( a, b ) {\n    this.x = a.x - b.x;\n    this.y = a.y - b.y;\n\n    return this;\n  },\n};\n\nMathUtil.Vector3 = function ( x, y, z ) {\n  this.x = x || 0;\n  this.y = y || 0;\n  this.z = z || 0;\n};\n\nMathUtil.Vector3.prototype = {\n  constructor: MathUtil.Vector3,\n\n  set: function ( x, y, z ) {\n    this.x = x;\n    this.y = y;\n    this.z = z;\n\n    return this;\n  },\n\n  copy: function ( v ) {\n    this.x = v.x;\n    this.y = v.y;\n    this.z = v.z;\n\n    return this;\n  },\n\n  length: function () {\n    return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );\n  },\n\n  normalize: function () {\n    var scalar = this.length();\n\n    if ( scalar !== 0 ) {\n      var invScalar = 1 / scalar;\n\n      this.multiplyScalar(invScalar);\n    } else {\n      this.x = 0;\n      this.y = 0;\n      this.z = 0;\n    }\n\n    return this;\n  },\n\n  multiplyScalar: function ( scalar ) {\n    this.x *= scalar;\n    this.y *= scalar;\n    this.z *= scalar;\n  },\n\n  applyQuaternion: function ( q ) {\n    var x = this.x;\n    var y = this.y;\n    var z = this.z;\n\n    var qx = q.x;\n    var qy = q.y;\n    var qz = q.z;\n    var qw = q.w;\n\n    // calculate quat * vector\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\n    // calculate result * inverse quat\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\n    return this;\n  },\n\n  dot: function ( v ) {\n    return this.x * v.x + this.y * v.y + this.z * v.z;\n  },\n\n  crossVectors: function ( a, b ) {\n    var ax = a.x, ay = a.y, az = a.z;\n    var bx = b.x, by = b.y, bz = b.z;\n\n    this.x = ay * bz - az * by;\n    this.y = az * bx - ax * bz;\n    this.z = ax * by - ay * bx;\n\n    return this;\n  },\n};\n\nMathUtil.Quaternion = function ( 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\nMathUtil.Quaternion.prototype = {\n  constructor: MathUtil.Quaternion,\n\n  set: function ( x, y, z, w ) {\n    this.x = x;\n    this.y = y;\n    this.z = z;\n    this.w = w;\n\n    return this;\n  },\n\n  copy: function ( quaternion ) {\n    this.x = quaternion.x;\n    this.y = quaternion.y;\n    this.z = quaternion.z;\n    this.w = quaternion.w;\n\n    return this;\n  },\n\n  setFromEulerXYZ: function( 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\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\n    return this;\n  },\n\n  setFromEulerYXZ: function( 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\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\n    return this;\n  },\n\n  setFromAxisAngle: function ( axis, angle ) {\n    // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm\n    // assumes axis is normalized\n\n    var halfAngle = angle / 2, s = Math.sin( halfAngle );\n\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\n    return this;\n  },\n\n  multiply: function ( q ) {\n    return this.multiplyQuaternions( this, q );\n  },\n\n  multiplyQuaternions: function ( a, b ) {\n    // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm\n\n    var qax = a.x, qay = a.y, qaz = a.z, qaw = a.w;\n    var qbx = b.x, qby = b.y, qbz = b.z, qbw = b.w;\n\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\n    return this;\n  },\n\n  inverse: function () {\n    this.x *= -1;\n    this.y *= -1;\n    this.z *= -1;\n\n    this.normalize();\n\n    return this;\n  },\n\n  normalize: function () {\n    var l = Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );\n\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\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\n    return this;\n  },\n\n  slerp: function ( qb, t ) {\n    if ( t === 0 ) return this;\n    if ( t === 1 ) return this.copy( qb );\n\n    var x = this.x, y = this.y, z = this.z, w = this.w;\n\n    // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/\n\n    var cosHalfTheta = w * qb.w + x * qb.x + y * qb.y + z * qb.z;\n\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\n      cosHalfTheta = - cosHalfTheta;\n    } else {\n      this.copy( qb );\n    }\n\n    if ( cosHalfTheta >= 1.0 ) {\n      this.w = w;\n      this.x = x;\n      this.y = y;\n      this.z = z;\n\n      return this;\n    }\n\n    var halfTheta = Math.acos( cosHalfTheta );\n    var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );\n\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\n      return this;\n    }\n\n    var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,\n    ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;\n\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\n    return this;\n  },\n\n  setFromUnitVectors: function () {\n    // http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final\n    // assumes direction vectors vFrom and vTo are normalized\n\n    var v1, r;\n    var EPS = 0.000001;\n\n    return function ( vFrom, vTo ) {\n      if ( v1 === undefined ) v1 = new MathUtil.Vector3();\n\n      r = vFrom.dot( vTo ) + 1;\n\n      if ( r < EPS ) {\n        r = 0;\n\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\n      this.x = v1.x;\n      this.y = v1.y;\n      this.z = v1.z;\n      this.w = r;\n\n      this.normalize();\n\n      return this;\n    }\n  }(),\n};\n\nmodule.exports = MathUtil;\n\n},{}],60:[function(_dereq_,module,exports){\n/*\n * Copyright 2016 Google Inc. All Rights Reserved.\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\nvar VRDisplay = _dereq_('./base.js').VRDisplay;\nvar MathUtil = _dereq_('./math-util.js');\nvar Util = _dereq_('./util.js');\n\n// How much to rotate per key stroke.\nvar KEY_SPEED = 0.15;\nvar KEY_ANIMATION_DURATION = 80;\n\n// How much to rotate for mouse events.\nvar MOUSE_SPEED_X = 0.5;\nvar MOUSE_SPEED_Y = 0.3;\n\n/**\n * VRDisplay based on mouse and keyboard input. Designed for desktops/laptops\n * where orientation events aren't supported. Cannot present.\n */\nfunction MouseKeyboardVRDisplay() {\n  this.displayName = 'Mouse and Keyboard VRDisplay (webvr-polyfill)';\n\n  this.capabilities.hasOrientation = true;\n\n  // Attach to mouse and keyboard events.\n  window.addEventListener('keydown', this.onKeyDown_.bind(this));\n  window.addEventListener('mousemove', this.onMouseMove_.bind(this));\n  window.addEventListener('mousedown', this.onMouseDown_.bind(this));\n  window.addEventListener('mouseup', this.onMouseUp_.bind(this));\n\n  // \"Private\" members.\n  this.phi_ = 0;\n  this.theta_ = 0;\n\n  // Variables for keyboard-based rotation animation.\n  this.targetAngle_ = null;\n  this.angleAnimation_ = null;\n\n  // State variables for calculations.\n  this.orientation_ = new MathUtil.Quaternion();\n\n  // Variables for mouse-based rotation.\n  this.rotateStart_ = new MathUtil.Vector2();\n  this.rotateEnd_ = new MathUtil.Vector2();\n  this.rotateDelta_ = new MathUtil.Vector2();\n  this.isDragging_ = false;\n\n  this.orientationOut_ = new Float32Array(4);\n}\nMouseKeyboardVRDisplay.prototype = new VRDisplay();\n\nMouseKeyboardVRDisplay.prototype.getImmediatePose = function() {\n  this.orientation_.setFromEulerYXZ(this.phi_, this.theta_, 0);\n\n  this.orientationOut_[0] = this.orientation_.x;\n  this.orientationOut_[1] = this.orientation_.y;\n  this.orientationOut_[2] = this.orientation_.z;\n  this.orientationOut_[3] = this.orientation_.w;\n\n  return {\n    position: null,\n    orientation: this.orientationOut_,\n    linearVelocity: null,\n    linearAcceleration: null,\n    angularVelocity: null,\n    angularAcceleration: null\n  };\n};\n\nMouseKeyboardVRDisplay.prototype.onKeyDown_ = function(e) {\n  // Track WASD and arrow keys.\n  if (e.keyCode == 38) { // Up key.\n    this.animatePhi_(this.phi_ + KEY_SPEED);\n  } else if (e.keyCode == 39) { // Right key.\n    this.animateTheta_(this.theta_ - KEY_SPEED);\n  } else if (e.keyCode == 40) { // Down key.\n    this.animatePhi_(this.phi_ - KEY_SPEED);\n  } else if (e.keyCode == 37) { // Left key.\n    this.animateTheta_(this.theta_ + KEY_SPEED);\n  }\n};\n\nMouseKeyboardVRDisplay.prototype.animateTheta_ = function(targetAngle) {\n  this.animateKeyTransitions_('theta_', targetAngle);\n};\n\nMouseKeyboardVRDisplay.prototype.animatePhi_ = function(targetAngle) {\n  // Prevent looking too far up or down.\n  targetAngle = Util.clamp(targetAngle, -Math.PI/2, Math.PI/2);\n  this.animateKeyTransitions_('phi_', targetAngle);\n};\n\n/**\n * Start an animation to transition an angle from one value to another.\n */\nMouseKeyboardVRDisplay.prototype.animateKeyTransitions_ = function(angleName, targetAngle) {\n  // If an animation is currently running, cancel it.\n  if (this.angleAnimation_) {\n    cancelAnimationFrame(this.angleAnimation_);\n  }\n  var startAngle = this[angleName];\n  var startTime = new Date();\n  // Set up an interval timer to perform the animation.\n  this.angleAnimation_ = requestAnimationFrame(function animate() {\n    // Once we're finished the animation, we're done.\n    var elapsed = new Date() - startTime;\n    if (elapsed >= KEY_ANIMATION_DURATION) {\n      this[angleName] = targetAngle;\n      cancelAnimationFrame(this.angleAnimation_);\n      return;\n    }\n    // loop with requestAnimationFrame\n    this.angleAnimation_ = requestAnimationFrame(animate.bind(this))\n    // Linearly interpolate the angle some amount.\n    var percent = elapsed / KEY_ANIMATION_DURATION;\n    this[angleName] = startAngle + (targetAngle - startAngle) * percent;\n  }.bind(this));\n};\n\nMouseKeyboardVRDisplay.prototype.onMouseDown_ = function(e) {\n  this.rotateStart_.set(e.clientX, e.clientY);\n  this.isDragging_ = true;\n};\n\n// Very similar to https://gist.github.com/mrflix/8351020\nMouseKeyboardVRDisplay.prototype.onMouseMove_ = function(e) {\n  if (!this.isDragging_ && !this.isPointerLocked_()) {\n    return;\n  }\n  // Support pointer lock API.\n  if (this.isPointerLocked_()) {\n    var movementX = e.movementX || e.mozMovementX || 0;\n    var movementY = e.movementY || e.mozMovementY || 0;\n    this.rotateEnd_.set(this.rotateStart_.x - movementX, this.rotateStart_.y - movementY);\n  } else {\n    this.rotateEnd_.set(e.clientX, e.clientY);\n  }\n  // Calculate how much we moved in mouse space.\n  this.rotateDelta_.subVectors(this.rotateEnd_, this.rotateStart_);\n  this.rotateStart_.copy(this.rotateEnd_);\n\n  // Keep track of the cumulative euler angles.\n  this.phi_ += 2 * Math.PI * this.rotateDelta_.y / screen.height * MOUSE_SPEED_Y;\n  this.theta_ += 2 * Math.PI * this.rotateDelta_.x / screen.width * MOUSE_SPEED_X;\n\n  // Prevent looking too far up or down.\n  this.phi_ = Util.clamp(this.phi_, -Math.PI/2, Math.PI/2);\n};\n\nMouseKeyboardVRDisplay.prototype.onMouseUp_ = function(e) {\n  this.isDragging_ = false;\n};\n\nMouseKeyboardVRDisplay.prototype.isPointerLocked_ = function() {\n  var el = document.pointerLockElement || document.mozPointerLockElement ||\n      document.webkitPointerLockElement;\n  return el !== undefined;\n};\n\nMouseKeyboardVRDisplay.prototype.resetPose = function() {\n  this.phi_ = 0;\n  this.theta_ = 0;\n};\n\nmodule.exports = MouseKeyboardVRDisplay;\n\n},{\"./base.js\":48,\"./math-util.js\":59,\"./util.js\":68}],61:[function(_dereq_,module,exports){\n(function (global){\n// This is the entry point if requiring/importing via node, or\n// a build tool that uses package.json entry (like browserify, webpack).\n// If running in node with a window mock available, globalize its members\n// if needed. Otherwise, just continue to `./main`\nif (typeof global !== 'undefined' && global.window) {\n  global.document = global.window.document;\n  global.navigator = global.window.navigator;\n}\n\n_dereq_('./main');\n\n}).call(this,typeof global !== \"undefined\" ? global : typeof self !== \"undefined\" ? self : typeof window !== \"undefined\" ? window : {})\n\n},{\"./main\":58}],62:[function(_dereq_,module,exports){\n/*\n * Copyright 2015 Google Inc. All Rights Reserved.\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\nvar Util = _dereq_('./util.js');\n\nfunction RotateInstructions() {\n  this.loadIcon_();\n\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  // Force this to be above the fullscreen canvas, which is at zIndex: 999999.\n  s.zIndex = 1000000;\n\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\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\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\n  var snackbarText = document.createElement('div');\n  snackbarText.style.float = 'left';\n  snackbarText.innerHTML = 'No Cardboard viewer?';\n\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\n  snackbar.appendChild(snackbarText);\n  snackbar.appendChild(snackbarButton);\n\n  this.overlay = overlay;\n  this.text = text;\n\n  this.hide();\n}\n\nRotateInstructions.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)\n      this.overlay.parentElement.removeChild(this.overlay);\n\n    parent.appendChild(this.overlay);\n  }\n\n  this.overlay.style.display = 'block';\n\n  var img = this.overlay.querySelector('img');\n  var s = img.style;\n\n  if (Util.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\nRotateInstructions.prototype.hide = function() {\n  this.overlay.style.display = 'none';\n};\n\nRotateInstructions.prototype.showTemporarily = function(ms, parent) {\n  this.show(parent);\n  this.timer = setTimeout(this.hide.bind(this), ms);\n};\n\nRotateInstructions.prototype.disableShowTemporarily = function() {\n  clearTimeout(this.timer);\n};\n\nRotateInstructions.prototype.update = function() {\n  this.disableShowTemporarily();\n  // In portrait VR mode, tell the user to rotate to landscape. Otherwise, hide\n  // the instructions.\n  if (!Util.isLandscapeMode() && Util.isMobile()) {\n    this.show();\n  } else {\n    this.hide();\n  }\n};\n\nRotateInstructions.prototype.loadIcon_ = function() {\n  // Encoded asset_src/rotate-instructions.svg\n  this.icon = Util.base64('image/svg+xml', 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjE5OHB4IiBoZWlnaHQ9IjI0MHB4IiB2aWV3Qm94PSIwIDAgMTk4IDI0MCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczpza2V0Y2g9Imh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaC9ucyI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDMuMy4zICgxMjA4MSkgLSBodHRwOi8vd3d3LmJvaGVtaWFuY29kaW5nLmNvbS9za2V0Y2ggLS0+CiAgICA8dGl0bGU+dHJhbnNpdGlvbjwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxkZWZzPjwvZGVmcz4KICAgIDxnIGlkPSJQYWdlLTEiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHNrZXRjaDp0eXBlPSJNU1BhZ2UiPgogICAgICAgIDxnIGlkPSJ0cmFuc2l0aW9uIiBza2V0Y2g6dHlwZT0iTVNBcnRib2FyZEdyb3VwIj4KICAgICAgICAgICAgPGcgaWQ9IkltcG9ydGVkLUxheWVycy1Db3B5LTQtKy1JbXBvcnRlZC1MYXllcnMtQ29weS0rLUltcG9ydGVkLUxheWVycy1Db3B5LTItQ29weSIgc2tldGNoOnR5cGU9Ik1TTGF5ZXJHcm91cCI+CiAgICAgICAgICAgICAgICA8ZyBpZD0iSW1wb3J0ZWQtTGF5ZXJzLUNvcHktNCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC4wMDAwMDAsIDEwNy4wMDAwMDApIiBza2V0Y2g6dHlwZT0iTVNTaGFwZUdyb3VwIj4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTQ5LjYyNSwyLjUyNyBDMTQ5LjYyNSwyLjUyNyAxNTUuODA1LDYuMDk2IDE1Ni4zNjIsNi40MTggTDE1Ni4zNjIsNy4zMDQgQzE1Ni4zNjIsNy40ODEgMTU2LjM3NSw3LjY2NCAxNTYuNCw3Ljg1MyBDMTU2LjQxLDcuOTM0IDE1Ni40Miw4LjAxNSAxNTYuNDI3LDguMDk1IEMxNTYuNTY3LDkuNTEgMTU3LjQwMSwxMS4wOTMgMTU4LjUzMiwxMi4wOTQgTDE2NC4yNTIsMTcuMTU2IEwxNjQuMzMzLDE3LjA2NiBDMTY0LjMzMywxNy4wNjYgMTY4LjcxNSwxNC41MzYgMTY5LjU2OCwxNC4wNDIgQzE3MS4wMjUsMTQuODgzIDE5NS41MzgsMjkuMDM1IDE5NS41MzgsMjkuMDM1IEwxOTUuNTM4LDgzLjAzNiBDMTk1LjUzOCw4My44MDcgMTk1LjE1Miw4NC4yNTMgMTk0LjU5LDg0LjI1MyBDMTk0LjM1Nyw4NC4yNTMgMTk0LjA5NSw4NC4xNzcgMTkzLjgxOCw4NC4wMTcgTDE2OS44NTEsNzAuMTc5IEwxNjkuODM3LDcwLjIwMyBMMTQyLjUxNSw4NS45NzggTDE0MS42NjUsODQuNjU1IEMxMzYuOTM0LDgzLjEyNiAxMzEuOTE3LDgxLjkxNSAxMjYuNzE0LDgxLjA0NSBDMTI2LjcwOSw4MS4wNiAxMjYuNzA3LDgxLjA2OSAxMjYuNzA3LDgxLjA2OSBMMTIxLjY0LDk4LjAzIEwxMTMuNzQ5LDEwMi41ODYgTDExMy43MTIsMTAyLjUyMyBMMTEzLjcxMiwxMzAuMTEzIEMxMTMuNzEyLDEzMC44ODUgMTEzLjMyNiwxMzEuMzMgMTEyLjc2NCwxMzEuMzMgQzExMi41MzIsMTMxLjMzIDExMi4yNjksMTMxLjI1NCAxMTEuOTkyLDEzMS4wOTQgTDY5LjUxOSwxMDYuNTcyIEM2OC41NjksMTA2LjAyMyA2Ny43OTksMTA0LjY5NSA2Ny43OTksMTAzLjYwNSBMNjcuNzk5LDEwMi41NyBMNjcuNzc4LDEwMi42MTcgQzY3LjI3LDEwMi4zOTMgNjYuNjQ4LDEwMi4yNDkgNjUuOTYyLDEwMi4yMTggQzY1Ljg3NSwxMDIuMjE0IDY1Ljc4OCwxMDIuMjEyIDY1LjcwMSwxMDIuMjEyIEM2NS42MDYsMTAyLjIxMiA2NS41MTEsMTAyLjIxNSA2NS40MTYsMTAyLjIxOSBDNjUuMTk1LDEwMi4yMjkgNjQuOTc0LDEwMi4yMzUgNjQuNzU0LDEwMi4yMzUgQzY0LjMzMSwxMDIuMjM1IDYzLjkxMSwxMDIuMjE2IDYzLjQ5OCwxMDIuMTc4IEM2MS44NDMsMTAyLjAyNSA2MC4yOTgsMTAxLjU3OCA1OS4wOTQsMTAwLjg4MiBMMTIuNTE4LDczLjk5MiBMMTIuNTIzLDc0LjAwNCBMMi4yNDUsNTUuMjU0IEMxLjI0NCw1My40MjcgMi4wMDQsNTEuMDM4IDMuOTQzLDQ5LjkxOCBMNTkuOTU0LDE3LjU3MyBDNjAuNjI2LDE3LjE4NSA2MS4zNSwxNy4wMDEgNjIuMDUzLDE3LjAwMSBDNjMuMzc5LDE3LjAwMSA2NC42MjUsMTcuNjYgNjUuMjgsMTguODU0IEw2NS4yODUsMTguODUxIEw2NS41MTIsMTkuMjY0IEw2NS41MDYsMTkuMjY4IEM2NS45MDksMjAuMDAzIDY2LjQwNSwyMC42OCA2Ni45ODMsMjEuMjg2IEw2Ny4yNiwyMS41NTYgQzY5LjE3NCwyMy40MDYgNzEuNzI4LDI0LjM1NyA3NC4zNzMsMjQuMzU3IEM3Ni4zMjIsMjQuMzU3IDc4LjMyMSwyMy44NCA4MC4xNDgsMjIuNzg1IEM4MC4xNjEsMjIuNzg1IDg3LjQ2NywxOC41NjYgODcuNDY3LDE4LjU2NiBDODguMTM5LDE4LjE3OCA4OC44NjMsMTcuOTk0IDg5LjU2NiwxNy45OTQgQzkwLjg5MiwxNy45OTQgOTIuMTM4LDE4LjY1MiA5Mi43OTIsMTkuODQ3IEw5Ni4wNDIsMjUuNzc1IEw5Ni4wNjQsMjUuNzU3IEwxMDIuODQ5LDI5LjY3NCBMMTAyLjc0NCwyOS40OTIgTDE0OS42MjUsMi41MjcgTTE0OS42MjUsMC44OTIgQzE0OS4zNDMsMC44OTIgMTQ5LjA2MiwwLjk2NSAxNDguODEsMS4xMSBMMTAyLjY0MSwyNy42NjYgTDk3LjIzMSwyNC41NDIgTDk0LjIyNiwxOS4wNjEgQzkzLjMxMywxNy4zOTQgOTEuNTI3LDE2LjM1OSA4OS41NjYsMTYuMzU4IEM4OC41NTUsMTYuMzU4IDg3LjU0NiwxNi42MzIgODYuNjQ5LDE3LjE1IEM4My44NzgsMTguNzUgNzkuNjg3LDIxLjE2OSA3OS4zNzQsMjEuMzQ1IEM3OS4zNTksMjEuMzUzIDc5LjM0NSwyMS4zNjEgNzkuMzMsMjEuMzY5IEM3Ny43OTgsMjIuMjU0IDc2LjA4NCwyMi43MjIgNzQuMzczLDIyLjcyMiBDNzIuMDgxLDIyLjcyMiA2OS45NTksMjEuODkgNjguMzk3LDIwLjM4IEw2OC4xNDUsMjAuMTM1IEM2Ny43MDYsMTkuNjcyIDY3LjMyMywxOS4xNTYgNjcuMDA2LDE4LjYwMSBDNjYuOTg4LDE4LjU1OSA2Ni45NjgsMTguNTE5IDY2Ljk0NiwxOC40NzkgTDY2LjcxOSwxOC4wNjUgQzY2LjY5LDE4LjAxMiA2Ni42NTgsMTcuOTYgNjYuNjI0LDE3LjkxMSBDNjUuNjg2LDE2LjMzNyA2My45NTEsMTUuMzY2IDYyLjA1MywxNS4zNjYgQzYxLjA0MiwxNS4zNjYgNjAuMDMzLDE1LjY0IDU5LjEzNiwxNi4xNTggTDMuMTI1LDQ4LjUwMiBDMC40MjYsNTAuMDYxIC0wLjYxMyw1My40NDIgMC44MTEsNTYuMDQgTDExLjA4OSw3NC43OSBDMTEuMjY2LDc1LjExMyAxMS41MzcsNzUuMzUzIDExLjg1LDc1LjQ5NCBMNTguMjc2LDEwMi4yOTggQzU5LjY3OSwxMDMuMTA4IDYxLjQzMywxMDMuNjMgNjMuMzQ4LDEwMy44MDYgQzYzLjgxMiwxMDMuODQ4IDY0LjI4NSwxMDMuODcgNjQuNzU0LDEwMy44NyBDNjUsMTAzLjg3IDY1LjI0OSwxMDMuODY0IDY1LjQ5NCwxMDMuODUyIEM2NS41NjMsMTAzLjg0OSA2NS42MzIsMTAzLjg0NyA2NS43MDEsMTAzLjg0NyBDNjUuNzY0LDEwMy44NDcgNjUuODI4LDEwMy44NDkgNjUuODksMTAzLjg1MiBDNjUuOTg2LDEwMy44NTYgNjYuMDgsMTAzLjg2MyA2Ni4xNzMsMTAzLjg3NCBDNjYuMjgyLDEwNS40NjcgNjcuMzMyLDEwNy4xOTcgNjguNzAyLDEwNy45ODggTDExMS4xNzQsMTMyLjUxIEMxMTEuNjk4LDEzMi44MTIgMTEyLjIzMiwxMzIuOTY1IDExMi43NjQsMTMyLjk2NSBDMTE0LjI2MSwxMzIuOTY1IDExNS4zNDcsMTMxLjc2NSAxMTUuMzQ3LDEzMC4xMTMgTDExNS4zNDcsMTAzLjU1MSBMMTIyLjQ1OCw5OS40NDYgQzEyMi44MTksOTkuMjM3IDEyMy4wODcsOTguODk4IDEyMy4yMDcsOTguNDk4IEwxMjcuODY1LDgyLjkwNSBDMTMyLjI3OSw4My43MDIgMTM2LjU1Nyw4NC43NTMgMTQwLjYwNyw4Ni4wMzMgTDE0MS4xNCw4Ni44NjIgQzE0MS40NTEsODcuMzQ2IDE0MS45NzcsODcuNjEzIDE0Mi41MTYsODcuNjEzIEMxNDIuNzk0LDg3LjYxMyAxNDMuMDc2LDg3LjU0MiAxNDMuMzMzLDg3LjM5MyBMMTY5Ljg2NSw3Mi4wNzYgTDE5Myw4NS40MzMgQzE5My41MjMsODUuNzM1IDE5NC4wNTgsODUuODg4IDE5NC41OSw4NS44ODggQzE5Ni4wODcsODUuODg4IDE5Ny4xNzMsODQuNjg5IDE5Ny4xNzMsODMuMDM2IEwxOTcuMTczLDI5LjAzNSBDMTk3LjE3MywyOC40NTEgMTk2Ljg2MSwyNy45MTEgMTk2LjM1NSwyNy42MTkgQzE5Ni4zNTUsMjcuNjE5IDE3MS44NDMsMTMuNDY3IDE3MC4zODUsMTIuNjI2IEMxNzAuMTMyLDEyLjQ4IDE2OS44NSwxMi40MDcgMTY5LjU2OCwxMi40MDcgQzE2OS4yODUsMTIuNDA3IDE2OS4wMDIsMTIuNDgxIDE2OC43NDksMTIuNjI3IEMxNjguMTQzLDEyLjk3OCAxNjUuNzU2LDE0LjM1NyAxNjQuNDI0LDE1LjEyNSBMMTU5LjYxNSwxMC44NyBDMTU4Ljc5NiwxMC4xNDUgMTU4LjE1NCw4LjkzNyAxNTguMDU0LDcuOTM0IEMxNTguMDQ1LDcuODM3IDE1OC4wMzQsNy43MzkgMTU4LjAyMSw3LjY0IEMxNTguMDA1LDcuNTIzIDE1Ny45OTgsNy40MSAxNTcuOTk4LDcuMzA0IEwxNTcuOTk4LDYuNDE4IEMxNTcuOTk4LDUuODM0IDE1Ny42ODYsNS4yOTUgMTU3LjE4MSw1LjAwMiBDMTU2LjYyNCw0LjY4IDE1MC40NDIsMS4xMTEgMTUwLjQ0MiwxLjExMSBDMTUwLjE4OSwwLjk2NSAxNDkuOTA3LDAuODkyIDE0OS42MjUsMC44OTIiIGlkPSJGaWxsLTEiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNOTYuMDI3LDI1LjYzNiBMMTQyLjYwMyw1Mi41MjcgQzE0My44MDcsNTMuMjIyIDE0NC41ODIsNTQuMTE0IDE0NC44NDUsNTUuMDY4IEwxNDQuODM1LDU1LjA3NSBMNjMuNDYxLDEwMi4wNTcgTDYzLjQ2LDEwMi4wNTcgQzYxLjgwNiwxMDEuOTA1IDYwLjI2MSwxMDEuNDU3IDU5LjA1NywxMDAuNzYyIEwxMi40ODEsNzMuODcxIEw5Ni4wMjcsMjUuNjM2IiBpZD0iRmlsbC0yIiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTYzLjQ2MSwxMDIuMTc0IEM2My40NTMsMTAyLjE3NCA2My40NDYsMTAyLjE3NCA2My40MzksMTAyLjE3MiBDNjEuNzQ2LDEwMi4wMTYgNjAuMjExLDEwMS41NjMgNTguOTk4LDEwMC44NjMgTDEyLjQyMiw3My45NzMgQzEyLjM4Niw3My45NTIgMTIuMzY0LDczLjkxNCAxMi4zNjQsNzMuODcxIEMxMi4zNjQsNzMuODMgMTIuMzg2LDczLjc5MSAxMi40MjIsNzMuNzcgTDk1Ljk2OCwyNS41MzUgQzk2LjAwNCwyNS41MTQgOTYuMDQ5LDI1LjUxNCA5Ni4wODUsMjUuNTM1IEwxNDIuNjYxLDUyLjQyNiBDMTQzLjg4OCw1My4xMzQgMTQ0LjY4Miw1NC4wMzggMTQ0Ljk1Nyw1NS4wMzcgQzE0NC45Nyw1NS4wODMgMTQ0Ljk1Myw1NS4xMzMgMTQ0LjkxNSw1NS4xNjEgQzE0NC45MTEsNTUuMTY1IDE0NC44OTgsNTUuMTc0IDE0NC44OTQsNTUuMTc3IEw2My41MTksMTAyLjE1OCBDNjMuNTAxLDEwMi4xNjkgNjMuNDgxLDEwMi4xNzQgNjMuNDYxLDEwMi4xNzQgTDYzLjQ2MSwxMDIuMTc0IFogTTEyLjcxNCw3My44NzEgTDU5LjExNSwxMDAuNjYxIEM2MC4yOTMsMTAxLjM0MSA2MS43ODYsMTAxLjc4MiA2My40MzUsMTAxLjkzNyBMMTQ0LjcwNyw1NS4wMTUgQzE0NC40MjgsNTQuMTA4IDE0My42ODIsNTMuMjg1IDE0Mi41NDQsNTIuNjI4IEw5Ni4wMjcsMjUuNzcxIEwxMi43MTQsNzMuODcxIEwxMi43MTQsNzMuODcxIFoiIGlkPSJGaWxsLTMiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTQ4LjMyNyw1OC40NzEgQzE0OC4xNDUsNTguNDggMTQ3Ljk2Miw1OC40OCAxNDcuNzgxLDU4LjQ3MiBDMTQ1Ljg4Nyw1OC4zODkgMTQ0LjQ3OSw1Ny40MzQgMTQ0LjYzNiw1Ni4zNCBDMTQ0LjY4OSw1NS45NjcgMTQ0LjY2NCw1NS41OTcgMTQ0LjU2NCw1NS4yMzUgTDYzLjQ2MSwxMDIuMDU3IEM2NC4wODksMTAyLjExNSA2NC43MzMsMTAyLjEzIDY1LjM3OSwxMDIuMDk5IEM2NS41NjEsMTAyLjA5IDY1Ljc0MywxMDIuMDkgNjUuOTI1LDEwMi4wOTggQzY3LjgxOSwxMDIuMTgxIDY5LjIyNywxMDMuMTM2IDY5LjA3LDEwNC4yMyBMMTQ4LjMyNyw1OC40NzEiIGlkPSJGaWxsLTQiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNjkuMDcsMTA0LjM0NyBDNjkuMDQ4LDEwNC4zNDcgNjkuMDI1LDEwNC4zNCA2OS4wMDUsMTA0LjMyNyBDNjguOTY4LDEwNC4zMDEgNjguOTQ4LDEwNC4yNTcgNjguOTU1LDEwNC4yMTMgQzY5LDEwMy44OTYgNjguODk4LDEwMy41NzYgNjguNjU4LDEwMy4yODggQzY4LjE1MywxMDIuNjc4IDY3LjEwMywxMDIuMjY2IDY1LjkyLDEwMi4yMTQgQzY1Ljc0MiwxMDIuMjA2IDY1LjU2MywxMDIuMjA3IDY1LjM4NSwxMDIuMjE1IEM2NC43NDIsMTAyLjI0NiA2NC4wODcsMTAyLjIzMiA2My40NSwxMDIuMTc0IEM2My4zOTksMTAyLjE2OSA2My4zNTgsMTAyLjEzMiA2My4zNDcsMTAyLjA4MiBDNjMuMzM2LDEwMi4wMzMgNjMuMzU4LDEwMS45ODEgNjMuNDAyLDEwMS45NTYgTDE0NC41MDYsNTUuMTM0IEMxNDQuNTM3LDU1LjExNiAxNDQuNTc1LDU1LjExMyAxNDQuNjA5LDU1LjEyNyBDMTQ0LjY0Miw1NS4xNDEgMTQ0LjY2OCw1NS4xNyAxNDQuNjc3LDU1LjIwNCBDMTQ0Ljc4MSw1NS41ODUgMTQ0LjgwNiw1NS45NzIgMTQ0Ljc1MSw1Ni4zNTcgQzE0NC43MDYsNTYuNjczIDE0NC44MDgsNTYuOTk0IDE0NS4wNDcsNTcuMjgyIEMxNDUuNTUzLDU3Ljg5MiAxNDYuNjAyLDU4LjMwMyAxNDcuNzg2LDU4LjM1NSBDMTQ3Ljk2NCw1OC4zNjMgMTQ4LjE0Myw1OC4zNjMgMTQ4LjMyMSw1OC4zNTQgQzE0OC4zNzcsNTguMzUyIDE0OC40MjQsNTguMzg3IDE0OC40MzksNTguNDM4IEMxNDguNDU0LDU4LjQ5IDE0OC40MzIsNTguNTQ1IDE0OC4zODUsNTguNTcyIEw2OS4xMjksMTA0LjMzMSBDNjkuMTExLDEwNC4zNDIgNjkuMDksMTA0LjM0NyA2OS4wNywxMDQuMzQ3IEw2OS4wNywxMDQuMzQ3IFogTTY1LjY2NSwxMDEuOTc1IEM2NS43NTQsMTAxLjk3NSA2NS44NDIsMTAxLjk3NyA2NS45MywxMDEuOTgxIEM2Ny4xOTYsMTAyLjAzNyA2OC4yODMsMTAyLjQ2OSA2OC44MzgsMTAzLjEzOSBDNjkuMDY1LDEwMy40MTMgNjkuMTg4LDEwMy43MTQgNjkuMTk4LDEwNC4wMjEgTDE0Ny44ODMsNTguNTkyIEMxNDcuODQ3LDU4LjU5MiAxNDcuODExLDU4LjU5MSAxNDcuNzc2LDU4LjU4OSBDMTQ2LjUwOSw1OC41MzMgMTQ1LjQyMiw1OC4xIDE0NC44NjcsNTcuNDMxIEMxNDQuNTg1LDU3LjA5MSAxNDQuNDY1LDU2LjcwNyAxNDQuNTIsNTYuMzI0IEMxNDQuNTYzLDU2LjAyMSAxNDQuNTUyLDU1LjcxNiAxNDQuNDg4LDU1LjQxNCBMNjMuODQ2LDEwMS45NyBDNjQuMzUzLDEwMi4wMDIgNjQuODY3LDEwMi4wMDYgNjUuMzc0LDEwMS45ODIgQzY1LjQ3MSwxMDEuOTc3IDY1LjU2OCwxMDEuOTc1IDY1LjY2NSwxMDEuOTc1IEw2NS42NjUsMTAxLjk3NSBaIiBpZD0iRmlsbC01IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTIuMjA4LDU1LjEzNCBDMS4yMDcsNTMuMzA3IDEuOTY3LDUwLjkxNyAzLjkwNiw0OS43OTcgTDU5LjkxNywxNy40NTMgQzYxLjg1NiwxNi4zMzMgNjQuMjQxLDE2LjkwNyA2NS4yNDMsMTguNzM0IEw2NS40NzUsMTkuMTQ0IEM2NS44NzIsMTkuODgyIDY2LjM2OCwyMC41NiA2Ni45NDUsMjEuMTY1IEw2Ny4yMjMsMjEuNDM1IEM3MC41NDgsMjQuNjQ5IDc1LjgwNiwyNS4xNTEgODAuMTExLDIyLjY2NSBMODcuNDMsMTguNDQ1IEM4OS4zNywxNy4zMjYgOTEuNzU0LDE3Ljg5OSA5Mi43NTUsMTkuNzI3IEw5Ni4wMDUsMjUuNjU1IEwxMi40ODYsNzMuODg0IEwyLjIwOCw1NS4xMzQgWiIgaWQ9IkZpbGwtNiIgZmlsbD0iI0ZBRkFGQSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMi40ODYsNzQuMDAxIEMxMi40NzYsNzQuMDAxIDEyLjQ2NSw3My45OTkgMTIuNDU1LDczLjk5NiBDMTIuNDI0LDczLjk4OCAxMi4zOTksNzMuOTY3IDEyLjM4NCw3My45NCBMMi4xMDYsNTUuMTkgQzEuMDc1LDUzLjMxIDEuODU3LDUwLjg0NSAzLjg0OCw0OS42OTYgTDU5Ljg1OCwxNy4zNTIgQzYwLjUyNSwxNi45NjcgNjEuMjcxLDE2Ljc2NCA2Mi4wMTYsMTYuNzY0IEM2My40MzEsMTYuNzY0IDY0LjY2NiwxNy40NjYgNjUuMzI3LDE4LjY0NiBDNjUuMzM3LDE4LjY1NCA2NS4zNDUsMTguNjYzIDY1LjM1MSwxOC42NzQgTDY1LjU3OCwxOS4wODggQzY1LjU4NCwxOS4xIDY1LjU4OSwxOS4xMTIgNjUuNTkxLDE5LjEyNiBDNjUuOTg1LDE5LjgzOCA2Ni40NjksMjAuNDk3IDY3LjAzLDIxLjA4NSBMNjcuMzA1LDIxLjM1MSBDNjkuMTUxLDIzLjEzNyA3MS42NDksMjQuMTIgNzQuMzM2LDI0LjEyIEM3Ni4zMTMsMjQuMTIgNzguMjksMjMuNTgyIDgwLjA1MywyMi41NjMgQzgwLjA2NCwyMi41NTcgODAuMDc2LDIyLjU1MyA4MC4wODgsMjIuNTUgTDg3LjM3MiwxOC4zNDQgQzg4LjAzOCwxNy45NTkgODguNzg0LDE3Ljc1NiA4OS41MjksMTcuNzU2IEM5MC45NTYsMTcuNzU2IDkyLjIwMSwxOC40NzIgOTIuODU4LDE5LjY3IEw5Ni4xMDcsMjUuNTk5IEM5Ni4xMzgsMjUuNjU0IDk2LjExOCwyNS43MjQgOTYuMDYzLDI1Ljc1NiBMMTIuNTQ1LDczLjk4NSBDMTIuNTI2LDczLjk5NiAxMi41MDYsNzQuMDAxIDEyLjQ4Niw3NC4wMDEgTDEyLjQ4Niw3NC4wMDEgWiBNNjIuMDE2LDE2Ljk5NyBDNjEuMzEyLDE2Ljk5NyA2MC42MDYsMTcuMTkgNTkuOTc1LDE3LjU1NCBMMy45NjUsNDkuODk5IEMyLjA4Myw1MC45ODUgMS4zNDEsNTMuMzA4IDIuMzEsNTUuMDc4IEwxMi41MzEsNzMuNzIzIEw5NS44NDgsMjUuNjExIEw5Mi42NTMsMTkuNzgyIEM5Mi4wMzgsMTguNjYgOTAuODcsMTcuOTkgODkuNTI5LDE3Ljk5IEM4OC44MjUsMTcuOTkgODguMTE5LDE4LjE4MiA4Ny40ODksMTguNTQ3IEw4MC4xNzIsMjIuNzcyIEM4MC4xNjEsMjIuNzc4IDgwLjE0OSwyMi43ODIgODAuMTM3LDIyLjc4NSBDNzguMzQ2LDIzLjgxMSA3Ni4zNDEsMjQuMzU0IDc0LjMzNiwyNC4zNTQgQzcxLjU4OCwyNC4zNTQgNjkuMDMzLDIzLjM0NyA2Ny4xNDIsMjEuNTE5IEw2Ni44NjQsMjEuMjQ5IEM2Ni4yNzcsMjAuNjM0IDY1Ljc3NCwxOS45NDcgNjUuMzY3LDE5LjIwMyBDNjUuMzYsMTkuMTkyIDY1LjM1NiwxOS4xNzkgNjUuMzU0LDE5LjE2NiBMNjUuMTYzLDE4LjgxOSBDNjUuMTU0LDE4LjgxMSA2NS4xNDYsMTguODAxIDY1LjE0LDE4Ljc5IEM2NC41MjUsMTcuNjY3IDYzLjM1NywxNi45OTcgNjIuMDE2LDE2Ljk5NyBMNjIuMDE2LDE2Ljk5NyBaIiBpZD0iRmlsbC03IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTQyLjQzNCw0OC44MDggTDQyLjQzNCw0OC44MDggQzM5LjkyNCw0OC44MDcgMzcuNzM3LDQ3LjU1IDM2LjU4Miw0NS40NDMgQzM0Ljc3MSw0Mi4xMzkgMzYuMTQ0LDM3LjgwOSAzOS42NDEsMzUuNzg5IEw1MS45MzIsMjguNjkxIEM1My4xMDMsMjguMDE1IDU0LjQxMywyNy42NTggNTUuNzIxLDI3LjY1OCBDNTguMjMxLDI3LjY1OCA2MC40MTgsMjguOTE2IDYxLjU3MywzMS4wMjMgQzYzLjM4NCwzNC4zMjcgNjIuMDEyLDM4LjY1NyA1OC41MTQsNDAuNjc3IEw0Ni4yMjMsNDcuNzc1IEM0NS4wNTMsNDguNDUgNDMuNzQyLDQ4LjgwOCA0Mi40MzQsNDguODA4IEw0Mi40MzQsNDguODA4IFogTTU1LjcyMSwyOC4xMjUgQzU0LjQ5NSwyOC4xMjUgNTMuMjY1LDI4LjQ2MSA1Mi4xNjYsMjkuMDk2IEwzOS44NzUsMzYuMTk0IEMzNi41OTYsMzguMDg3IDM1LjMwMiw0Mi4xMzYgMzYuOTkyLDQ1LjIxOCBDMzguMDYzLDQ3LjE3MyA0MC4wOTgsNDguMzQgNDIuNDM0LDQ4LjM0IEM0My42NjEsNDguMzQgNDQuODksNDguMDA1IDQ1Ljk5LDQ3LjM3IEw1OC4yODEsNDAuMjcyIEM2MS41NiwzOC4zNzkgNjIuODUzLDM0LjMzIDYxLjE2NCwzMS4yNDggQzYwLjA5MiwyOS4yOTMgNTguMDU4LDI4LjEyNSA1NS43MjEsMjguMTI1IEw1NS43MjEsMjguMTI1IFoiIGlkPSJGaWxsLTgiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTQ5LjU4OCwyLjQwNyBDMTQ5LjU4OCwyLjQwNyAxNTUuNzY4LDUuOTc1IDE1Ni4zMjUsNi4yOTcgTDE1Ni4zMjUsNy4xODQgQzE1Ni4zMjUsNy4zNiAxNTYuMzM4LDcuNTQ0IDE1Ni4zNjIsNy43MzMgQzE1Ni4zNzMsNy44MTQgMTU2LjM4Miw3Ljg5NCAxNTYuMzksNy45NzUgQzE1Ni41Myw5LjM5IDE1Ny4zNjMsMTAuOTczIDE1OC40OTUsMTEuOTc0IEwxNjUuODkxLDE4LjUxOSBDMTY2LjA2OCwxOC42NzUgMTY2LjI0OSwxOC44MTQgMTY2LjQzMiwxOC45MzQgQzE2OC4wMTEsMTkuOTc0IDE2OS4zODIsMTkuNCAxNjkuNDk0LDE3LjY1MiBDMTY5LjU0MywxNi44NjggMTY5LjU1MSwxNi4wNTcgMTY5LjUxNywxNS4yMjMgTDE2OS41MTQsMTUuMDYzIEwxNjkuNTE0LDEzLjkxMiBDMTcwLjc4LDE0LjY0MiAxOTUuNTAxLDI4LjkxNSAxOTUuNTAxLDI4LjkxNSBMMTk1LjUwMSw4Mi45MTUgQzE5NS41MDEsODQuMDA1IDE5NC43MzEsODQuNDQ1IDE5My43ODEsODMuODk3IEwxNTEuMzA4LDU5LjM3NCBDMTUwLjM1OCw1OC44MjYgMTQ5LjU4OCw1Ny40OTcgMTQ5LjU4OCw1Ni40MDggTDE0OS41ODgsMjIuMzc1IiBpZD0iRmlsbC05IiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE5NC41NTMsODQuMjUgQzE5NC4yOTYsODQuMjUgMTk0LjAxMyw4NC4xNjUgMTkzLjcyMiw4My45OTcgTDE1MS4yNSw1OS40NzYgQzE1MC4yNjksNTguOTA5IDE0OS40NzEsNTcuNTMzIDE0OS40NzEsNTYuNDA4IEwxNDkuNDcxLDIyLjM3NSBMMTQ5LjcwNSwyMi4zNzUgTDE0OS43MDUsNTYuNDA4IEMxNDkuNzA1LDU3LjQ1OSAxNTAuNDUsNTguNzQ0IDE1MS4zNjYsNTkuMjc0IEwxOTMuODM5LDgzLjc5NSBDMTk0LjI2Myw4NC4wNCAxOTQuNjU1LDg0LjA4MyAxOTQuOTQyLDgzLjkxNyBDMTk1LjIyNyw4My43NTMgMTk1LjM4NCw4My4zOTcgMTk1LjM4NCw4Mi45MTUgTDE5NS4zODQsMjguOTgyIEMxOTQuMTAyLDI4LjI0MiAxNzIuMTA0LDE1LjU0MiAxNjkuNjMxLDE0LjExNCBMMTY5LjYzNCwxNS4yMiBDMTY5LjY2OCwxNi4wNTIgMTY5LjY2LDE2Ljg3NCAxNjkuNjEsMTcuNjU5IEMxNjkuNTU2LDE4LjUwMyAxNjkuMjE0LDE5LjEyMyAxNjguNjQ3LDE5LjQwNSBDMTY4LjAyOCwxOS43MTQgMTY3LjE5NywxOS41NzggMTY2LjM2NywxOS4wMzIgQzE2Ni4xODEsMTguOTA5IDE2NS45OTUsMTguNzY2IDE2NS44MTQsMTguNjA2IEwxNTguNDE3LDEyLjA2MiBDMTU3LjI1OSwxMS4wMzYgMTU2LjQxOCw5LjQzNyAxNTYuMjc0LDcuOTg2IEMxNTYuMjY2LDcuOTA3IDE1Ni4yNTcsNy44MjcgMTU2LjI0Nyw3Ljc0OCBDMTU2LjIyMSw3LjU1NSAxNTYuMjA5LDcuMzY1IDE1Ni4yMDksNy4xODQgTDE1Ni4yMDksNi4zNjQgQzE1NS4zNzUsNS44ODMgMTQ5LjUyOSwyLjUwOCAxNDkuNTI5LDIuNTA4IEwxNDkuNjQ2LDIuMzA2IEMxNDkuNjQ2LDIuMzA2IDE1NS44MjcsNS44NzQgMTU2LjM4NCw2LjE5NiBMMTU2LjQ0Miw2LjIzIEwxNTYuNDQyLDcuMTg0IEMxNTYuNDQyLDcuMzU1IDE1Ni40NTQsNy41MzUgMTU2LjQ3OCw3LjcxNyBDMTU2LjQ4OSw3LjggMTU2LjQ5OSw3Ljg4MiAxNTYuNTA3LDcuOTYzIEMxNTYuNjQ1LDkuMzU4IDE1Ny40NTUsMTAuODk4IDE1OC41NzIsMTEuODg2IEwxNjUuOTY5LDE4LjQzMSBDMTY2LjE0MiwxOC41ODQgMTY2LjMxOSwxOC43MiAxNjYuNDk2LDE4LjgzNyBDMTY3LjI1NCwxOS4zMzYgMTY4LDE5LjQ2NyAxNjguNTQzLDE5LjE5NiBDMTY5LjAzMywxOC45NTMgMTY5LjMyOSwxOC40MDEgMTY5LjM3NywxNy42NDUgQzE2OS40MjcsMTYuODY3IDE2OS40MzQsMTYuMDU0IDE2OS40MDEsMTUuMjI4IEwxNjkuMzk3LDE1LjA2NSBMMTY5LjM5NywxMy43MSBMMTY5LjU3MiwxMy44MSBDMTcwLjgzOSwxNC41NDEgMTk1LjU1OSwyOC44MTQgMTk1LjU1OSwyOC44MTQgTDE5NS42MTgsMjguODQ3IEwxOTUuNjE4LDgyLjkxNSBDMTk1LjYxOCw4My40ODQgMTk1LjQyLDgzLjkxMSAxOTUuMDU5LDg0LjExOSBDMTk0LjkwOCw4NC4yMDYgMTk0LjczNyw4NC4yNSAxOTQuNTUzLDg0LjI1IiBpZD0iRmlsbC0xMCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNDUuNjg1LDU2LjE2MSBMMTY5LjgsNzAuMDgzIEwxNDMuODIyLDg1LjA4MSBMMTQyLjM2LDg0Ljc3NCBDMTM1LjgyNiw4Mi42MDQgMTI4LjczMiw4MS4wNDYgMTIxLjM0MSw4MC4xNTggQzExNi45NzYsNzkuNjM0IDExMi42NzgsODEuMjU0IDExMS43NDMsODMuNzc4IEMxMTEuNTA2LDg0LjQxNCAxMTEuNTAzLDg1LjA3MSAxMTEuNzMyLDg1LjcwNiBDMTEzLjI3LDg5Ljk3MyAxMTUuOTY4LDk0LjA2OSAxMTkuNzI3LDk3Ljg0MSBMMTIwLjI1OSw5OC42ODYgQzEyMC4yNiw5OC42ODUgOTQuMjgyLDExMy42ODMgOTQuMjgyLDExMy42ODMgTDcwLjE2Nyw5OS43NjEgTDE0NS42ODUsNTYuMTYxIiBpZD0iRmlsbC0xMSIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik05NC4yODIsMTEzLjgxOCBMOTQuMjIzLDExMy43ODUgTDY5LjkzMyw5OS43NjEgTDcwLjEwOCw5OS42NiBMMTQ1LjY4NSw1Ni4wMjYgTDE0NS43NDMsNTYuMDU5IEwxNzAuMDMzLDcwLjA4MyBMMTQzLjg0Miw4NS4yMDUgTDE0My43OTcsODUuMTk1IEMxNDMuNzcyLDg1LjE5IDE0Mi4zMzYsODQuODg4IDE0Mi4zMzYsODQuODg4IEMxMzUuNzg3LDgyLjcxNCAxMjguNzIzLDgxLjE2MyAxMjEuMzI3LDgwLjI3NCBDMTIwLjc4OCw4MC4yMDkgMTIwLjIzNiw4MC4xNzcgMTE5LjY4OSw4MC4xNzcgQzExNS45MzEsODAuMTc3IDExMi42MzUsODEuNzA4IDExMS44NTIsODMuODE5IEMxMTEuNjI0LDg0LjQzMiAxMTEuNjIxLDg1LjA1MyAxMTEuODQyLDg1LjY2NyBDMTEzLjM3Nyw4OS45MjUgMTE2LjA1OCw5My45OTMgMTE5LjgxLDk3Ljc1OCBMMTE5LjgyNiw5Ny43NzkgTDEyMC4zNTIsOTguNjE0IEMxMjAuMzU0LDk4LjYxNyAxMjAuMzU2LDk4LjYyIDEyMC4zNTgsOTguNjI0IEwxMjAuNDIyLDk4LjcyNiBMMTIwLjMxNyw5OC43ODcgQzEyMC4yNjQsOTguODE4IDk0LjU5OSwxMTMuNjM1IDk0LjM0LDExMy43ODUgTDk0LjI4MiwxMTMuODE4IEw5NC4yODIsMTEzLjgxOCBaIE03MC40MDEsOTkuNzYxIEw5NC4yODIsMTEzLjU0OSBMMTE5LjA4NCw5OS4yMjkgQzExOS42Myw5OC45MTQgMTE5LjkzLDk4Ljc0IDEyMC4xMDEsOTguNjU0IEwxMTkuNjM1LDk3LjkxNCBDMTE1Ljg2NCw5NC4xMjcgMTEzLjE2OCw5MC4wMzMgMTExLjYyMiw4NS43NDYgQzExMS4zODIsODUuMDc5IDExMS4zODYsODQuNDA0IDExMS42MzMsODMuNzM4IEMxMTIuNDQ4LDgxLjUzOSAxMTUuODM2LDc5Ljk0MyAxMTkuNjg5LDc5Ljk0MyBDMTIwLjI0Niw3OS45NDMgMTIwLjgwNiw3OS45NzYgMTIxLjM1NSw4MC4wNDIgQzEyOC43NjcsODAuOTMzIDEzNS44NDYsODIuNDg3IDE0Mi4zOTYsODQuNjYzIEMxNDMuMjMyLDg0LjgzOCAxNDMuNjExLDg0LjkxNyAxNDMuNzg2LDg0Ljk2NyBMMTY5LjU2Niw3MC4wODMgTDE0NS42ODUsNTYuMjk1IEw3MC40MDEsOTkuNzYxIEw3MC40MDEsOTkuNzYxIFoiIGlkPSJGaWxsLTEyIiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE2Ny4yMywxOC45NzkgTDE2Ny4yMyw2OS44NSBMMTM5LjkwOSw4NS42MjMgTDEzMy40NDgsNzEuNDU2IEMxMzIuNTM4LDY5LjQ2IDEzMC4wMiw2OS43MTggMTI3LjgyNCw3Mi4wMyBDMTI2Ljc2OSw3My4xNCAxMjUuOTMxLDc0LjU4NSAxMjUuNDk0LDc2LjA0OCBMMTE5LjAzNCw5Ny42NzYgTDkxLjcxMiwxMTMuNDUgTDkxLjcxMiw2Mi41NzkgTDE2Ny4yMywxOC45NzkiIGlkPSJGaWxsLTEzIiBmaWxsPSIjRkZGRkZGIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTkxLjcxMiwxMTMuNTY3IEM5MS42OTIsMTEzLjU2NyA5MS42NzIsMTEzLjU2MSA5MS42NTMsMTEzLjU1MSBDOTEuNjE4LDExMy41MyA5MS41OTUsMTEzLjQ5MiA5MS41OTUsMTEzLjQ1IEw5MS41OTUsNjIuNTc5IEM5MS41OTUsNjIuNTM3IDkxLjYxOCw2Mi40OTkgOTEuNjUzLDYyLjQ3OCBMMTY3LjE3MiwxOC44NzggQzE2Ny4yMDgsMTguODU3IDE2Ny4yNTIsMTguODU3IDE2Ny4yODgsMTguODc4IEMxNjcuMzI0LDE4Ljg5OSAxNjcuMzQ3LDE4LjkzNyAxNjcuMzQ3LDE4Ljk3OSBMMTY3LjM0Nyw2OS44NSBDMTY3LjM0Nyw2OS44OTEgMTY3LjMyNCw2OS45MyAxNjcuMjg4LDY5Ljk1IEwxMzkuOTY3LDg1LjcyNSBDMTM5LjkzOSw4NS43NDEgMTM5LjkwNSw4NS43NDUgMTM5Ljg3Myw4NS43MzUgQzEzOS44NDIsODUuNzI1IDEzOS44MTYsODUuNzAyIDEzOS44MDIsODUuNjcyIEwxMzMuMzQyLDcxLjUwNCBDMTMyLjk2Nyw3MC42ODIgMTMyLjI4LDcwLjIyOSAxMzEuNDA4LDcwLjIyOSBDMTMwLjMxOSw3MC4yMjkgMTI5LjA0NCw3MC45MTUgMTI3LjkwOCw3Mi4xMSBDMTI2Ljg3NCw3My4yIDEyNi4wMzQsNzQuNjQ3IDEyNS42MDYsNzYuMDgyIEwxMTkuMTQ2LDk3LjcwOSBDMTE5LjEzNyw5Ny43MzggMTE5LjExOCw5Ny43NjIgMTE5LjA5Miw5Ny43NzcgTDkxLjc3LDExMy41NTEgQzkxLjc1MiwxMTMuNTYxIDkxLjczMiwxMTMuNTY3IDkxLjcxMiwxMTMuNTY3IEw5MS43MTIsMTEzLjU2NyBaIE05MS44MjksNjIuNjQ3IEw5MS44MjksMTEzLjI0OCBMMTE4LjkzNSw5Ny41OTggTDEyNS4zODIsNzYuMDE1IEMxMjUuODI3LDc0LjUyNSAxMjYuNjY0LDczLjA4MSAxMjcuNzM5LDcxLjk1IEMxMjguOTE5LDcwLjcwOCAxMzAuMjU2LDY5Ljk5NiAxMzEuNDA4LDY5Ljk5NiBDMTMyLjM3Nyw2OS45OTYgMTMzLjEzOSw3MC40OTcgMTMzLjU1NCw3MS40MDcgTDEzOS45NjEsODUuNDU4IEwxNjcuMTEzLDY5Ljc4MiBMMTY3LjExMywxOS4xODEgTDkxLjgyOSw2Mi42NDcgTDkxLjgyOSw2Mi42NDcgWiIgaWQ9IkZpbGwtMTQiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTY4LjU0MywxOS4yMTMgTDE2OC41NDMsNzAuMDgzIEwxNDEuMjIxLDg1Ljg1NyBMMTM0Ljc2MSw3MS42ODkgQzEzMy44NTEsNjkuNjk0IDEzMS4zMzMsNjkuOTUxIDEyOS4xMzcsNzIuMjYzIEMxMjguMDgyLDczLjM3NCAxMjcuMjQ0LDc0LjgxOSAxMjYuODA3LDc2LjI4MiBMMTIwLjM0Niw5Ny45MDkgTDkzLjAyNSwxMTMuNjgzIEw5My4wMjUsNjIuODEzIEwxNjguNTQzLDE5LjIxMyIgaWQ9IkZpbGwtMTUiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNOTMuMDI1LDExMy44IEM5My4wMDUsMTEzLjggOTIuOTg0LDExMy43OTUgOTIuOTY2LDExMy43ODUgQzkyLjkzMSwxMTMuNzY0IDkyLjkwOCwxMTMuNzI1IDkyLjkwOCwxMTMuNjg0IEw5Mi45MDgsNjIuODEzIEM5Mi45MDgsNjIuNzcxIDkyLjkzMSw2Mi43MzMgOTIuOTY2LDYyLjcxMiBMMTY4LjQ4NCwxOS4xMTIgQzE2OC41MiwxOS4wOSAxNjguNTY1LDE5LjA5IDE2OC42MDEsMTkuMTEyIEMxNjguNjM3LDE5LjEzMiAxNjguNjYsMTkuMTcxIDE2OC42NiwxOS4yMTIgTDE2OC42Niw3MC4wODMgQzE2OC42Niw3MC4xMjUgMTY4LjYzNyw3MC4xNjQgMTY4LjYwMSw3MC4xODQgTDE0MS4yOCw4NS45NTggQzE0MS4yNTEsODUuOTc1IDE0MS4yMTcsODUuOTc5IDE0MS4xODYsODUuOTY4IEMxNDEuMTU0LDg1Ljk1OCAxNDEuMTI5LDg1LjkzNiAxNDEuMTE1LDg1LjkwNiBMMTM0LjY1NSw3MS43MzggQzEzNC4yOCw3MC45MTUgMTMzLjU5Myw3MC40NjMgMTMyLjcyLDcwLjQ2MyBDMTMxLjYzMiw3MC40NjMgMTMwLjM1Nyw3MS4xNDggMTI5LjIyMSw3Mi4zNDQgQzEyOC4xODYsNzMuNDMzIDEyNy4zNDcsNzQuODgxIDEyNi45MTksNzYuMzE1IEwxMjAuNDU4LDk3Ljk0MyBDMTIwLjQ1LDk3Ljk3MiAxMjAuNDMxLDk3Ljk5NiAxMjAuNDA1LDk4LjAxIEw5My4wODMsMTEzLjc4NSBDOTMuMDY1LDExMy43OTUgOTMuMDQ1LDExMy44IDkzLjAyNSwxMTMuOCBMOTMuMDI1LDExMy44IFogTTkzLjE0Miw2Mi44ODEgTDkzLjE0MiwxMTMuNDgxIEwxMjAuMjQ4LDk3LjgzMiBMMTI2LjY5NSw3Ni4yNDggQzEyNy4xNCw3NC43NTggMTI3Ljk3Nyw3My4zMTUgMTI5LjA1Miw3Mi4xODMgQzEzMC4yMzEsNzAuOTQyIDEzMS41NjgsNzAuMjI5IDEzMi43Miw3MC4yMjkgQzEzMy42ODksNzAuMjI5IDEzNC40NTIsNzAuNzMxIDEzNC44NjcsNzEuNjQxIEwxNDEuMjc0LDg1LjY5MiBMMTY4LjQyNiw3MC4wMTYgTDE2OC40MjYsMTkuNDE1IEw5My4xNDIsNjIuODgxIEw5My4xNDIsNjIuODgxIFoiIGlkPSJGaWxsLTE2IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE2OS44LDcwLjA4MyBMMTQyLjQ3OCw4NS44NTcgTDEzNi4wMTgsNzEuNjg5IEMxMzUuMTA4LDY5LjY5NCAxMzIuNTksNjkuOTUxIDEzMC4zOTMsNzIuMjYzIEMxMjkuMzM5LDczLjM3NCAxMjguNSw3NC44MTkgMTI4LjA2NCw3Ni4yODIgTDEyMS42MDMsOTcuOTA5IEw5NC4yODIsMTEzLjY4MyBMOTQuMjgyLDYyLjgxMyBMMTY5LjgsMTkuMjEzIEwxNjkuOCw3MC4wODMgWiIgaWQ9IkZpbGwtMTciIGZpbGw9IiNGQUZBRkEiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNOTQuMjgyLDExMy45MTcgQzk0LjI0MSwxMTMuOTE3IDk0LjIwMSwxMTMuOTA3IDk0LjE2NSwxMTMuODg2IEM5NC4wOTMsMTEzLjg0NSA5NC4wNDgsMTEzLjc2NyA5NC4wNDgsMTEzLjY4NCBMOTQuMDQ4LDYyLjgxMyBDOTQuMDQ4LDYyLjczIDk0LjA5Myw2Mi42NTIgOTQuMTY1LDYyLjYxMSBMMTY5LjY4MywxOS4wMSBDMTY5Ljc1NSwxOC45NjkgMTY5Ljg0NCwxOC45NjkgMTY5LjkxNywxOS4wMSBDMTY5Ljk4OSwxOS4wNTIgMTcwLjAzMywxOS4xMjkgMTcwLjAzMywxOS4yMTIgTDE3MC4wMzMsNzAuMDgzIEMxNzAuMDMzLDcwLjE2NiAxNjkuOTg5LDcwLjI0NCAxNjkuOTE3LDcwLjI4NSBMMTQyLjU5NSw4Ni4wNiBDMTQyLjUzOCw4Ni4wOTIgMTQyLjQ2OSw4Ni4xIDE0Mi40MDcsODYuMDggQzE0Mi4zNDQsODYuMDYgMTQyLjI5Myw4Ni4wMTQgMTQyLjI2Niw4NS45NTQgTDEzNS44MDUsNzEuNzg2IEMxMzUuNDQ1LDcwLjk5NyAxMzQuODEzLDcwLjU4IDEzMy45NzcsNzAuNTggQzEzMi45MjEsNzAuNTggMTMxLjY3Niw3MS4yNTIgMTMwLjU2Miw3Mi40MjQgQzEyOS41NCw3My41MDEgMTI4LjcxMSw3NC45MzEgMTI4LjI4Nyw3Ni4zNDggTDEyMS44MjcsOTcuOTc2IEMxMjEuODEsOTguMDM0IDEyMS43NzEsOTguMDgyIDEyMS43Miw5OC4xMTIgTDk0LjM5OCwxMTMuODg2IEM5NC4zNjIsMTEzLjkwNyA5NC4zMjIsMTEzLjkxNyA5NC4yODIsMTEzLjkxNyBMOTQuMjgyLDExMy45MTcgWiBNOTQuNTE1LDYyLjk0OCBMOTQuNTE1LDExMy4yNzkgTDEyMS40MDYsOTcuNzU0IEwxMjcuODQsNzYuMjE1IEMxMjguMjksNzQuNzA4IDEyOS4xMzcsNzMuMjQ3IDEzMC4yMjQsNzIuMTAzIEMxMzEuNDI1LDcwLjgzOCAxMzIuNzkzLDcwLjExMiAxMzMuOTc3LDcwLjExMiBDMTM0Ljk5NSw3MC4xMTIgMTM1Ljc5NSw3MC42MzggMTM2LjIzLDcxLjU5MiBMMTQyLjU4NCw4NS41MjYgTDE2OS41NjYsNjkuOTQ4IEwxNjkuNTY2LDE5LjYxNyBMOTQuNTE1LDYyLjk0OCBMOTQuNTE1LDYyLjk0OCBaIiBpZD0iRmlsbC0xOCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMDkuODk0LDkyLjk0MyBMMTA5Ljg5NCw5Mi45NDMgQzEwOC4xMiw5Mi45NDMgMTA2LjY1Myw5Mi4yMTggMTA1LjY1LDkwLjgyMyBDMTA1LjU4Myw5MC43MzEgMTA1LjU5Myw5MC42MSAxMDUuNjczLDkwLjUyOSBDMTA1Ljc1Myw5MC40NDggMTA1Ljg4LDkwLjQ0IDEwNS45NzQsOTAuNTA2IEMxMDYuNzU0LDkxLjA1MyAxMDcuNjc5LDkxLjMzMyAxMDguNzI0LDkxLjMzMyBDMTEwLjA0Nyw5MS4zMzMgMTExLjQ3OCw5MC44OTQgMTEyLjk4LDkwLjAyNyBDMTE4LjI5MSw4Ni45NiAxMjIuNjExLDc5LjUwOSAxMjIuNjExLDczLjQxNiBDMTIyLjYxMSw3MS40ODkgMTIyLjE2OSw2OS44NTYgMTIxLjMzMyw2OC42OTIgQzEyMS4yNjYsNjguNiAxMjEuMjc2LDY4LjQ3MyAxMjEuMzU2LDY4LjM5MiBDMTIxLjQzNiw2OC4zMTEgMTIxLjU2Myw2OC4yOTkgMTIxLjY1Niw2OC4zNjUgQzEyMy4zMjcsNjkuNTM3IDEyNC4yNDcsNzEuNzQ2IDEyNC4yNDcsNzQuNTg0IEMxMjQuMjQ3LDgwLjgyNiAxMTkuODIxLDg4LjQ0NyAxMTQuMzgyLDkxLjU4NyBDMTEyLjgwOCw5Mi40OTUgMTExLjI5OCw5Mi45NDMgMTA5Ljg5NCw5Mi45NDMgTDEwOS44OTQsOTIuOTQzIFogTTEwNi45MjUsOTEuNDAxIEMxMDcuNzM4LDkyLjA1MiAxMDguNzQ1LDkyLjI3OCAxMDkuODkzLDkyLjI3OCBMMTA5Ljg5NCw5Mi4yNzggQzExMS4yMTUsOTIuMjc4IDExMi42NDcsOTEuOTUxIDExNC4xNDgsOTEuMDg0IEMxMTkuNDU5LDg4LjAxNyAxMjMuNzgsODAuNjIxIDEyMy43OCw3NC41MjggQzEyMy43OCw3Mi41NDkgMTIzLjMxNyw3MC45MjkgMTIyLjQ1NCw2OS43NjcgQzEyMi44NjUsNzAuODAyIDEyMy4wNzksNzIuMDQyIDEyMy4wNzksNzMuNDAyIEMxMjMuMDc5LDc5LjY0NSAxMTguNjUzLDg3LjI4NSAxMTMuMjE0LDkwLjQyNSBDMTExLjY0LDkxLjMzNCAxMTAuMTMsOTEuNzQyIDEwOC43MjQsOTEuNzQyIEMxMDguMDgzLDkxLjc0MiAxMDcuNDgxLDkxLjU5MyAxMDYuOTI1LDkxLjQwMSBMMTA2LjkyNSw5MS40MDEgWiIgaWQ9IkZpbGwtMTkiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEzLjA5Nyw5MC4yMyBDMTE4LjQ4MSw4Ny4xMjIgMTIyLjg0NSw3OS41OTQgMTIyLjg0NSw3My40MTYgQzEyMi44NDUsNzEuMzY1IDEyMi4zNjIsNjkuNzI0IDEyMS41MjIsNjguNTU2IEMxMTkuNzM4LDY3LjMwNCAxMTcuMTQ4LDY3LjM2MiAxMTQuMjY1LDY5LjAyNiBDMTA4Ljg4MSw3Mi4xMzQgMTA0LjUxNyw3OS42NjIgMTA0LjUxNyw4NS44NCBDMTA0LjUxNyw4Ny44OTEgMTA1LDg5LjUzMiAxMDUuODQsOTAuNyBDMTA3LjYyNCw5MS45NTIgMTEwLjIxNCw5MS44OTQgMTEzLjA5Nyw5MC4yMyIgaWQ9IkZpbGwtMjAiIGZpbGw9IiNGQUZBRkEiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTA4LjcyNCw5MS42MTQgTDEwOC43MjQsOTEuNjE0IEMxMDcuNTgyLDkxLjYxNCAxMDYuNTY2LDkxLjQwMSAxMDUuNzA1LDkwLjc5NyBDMTA1LjY4NCw5MC43ODMgMTA1LjY2NSw5MC44MTEgMTA1LjY1LDkwLjc5IEMxMDQuNzU2LDg5LjU0NiAxMDQuMjgzLDg3Ljg0MiAxMDQuMjgzLDg1LjgxNyBDMTA0LjI4Myw3OS41NzUgMTA4LjcwOSw3MS45NTMgMTE0LjE0OCw2OC44MTIgQzExNS43MjIsNjcuOTA0IDExNy4yMzIsNjcuNDQ5IDExOC42MzgsNjcuNDQ5IEMxMTkuNzgsNjcuNDQ5IDEyMC43OTYsNjcuNzU4IDEyMS42NTYsNjguMzYyIEMxMjEuNjc4LDY4LjM3NyAxMjEuNjk3LDY4LjM5NyAxMjEuNzEyLDY4LjQxOCBDMTIyLjYwNiw2OS42NjIgMTIzLjA3OSw3MS4zOSAxMjMuMDc5LDczLjQxNSBDMTIzLjA3OSw3OS42NTggMTE4LjY1Myw4Ny4xOTggMTEzLjIxNCw5MC4zMzggQzExMS42NCw5MS4yNDcgMTEwLjEzLDkxLjYxNCAxMDguNzI0LDkxLjYxNCBMMTA4LjcyNCw5MS42MTQgWiBNMTA2LjAwNiw5MC41MDUgQzEwNi43OCw5MS4wMzcgMTA3LjY5NCw5MS4yODEgMTA4LjcyNCw5MS4yODEgQzExMC4wNDcsOTEuMjgxIDExMS40NzgsOTAuODY4IDExMi45OCw5MC4wMDEgQzExOC4yOTEsODYuOTM1IDEyMi42MTEsNzkuNDk2IDEyMi42MTEsNzMuNDAzIEMxMjIuNjExLDcxLjQ5NCAxMjIuMTc3LDY5Ljg4IDEyMS4zNTYsNjguNzE4IEMxMjAuNTgyLDY4LjE4NSAxMTkuNjY4LDY3LjkxOSAxMTguNjM4LDY3LjkxOSBDMTE3LjMxNSw2Ny45MTkgMTE1Ljg4Myw2OC4zNiAxMTQuMzgyLDY5LjIyNyBDMTA5LjA3MSw3Mi4yOTMgMTA0Ljc1MSw3OS43MzMgMTA0Ljc1MSw4NS44MjYgQzEwNC43NTEsODcuNzM1IDEwNS4xODUsODkuMzQzIDEwNi4wMDYsOTAuNTA1IEwxMDYuMDA2LDkwLjUwNSBaIiBpZD0iRmlsbC0yMSIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNDkuMzE4LDcuMjYyIEwxMzkuMzM0LDE2LjE0IEwxNTUuMjI3LDI3LjE3MSBMMTYwLjgxNiwyMS4wNTkgTDE0OS4zMTgsNy4yNjIiIGlkPSJGaWxsLTIyIiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE2OS42NzYsMTMuODQgTDE1OS45MjgsMTkuNDY3IEMxNTYuMjg2LDIxLjU3IDE1MC40LDIxLjU4IDE0Ni43ODEsMTkuNDkxIEMxNDMuMTYxLDE3LjQwMiAxNDMuMTgsMTQuMDAzIDE0Ni44MjIsMTEuOSBMMTU2LjMxNyw2LjI5MiBMMTQ5LjU4OCwyLjQwNyBMNjcuNzUyLDQ5LjQ3OCBMMTEzLjY3NSw3NS45OTIgTDExNi43NTYsNzQuMjEzIEMxMTcuMzg3LDczLjg0OCAxMTcuNjI1LDczLjMxNSAxMTcuMzc0LDcyLjgyMyBDMTE1LjAxNyw2OC4xOTEgMTE0Ljc4MSw2My4yNzcgMTE2LjY5MSw1OC41NjEgQzEyMi4zMjksNDQuNjQxIDE0MS4yLDMzLjc0NiAxNjUuMzA5LDMwLjQ5MSBDMTczLjQ3OCwyOS4zODggMTgxLjk4OSwyOS41MjQgMTkwLjAxMywzMC44ODUgQzE5MC44NjUsMzEuMDMgMTkxLjc4OSwzMC44OTMgMTkyLjQyLDMwLjUyOCBMMTk1LjUwMSwyOC43NSBMMTY5LjY3NiwxMy44NCIgaWQ9IkZpbGwtMjMiIGZpbGw9IiNGQUZBRkEiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEzLjY3NSw3Ni40NTkgQzExMy41OTQsNzYuNDU5IDExMy41MTQsNzYuNDM4IDExMy40NDIsNzYuMzk3IEw2Ny41MTgsNDkuODgyIEM2Ny4zNzQsNDkuNzk5IDY3LjI4NCw0OS42NDUgNjcuMjg1LDQ5LjQ3OCBDNjcuMjg1LDQ5LjMxMSA2Ny4zNzQsNDkuMTU3IDY3LjUxOSw0OS4wNzMgTDE0OS4zNTUsMi4wMDIgQzE0OS40OTksMS45MTkgMTQ5LjY3NywxLjkxOSAxNDkuODIxLDIuMDAyIEwxNTYuNTUsNS44ODcgQzE1Ni43NzQsNi4wMTcgMTU2Ljg1LDYuMzAyIDE1Ni43MjIsNi41MjYgQzE1Ni41OTIsNi43NDkgMTU2LjMwNyw2LjgyNiAxNTYuMDgzLDYuNjk2IEwxNDkuNTg3LDIuOTQ2IEw2OC42ODcsNDkuNDc5IEwxMTMuNjc1LDc1LjQ1MiBMMTE2LjUyMyw3My44MDggQzExNi43MTUsNzMuNjk3IDExNy4xNDMsNzMuMzk5IDExNi45NTgsNzMuMDM1IEMxMTQuNTQyLDY4LjI4NyAxMTQuMyw2My4yMjEgMTE2LjI1OCw1OC4zODUgQzExOS4wNjQsNTEuNDU4IDEyNS4xNDMsNDUuMTQzIDEzMy44NCw0MC4xMjIgQzE0Mi40OTcsMzUuMTI0IDE1My4zNTgsMzEuNjMzIDE2NS4yNDcsMzAuMDI4IEMxNzMuNDQ1LDI4LjkyMSAxODIuMDM3LDI5LjA1OCAxOTAuMDkxLDMwLjQyNSBDMTkwLjgzLDMwLjU1IDE5MS42NTIsMzAuNDMyIDE5Mi4xODYsMzAuMTI0IEwxOTQuNTY3LDI4Ljc1IEwxNjkuNDQyLDE0LjI0NCBDMTY5LjIxOSwxNC4xMTUgMTY5LjE0MiwxMy44MjkgMTY5LjI3MSwxMy42MDYgQzE2OS40LDEzLjM4MiAxNjkuNjg1LDEzLjMwNiAxNjkuOTA5LDEzLjQzNSBMMTk1LjczNCwyOC4zNDUgQzE5NS44NzksMjguNDI4IDE5NS45NjgsMjguNTgzIDE5NS45NjgsMjguNzUgQzE5NS45NjgsMjguOTE2IDE5NS44NzksMjkuMDcxIDE5NS43MzQsMjkuMTU0IEwxOTIuNjUzLDMwLjkzMyBDMTkxLjkzMiwzMS4zNSAxOTAuODksMzEuNTA4IDE4OS45MzUsMzEuMzQ2IEMxODEuOTcyLDI5Ljk5NSAxNzMuNDc4LDI5Ljg2IDE2NS4zNzIsMzAuOTU0IEMxNTMuNjAyLDMyLjU0MyAxNDIuODYsMzUuOTkzIDEzNC4zMDcsNDAuOTMxIEMxMjUuNzkzLDQ1Ljg0NyAxMTkuODUxLDUyLjAwNCAxMTcuMTI0LDU4LjczNiBDMTE1LjI3LDYzLjMxNCAxMTUuNTAxLDY4LjExMiAxMTcuNzksNzIuNjExIEMxMTguMTYsNzMuMzM2IDExNy44NDUsNzQuMTI0IDExNi45OSw3NC42MTcgTDExMy45MDksNzYuMzk3IEMxMTMuODM2LDc2LjQzOCAxMTMuNzU2LDc2LjQ1OSAxMTMuNjc1LDc2LjQ1OSIgaWQ9IkZpbGwtMjQiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTUzLjMxNiwyMS4yNzkgQzE1MC45MDMsMjEuMjc5IDE0OC40OTUsMjAuNzUxIDE0Ni42NjQsMTkuNjkzIEMxNDQuODQ2LDE4LjY0NCAxNDMuODQ0LDE3LjIzMiAxNDMuODQ0LDE1LjcxOCBDMTQzLjg0NCwxNC4xOTEgMTQ0Ljg2LDEyLjc2MyAxNDYuNzA1LDExLjY5OCBMMTU2LjE5OCw2LjA5MSBDMTU2LjMwOSw2LjAyNSAxNTYuNDUyLDYuMDYyIDE1Ni41MTgsNi4xNzMgQzE1Ni41ODMsNi4yODQgMTU2LjU0Nyw2LjQyNyAxNTYuNDM2LDYuNDkzIEwxNDYuOTQsMTIuMTAyIEMxNDUuMjQ0LDEzLjA4MSAxNDQuMzEyLDE0LjM2NSAxNDQuMzEyLDE1LjcxOCBDMTQ0LjMxMiwxNy4wNTggMTQ1LjIzLDE4LjMyNiAxNDYuODk3LDE5LjI4OSBDMTUwLjQ0NiwyMS4zMzggMTU2LjI0LDIxLjMyNyAxNTkuODExLDE5LjI2NSBMMTY5LjU1OSwxMy42MzcgQzE2OS42NywxMy41NzMgMTY5LjgxMywxMy42MTEgMTY5Ljg3OCwxMy43MjMgQzE2OS45NDMsMTMuODM0IDE2OS45MDQsMTMuOTc3IDE2OS43OTMsMTQuMDQyIEwxNjAuMDQ1LDE5LjY3IEMxNTguMTg3LDIwLjc0MiAxNTUuNzQ5LDIxLjI3OSAxNTMuMzE2LDIxLjI3OSIgaWQ9IkZpbGwtMjUiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEzLjY3NSw3NS45OTIgTDY3Ljc2Miw0OS40ODQiIGlkPSJGaWxsLTI2IiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTExMy42NzUsNzYuMzQyIEMxMTMuNjE1LDc2LjM0MiAxMTMuNTU1LDc2LjMyNyAxMTMuNSw3Ni4yOTUgTDY3LjU4Nyw0OS43ODcgQzY3LjQxOSw0OS42OSA2Ny4zNjIsNDkuNDc2IDY3LjQ1OSw0OS4zMDkgQzY3LjU1Niw0OS4xNDEgNjcuNzcsNDkuMDgzIDY3LjkzNyw0OS4xOCBMMTEzLjg1LDc1LjY4OCBDMTE0LjAxOCw3NS43ODUgMTE0LjA3NSw3NiAxMTMuOTc4LDc2LjE2NyBDMTEzLjkxNCw3Ni4yNzkgMTEzLjc5Niw3Ni4zNDIgMTEzLjY3NSw3Ni4zNDIiIGlkPSJGaWxsLTI3IiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTY3Ljc2Miw0OS40ODQgTDY3Ljc2MiwxMDMuNDg1IEM2Ny43NjIsMTA0LjU3NSA2OC41MzIsMTA1LjkwMyA2OS40ODIsMTA2LjQ1MiBMMTExLjk1NSwxMzAuOTczIEMxMTIuOTA1LDEzMS41MjIgMTEzLjY3NSwxMzEuMDgzIDExMy42NzUsMTI5Ljk5MyBMMTEzLjY3NSw3NS45OTIiIGlkPSJGaWxsLTI4IiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTExMi43MjcsMTMxLjU2MSBDMTEyLjQzLDEzMS41NjEgMTEyLjEwNywxMzEuNDY2IDExMS43OCwxMzEuMjc2IEw2OS4zMDcsMTA2Ljc1NSBDNjguMjQ0LDEwNi4xNDIgNjcuNDEyLDEwNC43MDUgNjcuNDEyLDEwMy40ODUgTDY3LjQxMiw0OS40ODQgQzY3LjQxMiw0OS4yOSA2Ny41NjksNDkuMTM0IDY3Ljc2Miw0OS4xMzQgQzY3Ljk1Niw0OS4xMzQgNjguMTEzLDQ5LjI5IDY4LjExMyw0OS40ODQgTDY4LjExMywxMDMuNDg1IEM2OC4xMTMsMTA0LjQ0NSA2OC44MiwxMDUuNjY1IDY5LjY1NywxMDYuMTQ4IEwxMTIuMTMsMTMwLjY3IEMxMTIuNDc0LDEzMC44NjggMTEyLjc5MSwxMzAuOTEzIDExMywxMzAuNzkyIEMxMTMuMjA2LDEzMC42NzMgMTEzLjMyNSwxMzAuMzgxIDExMy4zMjUsMTI5Ljk5MyBMMTEzLjMyNSw3NS45OTIgQzExMy4zMjUsNzUuNzk4IDExMy40ODIsNzUuNjQxIDExMy42NzUsNzUuNjQxIEMxMTMuODY5LDc1LjY0MSAxMTQuMDI1LDc1Ljc5OCAxMTQuMDI1LDc1Ljk5MiBMMTE0LjAyNSwxMjkuOTkzIEMxMTQuMDI1LDEzMC42NDggMTEzLjc4NiwxMzEuMTQ3IDExMy4zNSwxMzEuMzk5IEMxMTMuMTYyLDEzMS41MDcgMTEyLjk1MiwxMzEuNTYxIDExMi43MjcsMTMxLjU2MSIgaWQ9IkZpbGwtMjkiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEyLjg2LDQwLjUxMiBDMTEyLjg2LDQwLjUxMiAxMTIuODYsNDAuNTEyIDExMi44NTksNDAuNTEyIEMxMTAuNTQxLDQwLjUxMiAxMDguMzYsMzkuOTkgMTA2LjcxNywzOS4wNDEgQzEwNS4wMTIsMzguMDU3IDEwNC4wNzQsMzYuNzI2IDEwNC4wNzQsMzUuMjkyIEMxMDQuMDc0LDMzLjg0NyAxMDUuMDI2LDMyLjUwMSAxMDYuNzU0LDMxLjUwNCBMMTE4Ljc5NSwyNC41NTEgQzEyMC40NjMsMjMuNTg5IDEyMi42NjksMjMuMDU4IDEyNS4wMDcsMjMuMDU4IEMxMjcuMzI1LDIzLjA1OCAxMjkuNTA2LDIzLjU4MSAxMzEuMTUsMjQuNTMgQzEzMi44NTQsMjUuNTE0IDEzMy43OTMsMjYuODQ1IDEzMy43OTMsMjguMjc4IEMxMzMuNzkzLDI5LjcyNCAxMzIuODQxLDMxLjA2OSAxMzEuMTEzLDMyLjA2NyBMMTE5LjA3MSwzOS4wMTkgQzExNy40MDMsMzkuOTgyIDExNS4xOTcsNDAuNTEyIDExMi44Niw0MC41MTIgTDExMi44Niw0MC41MTIgWiBNMTI1LjAwNywyMy43NTkgQzEyMi43OSwyMy43NTkgMTIwLjcwOSwyNC4yNTYgMTE5LjE0NiwyNS4xNTggTDEwNy4xMDQsMzIuMTEgQzEwNS42MDIsMzIuOTc4IDEwNC43NzQsMzQuMTA4IDEwNC43NzQsMzUuMjkyIEMxMDQuNzc0LDM2LjQ2NSAxMDUuNTg5LDM3LjU4MSAxMDcuMDY3LDM4LjQzNCBDMTA4LjYwNSwzOS4zMjMgMTEwLjY2MywzOS44MTIgMTEyLjg1OSwzOS44MTIgTDExMi44NiwzOS44MTIgQzExNS4wNzYsMzkuODEyIDExNy4xNTgsMzkuMzE1IDExOC43MjEsMzguNDEzIEwxMzAuNzYyLDMxLjQ2IEMxMzIuMjY0LDMwLjU5MyAxMzMuMDkyLDI5LjQ2MyAxMzMuMDkyLDI4LjI3OCBDMTMzLjA5MiwyNy4xMDYgMTMyLjI3OCwyNS45OSAxMzAuOCwyNS4xMzYgQzEyOS4yNjEsMjQuMjQ4IDEyNy4yMDQsMjMuNzU5IDEyNS4wMDcsMjMuNzU5IEwxMjUuMDA3LDIzLjc1OSBaIiBpZD0iRmlsbC0zMCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNjUuNjMsMTYuMjE5IEwxNTkuODk2LDE5LjUzIEMxNTYuNzI5LDIxLjM1OCAxNTEuNjEsMjEuMzY3IDE0OC40NjMsMTkuNTUgQzE0NS4zMTYsMTcuNzMzIDE0NS4zMzIsMTQuNzc4IDE0OC40OTksMTIuOTQ5IEwxNTQuMjMzLDkuNjM5IEwxNjUuNjMsMTYuMjE5IiBpZD0iRmlsbC0zMSIgZmlsbD0iI0ZBRkFGQSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNTQuMjMzLDEwLjQ0OCBMMTY0LjIyOCwxNi4yMTkgTDE1OS41NDYsMTguOTIzIEMxNTguMTEyLDE5Ljc1IDE1Ni4xOTQsMjAuMjA2IDE1NC4xNDcsMjAuMjA2IEMxNTIuMTE4LDIwLjIwNiAxNTAuMjI0LDE5Ljc1NyAxNDguODE0LDE4Ljk0MyBDMTQ3LjUyNCwxOC4xOTkgMTQ2LjgxNCwxNy4yNDkgMTQ2LjgxNCwxNi4yNjkgQzE0Ni44MTQsMTUuMjc4IDE0Ny41MzcsMTQuMzE0IDE0OC44NSwxMy41NTYgTDE1NC4yMzMsMTAuNDQ4IE0xNTQuMjMzLDkuNjM5IEwxNDguNDk5LDEyLjk0OSBDMTQ1LjMzMiwxNC43NzggMTQ1LjMxNiwxNy43MzMgMTQ4LjQ2MywxOS41NSBDMTUwLjAzMSwyMC40NTUgMTUyLjA4NiwyMC45MDcgMTU0LjE0NywyMC45MDcgQzE1Ni4yMjQsMjAuOTA3IDE1OC4zMDYsMjAuNDQ3IDE1OS44OTYsMTkuNTMgTDE2NS42MywxNi4yMTkgTDE1NC4yMzMsOS42MzkiIGlkPSJGaWxsLTMyIiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE0NS40NDUsNzIuNjY3IEwxNDUuNDQ1LDcyLjY2NyBDMTQzLjY3Miw3Mi42NjcgMTQyLjIwNCw3MS44MTcgMTQxLjIwMiw3MC40MjIgQzE0MS4xMzUsNzAuMzMgMTQxLjE0NSw3MC4xNDcgMTQxLjIyNSw3MC4wNjYgQzE0MS4zMDUsNjkuOTg1IDE0MS40MzIsNjkuOTQ2IDE0MS41MjUsNzAuMDExIEMxNDIuMzA2LDcwLjU1OSAxNDMuMjMxLDcwLjgyMyAxNDQuMjc2LDcwLjgyMiBDMTQ1LjU5OCw3MC44MjIgMTQ3LjAzLDcwLjM3NiAxNDguNTMyLDY5LjUwOSBDMTUzLjg0Miw2Ni40NDMgMTU4LjE2Myw1OC45ODcgMTU4LjE2Myw1Mi44OTQgQzE1OC4xNjMsNTAuOTY3IDE1Ny43MjEsNDkuMzMyIDE1Ni44ODQsNDguMTY4IEMxNTYuODE4LDQ4LjA3NiAxNTYuODI4LDQ3Ljk0OCAxNTYuOTA4LDQ3Ljg2NyBDMTU2Ljk4OCw0Ny43ODYgMTU3LjExNCw0Ny43NzQgMTU3LjIwOCw0Ny44NCBDMTU4Ljg3OCw0OS4wMTIgMTU5Ljc5OCw1MS4yMiAxNTkuNzk4LDU0LjA1OSBDMTU5Ljc5OCw2MC4zMDEgMTU1LjM3Myw2OC4wNDYgMTQ5LjkzMyw3MS4xODYgQzE0OC4zNiw3Mi4wOTQgMTQ2Ljg1LDcyLjY2NyAxNDUuNDQ1LDcyLjY2NyBMMTQ1LjQ0NSw3Mi42NjcgWiBNMTQyLjQ3Niw3MSBDMTQzLjI5LDcxLjY1MSAxNDQuMjk2LDcyLjAwMiAxNDUuNDQ1LDcyLjAwMiBDMTQ2Ljc2Nyw3Mi4wMDIgMTQ4LjE5OCw3MS41NSAxNDkuNyw3MC42ODIgQzE1NS4wMSw2Ny42MTcgMTU5LjMzMSw2MC4xNTkgMTU5LjMzMSw1NC4wNjUgQzE1OS4zMzEsNTIuMDg1IDE1OC44NjgsNTAuNDM1IDE1OC4wMDYsNDkuMjcyIEMxNTguNDE3LDUwLjMwNyAxNTguNjMsNTEuNTMyIDE1OC42Myw1Mi44OTIgQzE1OC42Myw1OS4xMzQgMTU0LjIwNSw2Ni43NjcgMTQ4Ljc2NSw2OS45MDcgQzE0Ny4xOTIsNzAuODE2IDE0NS42ODEsNzEuMjgzIDE0NC4yNzYsNzEuMjgzIEMxNDMuNjM0LDcxLjI4MyAxNDMuMDMzLDcxLjE5MiAxNDIuNDc2LDcxIEwxNDIuNDc2LDcxIFoiIGlkPSJGaWxsLTMzIiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE0OC42NDgsNjkuNzA0IEMxNTQuMDMyLDY2LjU5NiAxNTguMzk2LDU5LjA2OCAxNTguMzk2LDUyLjg5MSBDMTU4LjM5Niw1MC44MzkgMTU3LjkxMyw0OS4xOTggMTU3LjA3NCw0OC4wMyBDMTU1LjI4OSw0Ni43NzggMTUyLjY5OSw0Ni44MzYgMTQ5LjgxNiw0OC41MDEgQzE0NC40MzMsNTEuNjA5IDE0MC4wNjgsNTkuMTM3IDE0MC4wNjgsNjUuMzE0IEMxNDAuMDY4LDY3LjM2NSAxNDAuNTUyLDY5LjAwNiAxNDEuMzkxLDcwLjE3NCBDMTQzLjE3Niw3MS40MjcgMTQ1Ljc2NSw3MS4zNjkgMTQ4LjY0OCw2OS43MDQiIGlkPSJGaWxsLTM0IiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE0NC4yNzYsNzEuMjc2IEwxNDQuMjc2LDcxLjI3NiBDMTQzLjEzMyw3MS4yNzYgMTQyLjExOCw3MC45NjkgMTQxLjI1Nyw3MC4zNjUgQzE0MS4yMzYsNzAuMzUxIDE0MS4yMTcsNzAuMzMyIDE0MS4yMDIsNzAuMzExIEMxNDAuMzA3LDY5LjA2NyAxMzkuODM1LDY3LjMzOSAxMzkuODM1LDY1LjMxNCBDMTM5LjgzNSw1OS4wNzMgMTQ0LjI2LDUxLjQzOSAxNDkuNyw0OC4yOTggQzE1MS4yNzMsNDcuMzkgMTUyLjc4NCw0Ni45MjkgMTU0LjE4OSw0Ni45MjkgQzE1NS4zMzIsNDYuOTI5IDE1Ni4zNDcsNDcuMjM2IDE1Ny4yMDgsNDcuODM5IEMxNTcuMjI5LDQ3Ljg1NCAxNTcuMjQ4LDQ3Ljg3MyAxNTcuMjYzLDQ3Ljg5NCBDMTU4LjE1Nyw0OS4xMzggMTU4LjYzLDUwLjg2NSAxNTguNjMsNTIuODkxIEMxNTguNjMsNTkuMTMyIDE1NC4yMDUsNjYuNzY2IDE0OC43NjUsNjkuOTA3IEMxNDcuMTkyLDcwLjgxNSAxNDUuNjgxLDcxLjI3NiAxNDQuMjc2LDcxLjI3NiBMMTQ0LjI3Niw3MS4yNzYgWiBNMTQxLjU1OCw3MC4xMDQgQzE0Mi4zMzEsNzAuNjM3IDE0My4yNDUsNzEuMDA1IDE0NC4yNzYsNzEuMDA1IEMxNDUuNTk4LDcxLjAwNSAxNDcuMDMsNzAuNDY3IDE0OC41MzIsNjkuNiBDMTUzLjg0Miw2Ni41MzQgMTU4LjE2Myw1OS4wMzMgMTU4LjE2Myw1Mi45MzkgQzE1OC4xNjMsNTEuMDMxIDE1Ny43MjksNDkuMzg1IDE1Ni45MDcsNDguMjIzIEMxNTYuMTMzLDQ3LjY5MSAxNTUuMjE5LDQ3LjQwOSAxNTQuMTg5LDQ3LjQwOSBDMTUyLjg2Nyw0Ny40MDkgMTUxLjQzNSw0Ny44NDIgMTQ5LjkzMyw0OC43MDkgQzE0NC42MjMsNTEuNzc1IDE0MC4zMDIsNTkuMjczIDE0MC4zMDIsNjUuMzY2IEMxNDAuMzAyLDY3LjI3NiAxNDAuNzM2LDY4Ljk0MiAxNDEuNTU4LDcwLjEwNCBMMTQxLjU1OCw3MC4xMDQgWiIgaWQ9IkZpbGwtMzUiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTUwLjcyLDY1LjM2MSBMMTUwLjM1Nyw2NS4wNjYgQzE1MS4xNDcsNjQuMDkyIDE1MS44NjksNjMuMDQgMTUyLjUwNSw2MS45MzggQzE1My4zMTMsNjAuNTM5IDE1My45NzgsNTkuMDY3IDE1NC40ODIsNTcuNTYzIEwxNTQuOTI1LDU3LjcxMiBDMTU0LjQxMiw1OS4yNDUgMTUzLjczMyw2MC43NDUgMTUyLjkxLDYyLjE3MiBDMTUyLjI2Miw2My4yOTUgMTUxLjUyNSw2NC4zNjggMTUwLjcyLDY1LjM2MSIgaWQ9IkZpbGwtMzYiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTE1LjkxNyw4NC41MTQgTDExNS41NTQsODQuMjIgQzExNi4zNDQsODMuMjQ1IDExNy4wNjYsODIuMTk0IDExNy43MDIsODEuMDkyIEMxMTguNTEsNzkuNjkyIDExOS4xNzUsNzguMjIgMTE5LjY3OCw3Ni43MTcgTDEyMC4xMjEsNzYuODY1IEMxMTkuNjA4LDc4LjM5OCAxMTguOTMsNzkuODk5IDExOC4xMDYsODEuMzI2IEMxMTcuNDU4LDgyLjQ0OCAxMTYuNzIyLDgzLjUyMSAxMTUuOTE3LDg0LjUxNCIgaWQ9IkZpbGwtMzciIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTE0LDEzMC40NzYgTDExNCwxMzAuMDA4IEwxMTQsNzYuMDUyIEwxMTQsNzUuNTg0IEwxMTQsNzYuMDUyIEwxMTQsMTMwLjAwOCBMMTE0LDEzMC40NzYiIGlkPSJGaWxsLTM4IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICA8L2c+CiAgICAgICAgICAgICAgICA8ZyBpZD0iSW1wb3J0ZWQtTGF5ZXJzLUNvcHkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDYyLjAwMDAwMCwgMC4wMDAwMDApIiBza2V0Y2g6dHlwZT0iTVNTaGFwZUdyb3VwIj4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTkuODIyLDM3LjQ3NCBDMTkuODM5LDM3LjMzOSAxOS43NDcsMzcuMTk0IDE5LjU1NSwzNy4wODIgQzE5LjIyOCwzNi44OTQgMTguNzI5LDM2Ljg3MiAxOC40NDYsMzcuMDM3IEwxMi40MzQsNDAuNTA4IEMxMi4zMDMsNDAuNTg0IDEyLjI0LDQwLjY4NiAxMi4yNDMsNDAuNzkzIEMxMi4yNDUsNDAuOTI1IDEyLjI0NSw0MS4yNTQgMTIuMjQ1LDQxLjM3MSBMMTIuMjQ1LDQxLjQxNCBMMTIuMjM4LDQxLjU0MiBDOC4xNDgsNDMuODg3IDUuNjQ3LDQ1LjMyMSA1LjY0Nyw0NS4zMjEgQzUuNjQ2LDQ1LjMyMSAzLjU3LDQ2LjM2NyAyLjg2LDUwLjUxMyBDMi44Niw1MC41MTMgMS45NDgsNTcuNDc0IDEuOTYyLDcwLjI1OCBDMS45NzcsODIuODI4IDIuNTY4LDg3LjMyOCAzLjEyOSw5MS42MDkgQzMuMzQ5LDkzLjI5MyA2LjEzLDkzLjczNCA2LjEzLDkzLjczNCBDNi40NjEsOTMuNzc0IDYuODI4LDkzLjcwNyA3LjIxLDkzLjQ4NiBMODIuNDgzLDQ5LjkzNSBDODQuMjkxLDQ4Ljg2NiA4NS4xNSw0Ni4yMTYgODUuNTM5LDQzLjY1MSBDODYuNzUyLDM1LjY2MSA4Ny4yMTQsMTAuNjczIDg1LjI2NCwzLjc3MyBDODUuMDY4LDMuMDggODQuNzU0LDIuNjkgODQuMzk2LDIuNDkxIEw4Mi4zMSwxLjcwMSBDODEuNTgzLDEuNzI5IDgwLjg5NCwyLjE2OCA4MC43NzYsMi4yMzYgQzgwLjYzNiwyLjMxNyA0MS44MDcsMjQuNTg1IDIwLjAzMiwzNy4wNzIgTDE5LjgyMiwzNy40NzQiIGlkPSJGaWxsLTEiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNODIuMzExLDEuNzAxIEw4NC4zOTYsMi40OTEgQzg0Ljc1NCwyLjY5IDg1LjA2OCwzLjA4IDg1LjI2NCwzLjc3MyBDODcuMjEzLDEwLjY3MyA4Ni43NTEsMzUuNjYgODUuNTM5LDQzLjY1MSBDODUuMTQ5LDQ2LjIxNiA4NC4yOSw0OC44NjYgODIuNDgzLDQ5LjkzNSBMNy4yMSw5My40ODYgQzYuODk3LDkzLjY2NyA2LjU5NSw5My43NDQgNi4zMTQsOTMuNzQ0IEw2LjEzMSw5My43MzMgQzYuMTMxLDkzLjczNCAzLjM0OSw5My4yOTMgMy4xMjgsOTEuNjA5IEMyLjU2OCw4Ny4zMjcgMS45NzcsODIuODI4IDEuOTYzLDcwLjI1OCBDMS45NDgsNTcuNDc0IDIuODYsNTAuNTEzIDIuODYsNTAuNTEzIEMzLjU3LDQ2LjM2NyA1LjY0Nyw0NS4zMjEgNS42NDcsNDUuMzIxIEM1LjY0Nyw0NS4zMjEgOC4xNDgsNDMuODg3IDEyLjIzOCw0MS41NDIgTDEyLjI0NSw0MS40MTQgTDEyLjI0NSw0MS4zNzEgQzEyLjI0NSw0MS4yNTQgMTIuMjQ1LDQwLjkyNSAxMi4yNDMsNDAuNzkzIEMxMi4yNCw0MC42ODYgMTIuMzAyLDQwLjU4MyAxMi40MzQsNDAuNTA4IEwxOC40NDYsMzcuMDM2IEMxOC41NzQsMzYuOTYyIDE4Ljc0NiwzNi45MjYgMTguOTI3LDM2LjkyNiBDMTkuMTQ1LDM2LjkyNiAxOS4zNzYsMzYuOTc5IDE5LjU1NCwzNy4wODIgQzE5Ljc0NywzNy4xOTQgMTkuODM5LDM3LjM0IDE5LjgyMiwzNy40NzQgTDIwLjAzMywzNy4wNzIgQzQxLjgwNiwyNC41ODUgODAuNjM2LDIuMzE4IDgwLjc3NywyLjIzNiBDODAuODk0LDIuMTY4IDgxLjU4MywxLjcyOSA4Mi4zMTEsMS43MDEgTTgyLjMxMSwwLjcwNCBMODIuMjcyLDAuNzA1IEM4MS42NTQsMC43MjggODAuOTg5LDAuOTQ5IDgwLjI5OCwxLjM2MSBMODAuMjc3LDEuMzczIEM4MC4xMjksMS40NTggNTkuNzY4LDEzLjEzNSAxOS43NTgsMzYuMDc5IEMxOS41LDM1Ljk4MSAxOS4yMTQsMzUuOTI5IDE4LjkyNywzNS45MjkgQzE4LjU2MiwzNS45MjkgMTguMjIzLDM2LjAxMyAxNy45NDcsMzYuMTczIEwxMS45MzUsMzkuNjQ0IEMxMS40OTMsMzkuODk5IDExLjIzNiw0MC4zMzQgMTEuMjQ2LDQwLjgxIEwxMS4yNDcsNDAuOTYgTDUuMTY3LDQ0LjQ0NyBDNC43OTQsNDQuNjQ2IDIuNjI1LDQ1Ljk3OCAxLjg3Nyw1MC4zNDUgTDEuODcxLDUwLjM4NCBDMS44NjIsNTAuNDU0IDAuOTUxLDU3LjU1NyAwLjk2NSw3MC4yNTkgQzAuOTc5LDgyLjg3OSAxLjU2OCw4Ny4zNzUgMi4xMzcsOTEuNzI0IEwyLjEzOSw5MS43MzkgQzIuNDQ3LDk0LjA5NCA1LjYxNCw5NC42NjIgNS45NzUsOTQuNzE5IEw2LjAwOSw5NC43MjMgQzYuMTEsOTQuNzM2IDYuMjEzLDk0Ljc0MiA2LjMxNCw5NC43NDIgQzYuNzksOTQuNzQyIDcuMjYsOTQuNjEgNy43MSw5NC4zNSBMODIuOTgzLDUwLjc5OCBDODQuNzk0LDQ5LjcyNyA4NS45ODIsNDcuMzc1IDg2LjUyNSw0My44MDEgQzg3LjcxMSwzNS45ODcgODguMjU5LDEwLjcwNSA4Ni4yMjQsMy41MDIgQzg1Ljk3MSwyLjYwOSA4NS41MiwxLjk3NSA4NC44ODEsMS42MiBMODQuNzQ5LDEuNTU4IEw4Mi42NjQsMC43NjkgQzgyLjU1MSwwLjcyNSA4Mi40MzEsMC43MDQgODIuMzExLDAuNzA0IiBpZD0iRmlsbC0yIiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTY2LjI2NywxMS41NjUgTDY3Ljc2MiwxMS45OTkgTDExLjQyMyw0NC4zMjUiIGlkPSJGaWxsLTMiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTIuMjAyLDkwLjU0NSBDMTIuMDI5LDkwLjU0NSAxMS44NjIsOTAuNDU1IDExLjc2OSw5MC4yOTUgQzExLjYzMiw5MC4wNTcgMTEuNzEzLDg5Ljc1MiAxMS45NTIsODkuNjE0IEwzMC4zODksNzguOTY5IEMzMC42MjgsNzguODMxIDMwLjkzMyw3OC45MTMgMzEuMDcxLDc5LjE1MiBDMzEuMjA4LDc5LjM5IDMxLjEyNyw3OS42OTYgMzAuODg4LDc5LjgzMyBMMTIuNDUxLDkwLjQ3OCBMMTIuMjAyLDkwLjU0NSIgaWQ9IkZpbGwtNCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMy43NjQsNDIuNjU0IEwxMy42NTYsNDIuNTkyIEwxMy43MDIsNDIuNDIxIEwxOC44MzcsMzkuNDU3IEwxOS4wMDcsMzkuNTAyIEwxOC45NjIsMzkuNjczIEwxMy44MjcsNDIuNjM3IEwxMy43NjQsNDIuNjU0IiBpZD0iRmlsbC01IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTguNTIsOTAuMzc1IEw4LjUyLDQ2LjQyMSBMOC41ODMsNDYuMzg1IEw3NS44NCw3LjU1NCBMNzUuODQsNTEuNTA4IEw3NS43NzgsNTEuNTQ0IEw4LjUyLDkwLjM3NSBMOC41Miw5MC4zNzUgWiBNOC43Nyw0Ni41NjQgTDguNzcsODkuOTQ0IEw3NS41OTEsNTEuMzY1IEw3NS41OTEsNy45ODUgTDguNzcsNDYuNTY0IEw4Ljc3LDQ2LjU2NCBaIiBpZD0iRmlsbC02IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTI0Ljk4Niw4My4xODIgQzI0Ljc1Niw4My4zMzEgMjQuMzc0LDgzLjU2NiAyNC4xMzcsODMuNzA1IEwxMi42MzIsOTAuNDA2IEMxMi4zOTUsOTAuNTQ1IDEyLjQyNiw5MC42NTggMTIuNyw5MC42NTggTDEzLjI2NSw5MC42NTggQzEzLjU0LDkwLjY1OCAxMy45NTgsOTAuNTQ1IDE0LjE5NSw5MC40MDYgTDI1LjcsODMuNzA1IEMyNS45MzcsODMuNTY2IDI2LjEyOCw4My40NTIgMjYuMTI1LDgzLjQ0OSBDMjYuMTIyLDgzLjQ0NyAyNi4xMTksODMuMjIgMjYuMTE5LDgyLjk0NiBDMjYuMTE5LDgyLjY3MiAyNS45MzEsODIuNTY5IDI1LjcwMSw4Mi43MTkgTDI0Ljk4Niw4My4xODIiIGlkPSJGaWxsLTciIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTMuMjY2LDkwLjc4MiBMMTIuNyw5MC43ODIgQzEyLjUsOTAuNzgyIDEyLjM4NCw5MC43MjYgMTIuMzU0LDkwLjYxNiBDMTIuMzI0LDkwLjUwNiAxMi4zOTcsOTAuMzk5IDEyLjU2OSw5MC4yOTkgTDI0LjA3NCw4My41OTcgQzI0LjMxLDgzLjQ1OSAyNC42ODksODMuMjI2IDI0LjkxOCw4My4wNzggTDI1LjYzMyw4Mi42MTQgQzI1LjcyMyw4Mi41NTUgMjUuODEzLDgyLjUyNSAyNS44OTksODIuNTI1IEMyNi4wNzEsODIuNTI1IDI2LjI0NCw4Mi42NTUgMjYuMjQ0LDgyLjk0NiBDMjYuMjQ0LDgzLjE2IDI2LjI0NSw4My4zMDkgMjYuMjQ3LDgzLjM4MyBMMjYuMjUzLDgzLjM4NyBMMjYuMjQ5LDgzLjQ1NiBDMjYuMjQ2LDgzLjUzMSAyNi4yNDYsODMuNTMxIDI1Ljc2Myw4My44MTIgTDE0LjI1OCw5MC41MTQgQzE0LDkwLjY2NSAxMy41NjQsOTAuNzgyIDEzLjI2Niw5MC43ODIgTDEzLjI2Niw5MC43ODIgWiBNMTIuNjY2LDkwLjUzMiBMMTIuNyw5MC41MzMgTDEzLjI2Niw5MC41MzMgQzEzLjUxOCw5MC41MzMgMTMuOTE1LDkwLjQyNSAxNC4xMzIsOTAuMjk5IEwyNS42MzcsODMuNTk3IEMyNS44MDUsODMuNDk5IDI1LjkzMSw4My40MjQgMjUuOTk4LDgzLjM4MyBDMjUuOTk0LDgzLjI5OSAyNS45OTQsODMuMTY1IDI1Ljk5NCw4Mi45NDYgTDI1Ljg5OSw4Mi43NzUgTDI1Ljc2OCw4Mi44MjQgTDI1LjA1NCw4My4yODcgQzI0LjgyMiw4My40MzcgMjQuNDM4LDgzLjY3MyAyNC4yLDgzLjgxMiBMMTIuNjk1LDkwLjUxNCBMMTIuNjY2LDkwLjUzMiBMMTIuNjY2LDkwLjUzMiBaIiBpZD0iRmlsbC04IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTEzLjI2Niw4OS44NzEgTDEyLjcsODkuODcxIEMxMi41LDg5Ljg3MSAxMi4zODQsODkuODE1IDEyLjM1NCw4OS43MDUgQzEyLjMyNCw4OS41OTUgMTIuMzk3LDg5LjQ4OCAxMi41NjksODkuMzg4IEwyNC4wNzQsODIuNjg2IEMyNC4zMzIsODIuNTM1IDI0Ljc2OCw4Mi40MTggMjUuMDY3LDgyLjQxOCBMMjUuNjMyLDgyLjQxOCBDMjUuODMyLDgyLjQxOCAyNS45NDgsODIuNDc0IDI1Ljk3OCw4Mi41ODQgQzI2LjAwOCw4Mi42OTQgMjUuOTM1LDgyLjgwMSAyNS43NjMsODIuOTAxIEwxNC4yNTgsODkuNjAzIEMxNCw4OS43NTQgMTMuNTY0LDg5Ljg3MSAxMy4yNjYsODkuODcxIEwxMy4yNjYsODkuODcxIFogTTEyLjY2Niw4OS42MjEgTDEyLjcsODkuNjIyIEwxMy4yNjYsODkuNjIyIEMxMy41MTgsODkuNjIyIDEzLjkxNSw4OS41MTUgMTQuMTMyLDg5LjM4OCBMMjUuNjM3LDgyLjY4NiBMMjUuNjY3LDgyLjY2OCBMMjUuNjMyLDgyLjY2NyBMMjUuMDY3LDgyLjY2NyBDMjQuODE1LDgyLjY2NyAyNC40MTgsODIuNzc1IDI0LjIsODIuOTAxIEwxMi42OTUsODkuNjAzIEwxMi42NjYsODkuNjIxIEwxMi42NjYsODkuNjIxIFoiIGlkPSJGaWxsLTkiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTIuMzcsOTAuODAxIEwxMi4zNyw4OS41NTQgTDEyLjM3LDkwLjgwMSIgaWQ9IkZpbGwtMTAiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNi4xMyw5My45MDEgQzUuMzc5LDkzLjgwOCA0LjgxNiw5My4xNjQgNC42OTEsOTIuNTI1IEMzLjg2LDg4LjI4NyAzLjU0LDgzLjc0MyAzLjUyNiw3MS4xNzMgQzMuNTExLDU4LjM4OSA0LjQyMyw1MS40MjggNC40MjMsNTEuNDI4IEM1LjEzNCw0Ny4yODIgNy4yMSw0Ni4yMzYgNy4yMSw0Ni4yMzYgQzcuMjEsNDYuMjM2IDgxLjY2NywzLjI1IDgyLjA2OSwzLjAxNyBDODIuMjkyLDIuODg4IDg0LjU1NiwxLjQzMyA4NS4yNjQsMy45NCBDODcuMjE0LDEwLjg0IDg2Ljc1MiwzNS44MjcgODUuNTM5LDQzLjgxOCBDODUuMTUsNDYuMzgzIDg0LjI5MSw0OS4wMzMgODIuNDgzLDUwLjEwMSBMNy4yMSw5My42NTMgQzYuODI4LDkzLjg3NCA2LjQ2MSw5My45NDEgNi4xMyw5My45MDEgQzYuMTMsOTMuOTAxIDMuMzQ5LDkzLjQ2IDMuMTI5LDkxLjc3NiBDMi41NjgsODcuNDk1IDEuOTc3LDgyLjk5NSAxLjk2Miw3MC40MjUgQzEuOTQ4LDU3LjY0MSAyLjg2LDUwLjY4IDIuODYsNTAuNjggQzMuNTcsNDYuNTM0IDUuNjQ3LDQ1LjQ4OSA1LjY0Nyw0NS40ODkgQzUuNjQ2LDQ1LjQ4OSA4LjA2NSw0NC4wOTIgMTIuMjQ1LDQxLjY3OSBMMTMuMTE2LDQxLjU2IEwxOS43MTUsMzcuNzMgTDE5Ljc2MSwzNy4yNjkgTDYuMTMsOTMuOTAxIiBpZD0iRmlsbC0xMSIgZmlsbD0iI0ZBRkFGQSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik02LjMxNyw5NC4xNjEgTDYuMTAyLDk0LjE0OCBMNi4xMDEsOTQuMTQ4IEw1Ljg1Nyw5NC4xMDEgQzUuMTM4LDkzLjk0NSAzLjA4NSw5My4zNjUgMi44ODEsOTEuODA5IEMyLjMxMyw4Ny40NjkgMS43MjcsODIuOTk2IDEuNzEzLDcwLjQyNSBDMS42OTksNTcuNzcxIDIuNjA0LDUwLjcxOCAyLjYxMyw1MC42NDggQzMuMzM4LDQ2LjQxNyA1LjQ0NSw0NS4zMSA1LjUzNSw0NS4yNjYgTDEyLjE2Myw0MS40MzkgTDEzLjAzMyw0MS4zMiBMMTkuNDc5LDM3LjU3OCBMMTkuNTEzLDM3LjI0NCBDMTkuNTI2LDM3LjEwNyAxOS42NDcsMzcuMDA4IDE5Ljc4NiwzNy4wMjEgQzE5LjkyMiwzNy4wMzQgMjAuMDIzLDM3LjE1NiAyMC4wMDksMzcuMjkzIEwxOS45NSwzNy44ODIgTDEzLjE5OCw0MS44MDEgTDEyLjMyOCw0MS45MTkgTDUuNzcyLDQ1LjcwNCBDNS43NDEsNDUuNzIgMy43ODIsNDYuNzcyIDMuMTA2LDUwLjcyMiBDMy4wOTksNTAuNzgyIDIuMTk4LDU3LjgwOCAyLjIxMiw3MC40MjQgQzIuMjI2LDgyLjk2MyAyLjgwOSw4Ny40MiAzLjM3Myw5MS43MjkgQzMuNDY0LDkyLjQyIDQuMDYyLDkyLjg4MyA0LjY4Miw5My4xODEgQzQuNTY2LDkyLjk4NCA0LjQ4Niw5Mi43NzYgNC40NDYsOTIuNTcyIEMzLjY2NSw4OC41ODggMy4yOTEsODQuMzcgMy4yNzYsNzEuMTczIEMzLjI2Miw1OC41MiA0LjE2Nyw1MS40NjYgNC4xNzYsNTEuMzk2IEM0LjkwMSw0Ny4xNjUgNy4wMDgsNDYuMDU5IDcuMDk4LDQ2LjAxNCBDNy4wOTQsNDYuMDE1IDgxLjU0MiwzLjAzNCA4MS45NDQsMi44MDIgTDgxLjk3MiwyLjc4NSBDODIuODc2LDIuMjQ3IDgzLjY5MiwyLjA5NyA4NC4zMzIsMi4zNTIgQzg0Ljg4NywyLjU3MyA4NS4yODEsMy4wODUgODUuNTA0LDMuODcyIEM4Ny41MTgsMTEgODYuOTY0LDM2LjA5MSA4NS43ODUsNDMuODU1IEM4NS4yNzgsNDcuMTk2IDg0LjIxLDQ5LjM3IDgyLjYxLDUwLjMxNyBMNy4zMzUsOTMuODY5IEM2Ljk5OSw5NC4wNjMgNi42NTgsOTQuMTYxIDYuMzE3LDk0LjE2MSBMNi4zMTcsOTQuMTYxIFogTTYuMTcsOTMuNjU0IEM2LjQ2Myw5My42OSA2Ljc3NCw5My42MTcgNy4wODUsOTMuNDM3IEw4Mi4zNTgsNDkuODg2IEM4NC4xODEsNDguODA4IDg0Ljk2LDQ1Ljk3MSA4NS4yOTIsNDMuNzggQzg2LjQ2NiwzNi4wNDkgODcuMDIzLDExLjA4NSA4NS4wMjQsNC4wMDggQzg0Ljg0NiwzLjM3NyA4NC41NTEsMi45NzYgODQuMTQ4LDIuODE2IEM4My42NjQsMi42MjMgODIuOTgyLDIuNzY0IDgyLjIyNywzLjIxMyBMODIuMTkzLDMuMjM0IEM4MS43OTEsMy40NjYgNy4zMzUsNDYuNDUyIDcuMzM1LDQ2LjQ1MiBDNy4zMDQsNDYuNDY5IDUuMzQ2LDQ3LjUyMSA0LjY2OSw1MS40NzEgQzQuNjYyLDUxLjUzIDMuNzYxLDU4LjU1NiAzLjc3NSw3MS4xNzMgQzMuNzksODQuMzI4IDQuMTYxLDg4LjUyNCA0LjkzNiw5Mi40NzYgQzUuMDI2LDkyLjkzNyA1LjQxMiw5My40NTkgNS45NzMsOTMuNjE1IEM2LjA4Nyw5My42NCA2LjE1OCw5My42NTIgNi4xNjksOTMuNjU0IEw2LjE3LDkzLjY1NCBMNi4xNyw5My42NTQgWiIgaWQ9IkZpbGwtMTIiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNy4zMTcsNjguOTgyIEM3LjgwNiw2OC43MDEgOC4yMDIsNjguOTI2IDguMjAyLDY5LjQ4NyBDOC4yMDIsNzAuMDQ3IDcuODA2LDcwLjczIDcuMzE3LDcxLjAxMiBDNi44MjksNzEuMjk0IDYuNDMzLDcxLjA2OSA2LjQzMyw3MC41MDggQzYuNDMzLDY5Ljk0OCA2LjgyOSw2OS4yNjUgNy4zMTcsNjguOTgyIiBpZD0iRmlsbC0xMyIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik02LjkyLDcxLjEzMyBDNi42MzEsNzEuMTMzIDYuNDMzLDcwLjkwNSA2LjQzMyw3MC41MDggQzYuNDMzLDY5Ljk0OCA2LjgyOSw2OS4yNjUgNy4zMTcsNjguOTgyIEM3LjQ2LDY4LjkgNy41OTUsNjguODYxIDcuNzE0LDY4Ljg2MSBDOC4wMDMsNjguODYxIDguMjAyLDY5LjA5IDguMjAyLDY5LjQ4NyBDOC4yMDIsNzAuMDQ3IDcuODA2LDcwLjczIDcuMzE3LDcxLjAxMiBDNy4xNzQsNzEuMDk0IDcuMDM5LDcxLjEzMyA2LjkyLDcxLjEzMyBNNy43MTQsNjguNjc0IEM3LjU1Nyw2OC42NzQgNy4zOTIsNjguNzIzIDcuMjI0LDY4LjgyMSBDNi42NzYsNjkuMTM4IDYuMjQ2LDY5Ljg3OSA2LjI0Niw3MC41MDggQzYuMjQ2LDcwLjk5NCA2LjUxNyw3MS4zMiA2LjkyLDcxLjMyIEM3LjA3OCw3MS4zMiA3LjI0Myw3MS4yNzEgNy40MTEsNzEuMTc0IEM3Ljk1OSw3MC44NTcgOC4zODksNzAuMTE3IDguMzg5LDY5LjQ4NyBDOC4zODksNjkuMDAxIDguMTE3LDY4LjY3NCA3LjcxNCw2OC42NzQiIGlkPSJGaWxsLTE0IiBmaWxsPSIjODA5N0EyIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTYuOTIsNzAuOTQ3IEM2LjY0OSw3MC45NDcgNi42MjEsNzAuNjQgNi42MjEsNzAuNTA4IEM2LjYyMSw3MC4wMTcgNi45ODIsNjkuMzkyIDcuNDExLDY5LjE0NSBDNy41MjEsNjkuMDgyIDcuNjI1LDY5LjA0OSA3LjcxNCw2OS4wNDkgQzcuOTg2LDY5LjA0OSA4LjAxNSw2OS4zNTUgOC4wMTUsNjkuNDg3IEM4LjAxNSw2OS45NzggNy42NTIsNzAuNjAzIDcuMjI0LDcwLjg1MSBDNy4xMTUsNzAuOTE0IDcuMDEsNzAuOTQ3IDYuOTIsNzAuOTQ3IE03LjcxNCw2OC44NjEgQzcuNTk1LDY4Ljg2MSA3LjQ2LDY4LjkgNy4zMTcsNjguOTgyIEM2LjgyOSw2OS4yNjUgNi40MzMsNjkuOTQ4IDYuNDMzLDcwLjUwOCBDNi40MzMsNzAuOTA1IDYuNjMxLDcxLjEzMyA2LjkyLDcxLjEzMyBDNy4wMzksNzEuMTMzIDcuMTc0LDcxLjA5NCA3LjMxNyw3MS4wMTIgQzcuODA2LDcwLjczIDguMjAyLDcwLjA0NyA4LjIwMiw2OS40ODcgQzguMjAyLDY5LjA5IDguMDAzLDY4Ljg2MSA3LjcxNCw2OC44NjEiIGlkPSJGaWxsLTE1IiBmaWxsPSIjODA5N0EyIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTcuNDQ0LDg1LjM1IEM3LjcwOCw4NS4xOTggNy45MjEsODUuMzE5IDcuOTIxLDg1LjYyMiBDNy45MjEsODUuOTI1IDcuNzA4LDg2LjI5MiA3LjQ0NCw4Ni40NDQgQzcuMTgxLDg2LjU5NyA2Ljk2Nyw4Ni40NzUgNi45NjcsODYuMTczIEM2Ljk2Nyw4NS44NzEgNy4xODEsODUuNTAyIDcuNDQ0LDg1LjM1IiBpZD0iRmlsbC0xNiIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik03LjIzLDg2LjUxIEM3LjA3NCw4Ni41MSA2Ljk2Nyw4Ni4zODcgNi45NjcsODYuMTczIEM2Ljk2Nyw4NS44NzEgNy4xODEsODUuNTAyIDcuNDQ0LDg1LjM1IEM3LjUyMSw4NS4zMDUgNy41OTQsODUuMjg0IDcuNjU4LDg1LjI4NCBDNy44MTQsODUuMjg0IDcuOTIxLDg1LjQwOCA3LjkyMSw4NS42MjIgQzcuOTIxLDg1LjkyNSA3LjcwOCw4Ni4yOTIgNy40NDQsODYuNDQ0IEM3LjM2Nyw4Ni40ODkgNy4yOTQsODYuNTEgNy4yMyw4Ni41MSBNNy42NTgsODUuMDk4IEM3LjU1OCw4NS4wOTggNy40NTUsODUuMTI3IDcuMzUxLDg1LjE4OCBDNy4wMzEsODUuMzczIDYuNzgxLDg1LjgwNiA2Ljc4MSw4Ni4xNzMgQzYuNzgxLDg2LjQ4MiA2Ljk2Niw4Ni42OTcgNy4yMyw4Ni42OTcgQzcuMzMsODYuNjk3IDcuNDMzLDg2LjY2NiA3LjUzOCw4Ni42MDcgQzcuODU4LDg2LjQyMiA4LjEwOCw4NS45ODkgOC4xMDgsODUuNjIyIEM4LjEwOCw4NS4zMTMgNy45MjMsODUuMDk4IDcuNjU4LDg1LjA5OCIgaWQ9IkZpbGwtMTciIGZpbGw9IiM4MDk3QTIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNy4yMyw4Ni4zMjIgTDcuMTU0LDg2LjE3MyBDNy4xNTQsODUuOTM4IDcuMzMzLDg1LjYyOSA3LjUzOCw4NS41MTIgTDcuNjU4LDg1LjQ3MSBMNy43MzQsODUuNjIyIEM3LjczNCw4NS44NTYgNy41NTUsODYuMTY0IDcuMzUxLDg2LjI4MiBMNy4yMyw4Ni4zMjIgTTcuNjU4LDg1LjI4NCBDNy41OTQsODUuMjg0IDcuNTIxLDg1LjMwNSA3LjQ0NCw4NS4zNSBDNy4xODEsODUuNTAyIDYuOTY3LDg1Ljg3MSA2Ljk2Nyw4Ni4xNzMgQzYuOTY3LDg2LjM4NyA3LjA3NCw4Ni41MSA3LjIzLDg2LjUxIEM3LjI5NCw4Ni41MSA3LjM2Nyw4Ni40ODkgNy40NDQsODYuNDQ0IEM3LjcwOCw4Ni4yOTIgNy45MjEsODUuOTI1IDcuOTIxLDg1LjYyMiBDNy45MjEsODUuNDA4IDcuODE0LDg1LjI4NCA3LjY1OCw4NS4yODQiIGlkPSJGaWxsLTE4IiBmaWxsPSIjODA5N0EyIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTc3LjI3OCw3Ljc2OSBMNzcuMjc4LDUxLjQzNiBMMTAuMjA4LDkwLjE2IEwxMC4yMDgsNDYuNDkzIEw3Ny4yNzgsNy43NjkiIGlkPSJGaWxsLTE5IiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTEwLjA4Myw5MC4zNzUgTDEwLjA4Myw0Ni40MjEgTDEwLjE0Niw0Ni4zODUgTDc3LjQwMyw3LjU1NCBMNzcuNDAzLDUxLjUwOCBMNzcuMzQxLDUxLjU0NCBMMTAuMDgzLDkwLjM3NSBMMTAuMDgzLDkwLjM3NSBaIE0xMC4zMzMsNDYuNTY0IEwxMC4zMzMsODkuOTQ0IEw3Ny4xNTQsNTEuMzY1IEw3Ny4xNTQsNy45ODUgTDEwLjMzMyw0Ni41NjQgTDEwLjMzMyw0Ni41NjQgWiIgaWQ9IkZpbGwtMjAiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgIDwvZz4KICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMjUuNzM3LDg4LjY0NyBMMTE4LjA5OCw5MS45ODEgTDExOC4wOTgsODQgTDEwNi42MzksODguNzEzIEwxMDYuNjM5LDk2Ljk4MiBMOTksMTAwLjMxNSBMMTEyLjM2OSwxMDMuOTYxIEwxMjUuNzM3LDg4LjY0NyIgaWQ9IkltcG9ydGVkLUxheWVycy1Db3B5LTIiIGZpbGw9IiM0NTVBNjQiIHNrZXRjaDp0eXBlPSJNU1NoYXBlR3JvdXAiPjwvcGF0aD4KICAgICAgICAgICAgPC9nPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+');\n};\n\nmodule.exports = RotateInstructions;\n\n},{\"./util.js\":68}],63:[function(_dereq_,module,exports){\n/*\n * Copyright 2015 Google Inc. All Rights Reserved.\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\nvar SensorSample = _dereq_('./sensor-sample.js');\nvar MathUtil = _dereq_('../math-util.js');\nvar Util = _dereq_('../util.js');\n\n/**\n * An implementation of a simple complementary filter, which fuses gyroscope and\n * accelerometer data from the 'devicemotion' event.\n *\n * Accelerometer data is very noisy, but stable over the long term.\n * Gyroscope data is smooth, but tends to drift over the long term.\n *\n * This fusion is relatively simple:\n * 1. Get orientation estimates from accelerometer by applying a low-pass filter\n *    on that data.\n * 2. Get orientation estimates from gyroscope by integrating over time.\n * 3. Combine the two estimates, weighing (1) in the long term, but (2) for the\n *    short term.\n */\nfunction ComplementaryFilter(kFilter) {\n  this.kFilter = kFilter;\n\n  // Raw sensor measurements.\n  this.currentAccelMeasurement = new SensorSample();\n  this.currentGyroMeasurement = new SensorSample();\n  this.previousGyroMeasurement = new SensorSample();\n\n  // Set default look direction to be in the correct direction.\n  if (Util.isIOS()) {\n    this.filterQ = new MathUtil.Quaternion(-1, 0, 0, 1);\n  } else {\n    this.filterQ = new MathUtil.Quaternion(1, 0, 0, 1);\n  }\n  this.previousFilterQ = new MathUtil.Quaternion();\n  this.previousFilterQ.copy(this.filterQ);\n\n  // Orientation based on the accelerometer.\n  this.accelQ = new MathUtil.Quaternion();\n  // Whether or not the orientation has been initialized.\n  this.isOrientationInitialized = false;\n  // Running estimate of gravity based on the current orientation.\n  this.estimatedGravity = new MathUtil.Vector3();\n  // Measured gravity based on accelerometer.\n  this.measuredGravity = new MathUtil.Vector3();\n\n  // Debug only quaternion of gyro-based orientation.\n  this.gyroIntegralQ = new MathUtil.Quaternion();\n}\n\nComplementaryFilter.prototype.addAccelMeasurement = function(vector, timestampS) {\n  this.currentAccelMeasurement.set(vector, timestampS);\n};\n\nComplementaryFilter.prototype.addGyroMeasurement = function(vector, timestampS) {\n  this.currentGyroMeasurement.set(vector, timestampS);\n\n  var deltaT = timestampS - this.previousGyroMeasurement.timestampS;\n  if (Util.isTimestampDeltaValid(deltaT)) {\n    this.run_();\n  }\n\n  this.previousGyroMeasurement.copy(this.currentGyroMeasurement);\n};\n\nComplementaryFilter.prototype.run_ = function() {\n\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\n  var deltaT = this.currentGyroMeasurement.timestampS -\n      this.previousGyroMeasurement.timestampS;\n\n  // Convert gyro rotation vector to a quaternion delta.\n  var gyroDeltaQ = this.gyroToQuaternionDelta_(this.currentGyroMeasurement.sample, deltaT);\n  this.gyroIntegralQ.multiply(gyroDeltaQ);\n\n  // filter_1 = K * (filter_0 + gyro * dT) + (1 - K) * accel.\n  this.filterQ.copy(this.previousFilterQ);\n  this.filterQ.multiply(gyroDeltaQ);\n\n  // Calculate the delta between the current estimated gravity and the real\n  // gravity vector from accelerometer.\n  var invFilterQ = new MathUtil.Quaternion();\n  invFilterQ.copy(this.filterQ);\n  invFilterQ.inverse();\n\n  this.estimatedGravity.set(0, 0, -1);\n  this.estimatedGravity.applyQuaternion(invFilterQ);\n  this.estimatedGravity.normalize();\n\n  this.measuredGravity.copy(this.currentAccelMeasurement.sample);\n  this.measuredGravity.normalize();\n\n  // Compare estimated gravity with measured gravity, get the delta quaternion\n  // between the two.\n  var deltaQ = new MathUtil.Quaternion();\n  deltaQ.setFromUnitVectors(this.estimatedGravity, this.measuredGravity);\n  deltaQ.inverse();\n\n  if (Util.isDebug()) {\n    console.log('Delta: %d deg, G_est: (%s, %s, %s), G_meas: (%s, %s, %s)',\n                MathUtil.radToDeg * Util.getQuaternionAngle(deltaQ),\n                (this.estimatedGravity.x).toFixed(1),\n                (this.estimatedGravity.y).toFixed(1),\n                (this.estimatedGravity.z).toFixed(1),\n                (this.measuredGravity.x).toFixed(1),\n                (this.measuredGravity.y).toFixed(1),\n                (this.measuredGravity.z).toFixed(1));\n  }\n\n  // Calculate the SLERP target: current orientation plus the measured-estimated\n  // quaternion delta.\n  var targetQ = new MathUtil.Quaternion();\n  targetQ.copy(this.filterQ);\n  targetQ.multiply(deltaQ);\n\n  // SLERP factor: 0 is pure gyro, 1 is pure accel.\n  this.filterQ.slerp(targetQ, 1 - this.kFilter);\n\n  this.previousFilterQ.copy(this.filterQ);\n};\n\nComplementaryFilter.prototype.getOrientation = function() {\n  return this.filterQ;\n};\n\nComplementaryFilter.prototype.accelToQuaternion_ = function(accel) {\n  var normAccel = new MathUtil.Vector3();\n  normAccel.copy(accel);\n  normAccel.normalize();\n  var quat = new MathUtil.Quaternion();\n  quat.setFromUnitVectors(new MathUtil.Vector3(0, 0, -1), normAccel);\n  quat.inverse();\n  return quat;\n};\n\nComplementaryFilter.prototype.gyroToQuaternionDelta_ = function(gyro, dt) {\n  // Extract axis and angle from the gyroscope data.\n  var quat = new MathUtil.Quaternion();\n  var axis = new MathUtil.Vector3();\n  axis.copy(gyro);\n  axis.normalize();\n  quat.setFromAxisAngle(axis, gyro.length() * dt);\n  return quat;\n};\n\n\nmodule.exports = ComplementaryFilter;\n\n},{\"../math-util.js\":59,\"../util.js\":68,\"./sensor-sample.js\":66}],64:[function(_dereq_,module,exports){\n/*\n * Copyright 2015 Google Inc. All Rights Reserved.\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 */\nvar ComplementaryFilter = _dereq_('./complementary-filter.js');\nvar PosePredictor = _dereq_('./pose-predictor.js');\nvar TouchPanner = _dereq_('../touch-panner.js');\nvar MathUtil = _dereq_('../math-util.js');\nvar Util = _dereq_('../util.js');\n\n/**\n * The pose sensor, implemented using DeviceMotion APIs.\n */\nfunction FusionPoseSensor() {\n  this.deviceId = 'webvr-polyfill:fused';\n  this.deviceName = 'VR Position Device (webvr-polyfill:fused)';\n\n  this.accelerometer = new MathUtil.Vector3();\n  this.gyroscope = new MathUtil.Vector3();\n\n  this.start();\n\n  this.filter = new ComplementaryFilter(window.WebVRConfig.K_FILTER);\n  this.posePredictor = new PosePredictor(window.WebVRConfig.PREDICTION_TIME_S);\n  this.touchPanner = new TouchPanner();\n\n  this.filterToWorldQ = new MathUtil.Quaternion();\n\n  // Set the filter to world transform, depending on OS.\n  if (Util.isIOS()) {\n    this.filterToWorldQ.setFromAxisAngle(new MathUtil.Vector3(1, 0, 0), Math.PI / 2);\n  } else {\n    this.filterToWorldQ.setFromAxisAngle(new MathUtil.Vector3(1, 0, 0), -Math.PI / 2);\n  }\n\n  this.inverseWorldToScreenQ = new MathUtil.Quaternion();\n  this.worldToScreenQ = new MathUtil.Quaternion();\n  this.originalPoseAdjustQ = new MathUtil.Quaternion();\n  this.originalPoseAdjustQ.setFromAxisAngle(new MathUtil.Vector3(0, 0, 1),\n                                           -window.orientation * Math.PI / 180);\n\n  this.setScreenTransform_();\n  // Adjust this filter for being in landscape mode.\n  if (Util.isLandscapeMode()) {\n    this.filterToWorldQ.multiply(this.inverseWorldToScreenQ);\n  }\n\n  // Keep track of a reset transform for resetSensor.\n  this.resetQ = new MathUtil.Quaternion();\n\n  this.isFirefoxAndroid = Util.isFirefoxAndroid();\n  this.isIOS = Util.isIOS();\n\n  this.orientationOut_ = new Float32Array(4);\n}\n\nFusionPoseSensor.prototype.getPosition = function() {\n  // This PoseSensor doesn't support position\n  return null;\n};\n\nFusionPoseSensor.prototype.getOrientation = function() {\n  // Convert from filter space to the the same system used by the\n  // deviceorientation event.\n  var orientation = this.filter.getOrientation();\n\n  // Predict orientation.\n  this.predictedQ = this.posePredictor.getPrediction(orientation, this.gyroscope, this.previousTimestampS);\n\n  // Convert to THREE coordinate system: -Z forward, Y up, X right.\n  var out = new MathUtil.Quaternion();\n  out.copy(this.filterToWorldQ);\n  out.multiply(this.resetQ);\n  if (!window.WebVRConfig.TOUCH_PANNER_DISABLED) {\n    out.multiply(this.touchPanner.getOrientation());\n  }\n  out.multiply(this.predictedQ);\n  out.multiply(this.worldToScreenQ);\n\n  // Handle the yaw-only case.\n  if (window.WebVRConfig.YAW_ONLY) {\n    // Make a quaternion that only turns around the Y-axis.\n    out.x = 0;\n    out.z = 0;\n    out.normalize();\n  }\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\nFusionPoseSensor.prototype.resetPose = function() {\n  // Reduce to inverted yaw-only.\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\n  // Take into account extra transformations in landscape mode.\n  if (Util.isLandscapeMode()) {\n    this.resetQ.multiply(this.inverseWorldToScreenQ);\n  }\n\n  // Take into account original pose.\n  this.resetQ.multiply(this.originalPoseAdjustQ);\n\n  if (!window.WebVRConfig.TOUCH_PANNER_DISABLED) {\n    this.touchPanner.resetSensor();\n  }\n};\n\nFusionPoseSensor.prototype.onDeviceMotion_ = function(deviceMotion) {\n  this.updateDeviceMotion_(deviceMotion);\n};\n\nFusionPoseSensor.prototype.updateDeviceMotion_ = function(deviceMotion) {\n  var accGravity = deviceMotion.accelerationIncludingGravity;\n  var rotRate = deviceMotion.rotationRate;\n  var timestampS = deviceMotion.timeStamp / 1000;\n\n  var deltaS = timestampS - this.previousTimestampS;\n  if (deltaS <= Util.MIN_TIMESTEP || deltaS > Util.MAX_TIMESTEP) {\n    console.warn('Invalid timestamps detected. Time step between successive ' +\n                 'gyroscope sensor samples is very small or not monotonic');\n    this.previousTimestampS = timestampS;\n    return;\n  }\n  this.accelerometer.set(-accGravity.x, -accGravity.y, -accGravity.z);\n  this.gyroscope.set(rotRate.alpha, rotRate.beta, rotRate.gamma);\n\n  // With iOS and Firefox Android, rotationRate is reported in degrees,\n  // so we first convert to radians.\n  if (this.isIOS || this.isFirefoxAndroid) {\n    this.gyroscope.multiplyScalar(Math.PI / 180);\n  }\n\n  this.filter.addAccelMeasurement(this.accelerometer, timestampS);\n  this.filter.addGyroMeasurement(this.gyroscope, timestampS);\n\n  this.previousTimestampS = timestampS;\n};\n\nFusionPoseSensor.prototype.onOrientationChange_ = function(screenOrientation) {\n  this.setScreenTransform_();\n};\n\n/**\n * This is only needed if we are in an cross origin iframe on iOS to work around\n * this issue: https://bugs.webkit.org/show_bug.cgi?id=152299.\n */\nFusionPoseSensor.prototype.onMessage_ = function(event) {\n  var message = event.data;\n\n  // If there's no message type, ignore it.\n  if (!message || !message.type) {\n    return;\n  }\n\n  // Ignore all messages that aren't devicemotion.\n  var type = message.type.toLowerCase();\n  if (type !== 'devicemotion') {\n    return;\n  }\n\n  // Update device motion.\n  this.updateDeviceMotion_(message.deviceMotionEvent);\n};\n\nFusionPoseSensor.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 MathUtil.Vector3(0, 0, 1), -Math.PI / 2);\n      break;\n    case -90:\n      this.worldToScreenQ.setFromAxisAngle(new MathUtil.Vector3(0, 0, 1), Math.PI / 2);\n      break;\n    case 180:\n      // TODO.\n      break;\n  }\n  this.inverseWorldToScreenQ.copy(this.worldToScreenQ);\n  this.inverseWorldToScreenQ.inverse();\n};\n\nFusionPoseSensor.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\n  // Only listen for postMessages if we're in an iOS and embedded inside a cross\n  // domain IFrame. In this case, the polyfill can still work if the containing\n  // page sends synthetic devicemotion events. For an example of this, see\n  // iframe-message-sender.js in VR View: https://goo.gl/XDtvFZ\n  if (Util.isIOS() && Util.isInsideCrossDomainIFrame()) {\n    window.addEventListener('message', this.onMessageCallback_);\n  }\n  window.addEventListener('orientationchange', this.onOrientationChangeCallback_);\n  window.addEventListener('devicemotion', this.onDeviceMotionCallback_);\n};\n\nFusionPoseSensor.prototype.stop = function() {\n  window.removeEventListener('devicemotion', this.onDeviceMotionCallback_);\n  window.removeEventListener('orientationchange', this.onOrientationChangeCallback_);\n  window.removeEventListener('message', this.onMessageCallback_);\n};\n\nmodule.exports = FusionPoseSensor;\n\n},{\"../math-util.js\":59,\"../touch-panner.js\":67,\"../util.js\":68,\"./complementary-filter.js\":63,\"./pose-predictor.js\":65}],65:[function(_dereq_,module,exports){\n/*\n * Copyright 2015 Google Inc. All Rights Reserved.\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 */\nvar MathUtil = _dereq_('../math-util');\nvar Util = _dereq_('../util');\n\n/**\n * Given an orientation and the gyroscope data, predicts the future orientation\n * of the head. This makes rendering appear faster.\n *\n * Also see: http://msl.cs.uiuc.edu/~lavalle/papers/LavYerKatAnt14.pdf\n *\n * @param {Number} predictionTimeS time from head movement to the appearance of\n * the corresponding image.\n */\nfunction PosePredictor(predictionTimeS) {\n  this.predictionTimeS = predictionTimeS;\n\n  // The quaternion corresponding to the previous state.\n  this.previousQ = new MathUtil.Quaternion();\n  // Previous time a prediction occurred.\n  this.previousTimestampS = null;\n\n  // The delta quaternion that adjusts the current pose.\n  this.deltaQ = new MathUtil.Quaternion();\n  // The output quaternion.\n  this.outQ = new MathUtil.Quaternion();\n}\n\nPosePredictor.prototype.getPrediction = function(currentQ, gyro, timestampS) {\n  if (!this.previousTimestampS) {\n    this.previousQ.copy(currentQ);\n    this.previousTimestampS = timestampS;\n    return currentQ;\n  }\n\n  // Calculate axis and angle based on gyroscope rotation rate data.\n  var axis = new MathUtil.Vector3();\n  axis.copy(gyro);\n  axis.normalize();\n\n  var angularSpeed = gyro.length();\n\n  // If we're rotating slowly, don't do prediction.\n  if (angularSpeed < MathUtil.degToRad * 20) {\n    if (Util.isDebug()) {\n      console.log('Moving slowly, at %s deg/s: no prediction',\n                  (MathUtil.radToDeg * angularSpeed).toFixed(1));\n    }\n    this.outQ.copy(currentQ);\n    this.previousQ.copy(currentQ);\n    return this.outQ;\n  }\n\n  // Get the predicted angle based on the time delta and latency.\n  var deltaT = timestampS - this.previousTimestampS;\n  var predictAngle = angularSpeed * this.predictionTimeS;\n\n  this.deltaQ.setFromAxisAngle(axis, predictAngle);\n  this.outQ.copy(this.previousQ);\n  this.outQ.multiply(this.deltaQ);\n\n  this.previousQ.copy(currentQ);\n  this.previousTimestampS = timestampS;\n\n  return this.outQ;\n};\n\n\nmodule.exports = PosePredictor;\n\n},{\"../math-util\":59,\"../util\":68}],66:[function(_dereq_,module,exports){\nfunction SensorSample(sample, timestampS) {\n  this.set(sample, timestampS);\n};\n\nSensorSample.prototype.set = function(sample, timestampS) {\n  this.sample = sample;\n  this.timestampS = timestampS;\n};\n\nSensorSample.prototype.copy = function(sensorSample) {\n  this.set(sensorSample.sample, sensorSample.timestampS);\n};\n\nmodule.exports = SensorSample;\n\n},{}],67:[function(_dereq_,module,exports){\n/*\n * Copyright 2015 Google Inc. All Rights Reserved.\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 */\nvar MathUtil = _dereq_('./math-util.js');\nvar Util = _dereq_('./util.js');\n\nvar ROTATE_SPEED = 0.5;\n/**\n * Provides a quaternion responsible for pre-panning the scene before further\n * transformations due to device sensors.\n */\nfunction TouchPanner() {\n  window.addEventListener('touchstart', this.onTouchStart_.bind(this));\n  window.addEventListener('touchmove', this.onTouchMove_.bind(this));\n  window.addEventListener('touchend', this.onTouchEnd_.bind(this));\n\n  this.isTouching = false;\n  this.rotateStart = new MathUtil.Vector2();\n  this.rotateEnd = new MathUtil.Vector2();\n  this.rotateDelta = new MathUtil.Vector2();\n\n  this.theta = 0;\n  this.orientation = new MathUtil.Quaternion();\n}\n\nTouchPanner.prototype.getOrientation = function() {\n  this.orientation.setFromEulerXYZ(0, 0, this.theta);\n  return this.orientation;\n};\n\nTouchPanner.prototype.resetSensor = function() {\n  this.theta = 0;\n};\n\nTouchPanner.prototype.onTouchStart_ = function(e) {\n  // Only respond if there is exactly one touch.\n  // Note that the Daydream controller passes in a `touchstart` event with\n  // no `touches` property, so we must check for that case too.\n  if (!e.touches || e.touches.length != 1) {\n    return;\n  }\n  this.rotateStart.set(e.touches[0].pageX, e.touches[0].pageY);\n  this.isTouching = true;\n};\n\nTouchPanner.prototype.onTouchMove_ = function(e) {\n  if (!this.isTouching) {\n    return;\n  }\n  this.rotateEnd.set(e.touches[0].pageX, e.touches[0].pageY);\n  this.rotateDelta.subVectors(this.rotateEnd, this.rotateStart);\n  this.rotateStart.copy(this.rotateEnd);\n\n  // On iOS, direction is inverted.\n  if (Util.isIOS()) {\n    this.rotateDelta.x *= -1;\n  }\n\n  var element = document.body;\n  this.theta += 2 * Math.PI * this.rotateDelta.x / element.clientWidth * ROTATE_SPEED;\n};\n\nTouchPanner.prototype.onTouchEnd_ = function(e) {\n  this.isTouching = false;\n};\n\nmodule.exports = TouchPanner;\n\n},{\"./math-util.js\":59,\"./util.js\":68}],68:[function(_dereq_,module,exports){\n/*\n * Copyright 2015 Google Inc. All Rights Reserved.\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\nvar Util = window.Util || {};\n\nUtil.MIN_TIMESTEP = 0.001;\nUtil.MAX_TIMESTEP = 1;\n\nUtil.base64 = function(mimeType, base64) {\n  return 'data:' + mimeType + ';base64,' + base64;\n};\n\nUtil.clamp = function(value, min, max) {\n  return Math.min(Math.max(min, value), max);\n};\n\nUtil.lerp = function(a, b, t) {\n  return a + ((b - a) * t);\n};\n\n/**\n * Light polyfill for `Promise.race`. Returns\n * a promise that resolves when the first promise\n * provided resolves.\n *\n * @param {Array<Promise>} promises\n */\nUtil.race = function(promises) {\n  if (Promise.race) {\n    return Promise.race(promises);\n  }\n\n  return new Promise(function (resolve, reject) {\n    for (var i = 0; i < promises.length; i++) {\n      promises[i].then(resolve, reject);\n    }\n  });\n};\n\nUtil.isIOS = (function() {\n  var isIOS = /iPad|iPhone|iPod/.test(navigator.platform);\n  return function() {\n    return isIOS;\n  };\n})();\n\nUtil.isWebViewAndroid = (function() {\n  var isWebViewAndroid = navigator.userAgent.indexOf('Version') !== -1 &&\n      navigator.userAgent.indexOf('Android') !== -1 &&\n      navigator.userAgent.indexOf('Chrome') !== -1;\n  return function() {\n    return isWebViewAndroid;\n  };\n})();\n\nUtil.isSafari = (function() {\n  var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n  return function() {\n    return isSafari;\n  };\n})();\n\nUtil.isFirefoxAndroid = (function() {\n  var isFirefoxAndroid = navigator.userAgent.indexOf('Firefox') !== -1 &&\n      navigator.userAgent.indexOf('Android') !== -1;\n  return function() {\n    return isFirefoxAndroid;\n  };\n})();\n\nUtil.isLandscapeMode = function() {\n  return (window.orientation == 90 || window.orientation == -90);\n};\n\n// Helper method to validate the time steps of sensor timestamps.\nUtil.isTimestampDeltaValid = function(timestampDeltaS) {\n  if (isNaN(timestampDeltaS)) {\n    return false;\n  }\n  if (timestampDeltaS <= Util.MIN_TIMESTEP) {\n    return false;\n  }\n  if (timestampDeltaS > Util.MAX_TIMESTEP) {\n    return false;\n  }\n  return true;\n};\n\nUtil.getScreenWidth = function() {\n  return Math.max(window.screen.width, window.screen.height) *\n      window.devicePixelRatio;\n};\n\nUtil.getScreenHeight = function() {\n  return Math.min(window.screen.width, window.screen.height) *\n      window.devicePixelRatio;\n};\n\nUtil.requestFullscreen = function(element) {\n  if (Util.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\n  return true;\n};\n\nUtil.exitFullscreen = function() {\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\n  return true;\n};\n\nUtil.getFullscreenElement = function() {\n  return document.fullscreenElement ||\n      document.webkitFullscreenElement ||\n      document.mozFullScreenElement ||\n      document.msFullscreenElement;\n};\n\nUtil.linkProgram = function(gl, vertexSource, fragmentSource, attribLocationMap) {\n  // No error checking for brevity.\n  var vertexShader = gl.createShader(gl.VERTEX_SHADER);\n  gl.shaderSource(vertexShader, vertexSource);\n  gl.compileShader(vertexShader);\n\n  var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);\n  gl.shaderSource(fragmentShader, fragmentSource);\n  gl.compileShader(fragmentShader);\n\n  var program = gl.createProgram();\n  gl.attachShader(program, vertexShader);\n  gl.attachShader(program, fragmentShader);\n\n  for (var attribName in attribLocationMap)\n    gl.bindAttribLocation(program, attribLocationMap[attribName], attribName);\n\n  gl.linkProgram(program);\n\n  gl.deleteShader(vertexShader);\n  gl.deleteShader(fragmentShader);\n\n  return program;\n};\n\nUtil.getProgramUniforms = function(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\nUtil.orthoMatrix = function (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\nUtil.copyArray = function (source, dest) {\n  for (var i = 0, n = source.length; i < n; i++) {\n    dest[i] = source[i];\n  }\n};\n\nUtil.isMobile = function() {\n  var check = false;\n  (function(a){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})(navigator.userAgent||navigator.vendor||window.opera);\n  return check;\n};\n\nUtil.extend = function(dest, src) {\n  for (var key in src) {\n    if (src.hasOwnProperty(key)) {\n      dest[key] = src[key];\n    }\n  }\n\n  return dest;\n}\n\nUtil.safariCssSizeWorkaround = function(canvas) {\n  // TODO(smus): Remove this workaround when Safari for iOS is fixed.\n  // iOS only workaround (for https://bugs.webkit.org/show_bug.cgi?id=152556).\n  //\n  // \"To the last I grapple with thee;\n  //  from hell's heart I stab at thee;\n  //  for hate's sake I spit my last breath at thee.\"\n  // -- Moby Dick, by Herman Melville\n  if (Util.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\n  // Debug only.\n  window.Util = Util;\n  window.canvas = canvas;\n};\n\nUtil.isDebug = function() {\n  return Util.getQueryParameter('debug');\n};\n\nUtil.getQueryParameter = function(name) {\n  var name = name.replace(/[\\[]/, \"\\\\[\").replace(/[\\]]/, \"\\\\]\");\n  var regex = new RegExp(\"[\\\\?&]\" + name + \"=([^&#]*)\"),\n      results = regex.exec(location.search);\n  return results === null ? \"\" : decodeURIComponent(results[1].replace(/\\+/g, \" \"));\n};\n\nUtil.frameDataFromPose = (function() {\n  var piOver180 = Math.PI / 180.0;\n  var rad45 = Math.PI * 0.25;\n\n  // Borrowed from glMatrix.\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\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\n  function mat4_fromRotationTranslation(out, q, v) {\n    // Quaternion math\n    var x = q[0], y = q[1], z = q[2], w = q[3],\n        x2 = x + x,\n        y2 = y + y,\n        z2 = z + z,\n\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\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\n    return out;\n  };\n\n  function mat4_translate(out, a, v) {\n    var x = v[0], y = v[1], z = v[2],\n        a00, a01, a02, a03,\n        a10, a11, a12, a13,\n        a20, a21, a22, a23;\n\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]; a01 = a[1]; a02 = a[2]; a03 = a[3];\n      a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];\n      a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];\n\n      out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03;\n      out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13;\n      out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23;\n\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\n    return out;\n  };\n\n  function mat4_invert(out, a) {\n    var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],\n        a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],\n        a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],\n        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],\n\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\n        // Calculate the determinant\n        det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\n\n    if (!det) {\n      return null;\n    }\n    det = 1.0 / det;\n\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\n    return out;\n  };\n\n  var defaultOrientation = new Float32Array([0, 0, 0, 1]);\n  var defaultPosition = new Float32Array([0, 0, 0]);\n\n  function updateEyeMatrices(projection, view, pose, parameters, vrDisplay) {\n    mat4_perspectiveFromFieldOfView(projection, parameters ? parameters.fieldOfView : null, vrDisplay.depthNear, vrDisplay.depthFar);\n\n    var orientation = pose.orientation || defaultOrientation;\n    var position = pose.position || defaultPosition;\n\n    mat4_fromRotationTranslation(view, orientation, position);\n    if (parameters)\n      mat4_translate(view, view, parameters.offset);\n    mat4_invert(view, view);\n  }\n\n  return function(frameData, pose, vrDisplay) {\n    if (!frameData || !pose)\n      return false;\n\n    frameData.pose = pose;\n    frameData.timestamp = pose.timestamp;\n\n    updateEyeMatrices(\n        frameData.leftProjectionMatrix, frameData.leftViewMatrix,\n        pose, vrDisplay.getEyeParameters(\"left\"), vrDisplay);\n    updateEyeMatrices(\n        frameData.rightProjectionMatrix, frameData.rightViewMatrix,\n        pose, vrDisplay.getEyeParameters(\"right\"), vrDisplay);\n\n    return true;\n  };\n})();\n\nUtil.isInsideCrossDomainIFrame = function() {\n  var isFramed = (window.self !== window.top);\n  var refDomain = Util.getDomainFromUrl(document.referrer);\n  var thisDomain = Util.getDomainFromUrl(window.location.href);\n\n  return isFramed && (refDomain !== thisDomain);\n};\n\n// From http://stackoverflow.com/a/23945027.\nUtil.getDomainFromUrl = function(url) {\n  var domain;\n  // Find & remove protocol (http, ftp, etc.) and get domain.\n  if (url.indexOf(\"://\") > -1) {\n    domain = url.split('/')[2];\n  }\n  else {\n    domain = url.split('/')[0];\n  }\n\n  //find & remove port number\n  domain = domain.split(':')[0];\n\n  return domain;\n}\n\nmodule.exports = Util;\n\n},{}],69:[function(_dereq_,module,exports){\n/*\n * Copyright 2015 Google Inc. All Rights Reserved.\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\nvar DeviceInfo = _dereq_('./device-info.js');\nvar Util = _dereq_('./util.js');\n\nvar DEFAULT_VIEWER = 'CardboardV1';\nvar VIEWER_KEY = 'WEBVR_CARDBOARD_VIEWER';\nvar CLASS_NAME = 'webvr-polyfill-viewer-selector';\n\n/**\n * Creates a viewer selector with the options specified. Supports being shown\n * and hidden. Generates events when viewer parameters change. Also supports\n * saving the currently selected index in localStorage.\n */\nfunction ViewerSelector() {\n  // Try to load the selected key from local storage.\n  try {\n    this.selectedKey = localStorage.getItem(VIEWER_KEY);\n  } catch (error) {\n    console.error('Failed to load viewer profile: %s', error);\n  }\n\n  //If none exists, or if localstorage is unavailable, use the default key.\n  if (!this.selectedKey) {\n    this.selectedKey = DEFAULT_VIEWER;\n  }\n\n  this.dialog = this.createDialog_(DeviceInfo.Viewers);\n  this.root = null;\n  this.onChangeCallbacks_ = [];\n}\n\nViewerSelector.prototype.show = function(root) {\n  this.root = root;\n\n  root.appendChild(this.dialog);\n\n  // Ensure the currently selected item is checked.\n  var selected = this.dialog.querySelector('#' + this.selectedKey);\n  selected.checked = true;\n\n  // Show the UI.\n  this.dialog.style.display = 'block';\n};\n\nViewerSelector.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\nViewerSelector.prototype.getCurrentViewer = function() {\n  return DeviceInfo.Viewers[this.selectedKey];\n};\n\nViewerSelector.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\nViewerSelector.prototype.onChange = function(cb) {\n  this.onChangeCallbacks_.push(cb);\n};\n\nViewerSelector.prototype.fireOnChange_ = function(viewer) {\n  for (var i = 0; i < this.onChangeCallbacks_.length; i++) {\n    this.onChangeCallbacks_[i](viewer);\n  }\n};\n\nViewerSelector.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\n  this.fireOnChange_(DeviceInfo.Viewers[this.selectedKey]);\n\n  // Attempt to save the viewer profile, but fails in private mode.\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\n/**\n * Creates the dialog.\n */\nViewerSelector.prototype.createDialog_ = function(options) {\n  var container = document.createElement('div');\n  container.classList.add(CLASS_NAME);\n  container.style.display = 'none';\n  // Create an overlay that dims the background, and which goes away when you\n  // tap it.\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\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\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\n  container.appendChild(overlay);\n  container.appendChild(dialog);\n\n  return container;\n};\n\nViewerSelector.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\nViewerSelector.prototype.createChoice_ = function(id, name) {\n  /*\n  <div class=\"choice\">\n  <input id=\"v1\" type=\"radio\" name=\"field\" value=\"v1\">\n  <label for=\"v1\">Cardboard V1</label>\n  </div>\n  */\n  var div = document.createElement('div');\n  div.style.marginTop = '8px';\n  div.style.color = 'black';\n\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\n  var label = document.createElement('label');\n  label.style.marginLeft = '4px';\n  label.setAttribute('for', id);\n  label.innerHTML = name;\n\n  div.appendChild(input);\n  div.appendChild(label);\n\n  return div;\n};\n\nViewerSelector.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\n  button.addEventListener('click', onclick);\n\n  return button;\n};\n\nmodule.exports = ViewerSelector;\n\n},{\"./device-info.js\":53,\"./util.js\":68}],70:[function(_dereq_,module,exports){\n/*\n * Copyright 2015 Google Inc. All Rights Reserved.\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\nvar Util = _dereq_('./util.js');\n\n/**\n * Android and iOS compatible wakelock implementation.\n *\n * Refactored thanks to dkovalev@.\n */\nfunction AndroidWakeLock() {\n  var video = document.createElement('video');\n  video.setAttribute('loop', '');\n\n  function addSourceToVideo(element, type, dataURI) {\n    var source = document.createElement('source');\n    source.src = dataURI;\n    source.type = 'video/' + type;\n    element.appendChild(source);\n  }\n\n  addSourceToVideo(video,'webm', Util.base64('video/webm', 'GkXfo0AgQoaBAUL3gQFC8oEEQvOBCEKCQAR3ZWJtQoeBAkKFgQIYU4BnQI0VSalmQCgq17FAAw9CQE2AQAZ3aGFtbXlXQUAGd2hhbW15RIlACECPQAAAAAAAFlSua0AxrkAu14EBY8WBAZyBACK1nEADdW5khkAFVl9WUDglhohAA1ZQOIOBAeBABrCBCLqBCB9DtnVAIueBAKNAHIEAAIAwAQCdASoIAAgAAUAmJaQAA3AA/vz0AAA='));\n  addSourceToVideo(video, 'mp4', Util.base64('video/mp4', 'AAAAHGZ0eXBpc29tAAACAGlzb21pc28ybXA0MQAAAAhmcmVlAAAAG21kYXQAAAGzABAHAAABthADAowdbb9/AAAC6W1vb3YAAABsbXZoZAAAAAB8JbCAfCWwgAAAA+gAAAAAAAEAAAEAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAIVdHJhawAAAFx0a2hkAAAAD3wlsIB8JbCAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAIAAAACAAAAAABsW1kaWEAAAAgbWRoZAAAAAB8JbCAfCWwgAAAA+gAAAAAVcQAAAAAAC1oZGxyAAAAAAAAAAB2aWRlAAAAAAAAAAAAAAAAVmlkZW9IYW5kbGVyAAAAAVxtaW5mAAAAFHZtaGQAAAABAAAAAAAAAAAAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAAEcc3RibAAAALhzdHNkAAAAAAAAAAEAAACobXA0dgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAIAAgASAAAAEgAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABj//wAAAFJlc2RzAAAAAANEAAEABDwgEQAAAAADDUAAAAAABS0AAAGwAQAAAbWJEwAAAQAAAAEgAMSNiB9FAEQBFGMAAAGyTGF2YzUyLjg3LjQGAQIAAAAYc3R0cwAAAAAAAAABAAAAAQAAAAAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAAEAAAABAAAAFHN0c3oAAAAAAAAAEwAAAAEAAAAUc3RjbwAAAAAAAAABAAAALAAAAGB1ZHRhAAAAWG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAK2lsc3QAAAAjqXRvbwAAABtkYXRhAAAAAQAAAABMYXZmNTIuNzguMw=='));\n\n  this.request = function() {\n    if (video.paused) {\n      video.play();\n    }\n  };\n\n  this.release = function() {\n    video.pause();\n  };\n}\n\nfunction iOSWakeLock() {\n  var timer = null;\n\n  this.request = function() {\n    if (!timer) {\n      timer = setInterval(function() {\n        window.location = window.location;\n        setTimeout(window.stop, 0);\n      }, 30000);\n    }\n  }\n\n  this.release = function() {\n    if (timer) {\n      clearInterval(timer);\n      timer = null;\n    }\n  }\n}\n\n\nfunction getWakeLock() {\n  var userAgent = navigator.userAgent || navigator.vendor || window.opera;\n  if (userAgent.match(/iPhone/i) || userAgent.match(/iPod/i)) {\n    return iOSWakeLock;\n  } else {\n    return AndroidWakeLock;\n  }\n}\n\nmodule.exports = getWakeLock();\n},{\"./util.js\":68}],71:[function(_dereq_,module,exports){\n/*\n * Copyright 2015 Google Inc. All Rights Reserved.\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\nvar Util = _dereq_('./util.js');\nvar CardboardVRDisplay = _dereq_('./cardboard-vr-display.js');\nvar MouseKeyboardVRDisplay = _dereq_('./mouse-keyboard-vr-display.js');\n// Uncomment to add positional tracking via webcam.\n//var WebcamPositionSensorVRDevice = require('./webcam-position-sensor-vr-device.js');\nvar VRDisplay = _dereq_('./base.js').VRDisplay;\nvar VRFrameData = _dereq_('./base.js').VRFrameData;\nvar HMDVRDevice = _dereq_('./base.js').HMDVRDevice;\nvar PositionSensorVRDevice = _dereq_('./base.js').PositionSensorVRDevice;\nvar VRDisplayHMDDevice = _dereq_('./display-wrappers.js').VRDisplayHMDDevice;\nvar VRDisplayPositionSensorDevice = _dereq_('./display-wrappers.js').VRDisplayPositionSensorDevice;\nvar version = _dereq_('../package.json').version;\n\nfunction WebVRPolyfill() {\n  this.displays = [];\n  this.devices = []; // For deprecated objects\n  this.devicesPopulated = false;\n  this.nativeWebVRAvailable = this.isWebVRAvailable();\n  this.nativeLegacyWebVRAvailable = this.isDeprecatedWebVRAvailable();\n  this.nativeGetVRDisplaysFunc = this.nativeWebVRAvailable ?\n                                 navigator.getVRDisplays :\n                                 null;\n\n  if (!this.nativeLegacyWebVRAvailable && !this.nativeWebVRAvailable) {\n    this.enablePolyfill();\n    if (window.WebVRConfig.ENABLE_DEPRECATED_API) {\n      this.enableDeprecatedPolyfill();\n    }\n  }\n\n  // Put a shim in place to update the API to 1.1 if needed.\n  InstallWebVRSpecShim();\n}\n\nWebVRPolyfill.prototype.isWebVRAvailable = function() {\n  return ('getVRDisplays' in navigator);\n};\n\nWebVRPolyfill.prototype.isDeprecatedWebVRAvailable = function() {\n  return ('getVRDevices' in navigator) || ('mozGetVRDevices' in navigator);\n};\n\nWebVRPolyfill.prototype.connectDisplay = function(vrDisplay) {\n  vrDisplay.fireVRDisplayConnect_();\n  this.displays.push(vrDisplay);\n};\n\nWebVRPolyfill.prototype.populateDevices = function() {\n  if (this.devicesPopulated) {\n    return;\n  }\n\n  // Initialize our virtual VR devices.\n  var vrDisplay = null;\n\n  // Add a Cardboard VRDisplay on compatible mobile devices\n  if (this.isCardboardCompatible()) {\n    vrDisplay = new CardboardVRDisplay();\n\n    this.connectDisplay(vrDisplay);\n\n    // For backwards compatibility\n    if (window.WebVRConfig.ENABLE_DEPRECATED_API) {\n      this.devices.push(new VRDisplayHMDDevice(vrDisplay));\n      this.devices.push(new VRDisplayPositionSensorDevice(vrDisplay));\n    }\n  }\n\n  // Add a Mouse and Keyboard driven VRDisplay for desktops/laptops\n  if (!this.isMobile() && !window.WebVRConfig.MOUSE_KEYBOARD_CONTROLS_DISABLED) {\n    vrDisplay = new MouseKeyboardVRDisplay();\n    this.connectDisplay(vrDisplay);\n\n    // For backwards compatibility\n    if (window.WebVRConfig.ENABLE_DEPRECATED_API) {\n      this.devices.push(new VRDisplayHMDDevice(vrDisplay));\n      this.devices.push(new VRDisplayPositionSensorDevice(vrDisplay));\n    }\n  }\n\n  // Uncomment to add positional tracking via webcam.\n  //if (!this.isMobile() && window.WebVRConfig.ENABLE_DEPRECATED_API) {\n  //  positionDevice = new WebcamPositionSensorVRDevice();\n  //  this.devices.push(positionDevice);\n  //}\n\n  this.devicesPopulated = true;\n};\n\nWebVRPolyfill.prototype.enablePolyfill = function() {\n  // Provide navigator.getVRDisplays.\n  navigator.getVRDisplays = this.getVRDisplays.bind(this);\n\n  // Polyfill native VRDisplay.getFrameData\n  if (this.nativeWebVRAvailable && window.VRFrameData) {\n    var NativeVRFrameData = window.VRFrameData;\n    var nativeFrameData = new window.VRFrameData();\n    var nativeGetFrameData = window.VRDisplay.prototype.getFrameData;\n    window.VRFrameData = VRFrameData;\n\n    window.VRDisplay.prototype.getFrameData = function(frameData) {\n      if (frameData instanceof NativeVRFrameData) {\n        nativeGetFrameData.call(this, frameData);\n        return;\n      }\n\n      /*\n      Copy frame data from the native object into the polyfilled object.\n      */\n\n      nativeGetFrameData.call(this, nativeFrameData);\n      frameData.pose = nativeFrameData.pose;\n      Util.copyArray(nativeFrameData.leftProjectionMatrix, frameData.leftProjectionMatrix);\n      Util.copyArray(nativeFrameData.rightProjectionMatrix, frameData.rightProjectionMatrix);\n      Util.copyArray(nativeFrameData.leftViewMatrix, frameData.leftViewMatrix);\n      Util.copyArray(nativeFrameData.rightViewMatrix, frameData.rightViewMatrix);\n      //todo: copy\n    };\n  }\n\n  // Provide the `VRDisplay` object.\n  window.VRDisplay = VRDisplay;\n\n  // Provide the `navigator.vrEnabled` property.\n  if (navigator && typeof navigator.vrEnabled === 'undefined') {\n    var self = this;\n    Object.defineProperty(navigator, 'vrEnabled', {\n      get: function () {\n        return self.isCardboardCompatible() &&\n            (self.isFullScreenAvailable() || Util.isIOS());\n      }\n    });\n  }\n\n  if (!('VRFrameData' in window)) {\n    // Provide the VRFrameData object.\n    window.VRFrameData = VRFrameData;\n  }\n};\n\nWebVRPolyfill.prototype.enableDeprecatedPolyfill = function() {\n  // Provide navigator.getVRDevices.\n  navigator.getVRDevices = this.getVRDevices.bind(this);\n\n  // Provide the CardboardHMDVRDevice and PositionSensorVRDevice objects.\n  window.HMDVRDevice = HMDVRDevice;\n  window.PositionSensorVRDevice = PositionSensorVRDevice;\n};\n\nWebVRPolyfill.prototype.getVRDisplays = function() {\n  this.populateDevices();\n  var polyfillDisplays = this.displays;\n\n  if (!this.nativeWebVRAvailable) {\n    return Promise.resolve(polyfillDisplays);\n  }\n\n  // Set up a race condition if this browser has a bug where\n  // `navigator.getVRDisplays()` never resolves.\n  var timeoutId;\n  var vrDisplaysNative = this.nativeGetVRDisplaysFunc.call(navigator);\n  var timeoutPromise = new Promise(function(resolve) {\n    timeoutId = setTimeout(function() {\n      console.warn('Native WebVR implementation detected, but `getVRDisplays()` failed to resolve. Falling back to polyfill.');\n      resolve([]);\n    }, window.WebVRConfig.GET_VR_DISPLAYS_TIMEOUT);\n  });\n\n  return Util.race([\n    vrDisplaysNative,\n    timeoutPromise\n  ]).then(function(nativeDisplays) {\n    clearTimeout(timeoutId);\n    if (window.WebVRConfig.ALWAYS_APPEND_POLYFILL_DISPLAY) {\n      return nativeDisplays.concat(polyfillDisplays);\n    } else {\n      return nativeDisplays.length > 0 ? nativeDisplays : polyfillDisplays;\n    }\n  });\n};\n\nWebVRPolyfill.prototype.getVRDevices = function() {\n  console.warn('getVRDevices is deprecated. Please update your code to use getVRDisplays instead.');\n  var self = this;\n  return new Promise(function(resolve, reject) {\n    try {\n      if (!self.devicesPopulated) {\n        if (self.nativeWebVRAvailable) {\n          return navigator.getVRDisplays(function(displays) {\n            for (var i = 0; i < displays.length; ++i) {\n              self.devices.push(new VRDisplayHMDDevice(displays[i]));\n              self.devices.push(new VRDisplayPositionSensorDevice(displays[i]));\n            }\n            self.devicesPopulated = true;\n            resolve(self.devices);\n          }, reject);\n        }\n\n        if (self.nativeLegacyWebVRAvailable) {\n          return (navigator.getVRDDevices || navigator.mozGetVRDevices)(function(devices) {\n            for (var i = 0; i < devices.length; ++i) {\n              if (devices[i] instanceof HMDVRDevice) {\n                self.devices.push(devices[i]);\n              }\n              if (devices[i] instanceof PositionSensorVRDevice) {\n                self.devices.push(devices[i]);\n              }\n            }\n            self.devicesPopulated = true;\n            resolve(self.devices);\n          }, reject);\n        }\n      }\n\n      self.populateDevices();\n      resolve(self.devices);\n    } catch (e) {\n      reject(e);\n    }\n  });\n};\n\nWebVRPolyfill.prototype.NativeVRFrameData = window.VRFrameData;\n\n/**\n * Determine if a device is mobile.\n */\nWebVRPolyfill.prototype.isMobile = function() {\n  return /Android/i.test(navigator.userAgent) ||\n      /iPhone|iPad|iPod/i.test(navigator.userAgent);\n};\n\nWebVRPolyfill.prototype.isCardboardCompatible = function() {\n  // For now, support all iOS and Android devices.\n  // Also enable the WebVRConfig.FORCE_VR flag for debugging.\n  return this.isMobile() || window.WebVRConfig.FORCE_ENABLE_VR;\n};\n\nWebVRPolyfill.prototype.isFullScreenAvailable = function() {\n  return (document.fullscreenEnabled ||\n          document.mozFullScreenEnabled ||\n          document.webkitFullscreenEnabled ||\n          false);\n};\n\n// Installs a shim that updates a WebVR 1.0 spec implementation to WebVR 1.1\nfunction InstallWebVRSpecShim() {\n  if ('VRDisplay' in window && !('VRFrameData' in window)) {\n    // Provide the VRFrameData object.\n    window.VRFrameData = VRFrameData;\n\n    // A lot of Chrome builds don't have depthNear and depthFar, even\n    // though they're in the WebVR 1.0 spec. Patch them in if they're not present.\n    if(!('depthNear' in window.VRDisplay.prototype)) {\n      window.VRDisplay.prototype.depthNear = 0.01;\n    }\n\n    if(!('depthFar' in window.VRDisplay.prototype)) {\n      window.VRDisplay.prototype.depthFar = 10000.0;\n    }\n\n    window.VRDisplay.prototype.getFrameData = function(frameData) {\n      return Util.frameDataFromPose(frameData, this.getPose(), this);\n    }\n  }\n};\n\nWebVRPolyfill.InstallWebVRSpecShim = InstallWebVRSpecShim;\nWebVRPolyfill.version = version;\n\nmodule.exports.WebVRPolyfill = WebVRPolyfill;\n\n},{\"../package.json\":47,\"./base.js\":48,\"./cardboard-vr-display.js\":51,\"./display-wrappers.js\":54,\"./mouse-keyboard-vr-display.js\":60,\"./util.js\":68}],72:[function(_dereq_,module,exports){\nvar newline = /\\n/\nvar newlineChar = '\\n'\nvar whitespace = /\\s/\n\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}\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') \n        return []\n\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\n    var measure = opt.measure || monospace\n    if (mode === 'pre')\n        return pre(measure, text, start, end, width)\n    else\n        return greedy(measure, text, start, end, width, mode)\n}\n\nfunction idxOf(text, chr, start, end) {\n    var idx = text.indexOf(chr, start)\n    if (idx === -1 || idx > end)\n        return end\n    return idx\n}\n\nfunction isWhitespace(chr) {\n    return whitespace.test(chr)\n}\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            \n            lineStart = i+1\n        }\n    }\n    return lines\n}\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\n    var testWidth = width\n    //if 'nowrap' is specified, we only wrap on newline chars\n    if (mode === 'nowrap')\n        testWidth = Number.MAX_VALUE\n\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) ))\n                break\n            start++\n        }\n\n        //determine visible # of glyphs for the available width\n        var measured = measure(text, start, newLine, testWidth)\n\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)))\n                    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)))\n                        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},{}],73:[function(_dereq_,module,exports){\n\"use strict\";\nvar window = _dereq_(\"global/window\")\nvar isFunction = _dereq_(\"is-function\")\nvar parseHeaders = _dereq_(\"parse-headers\")\nvar xtend = _dereq_(\"xtend\")\n\nmodule.exports = createXHR\ncreateXHR.XMLHttpRequest = window.XMLHttpRequest || noop\ncreateXHR.XDomainRequest = \"withCredentials\" in (new createXHR.XMLHttpRequest()) ? createXHR.XMLHttpRequest : window.XDomainRequest\n\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})\n\nfunction forEachArray(array, iterator) {\n    for (var i = 0; i < array.length; i++) {\n        iterator(array[i])\n    }\n}\n\nfunction isEmpty(obj){\n    for(var i in obj){\n        if(obj.hasOwnProperty(i)) return false\n    }\n    return true\n}\n\nfunction initParams(uri, options, callback) {\n    var params = uri\n\n    if (isFunction(options)) {\n        callback = options\n        if (typeof uri === \"string\") {\n            params = {uri:uri}\n        }\n    } else {\n        params = xtend(options, {uri: uri})\n    }\n\n    params.callback = callback\n    return params\n}\n\nfunction createXHR(uri, options, callback) {\n    options = initParams(uri, options, callback)\n    return _createXHR(options)\n}\n\nfunction _createXHR(options) {\n    if(typeof options.callback === \"undefined\"){\n        throw new Error(\"callback argument missing\")\n    }\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\n    function readystatechange() {\n        if (xhr.readyState === 4) {\n            setTimeout(loadFunc, 0)\n        }\n    }\n\n    function getBody() {\n        // Chrome with requestType=blob throws errors arround when even testing access to responseText\n        var body = undefined\n\n        if (xhr.response) {\n            body = xhr.response\n        } else {\n            body = xhr.responseText || getXml(xhr)\n        }\n\n        if (isJson) {\n            try {\n                body = JSON.parse(body)\n            } catch (e) {}\n        }\n\n        return body\n    }\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\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){ //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\n    var xhr = options.xhr || null\n\n    if (!xhr) {\n        if (options.cors || options.useXDR) {\n            xhr = new createXHR.XDomainRequest()\n        }else{\n            xhr = new createXHR.XMLHttpRequest()\n        }\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\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\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\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\n    if (\"responseType\" in options) {\n        xhr.responseType = options.responseType\n    }\n\n    if (\"beforeSend\" in options &&\n        typeof options.beforeSend === \"function\"\n    ) {\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\n    return xhr\n\n\n}\n\nfunction getXml(xhr) {\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\n    return null\n}\n\nfunction noop() {}\n\n},{\"global/window\":17,\"is-function\":21,\"parse-headers\":31,\"xtend\":75}],74:[function(_dereq_,module,exports){\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'\n      && 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},{}],75:[function(_dereq_,module,exports){\nmodule.exports = extend\n\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\n\nfunction extend() {\n    var target = {}\n\n    for (var i = 0; i < arguments.length; i++) {\n        var source = arguments[i]\n\n        for (var key in source) {\n            if (hasOwnProperty.call(source, key)) {\n                target[key] = source[key]\n            }\n        }\n    }\n\n    return target\n}\n\n},{}],76:[function(_dereq_,module,exports){\nmodule.exports={\n  \"name\": \"aframe\",\n  \"version\": \"0.7.1\",\n  \"description\": \"A web framework for building virtual reality experiences.\",\n  \"homepage\": \"https://aframe.io/\",\n  \"main\": \"dist/aframe-master.js\",\n  \"scripts\": {\n    \"browserify\": \"browserify src/index.js -s 'AFRAME' -p browserify-derequire\",\n    \"build\": \"shx mkdir -p build/ && npm run browserify -- --debug -t [envify --INSPECTOR_VERSION dev] -o build/aframe.js\",\n    \"codecov\": \"codecov\",\n    \"dev\": \"npm run build && cross-env INSPECTOR_VERSION=dev node ./scripts/budo -t envify\",\n    \"dist\": \"node scripts/updateVersionLog.js && npm run dist:min && npm run dist:max\",\n    \"dist:max\": \"npm run browserify -s -- --debug | exorcist dist/aframe-v0.7.1.js.map > dist/aframe-v0.7.1.js\",\n    \"dist:min\": \"npm run browserify -s -- --debug -p [minifyify --map aframe-v0.7.1.min.js.map --output dist/aframe-v0.7.1.min.js.map] -o dist/aframe-v0.7.1.min.js\",\n    \"docs\": \"markserv --dir docs --port 9001\",\n    \"preghpages\": \"node ./scripts/preghpages.js\",\n    \"ghpages\": \"ghpages -p gh-pages/\",\n    \"lint\": \"semistandard -v | snazzy\",\n    \"lint:fix\": \"semistandard --fix\",\n    \"precommit\": \"npm run lint\",\n    \"prerelease\": \"node scripts/release.js 0.6.1 0.7.0\",\n    \"start\": \"npm run dev\",\n    \"test\": \"karma start ./tests/karma.conf.js\",\n    \"test:docs\": \"node scripts/docsLint.js\",\n    \"test:firefox\": \"npm test -- --browsers Firefox\",\n    \"test:chrome\": \"npm test -- --browsers Chrome\",\n    \"test:node\": \"mocha --ui tdd tests/node\"\n  },\n  \"repository\": \"aframevr/aframe\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@tweenjs/tween.js\": \"^16.8.0\",\n    \"browserify-css\": \"^0.8.2\",\n    \"debug\": \"ngokevin/debug#noTimestamp\",\n    \"deep-assign\": \"^2.0.0\",\n    \"document-register-element\": \"dmarcos/document-register-element#8ccc532b7\",\n    \"envify\": \"^3.4.1\",\n    \"load-bmfont\": \"^1.2.3\",\n    \"object-assign\": \"^4.0.1\",\n    \"present\": \"0.0.6\",\n    \"promise-polyfill\": \"^3.1.0\",\n    \"style-attr\": \"^1.0.2\",\n    \"three\": \"^0.87.0\",\n    \"three-bmfont-text\": \"^2.1.0\",\n    \"webvr-polyfill\": \"^0.9.36\"\n  },\n  \"devDependencies\": {\n    \"browserify\": \"^13.1.0\",\n    \"browserify-derequire\": \"^0.9.4\",\n    \"browserify-istanbul\": \"^2.0.0\",\n    \"budo\": \"^9.2.0\",\n    \"chai\": \"^3.5.0\",\n    \"chai-shallow-deep-equal\": \"^1.4.0\",\n    \"chalk\": \"^1.1.3\",\n    \"codecov\": \"^1.0.1\",\n    \"cross-env\": \"^5.0.1\",\n    \"exorcist\": \"^0.4.0\",\n    \"ghpages\": \"0.0.8\",\n    \"git-rev\": \"^0.2.1\",\n    \"glob\": \"^7.1.1\",\n    \"husky\": \"^0.11.7\",\n    \"istanbul\": \"^0.4.5\",\n    \"jsdom\": \"^9.11.0\",\n    \"karma\": \"1.4.1\",\n    \"karma-browserify\": \"^5.1.0\",\n    \"karma-chai-shallow-deep-equal\": \"0.0.4\",\n    \"karma-chrome-launcher\": \"^2.0.0\",\n    \"karma-coverage\": \"^1.1.1\",\n    \"karma-env-preprocessor\": \"^0.1.1\",\n    \"karma-firefox-launcher\": \"^1.0.0\",\n    \"karma-mocha\": \"^1.1.1\",\n    \"karma-mocha-reporter\": \"^2.1.0\",\n    \"karma-sinon-chai\": \"1.2.4\",\n    \"lolex\": \"^1.5.1\",\n    \"markserv\": \"0.0.20\",\n    \"minifyify\": \"^7.3.3\",\n    \"mocha\": \"^3.0.2\",\n    \"mozilla-download\": \"^1.1.1\",\n    \"replace-in-file\": \"^2.5.3\",\n    \"semistandard\": \"^9.0.0\",\n    \"shelljs\": \"^0.7.7\",\n    \"shx\": \"^0.2.2\",\n    \"sinon\": \"^1.17.5\",\n    \"sinon-chai\": \"2.8.0\",\n    \"snazzy\": \"^5.0.0\",\n    \"too-wordy\": \"ngokevin/too-wordy\",\n    \"uglifyjs\": \"^2.4.10\",\n    \"write-good\": \"^0.9.1\"\n  },\n  \"link\": true,\n  \"browserify\": {\n    \"transform\": [\n      \"browserify-css\",\n      \"envify\"\n    ]\n  },\n  \"semistandard\": {\n    \"ignore\": [\n      \"build/**\",\n      \"dist/**\",\n      \"examples/**/shaders/*.js\",\n      \"**/vendor/**\"\n    ]\n  },\n  \"keywords\": [\n    \"3d\",\n    \"aframe\",\n    \"cardboard\",\n    \"components\",\n    \"oculus\",\n    \"three\",\n    \"three.js\",\n    \"rift\",\n    \"vive\",\n    \"vr\",\n    \"web-components\",\n    \"webvr\"\n  ],\n  \"browserify-css\": {\n    \"minify\": true\n  },\n  \"engines\": {\n    \"node\": \">= 4.6.0\",\n    \"npm\": \"^2.15.9\"\n  }\n}\n\n},{}],77:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar THREE = _dereq_('../lib/three');\nvar utils = _dereq_('../utils/');\nvar bind = utils.bind;\n\nvar checkHasPositionalTracking = utils.device.checkHasPositionalTracking;\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: {default: true},\n    far: {default: 10000},\n    fov: {default: 80, min: 0},\n    near: {default: 0.005, min: 0},\n    userHeight: {default: 0, min: 0},\n    zoom: {default: 1, 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    var sceneEl = el.sceneEl;\n\n    this.savedPose = null;\n\n    // Create camera.\n    camera = this.camera = new THREE.PerspectiveCamera();\n    el.setObject3D('camera', camera);\n\n    // Add listeners to save and restore camera pose if headset is present.\n    this.onEnterVR = bind(this.onEnterVR, this);\n    this.onExitVR = bind(this.onExitVR, this);\n    sceneEl.addEventListener('enter-vr', this.onEnterVR);\n    sceneEl.addEventListener('exit-vr', this.onExitVR);\n  },\n\n  /**\n   * Update three.js camera.\n   */\n  update: function (oldData) {\n    var el = this.el;\n    var data = this.data;\n    var camera = this.camera;\n    var system = this.system;\n\n    // Update height offset.\n    this.addHeightOffset(oldData.userHeight);\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\n    // Active property did not change.\n    if (oldData && oldData.active === data.active) { return; }\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\n  /**\n   * Remove camera on remove (callback).\n   */\n  remove: function () {\n    var sceneEl = this.el.sceneEl;\n    this.el.removeObject3D('camera');\n    sceneEl.removeEventListener('enter-vr', this.onEnterVR);\n    sceneEl.removeEventListener('exit-vr', this.onExitVR);\n  },\n\n  /**\n   * Save pose and remove the offset.\n   */\n  onEnterVR: function () {\n    this.saveCameraPose();\n    this.removeHeightOffset();\n  },\n\n  /**\n   * Restore the pose. Do not need to re-add the offset because it was saved on entering VR.\n   */\n  onExitVR: function () {\n    this.restoreCameraPose();\n  },\n\n  /**\n   * Offsets the position of the camera to set a human scale perspective\n   * This offset is not necessary when using a headset because the SDK\n   * will return the real user's head height and position.\n   */\n  addHeightOffset: function (oldOffset) {\n    var el = this.el;\n    var currentPosition;\n    var userHeightOffset = this.data.userHeight;\n\n    oldOffset = oldOffset || 0;\n    currentPosition = el.getAttribute('position') || {x: 0, y: 0, z: 0};\n    el.setAttribute('position', {\n      x: currentPosition.x,\n      y: currentPosition.y - oldOffset + userHeightOffset,\n      z: currentPosition.z\n    });\n  },\n\n  /**\n   * Remove the height offset (called when entering VR) since WebVR API gives absolute\n   * position.\n   */\n  removeHeightOffset: function () {\n    var currentPosition;\n    var el = this.el;\n    var hasPositionalTracking;\n    var userHeightOffset = this.data.userHeight;\n\n    // Remove the offset if there is positional tracking when entering VR.\n    // Necessary for fullscreen mode with no headset.\n    // Checking this.hasPositionalTracking to make the value injectable for unit tests.\n    hasPositionalTracking = this.hasPositionalTracking !== undefined ? this.hasPositionalTracking : checkHasPositionalTracking();\n\n    if (!userHeightOffset || !hasPositionalTracking) { return; }\n\n    currentPosition = el.getAttribute('position') || {x: 0, y: 0, z: 0};\n    el.setAttribute('position', {\n      x: currentPosition.x,\n      y: currentPosition.y - userHeightOffset,\n      z: currentPosition.z\n    });\n  },\n\n  /**\n   * Save camera pose before entering VR to restore later if exiting.\n   */\n  saveCameraPose: function () {\n    var el = this.el;\n    var hasPositionalTracking = this.hasPositionalTracking !== undefined ? this.hasPositionalTracking : checkHasPositionalTracking();\n\n    if (this.savedPose || !hasPositionalTracking) { return; }\n\n    this.savedPose = {\n      position: el.getAttribute('position'),\n      rotation: el.getAttribute('rotation')\n    };\n  },\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    var hasPositionalTracking = this.hasPositionalTracking !== undefined ? this.hasPositionalTracking : checkHasPositionalTracking();\n\n    if (!savedPose || !hasPositionalTracking) { return; }\n\n    // Reset camera orientation.\n    el.setAttribute('position', savedPose.position);\n    el.setAttribute('rotation', savedPose.rotation);\n    this.savedPose = null;\n  }\n});\n\n},{\"../core/component\":125,\"../lib/three\":173,\"../utils/\":195}],78:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar THREE = _dereq_('../lib/three');\n\nmodule.exports.Component = registerComponent('collada-model', {\n  schema: {type: 'asset'},\n\n  init: function () {\n    this.model = null;\n    this.loader = new THREE.ColladaLoader();\n    this.loader.options.convertUpAxis = true;\n  },\n\n  update: function () {\n    var self = this;\n    var el = this.el;\n    var src = this.data;\n\n    if (!src) { return; }\n\n    this.remove();\n\n    this.loader.load(src, function (colladaModel) {\n      self.model = colladaModel.scene;\n      el.setObject3D('mesh', self.model);\n      el.emit('model-loaded', {format: 'collada', model: self.model});\n    });\n  },\n\n  remove: function () {\n    if (!this.model) { return; }\n    this.el.removeObject3D('mesh');\n  }\n});\n\n},{\"../core/component\":125,\"../lib/three\":173}],79:[function(_dereq_,module,exports){\n/* global THREE */\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar utils = _dereq_('../utils/');\n\nvar bind = utils.bind;\n\nvar EVENTS = {\n  CLICK: 'click',\n  FUSING: 'fusing',\n  MOUSEENTER: 'mouseenter',\n  MOUSEDOWN: 'mousedown',\n  MOUSELEAVE: 'mouseleave',\n  MOUSEUP: 'mouseup'\n};\n\nvar STATES = {\n  FUSING: 'cursor-fusing',\n  HOVERING: 'cursor-hovering',\n  HOVERED: 'cursor-hovered'\n};\n\nvar CANVAS_EVENTS = {\n  DOWN: ['mousedown', 'touchstart'],\n  UP: ['mouseup', 'touchend']\n};\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\n  schema: {\n    downEvents: {default: []},\n    fuse: {default: utils.device.isMobile()},\n    fuseTimeout: {default: 1500, min: 0},\n    upEvents: {default: []},\n    rayOrigin: {default: 'entity', oneOf: ['mouse', 'entity']}\n  },\n\n  init: function () {\n    var self = this;\n\n    this.fuseTimeout = undefined;\n    this.cursorDownEl = null;\n    this.intersection = null;\n    this.intersectedEl = null;\n    this.canvasBounds = document.body.getBoundingClientRect();\n\n    // Debounce.\n    this.updateCanvasBounds = utils.debounce(function updateCanvasBounds () {\n      self.canvasBounds = self.el.sceneEl.canvas.getBoundingClientRect();\n    }, 200);\n\n    // Bind methods.\n    this.onCursorDown = bind(this.onCursorDown, this);\n    this.onCursorUp = bind(this.onCursorUp, this);\n    this.onIntersection = bind(this.onIntersection, this);\n    this.onIntersectionCleared = bind(this.onIntersectionCleared, this);\n    this.onMouseMove = bind(this.onMouseMove, this);\n  },\n\n  update: function (oldData) {\n    if (this.data.rayOrigin === oldData.rayOrigin) { return; }\n    this.updateMouseEventListeners();\n  },\n\n  play: function () {\n    this.addEventListeners();\n  },\n\n  pause: function () {\n    this.removeEventListeners();\n  },\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) { this.intersectedEl.removeState(STATES.HOVERED); }\n    this.removeEventListeners();\n  },\n\n  addEventListeners: function () {\n    var canvas;\n    var data = this.data;\n    var el = this.el;\n    var self = this;\n\n    function addCanvasListeners () {\n      canvas = el.sceneEl.canvas;\n      CANVAS_EVENTS.DOWN.forEach(function (downEvent) {\n        canvas.addEventListener(downEvent, self.onCursorDown);\n      });\n      CANVAS_EVENTS.UP.forEach(function (upEvent) {\n        canvas.addEventListener(upEvent, self.onCursorUp);\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\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-intersection-cleared', this.onIntersectionCleared);\n\n    window.addEventListener('resize', this.updateCanvasBounds);\n  },\n\n  removeEventListeners: function () {\n    var canvas;\n    var data = this.data;\n    var el = this.el;\n    var self = this;\n\n    canvas = el.sceneEl.canvas;\n    if (canvas) {\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\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    window.removeEventListener('mousemove', this.onMouseMove);\n    window.removeEventListener('resize', this.updateCanvasBounds);\n  },\n\n  updateMouseEventListeners: function () {\n    var el = this.el;\n    window.removeEventListener('mousemove', this.onMouseMove);\n    el.setAttribute('raycaster', 'useWorldCoordinates', false);\n    if (this.data.rayOrigin !== 'mouse') { return; }\n    window.addEventListener('mousemove', this.onMouseMove, false);\n    el.setAttribute('raycaster', 'useWorldCoordinates', true);\n    this.updateCanvasBounds();\n  },\n\n  onMouseMove: (function () {\n    var mouse = new THREE.Vector2();\n    var origin = new THREE.Vector3();\n    var direction = new THREE.Vector3();\n    var rayCasterConfig = {\n      origin: origin,\n      direction: direction\n    };\n    return function (evt) {\n      var camera = this.el.sceneEl.camera;\n      camera.parent.updateMatrixWorld();\n      camera.updateMatrixWorld();\n\n      // Calculate mouse position based on the canvas element\n      var bounds = this.canvasBounds;\n      var left = evt.clientX - bounds.left;\n      var top = evt.clientY - bounds.top;\n      mouse.x = (left / bounds.width) * 2 - 1;\n      mouse.y = -(top / bounds.height) * 2 + 1;\n\n      origin.setFromMatrixPosition(camera.matrixWorld);\n      direction.set(mouse.x, mouse.y, 0.5).unproject(camera).sub(origin).normalize();\n      this.el.setAttribute('raycaster', rayCasterConfig);\n    };\n  })(),\n\n  /**\n   * Trigger mousedown and keep track of the mousedowned entity.\n   */\n  onCursorDown: function (evt) {\n    this.twoWayEmit(EVENTS.MOUSEDOWN);\n    this.cursorDownEl = this.intersectedEl;\n  },\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    this.twoWayEmit(EVENTS.MOUSEUP);\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.cursorDownEl.emit(EVENTS.MOUSEUP, {cursorEl: this.el, intersection: null});\n    }\n\n    if (!this.data.fuse && this.intersectedEl && this.cursorDownEl === this.intersectedEl) {\n      this.twoWayEmit(EVENTS.CLICK);\n    }\n\n    this.cursorDownEl = null;\n  },\n\n  /**\n   * Handle intersection.\n   */\n  onIntersection: function (evt) {\n    var self = this;\n    var cursorEl = this.el;\n    var data = this.data;\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) { return; }\n\n    // Already intersecting this entity.\n    if (this.intersectedEl === intersectedEl) {\n      this.intersection = intersection;\n      return;\n    }\n\n    // Unset current intersection.\n    if (this.intersectedEl) { this.clearCurrentIntersection(); }\n\n    // Set new intersection.\n    this.intersection = intersection;\n    this.intersectedEl = intersectedEl;\n\n    // Hovering.\n    cursorEl.addState(STATES.HOVERING);\n    intersectedEl.addState(STATES.HOVERED);\n    self.twoWayEmit(EVENTS.MOUSEENTER);\n\n    // Begin fuse if necessary.\n    if (data.fuseTimeout === 0 || !data.fuse) { return; }\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\n  /**\n   * Handle intersection cleared.\n   */\n  onIntersectionCleared: function (evt) {\n    var cursorEl = this.el;\n    var intersectedEl = evt.detail.el;\n\n    // Ignore the cursor.\n    if (cursorEl === intersectedEl) { return; }\n\n    // Ignore if the event didn't occur on the current intersection.\n    if (intersectedEl !== this.intersectedEl) { return; }\n\n    this.clearCurrentIntersection();\n  },\n\n  clearCurrentIntersection: function () {\n    var cursorEl = this.el;\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\n    // Unset intersected entity (after emitting the event).\n    this.intersection = null;\n    this.intersectedEl = null;\n\n    // Clear fuseTimeout.\n    clearTimeout(this.fuseTimeout);\n  },\n\n  /**\n   * Helper to emit on both the cursor and the intersected entity (if exists).\n   */\n  twoWayEmit: function (evtName) {\n    var el = this.el;\n    var intersectedEl = this.intersectedEl;\n    var intersection = this.intersection;\n    el.emit(evtName, {intersectedEl: intersectedEl, intersection: intersection});\n    if (!intersectedEl) { return; }\n    intersectedEl.emit(evtName, {cursorEl: el, intersection: intersection});\n  }\n});\n\n},{\"../core/component\":125,\"../utils/\":195}],80:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar bind = _dereq_('../utils/bind');\nvar checkControllerPresentAndSetup = _dereq_('../utils/tracked-controls').checkControllerPresentAndSetup;\nvar emitIfAxesChanged = _dereq_('../utils/tracked-controls').emitIfAxesChanged;\n\nvar DAYDREAM_CONTROLLER_MODEL_BASE_URL = 'https://cdn.aframe.io/controllers/google/';\nvar DAYDREAM_CONTROLLER_MODEL_OBJ_URL = DAYDREAM_CONTROLLER_MODEL_BASE_URL + 'vr_controller_daydream.obj';\nvar DAYDREAM_CONTROLLER_MODEL_OBJ_MTL = DAYDREAM_CONTROLLER_MODEL_BASE_URL + 'vr_controller_daydream.mtl';\n\nvar GAMEPAD_ID_PREFIX = 'Daydream Controller';\n\n/**\n * Daydream controls.\n */\nmodule.exports.Component = registerComponent('daydream-controls', {\n  schema: {\n    hand: {default: ''},  // Informs the degenerate arm model.\n    buttonColor: {type: 'color', default: '#000000'},\n    buttonTouchedColor: {type: 'color', default: '#777777'},\n    buttonHighlightColor: {type: 'color', default: '#FFFFFF'},\n    model: {default: true},\n    // Use -999 as sentinel value to auto-determine based on hand.\n    rotationOffset: {default: 0},\n    armModel: {default: true}\n  },\n\n  // buttonId\n  // 0 - trackpad\n  // 1 - menu (never dispatched on this layer)\n  // 2 - system (never dispatched on this layer)\n  mapping: {\n    axes: {trackpad: [0, 1]},\n    buttons: ['trackpad', 'menu', 'system']\n  },\n\n  bindMethods: function () {\n    this.onModelLoaded = bind(this.onModelLoaded, this);\n    this.onControllersUpdate = bind(this.onControllersUpdate, this);\n    this.checkIfControllerPresent = bind(this.checkIfControllerPresent, this);\n    this.removeControllersUpdateListener = bind(this.removeControllersUpdateListener, this);\n    this.onAxisMoved = bind(this.onAxisMoved, this);\n    this.onGamepadConnectionEvent = bind(this.onGamepadConnectionEvent, this);\n  },\n\n  init: function () {\n    var self = this;\n    this.animationActive = 'pointing';\n    this.onButtonChanged = bind(this.onButtonChanged, this);\n    this.onButtonDown = function (evt) { self.onButtonEvent(evt.detail.id, 'down'); };\n    this.onButtonUp = function (evt) { self.onButtonEvent(evt.detail.id, 'up'); };\n    this.onButtonTouchStart = function (evt) { self.onButtonEvent(evt.detail.id, 'touchstart'); };\n    this.onButtonTouchEnd = function (evt) { self.onButtonEvent(evt.detail.id, 'touchend'); };\n    this.onAxisMoved = bind(this.onAxisMoved, this);\n    this.controllerPresent = false;\n    this.everGotGamepadEvent = false;\n    this.lastControllerCheck = 0;\n    this.bindMethods();\n    this.checkControllerPresentAndSetup = checkControllerPresentAndSetup;  // To allow mock.\n    this.emitIfAxesChanged = emitIfAxesChanged;  // To allow mock.\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('model-loaded', this.onModelLoaded);\n    el.addEventListener('axismove', this.onAxisMoved);\n    this.controllerEventsActive = true;\n  },\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\n  checkIfControllerPresent: function () {\n    this.checkControllerPresentAndSetup(this, GAMEPAD_ID_PREFIX, {hand: this.data.hand});\n  },\n\n  onGamepadConnectionEvent: function (evt) {\n    this.everGotGamepadEvent = true;\n    // Due to an apparent bug in FF Nightly\n    // where only one gamepadconnected / disconnected event is fired,\n    // which makes it difficult to handle in individual controller entities,\n    // we no longer remove the controllersupdate listener as a result.\n    this.checkIfControllerPresent();\n  },\n\n  play: function () {\n    this.checkIfControllerPresent();\n    this.addControllersUpdateListener();\n    window.addEventListener('gamepadconnected', this.onGamepadConnectionEvent, false);\n    window.addEventListener('gamepaddisconnected', this.onGamepadConnectionEvent, false);\n  },\n\n  pause: function () {\n    this.removeEventListeners();\n    this.removeControllersUpdateListener();\n    window.removeEventListener('gamepadconnected', this.onGamepadConnectionEvent, false);\n    window.removeEventListener('gamepaddisconnected', this.onGamepadConnectionEvent, false);\n  },\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      rotationOffset: data.rotationOffset\n    });\n    if (!this.data.model) { return; }\n    this.el.setAttribute('obj-model', {\n      obj: DAYDREAM_CONTROLLER_MODEL_OBJ_URL,\n      mtl: DAYDREAM_CONTROLLER_MODEL_OBJ_MTL\n    });\n  },\n\n  addControllersUpdateListener: function () {\n    this.el.sceneEl.addEventListener('controllersupdated', this.onControllersUpdate, false);\n  },\n\n  removeControllersUpdateListener: function () {\n    this.el.sceneEl.removeEventListener('controllersupdated', this.onControllersUpdate, false);\n  },\n\n  onControllersUpdate: function () {\n    if (!this.everGotGamepadEvent) { this.checkIfControllerPresent(); }\n  },\n\n  onModelLoaded: function (evt) {\n    var controllerObject3D = evt.detail.model;\n    var buttonMeshes;\n    if (!this.data.model) { return; }\n    buttonMeshes = this.buttonMeshes = {};\n    buttonMeshes.menu = controllerObject3D.getObjectByName('AppButton_AppButton_Cylinder.004');\n    buttonMeshes.system = controllerObject3D.getObjectByName('HomeButton_HomeButton_Cylinder.005');\n    buttonMeshes.trackpad = controllerObject3D.getObjectByName('TouchPad_TouchPad_Cylinder.003');\n    // Offset pivot point.\n    controllerObject3D.position.set(0, 0, -0.04);\n  },\n\n  onAxisMoved: function (evt) {\n    this.emitIfAxesChanged(this, this.mapping.axes, evt);\n  },\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\n  onButtonEvent: function (id, evtName) {\n    var buttonName = this.mapping.buttons[id];\n    var i;\n    if (Array.isArray(buttonName)) {\n      for (i = 0; i < buttonName.length; i++) {\n        this.el.emit(buttonName[i] + evtName);\n      }\n    } else {\n      this.el.emit(buttonName + evtName);\n    }\n    this.updateModel(buttonName, evtName);\n  },\n\n  updateModel: function (buttonName, evtName) {\n    var i;\n    if (!this.data.model) { return; }\n    if (Array.isArray(buttonName)) {\n      for (i = 0; i < buttonName.length; i++) {\n        this.updateButtonModel(buttonName[i], evtName);\n      }\n    } else {\n      this.updateButtonModel(buttonName, evtName);\n    }\n  },\n\n  updateButtonModel: function (buttonName, state) {\n    var buttonMeshes = this.buttonMeshes;\n    if (!buttonMeshes || !buttonMeshes[buttonName]) { return; }\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      default:\n        color = this.data.buttonColor;\n    }\n    buttonMeshes[buttonName].material.color.set(color);\n  }\n});\n\n},{\"../core/component\":125,\"../utils/bind\":189,\"../utils/tracked-controls\":199}],81:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar bind = _dereq_('../utils/bind');\nvar checkControllerPresentAndSetup = _dereq_('../utils/tracked-controls').checkControllerPresentAndSetup;\nvar emitIfAxesChanged = _dereq_('../utils/tracked-controls').emitIfAxesChanged;\n\nvar GEARVR_CONTROLLER_MODEL_BASE_URL = 'https://cdn.aframe.io/controllers/samsung/';\nvar GEARVR_CONTROLLER_MODEL_OBJ_URL = GEARVR_CONTROLLER_MODEL_BASE_URL + 'gear_vr_controller.obj';\nvar GEARVR_CONTROLLER_MODEL_OBJ_MTL = GEARVR_CONTROLLER_MODEL_BASE_URL + 'gear_vr_controller.mtl';\n\nvar GAMEPAD_ID_PREFIX = 'Gear VR';\n\n/**\n * Vive Controls Component\n * Interfaces with vive controllers and maps Gamepad events to\n * common controller buttons: trackpad, trigger, grip, menu and system\n * It loads a controller model and highlights the pressed buttons\n */\nmodule.exports.Component = registerComponent('gearvr-controls', {\n  schema: {\n    hand: {default: ''}, // This informs the degenerate arm model.\n    buttonColor: {type: 'color', default: '#000000'},\n    buttonTouchedColor: {type: 'color', default: '#777777'},\n    buttonHighlightColor: {type: 'color', default: '#FFFFFF'},\n    model: {default: true},\n    rotationOffset: {default: 0},\n    armModel: {default: true}\n  },\n\n  // buttonId\n  // 0 - trackpad\n  // 1 - triggeri\n  mapping: {\n    axes: {trackpad: [0, 1]},\n    buttons: ['trackpad', 'trigger']\n  },\n\n  bindMethods: function () {\n    this.onModelLoaded = bind(this.onModelLoaded, this);\n    this.onControllersUpdate = bind(this.onControllersUpdate, this);\n    this.checkIfControllerPresent = bind(this.checkIfControllerPresent, this);\n    this.removeControllersUpdateListener = bind(this.removeControllersUpdateListener, this);\n    this.onAxisMoved = bind(this.onAxisMoved, this);\n  },\n\n  init: function () {\n    var self = this;\n    this.animationActive = 'pointing';\n    this.onButtonChanged = bind(this.onButtonChanged, this);\n    this.onButtonDown = function (evt) { self.onButtonEvent(evt.detail.id, 'down'); };\n    this.onButtonUp = function (evt) { self.onButtonEvent(evt.detail.id, 'up'); };\n    this.onButtonTouchStart = function (evt) { self.onButtonEvent(evt.detail.id, 'touchstart'); };\n    this.onButtonTouchEnd = function (evt) { self.onButtonEvent(evt.detail.id, 'touchend'); };\n    this.onAxisMoved = bind(this.onAxisMoved, this);\n    this.controllerPresent = false;\n    this.everGotGamepadEvent = false;\n    this.lastControllerCheck = 0;\n    this.bindMethods();\n    this.checkControllerPresentAndSetup = checkControllerPresentAndSetup;  // To allow mock.\n    this.emitIfAxesChanged = emitIfAxesChanged;  // To allow mock.\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('model-loaded', this.onModelLoaded);\n    el.addEventListener('axismove', this.onAxisMoved);\n    this.controllerEventsActive = true;\n    this.addControllersUpdateListener();\n  },\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\n  checkIfControllerPresent: function () {\n    this.checkControllerPresentAndSetup(this, GAMEPAD_ID_PREFIX,\n                                        this.data.hand ? {hand: this.data.hand} : {});\n  },\n\n  play: function () {\n    this.checkIfControllerPresent();\n    this.addControllersUpdateListener();\n  },\n\n  pause: function () {\n    this.removeEventListeners();\n    this.removeControllersUpdateListener();\n  },\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      rotationOffset: data.rotationOffset\n    });\n    if (!this.data.model) { return; }\n    this.el.setAttribute('obj-model', {\n      obj: GEARVR_CONTROLLER_MODEL_OBJ_URL,\n      mtl: GEARVR_CONTROLLER_MODEL_OBJ_MTL\n    });\n  },\n\n  addControllersUpdateListener: function () {\n    this.el.sceneEl.addEventListener('controllersupdated', this.onControllersUpdate, false);\n  },\n\n  removeControllersUpdateListener: function () {\n    this.el.sceneEl.removeEventListener('controllersupdated', this.onControllersUpdate, false);\n  },\n\n  onControllersUpdate: function () {\n    this.checkIfControllerPresent();\n  },\n\n  // No need for onButtonChanged, since Gear VR controller has no analog buttons.\n\n  onModelLoaded: function (evt) {\n    var controllerObject3D = evt.detail.model;\n    var buttonMeshes;\n    if (!this.data.model) { return; }\n    buttonMeshes = this.buttonMeshes = {};\n    buttonMeshes.trigger = controllerObject3D.getObjectByName('Trigger');\n    buttonMeshes.trackpad = controllerObject3D.getObjectByName('Touchpad');\n  },\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\n  onButtonEvent: function (id, evtName) {\n    var buttonName = this.mapping.buttons[id];\n    var i;\n    if (Array.isArray(buttonName)) {\n      for (i = 0; i < buttonName.length; i++) {\n        this.el.emit(buttonName[i] + evtName);\n      }\n    } else {\n      this.el.emit(buttonName + evtName);\n    }\n    this.updateModel(buttonName, evtName);\n  },\n\n  onAxisMoved: function (evt) {\n    this.emitIfAxesChanged(this, this.mapping.axes, evt);\n  },\n\n  updateModel: function (buttonName, evtName) {\n    var i;\n    if (!this.data.model) { return; }\n    if (Array.isArray(buttonName)) {\n      for (i = 0; i < buttonName.length; i++) {\n        this.updateButtonModel(buttonName[i], evtName);\n      }\n    } else {\n      this.updateButtonModel(buttonName, evtName);\n    }\n  },\n\n  updateButtonModel: function (buttonName, state) {\n    var buttonMeshes = this.buttonMeshes;\n    if (!buttonMeshes || !buttonMeshes[buttonName]) { return; }\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      default:\n        color = this.data.buttonColor;\n    }\n    buttonMeshes[buttonName].material.color.set(color);\n  }\n});\n\n},{\"../core/component\":125,\"../utils/bind\":189,\"../utils/tracked-controls\":199}],82:[function(_dereq_,module,exports){\nvar debug = _dereq_('../utils/debug');\nvar geometries = _dereq_('../core/geometry').geometries;\nvar geometryNames = _dereq_('../core/geometry').geometryNames;\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar THREE = _dereq_('../lib/three');\n\nvar dummyGeometry = new THREE.Geometry();\nvar warn = debug('components:geometry:warn');\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: {default: true},\n    mergeTo: {type: 'selector'},\n    primitive: {default: 'box', oneOf: geometryNames},\n    skipCache: {default: false}\n  },\n\n  init: function () {\n    this.geometry = null;\n  },\n\n  /**\n   * Talk to geometry system to get or create geometry.\n   */\n  update: function (previousData) {\n    var data = this.data;\n    var mesh = this.el.getOrCreateObject3D('mesh', THREE.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 = mesh.geometry = system.getOrCreateGeometry(data);\n    if (data.mergeTo) {\n      this.mergeTo(data.mergeTo);\n    }\n  },\n\n  /**\n   * Merge geometry to another entity's geometry.\n   * Remove the entity from the scene. Not a reversible operation.\n   *\n   * @param {Element} toEl - Entity where the geometry will be merged to.\n   */\n  mergeTo: function (toEl) {\n    var el = this.el;\n    var mesh = el.getObject3D('mesh');\n    var toMesh;\n\n    if (!toEl || !toEl.isEntity) {\n      warn('There is not a valid entity to merge the geometry to');\n      return;\n    }\n\n    if (toEl === el) {\n      warn('Source and target geometries cannot be the same for merge');\n      return;\n    }\n\n    // Create mesh if entity does not have one.\n    toMesh = toEl.getObject3D('mesh');\n    if (!toMesh) {\n      toMesh = toEl.getOrCreateObject3D('mesh', THREE.Mesh);\n      toEl.setAttribute('material', el.getAttribute('material'));\n      return;\n    }\n\n    if (toMesh.geometry instanceof THREE.Geometry === false ||\n        mesh.geometry instanceof THREE.Geometry === false) {\n      warn('Geometry merge is only available for `THREE.Geometry` types. ' +\n           'Check that both of the merging geometry and the target geometry have `buffer` ' +\n           'set to false');\n      return;\n    }\n\n    if (this.data.skipCache === false) {\n      warn('Cached geometries are not allowed to merge. Set `skipCache` to true');\n      return;\n    }\n\n    mesh.parent.updateMatrixWorld();\n    toMesh.geometry.merge(mesh.geometry, mesh.matrixWorld);\n    el.emit('geometry-merged', {mergeTarget: toEl});\n    el.parentNode.removeChild(el);\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  /**\n   * Update geometry component schema based on geometry type.\n   *\n   * @param {object} data - New data passed by Component.\n   */\n  updateSchema: function (data) {\n    var newGeometryType = data.primitive;\n    var currentGeometryType = this.data && this.data.primitive;\n    var schema = geometries[newGeometryType] && geometries[newGeometryType].schema;\n\n    // Geometry has no schema.\n    if (!schema) { throw new Error('Unknown geometry schema `' + newGeometryType + '`'); }\n    // Nothing has changed.\n    if (currentGeometryType && currentGeometryType === newGeometryType) { return; }\n\n    this.extendSchema(schema);\n  }\n});\n\n},{\"../core/component\":125,\"../core/geometry\":126,\"../lib/three\":173,\"../utils/debug\":191}],83:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar THREE = _dereq_('../lib/three');\nvar utils = _dereq_('../utils/');\nvar warn = utils.debug('components:gltf-model:warn');\n\n/**\n * glTF model loader.\n */\nmodule.exports.Component = registerComponent('gltf-model', {\n  schema: {type: 'model'},\n\n  init: function () {\n    this.model = null;\n    this.loader = new THREE.GLTFLoader();\n  },\n\n  update: function () {\n    var self = this;\n    var el = this.el;\n    var src = this.data;\n\n    if (!src) { return; }\n\n    this.remove();\n\n    this.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', {format: 'gltf', model: self.model});\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', {format: 'gltf', src: src});\n    });\n  },\n\n  remove: function () {\n    if (!this.model) { return; }\n    this.el.removeObject3D('mesh');\n  }\n});\n\n},{\"../core/component\":125,\"../lib/three\":173,\"../utils/\":195}],84:[function(_dereq_,module,exports){\n/* global THREE */\nvar registerComponent = _dereq_('../core/component').registerComponent;\n\n// Found at https://github.com/aframevr/assets.\nvar MODEL_URLS = {\n  left: 'https://cdn.aframe.io/controllers/oculus-hands/v2/leftHand.json',\n  right: 'https://cdn.aframe.io/controllers/oculus-hands/v2/rightHand.json'\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';\nEVENTS[ANIMATIONS.thumb] = 'thumb';\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: {default: 'left'},\n\n  init: function () {\n    var self = this;\n    var el = this.el;\n    // Current pose.\n    this.gesture = ANIMATIONS.open;\n    // Active buttons populated by events provided by the attached controls.\n    this.pressedButtons = {};\n    this.touchedButtons = {};\n    this.loader = new THREE.ObjectLoader();\n    this.loader.setCrossOrigin('anonymous');\n\n    this.onGripDown = function () { self.handleButton('grip', 'down'); };\n    this.onGripUp = function () { self.handleButton('grip', 'up'); };\n    this.onTrackpadDown = function () { self.handleButton('trackpad', 'down'); };\n    this.onTrackpadUp = function () { self.handleButton('trackpad', 'up'); };\n    this.onTrackpadTouchStart = function () { self.handleButton('trackpad', 'touchstart'); };\n    this.onTrackpadTouchEnd = function () { self.handleButton('trackpad', 'touchend'); };\n    this.onTriggerDown = function () { self.handleButton('trigger', 'down'); };\n    this.onTriggerUp = function () { self.handleButton('trigger', 'up'); };\n    this.onTriggerTouchStart = function () { self.handleButton('trigger', 'touchstart'); };\n    this.onTriggerTouchEnd = function () { self.handleButton('trigger', 'touchend'); };\n    this.onGripTouchStart = function () { self.handleButton('grip', 'touchstart'); };\n    this.onGripTouchEnd = function () { self.handleButton('grip', 'touchend'); };\n    this.onThumbstickDown = function () { self.handleButton('thumbstick', 'down'); };\n    this.onThumbstickUp = function () { self.handleButton('thumbstick', 'up'); };\n    this.onAorXTouchStart = function () { self.handleButton('AorX', 'touchstart'); };\n    this.onAorXTouchEnd = function () { self.handleButton('AorX', 'touchend'); };\n    this.onBorYTouchStart = function () { self.handleButton('BorY', 'touchstart'); };\n    this.onBorYTouchEnd = function () { self.handleButton('BorY', 'touchend'); };\n    this.onSurfaceTouchStart = function () { self.handleButton('surface', 'touchstart'); };\n    this.onSurfaceTouchEnd = function () { self.handleButton('surface', 'touchend'); };\n    this.onControllerConnected = function () { self.setModelVisibility(true); };\n    this.onControllerDisconnected = function () { self.setModelVisibility(false); };\n\n    el.addEventListener('controllerconnected', this.onControllerConnected);\n    el.addEventListener('controllerdisconnected', this.onControllerDisconnected);\n  },\n\n  play: function () {\n    this.addEventListeners();\n  },\n\n  pause: function () {\n    this.removeEventListeners();\n  },\n\n  tick: function (time, delta) {\n    var mesh = this.el.getObject3D('mesh');\n\n    if (!mesh || !mesh.mixer) { return; }\n\n    mesh.mixer.update(delta / 1000);\n  },\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\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  /**\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;\n\n    // Get common configuration to abstract different vendor controls.\n    controlConfiguration = {\n      hand: hand,\n      model: false,\n      rotationOffset: hand === 'left' ? 90 : -90\n    };\n\n    // Set model.\n    if (hand !== previousHand) {\n      this.loader.load(MODEL_URLS[hand], function (scene) {\n        var mesh = scene.getObjectByName('Hand');\n        mesh.material.skinning = true;\n        mesh.mixer = new THREE.AnimationMixer(mesh);\n        el.setObject3D('mesh', mesh);\n        mesh.position.set(0, 0, 0);\n        mesh.rotation.set(0, 0, 0);\n        // hidden by default\n        mesh.visible = false;\n        el.setAttribute('vive-controls', controlConfiguration);\n        el.setAttribute('oculus-touch-controls', controlConfiguration);\n        el.setAttribute('windows-motion-controls', controlConfiguration);\n      });\n    }\n  },\n\n  remove: function () {\n    this.el.removeObject3D('mesh');\n  },\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]) { return; }\n      this.touchedButtons[button] = isTouched;\n    } else {\n      // Update button object.\n      if (isPressed === this.pressedButtons[button]) { return; }\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) { return; }\n\n    // Animate gesture.\n    this.animateGesture(this.gesture, lastGesture);\n\n    // Emit events.\n    this.emitGestureEvents(this.gesture, lastGesture);\n  },\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 (isGripActive) {\n      if (isVive) {\n        gesture = ANIMATIONS.fist;\n      } else\n        if (isSurfaceActive || isABXYActive || isTrackpadActive) {\n          gesture = isTriggerActive ? ANIMATIONS.fist : ANIMATIONS.point;\n        } else {\n          gesture = isTriggerActive ? ANIMATIONS.thumbUp : ANIMATIONS.pointThumb;\n        }\n    } else {\n      if (isTriggerActive) {\n        gesture = !isVive ? ANIMATIONS.hold : ANIMATIONS.fist;\n      } else if (isVive && isTrackpadActive) {\n        gesture = ANIMATIONS.point;\n      }\n    }\n\n    return gesture;\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    // If no gesture, then reverse the current gesture back to open pose.\n    this.playAnimation(lastGesture, lastGesture, true);\n  },\n\n  /**\n   * Emit `hand-controls`-specific events.\n   */\n  emitGestureEvents: function (gesture, lastGesture) {\n    var el = this.el;\n    var eventName;\n\n    if (lastGesture === gesture) { return; }\n\n    // Emit event for lastGesture not inactive.\n    eventName = getGestureEventName(lastGesture, false);\n    if (eventName) { el.emit(eventName); }\n\n    // Emit event for current gesture now active.\n    eventName = getGestureEventName(gesture, true);\n    if (eventName) { 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 fromAction;\n    var mesh = this.el.getObject3D('mesh');\n    var toAction;\n\n    if (!mesh) { return; }\n\n    // Grab clip action.\n    toAction = mesh.mixer.clipAction(gesture);\n    toAction.clampWhenFinished = true;\n    toAction.loop = THREE.PingPong;\n    toAction.repetitions = 0;\n    toAction.timeScale = reverse ? -1 : 1;\n    toAction.weight = 1;\n\n    // No gesture to gesture or gesture to no gesture.\n    if (!lastGesture || gesture === lastGesture) {\n      // Stop all current animations.\n      mesh.mixer.stopAllAction();\n\n      // Play animation.\n      toAction.play();\n      return;\n    }\n\n    // Animate or crossfade from gesture to gesture.\n    fromAction = mesh.mixer.clipAction(lastGesture);\n    mesh.mixer.stopAllAction();\n    fromAction.weight = 0.15;\n    fromAction.play();\n    toAction.play();\n    fromAction.crossFadeTo(toAction, 0.15, true);\n  },\n\n  setModelVisibility: function (visible) {\n    var model = this.el.getObject3D('mesh');\n    if (!model) { return; }\n    model.visible = visible;\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\n  if (!gesture) { return; }\n\n  eventName = EVENTS[gesture];\n  if (eventName === 'grip') {\n    return eventName + (active ? 'close' : 'open');\n  }\n  if (eventName === 'point' || eventName === 'thumb') {\n    return eventName + (active ? 'up' : 'down');\n  }\n  if (eventName === 'pointing' || eventName === 'pistol') {\n    return eventName + (active ? 'start' : 'end');\n  }\n  return;\n}\n\nfunction isViveController (trackedControls) {\n  var controllerId = trackedControls && trackedControls.controller &&\n                     trackedControls.controller.id;\n  return controllerId && controllerId.indexOf('OpenVR ') === 0;\n}\n\n},{\"../core/component\":125}],85:[function(_dereq_,module,exports){\n_dereq_('./camera');\n_dereq_('./collada-model');\n_dereq_('./cursor');\n_dereq_('./daydream-controls');\n_dereq_('./gearvr-controls');\n_dereq_('./geometry');\n_dereq_('./gltf-model');\n_dereq_('./hand-controls');\n_dereq_('./laser-controls');\n_dereq_('./light');\n_dereq_('./line');\n_dereq_('./link');\n_dereq_('./look-controls');\n_dereq_('./material');\n_dereq_('./obj-model');\n_dereq_('./oculus-touch-controls');\n_dereq_('./position');\n_dereq_('./raycaster');\n_dereq_('./rotation');\n_dereq_('./scale');\n_dereq_('./shadow');\n_dereq_('./sound');\n_dereq_('./text');\n_dereq_('./tracked-controls');\n_dereq_('./visible');\n_dereq_('./vive-controls');\n_dereq_('./wasd-controls');\n_dereq_('./windows-motion-controls');\n\n_dereq_('./scene/debug');\n_dereq_('./scene/embedded');\n_dereq_('./scene/inspector');\n_dereq_('./scene/fog');\n_dereq_('./scene/keyboard-shortcuts');\n_dereq_('./scene/pool');\n_dereq_('./scene/screenshot');\n_dereq_('./scene/stats');\n_dereq_('./scene/vr-mode-ui');\n\n},{\"./camera\":77,\"./collada-model\":78,\"./cursor\":79,\"./daydream-controls\":80,\"./gearvr-controls\":81,\"./geometry\":82,\"./gltf-model\":83,\"./hand-controls\":84,\"./laser-controls\":86,\"./light\":87,\"./line\":88,\"./link\":89,\"./look-controls\":90,\"./material\":91,\"./obj-model\":92,\"./oculus-touch-controls\":93,\"./position\":94,\"./raycaster\":95,\"./rotation\":96,\"./scale\":97,\"./scene/debug\":98,\"./scene/embedded\":99,\"./scene/fog\":100,\"./scene/inspector\":101,\"./scene/keyboard-shortcuts\":102,\"./scene/pool\":103,\"./scene/screenshot\":104,\"./scene/stats\":105,\"./scene/vr-mode-ui\":106,\"./shadow\":107,\"./sound\":108,\"./text\":109,\"./tracked-controls\":110,\"./visible\":111,\"./vive-controls\":112,\"./wasd-controls\":113,\"./windows-motion-controls\":114}],86:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar utils = _dereq_('../utils/');\n\nregisterComponent('laser-controls', {\n  schema: {\n    hand: {default: 'right'}\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\n    // Set all controller models.\n    el.setAttribute('daydream-controls', {hand: data.hand});\n    el.setAttribute('gearvr-controls', {hand: data.hand});\n    el.setAttribute('oculus-touch-controls', {hand: data.hand});\n    el.setAttribute('vive-controls', {hand: data.hand});\n    el.setAttribute('windows-motion-controls', {hand: data.hand});\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\n    function createRay (evt) {\n      var controllerConfig = config[evt.detail.name];\n\n      if (!controllerConfig) { return; }\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\n      el.setAttribute('cursor', utils.extend({\n        fuse: false\n      }, controllerConfig.cursor));\n    }\n\n    function hideRay () {\n      el.setAttribute('raycaster', 'showLine', false);\n    }\n  },\n\n  config: {\n    'daydream-controls': {\n      cursor: {downEvents: ['trackpaddown'], upEvents: ['trackpadup']}\n    },\n\n    'gearvr-controls': {\n      cursor: {downEvents: ['trackpaddown'], upEvents: ['trackpadup']},\n      raycaster: {origin: {x: 0, y: 0.0005, z: 0}}\n    },\n\n    'oculus-touch-controls': {\n      cursor: {downEvents: ['triggerdown'], upEvents: ['triggerup']},\n      raycaster: {origin: {x: 0.001, y: 0, z: 0.065}, direction: {x: 0, y: -0.8, z: -1}}\n    },\n\n    'vive-controls': {\n      cursor: {downEvents: ['triggerdown'], upEvents: ['triggerup']}\n    },\n\n    'windows-motion-controls': {\n      cursor: {downEvents: ['triggerdown'], upEvents: ['triggerup']},\n      raycaster: {showLine: false}\n    }\n  }\n});\n\n},{\"../core/component\":125,\"../utils/\":195}],87:[function(_dereq_,module,exports){\nvar bind = _dereq_('../utils/bind');\nvar diff = _dereq_('../utils').diff;\nvar debug = _dereq_('../utils/debug');\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar THREE = _dereq_('../lib/three');\n\nvar degToRad = THREE.Math.degToRad;\nvar warn = debug('components:light:warn');\n\n/**\n * Light component.\n */\nmodule.exports.Component = registerComponent('light', {\n  schema: {\n    angle: {default: 60, if: {type: ['spot']}},\n    color: {type: 'color'},\n    groundColor: {type: 'color', if: {type: ['hemisphere']}},\n    decay: {default: 1, if: {type: ['point', 'spot']}},\n    distance: {default: 0.0, min: 0, if: {type: ['point', 'spot']}},\n    intensity: {default: 1.0, min: 0, if: {type: ['ambient', 'directional', 'hemisphere', 'point', 'spot']}},\n    penumbra: {default: 0, min: 0, max: 1, if: {type: ['spot']}},\n    type: {default: 'directional', oneOf: ['ambient', 'directional', 'hemisphere', 'point', 'spot']},\n    target: {type: 'selector', if: {type: ['spot', 'directional']}},\n\n    // Shadows.\n    castShadow: {default: false, if: {type: ['point', 'spot', 'directional']}},\n    shadowBias: {default: 0, if: {castShadow: true}},\n    shadowCameraFar: {default: 500, if: {castShadow: true}},\n    shadowCameraFov: {default: 90, if: {castShadow: true}},\n    shadowCameraNear: {default: 0.5, if: {castShadow: true}},\n    shadowCameraTop: {default: 5, if: {castShadow: true}},\n    shadowCameraRight: {default: 5, if: {castShadow: true}},\n    shadowCameraBottom: {default: -5, if: {castShadow: true}},\n    shadowCameraLeft: {default: -5, if: {castShadow: true}},\n    shadowCameraVisible: {default: false, if: {castShadow: true}},\n    shadowMapHeight: {default: 512, if: {castShadow: true}},\n    shadowMapWidth: {default: 512, if: {castShadow: true}}\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  /**\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\n        switch (key) {\n          case 'color': {\n            light.color.set(value);\n            break;\n          }\n\n          case 'groundColor': {\n            light.groundColor.set(value);\n            break;\n          }\n\n          case 'angle': {\n            light.angle = degToRad(value);\n            break;\n          }\n\n          case 'target': {\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', bind(self.onSetTarget, self, value, light));\n              }\n            }\n            break;\n          }\n\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            if (!shadowsLoaded) {\n              self.updateShadow();\n              shadowsLoaded = true;\n            }\n            break;\n\n          default: {\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\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\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    }\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\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\n    if (!data.castShadow) { return light; }\n\n    // Shadow appearance.\n    light.shadow.bias = data.shadowBias;\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\n    if (cameraHelper) { 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).getHex();\n    var decay = data.decay;\n    var distance = data.distance;\n    var groundColor = new THREE.Color(data.groundColor).getHex();\n    var intensity = data.intensity;\n    var type = data.type;\n    var target = data.target;\n    var light = null;\n\n    switch (type.toLowerCase()) {\n      case 'ambient': {\n        return new THREE.AmbientLight(color, intensity);\n      }\n\n      case 'directional': {\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', bind(this.onSetTarget, this, target, light));\n          }\n        }\n        return light;\n      }\n\n      case 'hemisphere': {\n        return new THREE.HemisphereLight(color, groundColor, intensity);\n      }\n\n      case 'point': {\n        return new THREE.PointLight(color, intensity, distance, decay);\n      }\n\n      case 'spot': {\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', bind(this.onSetTarget, this, target, light));\n          }\n        }\n        return light;\n      }\n\n      default: {\n        warn('%s is not a valid light type. ' +\n           'Choose from ambient, directional, hemisphere, point, spot.', type);\n      }\n    }\n  },\n\n  onSetTarget: function (targetEl, light) {\n    light.target = targetEl.object3D;\n  },\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},{\"../core/component\":125,\"../lib/three\":173,\"../utils\":195,\"../utils/bind\":189,\"../utils/debug\":191}],88:[function(_dereq_,module,exports){\n/* global THREE */\nvar registerComponent = _dereq_('../core/component').registerComponent;\n\nmodule.exports.Component = registerComponent('line', {\n  schema: {\n    start: {type: 'vec3', default: {x: 0, y: 0, z: 0}},\n    end: {type: 'vec3', default: {x: 0, y: 0, z: 0}},\n    color: {type: 'color', default: '#74BEC1'},\n    opacity: {type: 'number', default: 1},\n    visible: {default: true}\n  },\n\n  multiple: true,\n\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.addAttribute('position', new THREE.BufferAttribute(new Float32Array(2 * 3), 3));\n\n    this.line = new THREE.Line(geometry, material);\n    this.el.setObject3D(this.attrName, this.line);\n  },\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\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\n    if (geoNeedsUpdate) {\n      geometry.attributes.position.needsUpdate = true;\n      geometry.computeBoundingSphere();\n    }\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\n  remove: function () {\n    this.el.removeObject3D('line', this.line);\n  }\n});\n\nfunction isEqualVec3 (a, b) {\n  if (!a || !b) { return false; }\n  return (a.x === b.x && a.y === b.y && a.z === b.z);\n}\n\n},{\"../core/component\":125}],89:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar registerShader = _dereq_('../core/shader').registerShader;\nvar THREE = _dereq_('../lib/three');\n\n/**\n * Link component. Connect experiences and traverse between them in VR\n *\n * @member {object} hiddenEls - Stores the hidden elements during peek mode.\n */\nmodule.exports.Component = registerComponent('link', {\n  schema: {\n    color: {default: 'white', type: 'color'},\n    highlighted: {default: false},\n    highlightedColor: {default: '#24CAFF', type: 'color'},\n    href: {default: ''},\n    image: {type: 'asset'},\n    on: {default: 'click'},\n    peekMode: {default: false},\n    title: {default: ''},\n    visualAspectEnabled: {default: true}\n  },\n\n  init: function () {\n    this.navigate = this.navigate.bind(this);\n    this.previousQuaternion = undefined;\n    // Store hidden elements during peek mode so we can show them again later.\n    this.hiddenEls = [];\n    this.initVisualAspect();\n  },\n\n  update: function (oldData) {\n    var data = this.data;\n    var el = this.el;\n    var strokeColor = data.highlighted ? data.highlightedColor : data.color;\n    el.setAttribute('material', 'strokeColor', strokeColor);\n    if (data.on !== oldData.on) { this.updateEventListener(); }\n    if (data.visualAspectEnabled && oldData.peekMode !== undefined && data.peekMode !== oldData.peekMode) {\n      this.updatePeekMode();\n    }\n    if (!data.image || oldData.image === data.image) { return; }\n    el.setAttribute('material', 'pano',\n                    typeof data.image === 'string' ? data.image : data.image.src);\n  },\n\n  /*\n   * Hide / Show all elements and Hide / Show the full 360 preview\n   * 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\n  play: function () {\n    this.updateEventListener();\n  },\n\n  pause: function () {\n    this.removeEventListener();\n  },\n\n  updateEventListener: function () {\n    var el = this.el;\n    if (!el.isPlaying) { return; }\n    this.removeEventListener();\n    el.addEventListener(this.data.on, this.navigate);\n  },\n\n  removeEventListener: function () {\n    var on = this.data.on;\n    if (!on) { return; }\n    this.el.removeEventListener(on, this.navigate);\n  },\n\n  initVisualAspect: function () {\n    var el = this.el;\n    var textEl;\n    var sphereEl;\n    var semiSphereEl;\n    if (!this.data.visualAspectEnabled) { return; }\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', {primitive: 'circle', radius: 1.0, segments: 64});\n    el.setAttribute('material', {\n      shader: 'portal',\n      pano: this.data.image,\n      side: 'double'\n    });\n    // Set text that displays the link title / url\n    textEl.setAttribute('text', {\n      color: 'white',\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 the sphere that is rendered when the camera is close\n    // to the portal to allow the user 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 the sphere that is rendered when the camera is close\n    // to the portal to allow the user 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  },\n\n  navigate: function () {\n    window.location = this.data.href;\n  },\n\n  /**\n   * The tick handles:\n   * 1. Swap the plane the represents the portal with a sphere with a hole when the camera is close\n   * so the user can peek inside the portal. The sphere is rendered on the oposite side of the portal\n   * from where the user enters.\n   * 2. It places the url / title above or inside the portal depending on the distance to the camera.\n   * 3. The portal faces the camera when it's far away from the user.\n   *\n   */\n  tick: (function () {\n    var elWorldPosition = new THREE.Vector3();\n    var cameraWorldPosition = new THREE.Vector3();\n    var scale = new THREE.Vector3();\n    var quaternion = new THREE.Quaternion();\n    return function () {\n      if (!this.data.visualAspectEnabled) { return; }\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      // Update matrices\n      object3D.updateMatrixWorld();\n      camera.parent.updateMatrixWorld();\n      camera.updateMatrixWorld();\n\n      object3D.matrix.decompose(elWorldPosition, quaternion, scale);\n      elWorldPosition.setFromMatrixPosition(object3D.matrixWorld);\n      cameraWorldPosition.setFromMatrixPosition(camera.matrixWorld);\n      distance = elWorldPosition.distanceTo(cameraWorldPosition);\n      // Store original orientation to be restored when the portal\n      // stops facing the camera\n      this.previousQuaternion = this.previousQuaternion || quaternion.clone();\n\n      // If the portal is far away from the user the portal faces the camera\n      if (distance > 20) {\n        object3D.lookAt(cameraWorldPosition);\n      } else { // When the portal is close to the user (camera)\n        cameraPortalOrientation = this.calculateCameraPortalOrientation();\n        // If the user gets very close to the portal it is replaced\n        // by a holed sphere where she can peek inside\n        if (distance < 0.5) {\n          // Configure text size and sphere orientation depending\n          // the side the user approaches the portal\n          if (this.semiSphereEl.getAttribute('visible') === true) { return; }\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 wich 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\n  hideAll: function () {\n    var el = this.el;\n    var hiddenEls = this.hiddenEls;\n    var self = this;\n    if (hiddenEls.length > 0) { return; }\n    el.sceneEl.object3D.traverse(function (object) {\n      if (object && object.el && object.el.hasAttribute('link-controls')) { return; }\n      if (!object.el || object === el.sceneEl.object3D || object.el === el || object.el === self.sphereEl ||\n          object.el === el.sceneEl.cameraEl || object.el.getAttribute('visible') === false || object.el === self.textEl || object.el === self.semiSphereEl) { return; }\n      object.el.setAttribute('visible', false);\n      hiddenEls.push(object.el);\n    });\n  },\n\n  showAll: function () {\n    this.hiddenEls.forEach(function (el) { el.setAttribute('visible', true); });\n    this.hiddenEls = [];\n  },\n\n  /**\n   *  Calculate if the camera / user faces the front or back face of the portal\n   *  @returns {number} > 0 if the camera faces the front of the portal < 0 if it faces the back.\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\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      // The side where the camera (user) approaches the portal\n      // is given by the sign of the dot product of the portal normal\n      // and the portal to camera vectors.\n      return Math.sign(portalNormal.dot(cameraPosition));\n    };\n  })(),\n\n  remove: function () {\n    this.removeEventListener();\n  }\n});\n\n/* eslint-disable */\nregisterShader('portal', {\n  schema: {\n    pano: {type: 'map', is: 'uniform'},\n    borderEnabled: {default: 1.0, type: 'int', is: 'uniform'},\n    strokeColor: {default: 'white', type: 'color', is: 'uniform'}\n  },\n\n  vertexShader: [\n    'vec3 portalPosition;',\n    'varying vec3 vWorldPosition;',\n    'varying float vDistanceToCenter;',\n    'varying float vDistance;',\n    'void main() {',\n      'vDistanceToCenter = clamp(length(position - vec3(0.0, 0.0, 0.0)), 0.0, 1.0);',\n      'portalPosition = (modelMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;',\n      'vDistance = length(portalPosition - cameraPosition);',\n      'vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;',\n      'gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);',\n    '}'\n  ].join('\\n'),\n\n  fragmentShader: [\n    '#define RECIPROCAL_PI2 0.15915494',\n    'uniform sampler2D pano;',\n    'uniform vec3 strokeColor;',\n    'uniform float borderEnabled;',\n    'varying float vDistanceToCenter;',\n    'varying float vDistance;',\n    'varying vec3 vWorldPosition;',\n    'void main() {',\n      'vec3 direction = normalize(vWorldPosition - cameraPosition);',\n      'vec2 sampleUV;',\n      'float borderThickness = clamp(exp(-vDistance / 50.0), 0.6, 0.95);',\n      'sampleUV.y = saturate(direction.y * 0.5  + 0.5);',\n      'sampleUV.x = atan(direction.z, -direction.x) * -RECIPROCAL_PI2 + 0.5;',\n      'if (vDistanceToCenter > borderThickness && borderEnabled == 1.0) {',\n        'gl_FragColor = vec4(strokeColor, 1.0);',\n      '} else {',\n        'gl_FragColor = mix(texture2D(pano, sampleUV), vec4(0.93, 0.17, 0.36, 1.0), clamp(pow((vDistance / 15.0), 2.0), 0.0, 1.0));',\n      '}',\n    '}'\n  ].join('\\n')\n});\n/* eslint-enable */\n\n},{\"../core/component\":125,\"../core/shader\":134,\"../lib/three\":173}],90:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar THREE = _dereq_('../lib/three');\nvar DEFAULT_CAMERA_HEIGHT = _dereq_('../constants').DEFAULT_CAMERA_HEIGHT;\nvar bind = _dereq_('../utils/bind');\n\n// To avoid recalculation at every mouse movement tick\nvar GRABBING_CLASS = 'a-grabbing';\nvar PI_2 = Math.PI / 2;\nvar radToDeg = THREE.Math.radToDeg;\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\n  schema: {\n    enabled: {default: true},\n    touchEnabled: {default: true},\n    hmdEnabled: {default: true},\n    reverseMouseDrag: {default: false},\n    standing: {default: true}\n  },\n\n  init: function () {\n    var sceneEl = this.el.sceneEl;\n\n    this.previousHMDPosition = new THREE.Vector3();\n    this.hmdQuaternion = new THREE.Quaternion();\n    this.hmdEuler = new THREE.Euler();\n    this.position = new THREE.Vector3();\n    this.rotation = {};\n\n    this.setupMouseControls();\n    this.setupHMDControls();\n    this.bindMethods();\n\n    // Reset previous HMD position when we exit VR.\n    sceneEl.addEventListener('exit-vr', this.onExitVR);\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 pitch and yaw if disabling HMD.\n    if (oldData && !data.hmdEnabled && !oldData.hmdEnabled) {\n      this.pitchObject.rotation.set(0, 0, 0);\n      this.yawObject.rotation.set(0, 0, 0);\n    }\n  },\n\n  tick: function (t) {\n    var data = this.data;\n    if (!data.enabled) { return; }\n    this.controls.standing = data.standing;\n    this.controls.userHeight = this.getUserHeight();\n    this.controls.update();\n    this.updateOrientation();\n    this.updatePosition();\n  },\n\n  /**\n   * Return user height to use for standing poses, where a device doesn't provide an offset.\n   */\n  getUserHeight: function () {\n    var el = this.el;\n    var userHeight = el.hasAttribute('camera') && el.getAttribute('camera').userHeight || DEFAULT_CAMERA_HEIGHT;\n    return userHeight;\n  },\n\n  play: function () {\n    this.addEventListeners();\n  },\n\n  pause: function () {\n    this.removeEventListeners();\n  },\n\n  remove: function () {\n    this.removeEventListeners();\n  },\n\n  bindMethods: function () {\n    this.onMouseDown = bind(this.onMouseDown, this);\n    this.onMouseMove = bind(this.onMouseMove, this);\n    this.onMouseUp = bind(this.onMouseUp, this);\n    this.onTouchStart = bind(this.onTouchStart, this);\n    this.onTouchMove = bind(this.onTouchMove, this);\n    this.onTouchEnd = bind(this.onTouchEnd, this);\n    this.onExitVR = bind(this.onExitVR, this);\n  },\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  /**\n   * Set up VR controls that will copy data to the dolly.\n   */\n  setupHMDControls: function () {\n    this.dolly = new THREE.Object3D();\n    this.euler = new THREE.Euler();\n    this.controls = new THREE.VRControls(this.dolly);\n    this.controls.userHeight = 0.0;\n  },\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', bind(this.addEventListeners, 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    window.addEventListener('touchmove', this.onTouchMove);\n    window.addEventListener('touchend', this.onTouchEnd);\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\n    if (!canvasEl) { return; }\n\n    // Mouse events.\n    canvasEl.removeEventListener('mousedown', this.onMouseDown);\n    canvasEl.removeEventListener('mousemove', this.onMouseMove);\n    canvasEl.removeEventListener('mouseup', this.onMouseUp);\n    canvasEl.removeEventListener('mouseout', this.onMouseUp);\n\n    // Touch events.\n    canvasEl.removeEventListener('touchstart', this.onTouchStart);\n    canvasEl.removeEventListener('touchmove', this.onTouchMove);\n    canvasEl.removeEventListener('touchend', this.onTouchEnd);\n  },\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 currentRotation;\n    var deltaRotation;\n    var hmdEuler = this.hmdEuler;\n    var hmdQuaternion = this.hmdQuaternion;\n    var pitchObject = this.pitchObject;\n    var yawObject = this.yawObject;\n    var sceneEl = this.el.sceneEl;\n    var rotation = this.rotation;\n\n    // Calculate HMD quaternion.\n    hmdQuaternion = hmdQuaternion.copy(this.dolly.quaternion);\n    hmdEuler.setFromQuaternion(hmdQuaternion, 'YXZ');\n\n    if (sceneEl.isMobile) {\n      // On mobile, do camera rotation with touch events and sensors.\n      rotation.x = radToDeg(hmdEuler.x) + radToDeg(pitchObject.rotation.x);\n      rotation.y = radToDeg(hmdEuler.y) + radToDeg(yawObject.rotation.y);\n      rotation.z = radToDeg(hmdEuler.z);\n    } else if (!sceneEl.is('vr-mode') || isNullVector(hmdEuler) || !this.data.hmdEnabled) {\n      // Mouse drag if WebVR not active (not connected, no incoming sensor data).\n      currentRotation = this.el.getAttribute('rotation');\n      deltaRotation = this.calculateDeltaRotation();\n      if (this.data.reverseMouseDrag) {\n        rotation.x = currentRotation.x - deltaRotation.x;\n        rotation.y = currentRotation.y - deltaRotation.y;\n        rotation.z = currentRotation.z;\n      } else {\n        rotation.x = currentRotation.x + deltaRotation.x;\n        rotation.y = currentRotation.y + deltaRotation.y;\n        rotation.z = currentRotation.z;\n      }\n    } else {\n      // Mouse rotation ignored with an active headset. Use headset rotation.\n      rotation.x = radToDeg(hmdEuler.x);\n      rotation.y = radToDeg(hmdEuler.y);\n      rotation.z = radToDeg(hmdEuler.z);\n    }\n\n    this.el.setAttribute('rotation', rotation);\n  },\n\n  /**\n   * Calculate delta rotation for mouse-drag and touch-drag.\n   */\n  calculateDeltaRotation: function () {\n    var currentRotationX = radToDeg(this.pitchObject.rotation.x);\n    var currentRotationY = radToDeg(this.yawObject.rotation.y);\n    var deltaRotation;\n    deltaRotation = {\n      x: currentRotationX - (this.previousRotationX || 0),\n      y: currentRotationY - (this.previousRotationY || 0)\n    };\n    // Store current rotation for next tick.\n    this.previousRotationX = currentRotationX;\n    this.previousRotationY = currentRotationY;\n    return deltaRotation;\n  },\n\n  /**\n   * Handle positional tracking.\n   */\n  updatePosition: function () {\n    var el = this.el;\n    var currentHMDPosition;\n    var currentPosition;\n    var position = this.position;\n    var previousHMDPosition = this.previousHMDPosition;\n    var sceneEl = this.el.sceneEl;\n\n    if (!sceneEl.is('vr-mode')) { return; }\n\n    // Calculate change in position.\n    currentHMDPosition = this.calculateHMDPosition();\n\n    currentPosition = el.getAttribute('position');\n\n    position.copy(currentPosition).sub(previousHMDPosition).add(currentHMDPosition);\n    el.setAttribute('position', position);\n    previousHMDPosition.copy(currentHMDPosition);\n  },\n\n  /**\n   * Get headset position from VRControls.\n   */\n  calculateHMDPosition: (function () {\n    var position = new THREE.Vector3();\n    return function () {\n      this.dolly.updateMatrix();\n      position.setFromMatrixPosition(this.dolly.matrix);\n      return position;\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 (event) {\n    var pitchObject = this.pitchObject;\n    var yawObject = this.yawObject;\n    var previousMouseEvent = this.previousMouseEvent;\n    var movementX;\n    var movementY;\n\n    // Not dragging or not enabled.\n    if (!this.mouseDown || !this.data.enabled) { return; }\n\n     // Calculate delta.\n    movementX = event.movementX || event.mozMovementX;\n    movementY = event.movementY || event.mozMovementY;\n    if (movementX === undefined || movementY === undefined) {\n      movementX = event.screenX - previousMouseEvent.screenX;\n      movementY = event.screenY - previousMouseEvent.screenY;\n    }\n    this.previousMouseEvent = event;\n\n    // Calculate rotation.\n    yawObject.rotation.y -= movementX * 0.002;\n    pitchObject.rotation.x -= movementY * 0.002;\n    pitchObject.rotation.x = Math.max(-PI_2, Math.min(PI_2, pitchObject.rotation.x));\n  },\n\n  /**\n   * Register mouse down to detect mouse drag.\n   */\n  onMouseDown: function (evt) {\n    if (!this.data.enabled) { return; }\n    // Handle only primary button.\n    if (evt.button !== 0) { return; }\n    this.mouseDown = true;\n    this.previousMouseEvent = evt;\n    document.body.classList.add(GRABBING_CLASS);\n  },\n\n  /**\n   * Register mouse up to detect release of mouse drag.\n   */\n  onMouseUp: function () {\n    this.mouseDown = false;\n    document.body.classList.remove(GRABBING_CLASS);\n  },\n\n  /**\n   * Register touch down to detect touch drag.\n   */\n  onTouchStart: function (evt) {\n    if (evt.touches.length !== 1 || !this.data.touchEnabled) { return; }\n    this.touchStart = {\n      x: evt.touches[0].pageX,\n      y: evt.touches[0].pageY\n    };\n    this.touchStarted = true;\n  },\n\n  /**\n   * Translate touch move to Y-axis rotation.\n   */\n  onTouchMove: function (evt) {\n    var canvas = this.el.sceneEl.canvas;\n    var deltaY;\n    var yawObject = this.yawObject;\n\n    if (!this.touchStarted || !this.data.touchEnabled) { return; }\n\n    deltaY = 2 * Math.PI * (evt.touches[0].pageX - this.touchStart.x) / canvas.clientWidth;\n\n    // Limit touch orientaion to to yaw (y axis).\n    yawObject.rotation.y -= deltaY * 0.5;\n    this.touchStart = {\n      x: evt.touches[0].pageX,\n      y: evt.touches[0].pageY\n    };\n  },\n\n  /**\n   * Register touch end to detect release of touch drag.\n   */\n  onTouchEnd: function () {\n    this.touchStarted = false;\n  },\n\n  onExitVR: function () {\n    this.previousHMDPosition.set(0, 0, 0);\n  },\n\n  /**\n   * Toggle the feature of showing/hiding the grab cursor.\n   */\n  updateGrabCursor: function (enabled) {\n    var sceneEl = this.el.sceneEl;\n\n    function enableGrabCursor () { sceneEl.canvas.classList.add('a-grab-cursor'); }\n    function disableGrabCursor () { 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\n    if (enabled) {\n      enableGrabCursor();\n      return;\n    }\n    disableGrabCursor();\n  }\n});\n\nfunction isNullVector (vector) {\n  return vector.x === 0 && vector.y === 0 && vector.z === 0;\n}\n\n},{\"../constants\":116,\"../core/component\":125,\"../lib/three\":173,\"../utils/bind\":189}],91:[function(_dereq_,module,exports){\n/* global Promise */\nvar utils = _dereq_('../utils/');\nvar component = _dereq_('../core/component');\nvar THREE = _dereq_('../lib/three');\nvar shader = _dereq_('../core/shader');\n\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: {default: 0.0, min: 0.0, max: 1.0},\n    depthTest: {default: true},\n    depthWrite: {default: true},\n    flatShading: {default: false},\n    npot: {default: false},\n    offset: {type: 'vec2', default: {x: 0, y: 0}},\n    opacity: {default: 1.0, min: 0.0, max: 1.0},\n    repeat: {type: 'vec2', default: {x: 1, y: 1}},\n    shader: {default: 'standard', oneOf: shaderNames},\n    side: {default: 'front', oneOf: ['front', 'back', 'double']},\n    transparent: {default: false},\n    vertexColors: {type: 'string', default: 'none', oneOf: ['face', 'vertex']},\n    visible: {default: true}\n  },\n\n  init: function () {\n    this.material = null;\n  },\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\n  updateSchema: function (data) {\n    var newShader = data.shader;\n    var currentShader = this.data && this.data.shader;\n    var shader = newShader || currentShader;\n    var schema = shaders[shader] && shaders[shader].schema;\n    if (!schema) { error('Unknown shader schema ' + shader); }\n    if (currentShader && newShader === currentShader) { return; }\n    this.extendSchema(schema);\n    this.updateBehavior();\n  },\n\n  updateBehavior: function () {\n    var schema = this.schema;\n    var self = this;\n    var sceneEl = this.el.sceneEl;\n    var tickProperties = {};\n    var tick = function (time, delta) {\n      Object.keys(tickProperties).forEach(function update (key) {\n        tickProperties[key] = time;\n      });\n      self.shader.update(tickProperties);\n    };\n    this.tick = undefined;\n    Object.keys(schema).forEach(function (key) {\n      if (schema[key].type === 'time') {\n        self.tick = tick;\n        tickProperties[key] = true;\n      }\n    });\n    if (!sceneEl) { return; }\n    if (!this.tick) {\n      sceneEl.removeBehavior(this);\n    } else {\n      sceneEl.addBehavior(this);\n    }\n  },\n\n  updateShader: function (shaderName) {\n    var data = this.data;\n    var Shader = shaders[shaderName] && shaders[shaderName].Shader;\n    var shaderInstance;\n\n    if (!Shader) { throw new Error('Unknown shader ' + shaderName); }\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  /**\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\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 = parseVertexColors(data.vertexColors);\n    material.visible = data.visible;\n\n    // Check if material needs update.\n    if (Object.keys(oldData).length &&\n        (oldData.alphaTest !== data.alphaTest ||\n         oldData.side !== data.side ||\n         oldData.vertexColors !== data.vertexColors)) {\n      material.needsUpdate = true;\n    }\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) { object3D.material = defaultMaterial; }\n    disposeMaterial(material, this.system);\n  },\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 mesh = this.el.getOrCreateObject3D('mesh', THREE.Mesh);\n    var system = this.system;\n    if (this.material) { disposeMaterial(this.material, system); }\n    this.material = mesh.material = material;\n    system.registerMaterial(material);\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      return THREE.BackSide;\n    }\n    case 'double': {\n      return THREE.DoubleSide;\n    }\n    default: {\n      // Including case `front`.\n      return THREE.FrontSide;\n    }\n  }\n}\n\n/**\n * Return a three.js constant determining vertex coloring.\n */\nfunction parseVertexColors (coloring) {\n  switch (coloring) {\n    case 'face': {\n      return THREE.FaceColors;\n    }\n    case 'vertex': {\n      return THREE.VertexColors;\n    }\n    default: {\n      return THREE.NoColors;\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\n},{\"../core/component\":125,\"../core/shader\":134,\"../lib/three\":173,\"../utils/\":195}],92:[function(_dereq_,module,exports){\nvar debug = _dereq_('../utils/debug');\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar THREE = _dereq_('../lib/three');\n\nvar warn = debug('components:obj-model:warn');\n\nmodule.exports.Component = registerComponent('obj-model', {\n  schema: {\n    mtl: {type: 'model'},\n    obj: {type: 'model'}\n  },\n\n  init: function () {\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  },\n\n  update: function () {\n    var data = this.data;\n    if (!data.obj) { return; }\n    this.remove();\n    this.loadObj(data.obj, data.mtl);\n  },\n\n  remove: function () {\n    if (!this.model) { return; }\n    this.el.removeObject3D('mesh');\n  },\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\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.setTexturePath(mtlUrl.substr(0, mtlUrl.lastIndexOf('/') + 1));\n      mtlLoader.load(mtlUrl, function (materials) {\n        materials.preload();\n        objLoader.setMaterials(materials);\n        objLoader.load(objUrl, function (objModel) {\n          self.model = objModel;\n          el.setObject3D('mesh', objModel);\n          el.emit('model-loaded', {format: 'obj', model: objModel});\n        });\n      });\n      return;\n    }\n\n    // .OBJ only.\n    objLoader.load(objUrl, function loadObjOnly (objModel) {\n      // Apply material.\n      var material = el.components.material;\n      if (material) {\n        objModel.traverse(function (child) {\n          if (child instanceof THREE.Mesh) {\n            child.material = material.material;\n          }\n        });\n      }\n\n      self.model = objModel;\n      el.setObject3D('mesh', objModel);\n      el.emit('model-loaded', {format: 'obj', model: objModel});\n    });\n  }\n});\n\n},{\"../core/component\":125,\"../lib/three\":173,\"../utils/debug\":191}],93:[function(_dereq_,module,exports){\nvar bind = _dereq_('../utils/bind');\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar controllerUtils = _dereq_('../utils/tracked-controls');\n\nvar TOUCH_CONTROLLER_MODEL_BASE_URL = 'https://cdn.aframe.io/controllers/oculus/oculus-touch-controller-';\nvar TOUCH_CONTROLLER_MODEL_OBJ_URL_L = TOUCH_CONTROLLER_MODEL_BASE_URL + 'left.obj';\nvar TOUCH_CONTROLLER_MODEL_OBJ_MTL_L = TOUCH_CONTROLLER_MODEL_BASE_URL + 'left.mtl';\nvar TOUCH_CONTROLLER_MODEL_OBJ_URL_R = TOUCH_CONTROLLER_MODEL_BASE_URL + 'right.obj';\nvar TOUCH_CONTROLLER_MODEL_OBJ_MTL_R = TOUCH_CONTROLLER_MODEL_BASE_URL + 'right.mtl';\n\nvar GAMEPAD_ID_PREFIX = 'Oculus Touch';\n\nvar PIVOT_OFFSET = {x: 0, y: -0.015, z: 0.04};\n\n/**\n * Oculus Touch controls component.\n * Interface with Oculus Touch controllers and maps Gamepad events to\n * common controller buttons: trackpad, trigger, grip, menu and system\n * Load a controller model and highlights the pressed buttons\n */\nmodule.exports.Component = registerComponent('oculus-touch-controls', {\n  schema: {\n    hand: {default: 'left'},\n    buttonColor: {type: 'color', default: '#999'},  // Off-white.\n    buttonTouchColor: {type: 'color', default: '#8AB'},\n    buttonHighlightColor: {type: 'color', default: '#2DF'},  // Light blue.\n    model: {default: true},\n    rotationOffset: {default: 0}\n  },\n\n  // buttonId\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  mapping: {\n    left: {\n      axes: {thumbstick: [0, 1]},\n      buttons: ['thumbstick', 'trigger', 'grip', 'xbutton', 'ybutton', 'surface']\n    },\n    right: {\n      axes: {thumbstick: [0, 1]},\n      buttons: ['thumbstick', 'trigger', 'grip', 'abutton', 'bbutton', 'surface']\n    }\n  },\n\n  bindMethods: function () {\n    this.onModelLoaded = bind(this.onModelLoaded, this);\n    this.onControllersUpdate = bind(this.onControllersUpdate, this);\n    this.checkIfControllerPresent = bind(this.checkIfControllerPresent, this);\n    this.onAxisMoved = bind(this.onAxisMoved, this);\n  },\n\n  init: function () {\n    var self = this;\n    this.onButtonChanged = bind(this.onButtonChanged, this);\n    this.onButtonDown = function (evt) { self.onButtonEvent(evt.detail.id, 'down'); };\n    this.onButtonUp = function (evt) { self.onButtonEvent(evt.detail.id, 'up'); };\n    this.onButtonTouchStart = function (evt) { self.onButtonEvent(evt.detail.id, 'touchstart'); };\n    this.onButtonTouchEnd = function (evt) { self.onButtonEvent(evt.detail.id, 'touchend'); };\n    this.controllerPresent = false;\n    this.lastControllerCheck = 0;\n    this.previousButtonValues = {};\n    this.bindMethods();\n\n    // Allow mock.\n    this.emitIfAxesChanged = controllerUtils.emitIfAxesChanged;\n    this.checkControllerPresentAndSetup = controllerUtils.checkControllerPresentAndSetup;\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    el.addEventListener('model-loaded', this.onModelLoaded);\n    this.controllerEventsActive = true;\n  },\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\n  checkIfControllerPresent: function () {\n    this.checkControllerPresentAndSetup(this, GAMEPAD_ID_PREFIX, {\n      hand: this.data.hand\n    });\n  },\n\n  play: function () {\n    this.checkIfControllerPresent();\n    this.addControllersUpdateListener();\n  },\n\n  pause: function () {\n    this.removeEventListeners();\n    this.removeControllersUpdateListener();\n  },\n\n  updateControllerModel: function () {\n    var objUrl, mtlUrl;\n    if (!this.data.model) { return; }\n    if (this.data.hand === 'right') {\n      objUrl = 'url(' + TOUCH_CONTROLLER_MODEL_OBJ_URL_R + ')';\n      mtlUrl = 'url(' + TOUCH_CONTROLLER_MODEL_OBJ_MTL_R + ')';\n    } else {\n      objUrl = 'url(' + TOUCH_CONTROLLER_MODEL_OBJ_URL_L + ')';\n      mtlUrl = 'url(' + TOUCH_CONTROLLER_MODEL_OBJ_MTL_L + ')';\n    }\n    this.el.setAttribute('obj-model', {obj: objUrl, mtl: mtlUrl});\n  },\n\n  injectTrackedControls: function () {\n    var data = this.data;\n    var offset = data.hand === 'right' ? -90 : 90;\n    this.el.setAttribute('tracked-controls', {\n      id: data.hand === 'right' ? 'Oculus Touch (Right)' : 'Oculus Touch (Left)',\n      controller: 0,\n      rotationOffset: data.rotationOffset !== -999 ? data.rotationOffset : offset\n    });\n    this.updateControllerModel();\n  },\n\n  addControllersUpdateListener: function () {\n    this.el.sceneEl.addEventListener('controllersupdated', this.onControllersUpdate, false);\n  },\n\n  removeControllersUpdateListener: function () {\n    this.el.sceneEl.removeEventListener('controllersupdated', this.onControllersUpdate, false);\n  },\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  onButtonChanged: function (evt) {\n    var button = this.mapping[this.data.hand].buttons[evt.detail.id];\n    var buttonMeshes = this.buttonMeshes;\n    var analogValue;\n\n    if (!button) { return; }\n\n    if (button === 'trigger' || button === 'grip') { analogValue = evt.detail.state.value; }\n\n    // Update trigger and/or grip meshes, if any.\n    if (buttonMeshes) {\n      if (button === 'trigger' && buttonMeshes.trigger) {\n        buttonMeshes.trigger.rotation.x = -analogValue * (Math.PI / 24);\n      }\n      if (button === 'grip' && buttonMeshes.grip) {\n        buttonMeshes.grip.rotation.y = (this.data.hand === 'left' ? -1 : 1) * analogValue * (Math.PI / 60);\n      }\n    }\n\n    // Pass along changed event with button state, using the buttom mapping for convenience.\n    this.el.emit(button + 'changed', evt.detail.state);\n  },\n\n  onModelLoaded: function (evt) {\n    var controllerObject3D = evt.detail.model;\n    var buttonMeshes;\n    if (!this.data.model) { return; }\n\n    var leftHand = this.data.hand === 'left';\n    buttonMeshes = this.buttonMeshes = {};\n\n    buttonMeshes.grip = controllerObject3D.getObjectByName(leftHand ? 'buttonHand_oculus-touch-controller-left.004' : 'buttonHand_oculus-touch-controller-right.005');\n    buttonMeshes.thumbstick = controllerObject3D.getObjectByName(leftHand ? 'stick_oculus-touch-controller-left.007' : 'stick_oculus-touch-controller-right.004');\n    buttonMeshes.trigger = controllerObject3D.getObjectByName(leftHand ? 'buttonTrigger_oculus-touch-controller-left.005' : 'buttonTrigger_oculus-touch-controller-right.006');\n    buttonMeshes.xbutton = controllerObject3D.getObjectByName('buttonX_oculus-touch-controller-left.002');\n    buttonMeshes.abutton = controllerObject3D.getObjectByName('buttonA_oculus-touch-controller-right.002');\n    buttonMeshes.ybutton = controllerObject3D.getObjectByName('buttonY_oculus-touch-controller-left.001');\n    buttonMeshes.bbutton = controllerObject3D.getObjectByName('buttonB_oculus-touch-controller-right.003');\n\n    // Offset pivot point\n    controllerObject3D.position = PIVOT_OFFSET;\n  },\n\n  onButtonEvent: function (id, evtName) {\n    var buttonName = this.mapping[this.data.hand].buttons[id];\n    var i;\n    if (Array.isArray(buttonName)) {\n      for (i = 0; i < buttonName.length; i++) {\n        this.el.emit(buttonName[i] + evtName);\n      }\n    } else {\n      this.el.emit(buttonName + evtName);\n    }\n    this.updateModel(buttonName, evtName);\n  },\n\n  onAxisMoved: function (evt) {\n    this.emitIfAxesChanged(this, this.mapping[this.data.hand].axes, evt);\n  },\n\n  updateModel: function (buttonName, evtName) {\n    var i;\n    if (Array.isArray(buttonName)) {\n      for (i = 0; i < buttonName.length; i++) {\n        this.updateButtonModel(buttonName[i], evtName);\n      }\n    } else {\n      this.updateButtonModel(buttonName, evtName);\n    }\n  },\n\n  updateButtonModel: function (buttonName, state) {\n    var color = (state === 'up' || state === 'touchend') ? this.data.buttonColor : state === 'touchstart' ? this.data.buttonTouchColor : this.data.buttonHighlightColor;\n    var buttonMeshes = this.buttonMeshes;\n    if (!this.data.model) { return; }\n    if (buttonMeshes && buttonMeshes[buttonName]) {\n      buttonMeshes[buttonName].material.color.set(color);\n    }\n  }\n});\n\n},{\"../core/component\":125,\"../utils/bind\":189,\"../utils/tracked-controls\":199}],94:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../core/component').registerComponent;\n\nmodule.exports.Component = registerComponent('position', {\n  schema: {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});\n\n},{\"../core/component\":125}],95:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar THREE = _dereq_('../lib/three');\nvar utils = _dereq_('../utils/');\n\nvar bind = utils.bind;\n\nvar dummyVec = new THREE.Vector3();\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    direction: {type: 'vec3', default: {x: 0, y: 0, z: -1}},\n    far: {default: 1000},\n    interval: {default: 100},\n    near: {default: 0},\n    objects: {default: ''},\n    origin: {type: 'vec3'},\n    recursive: {default: true},\n    showLine: {default: false},\n    useWorldCoordinates: {default: false}\n  },\n\n  init: function () {\n    // Calculate unit vector for line direction. Can be multiplied via scalar to performantly\n    // adjust line length.\n    this.lineData = {};\n    this.lineEndVec3 = new THREE.Vector3();\n    this.unitLineEndVec3 = new THREE.Vector3();\n    this.intersectedEls = [];\n    this.objects = null;\n    this.prevCheckTime = undefined;\n    this.prevIntersectedEls = [];\n    this.raycaster = new THREE.Raycaster();\n    this.updateOriginDirection();\n    this.refreshObjects = bind(this.refreshObjects, this);\n    this.refreshOnceChildLoaded = bind(this.refreshOnceChildLoaded, this);\n  },\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 &&\n        (data.far !== oldData.far || data.origin !== oldData.origin ||\n         data.direction !== oldData.direction || data.showLine !== oldData.showLine)) {\n      this.unitLineEndVec3.copy(data.origin).add(data.direction).normalize();\n      this.drawLine();\n    }\n    if (!data.showLine && oldData.showLine) {\n      el.removeAttribute('line');\n    }\n\n    this.refreshObjects();\n  },\n\n  play: function () {\n    this.el.sceneEl.addEventListener('loaded', this.refreshObjects);\n    this.el.sceneEl.addEventListener('child-attached', this.refreshOnceChildLoaded);\n    this.el.sceneEl.addEventListener('child-detached', this.refreshObjects);\n  },\n\n  pause: function () {\n    this.el.sceneEl.removeEventListener('loaded', this.refreshObjects);\n    this.el.sceneEl.removeEventListener('child-attached', this.refreshOnceChildLoaded);\n    this.el.sceneEl.removeEventListener('child-detached', this.refreshObjects);\n  },\n\n  remove: function () {\n    if (this.data.showLine) {\n      this.el.removeAttribute('line');\n    }\n  },\n\n  /**\n   * Update list of objects to test for intersection once child is loaded.\n   */\n  refreshOnceChildLoaded: function (evt) {\n    var self = this;\n    var childEl = evt.detail.el;\n    if (!childEl) { return; }\n    if (childEl.hasLoaded) {\n      this.refreshObjects();\n    } else {\n      childEl.addEventListener('loaded', function nowRefresh (evt) {\n        childEl.removeEventListener('loaded', nowRefresh);\n        self.refreshObjects();\n      });\n    }\n  },\n\n  /**\n   * Update list of objects to test for intersection.\n   */\n  refreshObjects: function () {\n    var children;\n    var data = this.data;\n    var i;\n    var objects;\n    // Target entities.\n    var targetEls = data.objects ? this.el.sceneEl.querySelectorAll(data.objects) : null;\n\n    // Push meshes onto list of objects to intersect.\n    if (targetEls) {\n      objects = [];\n      for (i = 0; i < targetEls.length; i++) {\n        objects.push(targetEls[i].object3D);\n      }\n    } else {\n      // If objects not defined, intersect with everything.\n      objects = this.el.sceneEl.object3D.children;\n    }\n\n    this.objects = [];\n    for (i = 0; i < objects.length; i++) {\n      // A-Frame wraps everything in THREE.Group. Grab the children.\n      children = objects[i].children;\n\n      // Add the object3D children for non-recursive raycasting.\n      // If no children, refresh after entity loaded.\n      if (children) { this.objects.push.apply(this.objects, children); }\n    }\n  },\n\n  /**\n   * Check for intersections and cleared intersections on an interval.\n   */\n  tick: (function () {\n    var intersections = [];\n\n    return function (time) {\n      var el = this.el;\n      var data = this.data;\n      var i;\n      var intersectedEls = this.intersectedEls;\n      var intersection;\n      var lineLength;\n      var prevCheckTime = this.prevCheckTime;\n      var prevIntersectedEls = this.prevIntersectedEls;\n      var rawIntersections;\n\n      // Only check for intersection if interval time has passed.\n      if (prevCheckTime && (time - prevCheckTime < data.interval)) { return; }\n      // Update check time.\n      this.prevCheckTime = time;\n\n      // Store old previously intersected entities.\n      copyArray(this.prevIntersectedEls, this.intersectedEls);\n\n      // Raycast.\n      this.updateOriginDirection();\n      rawIntersections = this.raycaster.intersectObjects(this.objects, data.recursive);\n\n      // Only keep intersections against objects that have a reference to an entity.\n      intersections.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        }\n      }\n\n      // Update intersectedEls.\n      intersectedEls.length = intersections.length;\n      for (i = 0; i < intersections.length; i++) {\n        intersectedEls[i] = intersections[i].object.el;\n      }\n\n      // Emit intersected on intersected entity per intersected entity.\n      for (i = 0; i < intersections.length; i++) {\n        intersections[i].object.el.emit('raycaster-intersected', {\n          el: el,\n          intersection: intersections[i]\n        });\n      }\n\n      // Emit all intersections at once on raycasting entity.\n      if (intersections.length) {\n        el.emit('raycaster-intersection', {\n          els: intersectedEls,\n          intersections: intersections\n        });\n      }\n\n      // Emit intersection cleared on both entities per formerly intersected entity.\n      for (i = 0; i < prevIntersectedEls.length; i++) {\n        if (intersectedEls.indexOf(prevIntersectedEls[i]) !== -1) { return; }\n        el.emit('raycaster-intersection-cleared', {el: prevIntersectedEls[i]});\n        prevIntersectedEls[i].emit('raycaster-intersected-cleared', {el: el});\n      }\n\n      // Update line length.\n      if (data.showLine) {\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  })(),\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 quaternion = new THREE.Quaternion();\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\n      if (data.useWorldCoordinates) {\n        this.raycaster.set(data.origin, data.direction);\n        return;\n      }\n\n      // Grab the position and rotation.\n      el.object3D.updateMatrixWorld();\n      el.object3D.matrixWorld.decompose(originVec3, quaternion, dummyVec);\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).add(data.origin).applyQuaternion(quaternion).normalize();\n\n      // Apply offset and direction, in world coordinates.\n      this.raycaster.set(originVec3, direction);\n    };\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 lineEndVec3 = new THREE.Vector3();\n    var lineData = {};\n\n    return function (length) {\n      var data = this.data;\n      var el = this.el;\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.\n      lineData.start = data.origin;\n      lineData.end = lineEndVec3.copy(this.unitLineEndVec3).multiplyScalar(length);\n      el.setAttribute('line', lineData);\n    };\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},{\"../core/component\":125,\"../lib/three\":173,\"../utils/\":195}],96:[function(_dereq_,module,exports){\nvar degToRad = _dereq_('../lib/three').Math.degToRad;\nvar registerComponent = _dereq_('../core/component').registerComponent;\n\nmodule.exports.Component = registerComponent('rotation', {\n  schema: {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));\n    object3D.rotation.order = 'YXZ';\n  }\n});\n\n},{\"../core/component\":125,\"../lib/three\":173}],97:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../core/component').registerComponent;\n\n// Avoids triggering a zero-determinant which makes object3D matrix non-invertible.\nvar zeroScale = 0.00001;\n\nmodule.exports.Component = registerComponent('scale', {\n  schema: {\n    type: 'vec3',\n    default: {x: 1, y: 1, z: 1}\n  },\n\n  update: function () {\n    var data = this.data;\n    var object3D = this.el.object3D;\n    var x = data.x === 0 ? zeroScale : data.x;\n    var y = data.y === 0 ? zeroScale : data.y;\n    var z = data.z === 0 ? zeroScale : data.z;\n    object3D.scale.set(x, y, z);\n  }\n});\n\n},{\"../core/component\":125}],98:[function(_dereq_,module,exports){\nvar register = _dereq_('../../core/component').registerComponent;\n\nmodule.exports.Component = register('debug', {\n  schema: {default: true}\n});\n\n},{\"../../core/component\":125}],99:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../../core/component').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: ['vr-mode-ui'],\n\n  schema: {default: true},\n\n  update: function () {\n    var sceneEl = this.el;\n    var enterVREl = sceneEl.querySelector('.a-enter-vr');\n    if (this.data === true) {\n      if (enterVREl) { enterVREl.classList.add('embedded'); }\n      sceneEl.removeFullScreenStyles();\n    } else {\n      if (enterVREl) { enterVREl.classList.remove('embedded'); }\n      sceneEl.addFullScreenStyles();\n    }\n  }\n\n});\n\n},{\"../../core/component\":125}],100:[function(_dereq_,module,exports){\nvar register = _dereq_('../../core/component').registerComponent;\nvar THREE = _dereq_('../../lib/three');\nvar debug = _dereq_('../../utils/debug');\n\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: {type: 'color', default: '#000'},\n    density: {default: 0.00025},\n    far: {default: 1000, min: 0},\n    near: {default: 1, min: 0},\n    type: {default: 'linear', oneOf: ['linear', 'exponential']}\n  },\n\n  update: function () {\n    var data = this.data;\n    var el = this.el;\n    var fog = this.el.object3D.fog;\n\n    if (!el.isScene) {\n      warn('Fog component can only be applied to <a-scene>');\n      return;\n    }\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      el.systems.material.updateMaterials();\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') { value = new THREE.Color(value); }\n      fog[key] = value;\n    });\n  },\n\n  /**\n   * Remove fog on remove (callback).\n   */\n  remove: function () {\n    var fog = this.el.object3D.fog;\n    if (!fog) { return; }\n    fog.far = 0;\n    fog.near = 0.1;\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},{\"../../core/component\":125,\"../../lib/three\":173,\"../../utils/debug\":191}],101:[function(_dereq_,module,exports){\n(function (process){\n/* global AFRAME */\nvar AFRAME_INJECTED = _dereq_('../../constants').AFRAME_INJECTED;\nvar bind = _dereq_('../../utils/bind');\nvar pkg = _dereq_('../../../package');\nvar registerComponent = _dereq_('../../core/component').registerComponent;\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}\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 = process.env.INSPECTOR_VERSION === 'dev' ? INSPECTOR_DEV_URL : INSPECTOR_RELEASE_URL;\nvar LOADING_MESSAGE = 'Loading Inspector';\nvar LOADING_ERROR_MESSAGE = 'Error loading Inspector';\n\nmodule.exports.Component = registerComponent('inspector', {\n  schema: {\n    url: {default: INSPECTOR_URL}\n  },\n\n  init: function () {\n    this.onKeydown = bind(this.onKeydown, this);\n    this.onMessage = bind(this.onMessage, this);\n    this.initOverlay();\n    window.addEventListener('keydown', this.onKeydown);\n    window.addEventListener('message', this.onMessage);\n  },\n\n  initOverlay: function () {\n    var dotsHTML = '<span class=\"dots\"><span>.</span><span>.</span><span>.</span></span>';\n    this.loadingMessageEl = document.createElement('div');\n    this.loadingMessageEl.classList.add('a-inspector-loader');\n    this.loadingMessageEl.innerHTML = LOADING_MESSAGE + dotsHTML;\n  },\n\n  remove: function () {\n    this.removeEventListeners();\n  },\n\n  /**\n   * <ctrl> + <alt> + i keyboard shortcut.\n   */\n  onKeydown: function (evt) {\n    var shortcutPressed = evt.keyCode === 73 && evt.ctrlKey && evt.altKey;\n    if (!this.data || !shortcutPressed) { return; }\n    this.injectInspector();\n  },\n\n  showLoader: function () {\n    document.body.appendChild(this.loadingMessageEl);\n  },\n\n  hideLoader: function () {\n    document.body.removeChild(this.loadingMessageEl);\n  },\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') { this.injectInspector(); }\n  },\n\n  injectInspector: function () {\n    var self = this;\n    var script;\n\n    if (AFRAME.INSPECTOR || AFRAME.inspectorInjected) { 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();\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\n  removeEventListeners: function () {\n    window.removeEventListener('keydown', this.onKeydown);\n    window.removeEventListener('message', this.onMessage);\n  }\n});\n\n}).call(this,_dereq_('_process'))\n\n},{\"../../../package\":76,\"../../constants\":116,\"../../core/component\":125,\"../../utils/bind\":189,\"_process\":6}],102:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../../core/component').registerComponent;\nvar shouldCaptureKeyEvent = _dereq_('../../utils/').shouldCaptureKeyEvent;\n\nmodule.exports.Component = registerComponent('keyboard-shortcuts', {\n  schema: {\n    enterVR: {default: true},\n    exitVR: {default: true}\n  },\n\n  init: function () {\n    var self = this;\n    var scene = this.el;\n\n    this.listener = window.addEventListener('keyup', function (event) {\n      if (!shouldCaptureKeyEvent(event)) { return; }\n      if (self.enterVREnabled && event.keyCode === 70) {  // f.\n        scene.enterVR();\n      }\n      if (self.enterVREnabled && event.keyCode === 27) {  // escape.\n        scene.exitVR();\n      }\n    }, false);\n  },\n\n  update: function (oldData) {\n    var data = this.data;\n    this.enterVREnabled = data.enterVR;\n  },\n\n  remove: function () {\n    window.removeEventListener('keyup', this.listener);\n  }\n});\n\n},{\"../../core/component\":125,\"../../utils/\":195}],103:[function(_dereq_,module,exports){\nvar debug = _dereq_('../../utils/debug');\nvar registerComponent = _dereq_('../../core/component').registerComponent;\n\nvar warn = debug('components:pool:warn');\n\n/**\n * Pool component.\n * A pool of entities that will be reused.\n * It avoids creating and destroying the same kind of entities\n * in dynamic scenes. It will help reduce GC pauses. Useful for example\n * in a game where you want 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 *\n */\nmodule.exports.Component = registerComponent('pool', {\n  schema: {\n    mixin: {default: ''},\n    size: {default: 0},\n    dynamic: {default: false}\n  },\n\n  multiple: true,\n\n  initPool: function () {\n    var i;\n    var mixin = this.data.mixin;\n    if (!mixin) { return; }\n    this.availableEls = [];\n    this.usedEls = [];\n    for (i = 0; i < this.data.size; ++i) {\n      this.createEntity();\n    }\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  /**\n   * Add a new entity to the list of available entities.\n   */\n  createEntity: function () {\n    var el = document.createElement('a-entity');\n    el.play = this.wrapPlay(el.play);\n    el.setAttribute('mixin', this.data.mixin);\n    el.setAttribute('visible', false);\n    this.el.appendChild(el);\n    this.availableEls.push(el);\n  },\n\n  /**\n   * Play wrapper for pooled entities. When pausing and playing\n   * a scene we don't want to play the 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) { return; }\n      playMethod.call(this);\n    };\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.name);\n        return;\n      } else {\n        warn('Requested entity from empty pool. This pool is dynamic' +\n        'and will resize automatically. You might want to increase its initial size' + this.name);\n      }\n      this.createEntity();\n    }\n    el = this.availableEls.shift();\n    this.usedEls.push(el);\n    el.setAttribute('visible', true);\n    return el;\n  },\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.name);\n      return;\n    }\n    this.usedEls.splice(index, 1);\n    this.availableEls.push(el);\n    el.setAttribute('visible', false);\n    el.pause();\n  }\n});\n\n},{\"../../core/component\":125,\"../../utils/debug\":191}],104:[function(_dereq_,module,exports){\n/* global ImageData, URL */\nvar registerComponent = _dereq_('../../core/component').registerComponent;\nvar THREE = _dereq_('../../lib/three');\n\nvar VERTEX_SHADER = [\n  'attribute vec3 position;',\n  'attribute vec2 uv;',\n  'uniform mat4 projectionMatrix;',\n  'uniform mat4 modelViewMatrix;',\n  'varying vec2 vUv;',\n  'void main()  {',\n  '  vUv = vec2( 1.- uv.x, uv.y );',\n  '  gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',\n  '}'\n].join('\\n');\n\nvar FRAGMENT_SHADER = [\n  'precision mediump float;',\n  'uniform samplerCube map;',\n  'varying vec2 vUv;',\n  '#define M_PI 3.141592653589793238462643383279',\n  'void main() {',\n  '  vec2 uv = vUv;',\n  '  float longitude = uv.x * 2. * M_PI - M_PI + M_PI / 2.;',\n  '  float latitude = uv.y * M_PI;',\n  '  vec3 dir = vec3(',\n  '    - sin( longitude ) * sin( latitude ),',\n  '    cos( latitude ),',\n  '    - cos( longitude ) * sin( latitude )',\n  '  );',\n  '  normalize( dir );',\n  '  gl_FragColor = vec4( textureCube( map, dir ).rgb, 1.0 );',\n  '}'\n].join('\\n');\n\n/**\n * Component to take screenshots of the scene using a keboard shortcut (alt+s).\n * It can be configured to either take 360&deg; 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 ortographic camera.\n */\nmodule.exports.Component = registerComponent('screenshot', {\n  schema: {\n    width: {default: 4096},\n    height: {default: 2048}\n  },\n\n  init: function () {\n    var el = this.el;\n    var self = this;\n\n    if (el.renderer) {\n      setup();\n    } else {\n      el.addEventListener('render-target-loaded', setup);\n    }\n\n    function setup () {\n      var gl = el.renderer.getContext();\n      self.cubeMapSize = gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE);\n      self.material = new THREE.RawShaderMaterial({\n        uniforms: {map: {type: 't', value: null}},\n        vertexShader: VERTEX_SHADER,\n        fragmentShader: FRAGMENT_SHADER,\n        side: THREE.DoubleSide\n      });\n      self.quad = new THREE.Mesh(\n        new THREE.PlaneBufferGeometry(1, 1),\n        self.material\n      );\n      self.quad.visible = false;\n      self.camera = new THREE.OrthographicCamera(-1 / 2, 1 / 2, 1 / 2, -1 / 2, -10000, 10000);\n      self.canvas = document.createElement('canvas');\n      self.ctx = self.canvas.getContext('2d');\n      if (el.camera) { el.camera.add(self.quad); }\n      self.onKeyDown = self.onKeyDown.bind(self);\n      self.onCameraActive = self.onCameraActive.bind(self);\n      el.addEventListener('camera-set-active', self.onCameraActive);\n    }\n  },\n\n  getRenderTarget: function (width, height) {\n    return new THREE.WebGLRenderTarget(width, height, {\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\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\n  play: function () {\n    window.addEventListener('keydown', this.onKeyDown);\n  },\n\n  onCameraActive: function (evt) {\n    var cameraParent = this.quad.parent;\n    if (cameraParent) { cameraParent.remove(this.quad); }\n    evt.detail.cameraEl.getObject3D('camera').add(this.quad);\n  },\n\n  /**\n   * <ctrl> + <alt> + s = Regular screenshot.\n   * <ctrl> + <alt> + <shift> + s = Equirectangular screenshot.\n  */\n  onKeyDown: function (evt) {\n    var shortcutPressed = evt.keyCode === 83 && evt.ctrlKey && evt.altKey;\n    if (!this.data || !shortcutPressed) { return; }\n    var projection = evt.shiftKey ? 'equirectangular' : 'perspective';\n    this.capture(projection);\n  },\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    // 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 = el.camera;\n      size = {width: this.data.width, height: this.data.height};\n    } else {\n      // Use ortho camera.\n      camera = this.camera;\n      // Copy position and rotation of scene camera into the ortho one.\n      camera.position.copy(el.camera.getWorldPosition());\n      camera.rotation.copy(el.camera.getWorldRotation());\n      // Create cube camera and copy position from scene camera.\n      cubeCamera = new THREE.CubeCamera(el.camera.near, el.camera.far,\n                                        Math.min(this.cubeMapSize, 2048));\n      cubeCamera.position.copy(el.camera.getWorldPosition());\n      cubeCamera.rotation.copy(el.camera.getWorldRotation());\n      // Render scene with cube camera.\n      cubeCamera.updateCubeMap(el.renderer, el.object3D);\n      this.quad.material.uniforms.map.value = cubeCamera.renderTarget.texture;\n      size = {width: this.data.width, height: this.data.height};\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  /**\n   * Maintained for backwards compatibility.\n   */\n  capture: function (projection) {\n    var params = this.setCapture(projection);\n    this.renderCapture(params.camera, params.size, params.projection);\n    // Trigger file download.\n    this.saveCapture();\n  },\n\n  /**\n   * Return canvas instead of triggering download (e.g., for uploading blob to server).\n   */\n  getCanvas: function (projection) {\n    var params = this.setCapture(projection);\n    this.renderCapture(params.camera, params.size, params.projection);\n    return this.canvas;\n  },\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 = this.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.render(el.object3D, camera, output, true);\n    renderer.autoClear = autoClear;\n    // Read image pizels back.\n    renderer.readRenderTargetPixels(output, 0, 0, size.width, size.height, pixels);\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\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  /**\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},{\"../../core/component\":125,\"../../lib/three\":173}],105:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../../core/component').registerComponent;\nvar RStats = _dereq_('../../../vendor/rStats');\nvar utils = _dereq_('../../utils');\n_dereq_('../../../vendor/rStats.extras');\n_dereq_('../../lib/rStatsAframe');\n\nvar AFrameStats = window.aframeStats;\nvar bind = utils.bind;\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: {default: true},\n\n  init: function () {\n    var scene = this.el;\n\n    if (utils.getUrlParameter('stats') === 'false') { return; }\n\n    this.stats = createStats(scene);\n    this.statsEl = document.querySelector('.rs-base');\n\n    this.hideBound = bind(this.hide, this);\n    this.showBound = bind(this.show, this);\n\n    scene.addEventListener('enter-vr', this.hideBound);\n    scene.addEventListener('exit-vr', this.showBound);\n  },\n\n  update: function () {\n    if (!this.stats) { return; }\n    return (!this.data) ? this.hide() : this.show();\n  },\n\n  remove: function () {\n    this.el.removeEventListener('enter-vr', this.hideBound);\n    this.el.removeEventListener('exit-vr', this.showBound);\n    if (!this.statsEl) { return; }  // Scene detached.\n    this.statsEl.parentNode.removeChild(this.statsEl);\n  },\n\n  tick: function () {\n    var stats = this.stats;\n\n    if (!stats) { return; }\n\n    stats('rAF').tick();\n    stats('FPS').frame();\n    stats().update();\n  },\n\n  hide: function () {\n    this.statsEl.classList.add(HIDDEN_CLASS);\n  },\n\n  show: function () {\n    this.statsEl.classList.remove(HIDDEN_CLASS);\n  }\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: [],  // Our stylesheet is injected from `src/index.js`.\n    values: {\n      fps: {caption: 'fps', below: 30}\n    },\n    groups: [\n      {caption: 'Framerate', values: ['fps', 'raf']}\n    ],\n    plugins: plugins\n  });\n}\n\n},{\"../../../vendor/rStats\":203,\"../../../vendor/rStats.extras\":202,\"../../core/component\":125,\"../../lib/rStatsAframe\":172,\"../../utils\":195}],106:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../../core/component').registerComponent;\nvar constants = _dereq_('../../constants/');\nvar utils = _dereq_('../../utils/');\nvar bind = utils.bind;\n\nvar ENTER_VR_CLASS = 'a-enter-vr';\nvar ENTER_VR_BTN_CLASS = 'a-enter-vr-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('vr-mode-ui', {\n  dependencies: ['canvas'],\n\n  schema: {\n    enabled: {default: true}\n  },\n\n  init: function () {\n    var self = this;\n    var sceneEl = this.el;\n\n    if (utils.getUrlParameter('ui') === 'false') { return; }\n\n    this.enterVR = bind(sceneEl.enterVR, sceneEl);\n    this.exitVR = bind(sceneEl.exitVR, sceneEl);\n    this.insideLoader = false;\n    this.enterVREl = null;\n    this.orientationModalEl = null;\n\n    // Hide/show VR UI when entering/exiting VR mode.\n    sceneEl.addEventListener('enter-vr', bind(this.updateEnterVRInterface, this));\n    sceneEl.addEventListener('exit-vr', bind(this.updateEnterVRInterface, this));\n\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',\n                            bind(this.toggleOrientationModalIfNeeded, this));\n  },\n\n  update: function () {\n    var sceneEl = this.el;\n\n    if (!this.data.enabled || this.insideLoader || utils.getUrlParameter('ui') === 'false') {\n      return this.remove();\n    }\n    if (this.enterVREl || this.orientationModalEl) { return; }\n\n    // Add UI if enabled and not already present.\n    this.enterVREl = createEnterVRButton(this.enterVR);\n    sceneEl.appendChild(this.enterVREl);\n\n    this.orientationModalEl = createOrientationModal(this.exitVR);\n    sceneEl.appendChild(this.orientationModalEl);\n\n    this.updateEnterVRInterface();\n  },\n\n  remove: function () {\n    [this.enterVREl, this.orientationModalEl].forEach(function (uiElement) {\n      if (uiElement) {\n        uiElement.parentNode.removeChild(uiElement);\n      }\n    });\n  },\n\n  updateEnterVRInterface: function () {\n    this.toggleEnterVRButtonIfNeeded();\n    this.toggleOrientationModalIfNeeded();\n  },\n\n  toggleEnterVRButtonIfNeeded: function () {\n    var sceneEl = this.el;\n    if (!this.enterVREl) { return; }\n    if (sceneEl.is('vr-mode')) {\n      this.enterVREl.classList.add(HIDDEN_CLASS);\n    } else {\n      this.enterVREl.classList.remove(HIDDEN_CLASS);\n    }\n  },\n\n  toggleOrientationModalIfNeeded: function () {\n    var sceneEl = this.el;\n    var orientationModalEl = this.orientationModalEl;\n    if (!orientationModalEl || !sceneEl.isMobile) { return; }\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 * Creates a button that when clicked will enter into stereo-rendering mode for VR.\n *\n * Structure: <div><button></div>\n *\n * @param {function} enterVRHandler\n * @returns {Element} Wrapper <div>.\n */\nfunction createEnterVRButton (enterVRHandler) {\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 mode on a desktop. Visit https://webvr.rocks or https://webvr.info for more information.');\n  vrButton.setAttribute(constants.AFRAME_INJECTED, '');\n\n  // Insert elements.\n  wrapper.appendChild(vrButton);\n  vrButton.addEventListener('click', function (evt) {\n    enterVRHandler();\n  });\n  return wrapper;\n}\n\n/**\n * Create a modal that tells mobile users to orient the phone to landscape.\n * Add a close button that if clicked, exits VR and closes the modal.\n */\nfunction createOrientationModal (exitVRHandler) {\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\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', exitVRHandler);\n\n  modal.appendChild(exit);\n\n  return modal;\n}\n\n},{\"../../constants/\":116,\"../../core/component\":125,\"../../utils/\":195}],107:[function(_dereq_,module,exports){\nvar component = _dereq_('../core/component');\nvar THREE = _dereq_('../lib/three');\nvar bind = _dereq_('../utils/bind');\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: {default: true},\n    receive: {default: true}\n  },\n\n  init: function () {\n    this.onMeshChanged = bind(this.update, this);\n    this.el.addEventListener('object3dset', this.onMeshChanged);\n    this.system.setShadowMapEnabled(true);\n  },\n\n  update: function () {\n    var data = this.data;\n    this.updateDescendants(data.cast, data.receive);\n  },\n\n  remove: function () {\n    var el = this.el;\n    el.removeEventListener('object3dset', this.onMeshChanged);\n    this.updateDescendants(false, false);\n  },\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)) { 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 = node.material.materials || [node.material];\n        for (var i = 0; i < materials.length; i++) {\n          materials[i].needsUpdate = true;\n        }\n      }\n    });\n  }\n});\n\n},{\"../core/component\":125,\"../lib/three\":173,\"../utils/bind\":189}],108:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar debug = _dereq_('../utils/debug');\nvar bind = _dereq_('../utils/bind');\nvar THREE = _dereq_('../lib/three');\n\nvar warn = debug('components:sound:warn');\n\n/**\n * Sound component.\n */\nmodule.exports.Component = registerComponent('sound', {\n  schema: {\n    autoplay: {default: false},\n    distanceModel: {default: 'inverse',\n      oneOf: ['linear', 'inverse', 'exponential']},\n    loop: {default: false},\n    maxDistance: {default: 10000},\n    on: {default: ''},\n    poolSize: {default: 1},\n    positional: {default: true},\n    refDistance: {default: 1},\n    rolloffFactor: {default: 1},\n    src: {type: 'audio'},\n    volume: {default: 1}\n  },\n\n  multiple: true,\n\n  init: function () {\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    this.playSound = bind(this.playSound, this);\n  },\n\n  update: function (oldData) {\n    var data = this.data;\n    var srcChanged = data.src !== oldData.src;\n    // Create new sound if not yet created or changing `src`.\n    if (srcChanged) {\n      if (!data.src) {\n        warn('Audio source was not specified with `src`');\n        return;\n      }\n      this.setupSound();\n    }\n\n    this.pool.children.forEach(function (sound) {\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.setVolume(data.volume);\n      sound.isPaused = false;\n    });\n\n    if (data.on !== oldData.on) {\n      this.updateEventListener(oldData.on);\n    }\n    // All sound values set. Load in `src`.\n    if (srcChanged) {\n      var self = this;\n\n      this.loaded = false;\n      this.audioLoader.load(data.src, function (buffer) {\n        self.pool.children.forEach(function (sound) {\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) { self.playSound(); }\n        self.el.emit('sound-loaded');\n      });\n    }\n  },\n\n  pause: function () {\n    this.stopSound();\n    this.removeEventListener();\n  },\n\n  play: function () {\n    if (this.data.autoplay) { this.playSound(); }\n    this.updateEventListener();\n  },\n\n  remove: function () {\n    this.removeEventListener();\n    this.el.removeObject3D(this.attrName);\n    try {\n      this.pool.children.forEach(function (sound) {\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  /**\n  *  Update listener attached to the user defined on event.\n  */\n  updateEventListener: function (oldEvt) {\n    var el = this.el;\n    if (oldEvt) { el.removeEventListener(oldEvt, this.playSound); }\n    el.addEventListener(this.data.on, this.playSound);\n  },\n\n  removeEventListener: function () {\n    this.el.removeEventListener(this.data.on, this.playSound);\n  },\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 sceneEl = el.sceneEl;\n\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\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 (var i = 0; i < this.data.poolSize; i++) {\n      var 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\n    this.pool.children.forEach(function (sound) {\n      sound.onEnded = function () {\n        sound.isPlaying = false;\n        el.emit('sound-ended', {index: i});\n      };\n    });\n  },\n\n  /**\n   * Pause all the sounds in the pool.\n   */\n  pauseSound: function () {\n    this.isPlaying = false;\n    this.pool.children.forEach(function (sound) {\n      if (!sound.source || !sound.source.buffer || !sound.isPlaying || sound.isPaused) { return; }\n      sound.isPaused = true;\n      sound.pause();\n    });\n  },\n\n  /**\n   * Look for an unused sound in the pool and play it if found.\n   */\n  playSound: function () {\n    if (!this.loaded) {\n      warn('Sound not loaded yet. It will be played once it finished loading');\n      this.mustPlay = true;\n      return;\n    }\n\n    var found = false;\n    this.isPlaying = true;\n    this.pool.children.forEach(function (sound) {\n      if (!sound.isPlaying && sound.buffer && !found) {\n        sound.play();\n        sound.isPaused = false;\n        found = true;\n        return;\n      }\n    });\n\n    if (!found) {\n      warn('All the sounds are playing. If you need to play more sounds simultaneously ' +\n           'consider increasing the size of pool with the `poolSize` attribute.', this.el);\n      return;\n    }\n\n    this.mustPlay = false;\n  },\n\n  /**\n   * Stop all the sounds in the pool.\n   */\n  stopSound: function () {\n    this.isPlaying = false;\n    this.pool.children.forEach(function (sound) {\n      if (!sound.source || !sound.source.buffer) { return; }\n      sound.stop();\n    });\n  }\n});\n\n},{\"../core/component\":125,\"../lib/three\":173,\"../utils/bind\":189,\"../utils/debug\":191}],109:[function(_dereq_,module,exports){\nvar createTextGeometry = _dereq_('three-bmfont-text');\nvar loadBMFont = _dereq_('load-bmfont');\nvar path = _dereq_('path');\n\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar coreShader = _dereq_('../core/shader');\nvar THREE = _dereq_('../lib/three');\nvar utils = _dereq_('../utils/');\n\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;\n\nvar FONT_BASE_URL = 'https://cdn.aframe.io/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;\n\nvar cache = new PromiseCache();\nvar fontWidthFactors = {};\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\n  schema: {\n    align: {type: 'string', default: 'left', oneOf: ['left', 'right', 'center']},\n    alphaTest: {default: 0.5},\n    // `anchor` defaults to center to match geometries.\n    anchor: {default: 'center', oneOf: ['left', 'right', 'center', 'align']},\n    baseline: {default: 'center', oneOf: ['top', 'center', 'bottom']},\n    color: {type: 'color', default: '#FFF'},\n    font: {type: 'string', default: DEFAULT_FONT},\n    // `fontImage` defaults to the font name as a .png (e.g., mozillavr.fnt -> mozillavr.png).\n    fontImage: {type: 'string'},\n    // `height` has no default, will be populated at layout.\n    height: {type: 'number'},\n    letterSpacing: {type: 'number', default: 0},\n    // `lineHeight` defaults to font's `lineHeight` value.\n    lineHeight: {type: 'number'},\n    opacity: {type: 'number', default: 1.0},\n    shader: {default: 'sdf', oneOf: shaders},\n    side: {default: 'front', oneOf: ['front', 'back', 'double']},\n    tabSize: {default: 4},\n    transparent: {default: true},\n    value: {type: 'string'},\n    whiteSpace: {default: 'normal', oneOf: ['normal', 'pre', 'nowrap']},\n    // `width` defaults to geometry width if present, else `DEFAULT_WIDTH`.\n    width: {type: 'number'},\n    // `wrapCount` units are about one default font character. Wrap roughly at this number.\n    wrapCount: {type: 'number', default: 40},\n    // `wrapPixels` will wrap using bmfont pixel units (e.g., dejavu's is 32 pixels).\n    wrapPixels: {type: 'number'},\n    // `yOffset` to adjust generated fonts from tools that may have incorrect metrics.\n    yOffset: {type: 'number', default: 0},\n    // `zOffset` will provide a small z offset to avoid z-fighting.\n    zOffset: {type: 'number', default: 0.001}\n  },\n\n  init: function () {\n    this.texture = new THREE.Texture();\n    this.texture.anisotropy = MAX_ANISOTROPY;\n\n    this.geometry = createTextGeometry();\n\n    this.createOrUpdateMaterial();\n    this.mesh = new THREE.Mesh(this.geometry, this.material);\n    this.el.setObject3D(this.attrName, this.mesh);\n  },\n\n  update: function (oldData) {\n    var data = coerceData(this.data);\n    var font = this.currentFont;\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, data, font);\n      this.updateLayout(data);\n    }\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  /**\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;\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\n    hasChangedShader = (this.shaderObject && this.shaderObject.name) !== shaderName;\n    shaderData = {\n      alphaTest: data.alphaTest,\n      color: data.color,\n      map: this.texture,\n      opacity: data.opacity,\n      side: parseSide(data.side),\n      transparent: data.transparent\n    };\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      updateBaseMaterial(material, shaderData);\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    updateBaseMaterial(this.material, shaderData);\n    if (this.mesh) { 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\n    if (!data.font) { warn('No font specified. Using the default font.'); }\n\n    // Make invisible during font swap.\n    this.mesh.visible = false;\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 coercedData;\n      var fontImgSrc;\n\n      if (font.pages.length !== 1) {\n        throw new Error('Currently only single-page bitmap fonts are supported.');\n      }\n\n      if (!fontWidthFactors[fontSrc]) {\n        font.widthFactor = fontWidthFactors[font] = computeFontWidthFactor(font);\n      }\n\n      // Update geometry given font metrics.\n      coercedData = coerceData(data);\n      self.updateGeometry(geometry, self.data, font);\n\n      // Set font and update layout.\n      self.currentFont = font;\n      self.updateLayout(coercedData);\n\n      // Look up font image URL to use, and perform cached load.\n      fontImgSrc = data.fontImage || fontSrc.replace(/(\\.fnt)|(\\.json)/, '.png') ||\n                   path.dirname(data.font) + '/' + font.pages[0];\n      cache.get(fontImgSrc, function () {\n        return loadTexture(fontImgSrc);\n      }).then(function (image) {\n        // Make mesh visible and apply font image as texture.\n        self.mesh.visible = true;\n        self.texture.image = image;\n        self.texture.needsUpdate = true;\n        el.emit('textfontset', {font: data.font, fontObj: font});\n      }).catch(function (err) {\n        error(err);\n        throw err;\n      });\n    }).catch(function (err) {\n      error(err);\n      throw err;\n    });\n  },\n\n  /**\n   * Update layout with anchor, alignment, baseline, and considering any meshes.\n   */\n  updateLayout: function (data) {\n    var anchor;\n    var baseline;\n    var el = this.el;\n    var geometry = this.geometry;\n    var geometryComponent = el.getAttribute('geometry');\n    var height;\n    var layout = geometry.layout;\n    var mesh = this.mesh;\n    var textRenderWidth;\n    var textScale;\n    var width;\n    var x;\n    var y;\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,\n                                   this.currentFont.widthFactor);\n    textScale = width / textRenderWidth;\n\n    // Determine height to use.\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) {\n      if (!geometryComponent.width) { el.setAttribute('geometry', 'width', width); }\n      if (!geometryComponent.height) { el.setAttribute('geometry', 'height', height); }\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;\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    this.geometry.computeBoundingSphere();\n  },\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  /**\n   * Update the text geometry using `three-bmfont-text.update`.\n   */\n  updateGeometry: function (geometry, data, font) {\n    geometry.update(utils.extend({}, data, {\n      font: font,\n      width: computeWidth(data.wrapPixels, data.wrapCount, font.widthFactor),\n      text: data.value.toString().replace(/\\\\n/g, '\\n').replace(/\\\\t/g, '\\t'),\n      lineHeight: data.lineHeight || font.common.lineHeight\n    }));\n  }\n});\n\nfunction parseSide (side) {\n  switch (side) {\n    case 'back': {\n      return THREE.BackSide;\n    }\n    case 'double': {\n      return THREE.DoubleSide;\n    }\n    default: {\n      return THREE.FrontSide;\n    }\n  }\n}\n\n/**\n * Coerce some data to numbers.\n * as they will be passed directly into text creation and update\n */\nfunction coerceData (data) {\n  data = utils.clone(data);\n  if (data.lineHeight !== undefined) {\n    data.lineHeight = parseFloat(data.lineHeight);\n    if (!isFinite(data.lineHeight)) { data.lineHeight = undefined; }\n  }\n  if (data.width !== undefined) {\n    data.width = parseFloat(data.width);\n    if (!isFinite(data.width)) { data.width = undefined; }\n  }\n  return data;\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) { yOffset = 30; }\n      if (yOffset) { font.chars.map(function doOffset (ch) { ch.yoffset += yOffset; }); }\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}\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\n  return {\n    material: shader,\n    shader: shaderObject\n  };\n}\n\n/**\n * @todo Add more supported material properties (e.g., `visible`).\n */\nfunction updateBaseMaterial (material, data) {\n  material.side = data.side;\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\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},{\"../core/component\":125,\"../core/shader\":134,\"../lib/three\":173,\"../utils/\":195,\"load-bmfont\":24,\"path\":32,\"three-bmfont-text\":37}],110:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar controllerUtils = _dereq_('../utils/tracked-controls');\nvar THREE = _dereq_('../lib/three');\nvar DEFAULT_CAMERA_HEIGHT = _dereq_('../constants').DEFAULT_CAMERA_HEIGHT;\n\nvar DEFAULT_HANDEDNESS = _dereq_('../constants').DEFAULT_HANDEDNESS;\n// Vector from eyes to elbow (divided by user height).\nvar EYES_TO_ELBOW = {x: 0.175, y: -0.3, z: -0.03};\n// Vector from eyes to elbow (divided by user height).\nvar FOREARM = {x: 0, y: 0, z: -0.175};\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. 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 given value for hand. If set, we ignore 'controller' property\n */\nmodule.exports.Component = registerComponent('tracked-controls', {\n  schema: {\n    controller: {default: 0},\n    id: {type: 'string', default: ''},\n    hand: {type: 'string', default: ''},\n    idPrefix: {type: 'string', default: ''},\n    rotationOffset: {default: 0},\n    // Arm model parameters when not 6DoF.\n    armModel: {default: true},\n    headElement: {type: 'selector'}\n  },\n\n  init: function () {\n    this.axis = [0, 0, 0];\n    this.buttonStates = {};\n    this.targetControllerNumber = this.data.controller;\n\n    this.dolly = new THREE.Object3D();\n    this.controllerEuler = new THREE.Euler();\n    this.controllerEuler.order = 'YXZ';\n    this.controllerPosition = new THREE.Vector3();\n    this.controllerQuaternion = new THREE.Quaternion();\n    this.deltaControllerPosition = new THREE.Vector3();\n    this.position = new THREE.Vector3();\n    this.rotation = {};\n    this.standingMatrix = new THREE.Matrix4();\n\n    this.previousControllerPosition = new THREE.Vector3();\n    this.updateGamepad();\n  },\n\n  tick: function (time, delta) {\n    var mesh = this.el.getObject3D('mesh');\n    // Update mesh animations.\n    if (mesh && mesh.update) { mesh.update(delta / 1000); }\n    this.updateGamepad();\n    this.updatePose();\n    this.updateButtons();\n  },\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  /**\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  /**\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.findMatchingController(\n      this.system.controllers,\n      data.id,\n      data.idPrefix,\n      data.hand,\n      data.controller\n    );\n\n    this.controller = controller;\n  },\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 headCamera;\n    var headEl;\n    var headObject3D;\n    var pose;\n    var userHeight;\n\n    headEl = this.getHeadElement();\n    headObject3D = headEl.object3D;\n    headCamera = headEl.components.camera;\n    userHeight = (headCamera ? headCamera.data.userHeight : 0) || this.defaultUserHeight();\n\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(\n      EYES_TO_ELBOW.x * (hand === 'left' ? -1 : hand === 'right' ? 1 : 0),\n      EYES_TO_ELBOW.y,  // 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  /**\n   * Read pose from controller (from Gamepad API), apply transforms, apply to entity.\n   */\n  updatePose: function () {\n    var controller = this.controller;\n    var controllerEuler = this.controllerEuler;\n    var controllerPosition = this.controllerPosition;\n    var elPosition;\n    var previousControllerPosition = this.previousControllerPosition;\n    var dolly = this.dolly;\n    var el = this.el;\n    var pose;\n    var standingMatrix = this.standingMatrix;\n    var vrDisplay = this.system.vrDisplay;\n    var headEl = this.getHeadElement();\n    var headCamera = headEl.components.camera;\n    var userHeight = (headCamera ? headCamera.data.userHeight : 0) || this.defaultUserHeight();\n\n    if (!controller) { return; }\n\n    // Compose pose from Gamepad.\n    pose = controller.pose;\n    if (pose.orientation !== null) {\n      dolly.quaternion.fromArray(pose.orientation);\n    }\n\n    // controller position or arm model\n    if (pose.position !== null) {\n      dolly.position.fromArray(pose.position);\n    } else {\n      // Controller not 6DOF, apply arm model.\n      if (this.data.armModel) { this.applyArmModel(dolly.position); }\n    }\n\n    // Apply transforms, if 6DOF and in VR.\n    if (pose.position != null && vrDisplay) {\n      if (vrDisplay.stageParameters) {\n        standingMatrix.fromArray(vrDisplay.stageParameters.sittingToStandingTransform);\n        dolly.matrix.compose(dolly.position, dolly.quaternion, dolly.scale);\n        dolly.matrix.multiplyMatrices(standingMatrix, dolly.matrix);\n      } else {\n        // Apply default camera height\n        dolly.position.y += userHeight;\n        dolly.matrix.compose(dolly.position, dolly.quaternion, dolly.scale);\n      }\n    } else {\n      dolly.matrix.compose(dolly.position, dolly.quaternion, dolly.scale);\n    }\n\n    // Decompose.\n    controllerEuler.setFromRotationMatrix(dolly.matrix);\n    controllerPosition.setFromMatrixPosition(dolly.matrix);\n\n    // Apply rotation.\n    this.rotation.x = THREE.Math.radToDeg(controllerEuler.x);\n    this.rotation.y = THREE.Math.radToDeg(controllerEuler.y);\n    this.rotation.z = THREE.Math.radToDeg(controllerEuler.z) + this.data.rotationOffset;\n    el.setAttribute('rotation', this.rotation);\n\n    // Apply position.\n    elPosition = el.getAttribute('position');\n    this.position.copy(elPosition).sub(previousControllerPosition).add(controllerPosition);\n    el.setAttribute('position', this.position);\n    previousControllerPosition.copy(controllerPosition);\n  },\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\n    if (!controller) { return; }\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] = {pressed: false, touched: false, value: 0};\n      }\n\n      buttonState = controller.buttons[id];\n      this.handleButton(id, buttonState);\n    }\n    // Check axes.\n    this.handleAxes();\n  },\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 = this.handlePress(id, buttonState) ||\n                  this.handleTouch(id, buttonState) ||\n                  this.handleValue(id, buttonState);\n    if (!changed) { return false; }\n    this.el.emit('buttonchanged', {id: id, state: buttonState});\n    return true;\n  },\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 = [];\n\n    // Check if axis changed.\n    for (i = 0; i < controllerAxes.length; ++i) {\n      changedAxes.push(previousAxis[i] !== controllerAxes[i]);\n      if (changedAxes[i]) { changed = true; }\n    }\n    if (!changed) { return false; }\n\n    this.axis = controllerAxes.slice();\n    this.el.emit('axismove', {axis: this.axis, changed: changedAxes});\n    return true;\n  },\n\n  /**\n   * Determine whether a button press has occured 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) { return false; }\n\n    evtName = buttonState.pressed ? 'down' : 'up';\n    this.el.emit('button' + evtName, {id: id, state: buttonState});\n    previousButtonState.pressed = buttonState.pressed;\n    return true;\n  },\n\n  /**\n   * Determine whether a button touch has occured 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) { return false; }\n\n    evtName = buttonState.touched ? 'start' : 'end';\n    // Due to unfortunate name collision, add empty touches array to avoid Daydream error.\n    this.el.emit('touch' + evtName, {id: id, state: buttonState}, true, {touches: []});\n    previousButtonState.touched = buttonState.touched;\n    return true;\n  },\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) { return false; }\n\n    previousButtonState.value = buttonState.value;\n    return true;\n  }\n});\n\n},{\"../constants\":116,\"../core/component\":125,\"../lib/three\":173,\"../utils/tracked-controls\":199}],111:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../core/component').registerComponent;\n\n/**\n * Visibility component.\n */\nmodule.exports.Component = registerComponent('visible', {\n  schema: {default: true},\n\n  update: function () {\n    this.el.object3D.visible = this.data;\n  }\n});\n\n},{\"../core/component\":125}],112:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar utils = _dereq_('../utils/');\n\nvar bind = utils.bind;\nvar checkControllerPresentAndSetup = utils.trackedControls.checkControllerPresentAndSetup;\nvar emitIfAxesChanged = utils.trackedControls.emitIfAxesChanged;\n\nvar VIVE_CONTROLLER_MODEL_OBJ_URL = 'https://cdn.aframe.io/controllers/vive/vr_controller_vive.obj';\nvar VIVE_CONTROLLER_MODEL_OBJ_MTL = 'https://cdn.aframe.io/controllers/vive/vr_controller_vive.mtl';\n\nvar GAMEPAD_ID_PREFIX = 'OpenVR ';\n\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('vive-controls', {\n  schema: {\n    hand: {default: 'left'},\n    buttonColor: {type: 'color', default: '#FAFAFA'},  // Off-white.\n    buttonHighlightColor: {type: 'color', default: '#22D1EE'},  // Light blue.\n    model: {default: true},\n    rotationOffset: {default: 0}\n  },\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   */\n  mapping: {\n    axes: {trackpad: [0, 1]},\n    buttons: ['trackpad', 'trigger', 'grip', 'menu', 'system']\n  },\n\n  init: function () {\n    var self = this;\n    this.animationActive = 'pointing';\n    this.checkControllerPresentAndSetup = checkControllerPresentAndSetup;  // To allow mock.\n    this.controllerPresent = false;\n    this.emitIfAxesChanged = emitIfAxesChanged;  // To allow mock.\n    this.lastControllerCheck = 0;\n    this.onButtonChanged = bind(this.onButtonChanged, this);\n    this.onButtonDown = function (evt) { self.onButtonEvent(evt.detail.id, 'down'); };\n    this.onButtonUp = function (evt) { self.onButtonEvent(evt.detail.id, 'up'); };\n    this.onButtonTouchEnd = function (evt) { self.onButtonEvent(evt.detail.id, 'touchend'); };\n    this.onButtonTouchStart = function (evt) { self.onButtonEvent(evt.detail.id, 'touchstart'); };\n    this.onAxisMoved = bind(this.onAxisMoved, this);\n    this.previousButtonValues = {};\n\n    this.bindMethods();\n  },\n\n  play: function () {\n    this.checkIfControllerPresent();\n    this.addControllersUpdateListener();\n  },\n\n  pause: function () {\n    this.removeEventListeners();\n    this.removeControllersUpdateListener();\n  },\n\n  bindMethods: function () {\n    this.onModelLoaded = bind(this.onModelLoaded, this);\n    this.onControllersUpdate = bind(this.onControllersUpdate, this);\n    this.checkIfControllerPresent = bind(this.checkIfControllerPresent, this);\n    this.removeControllersUpdateListener = bind(this.removeControllersUpdateListener, this);\n    this.onAxisMoved = bind(this.onAxisMoved, this);\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('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\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  /**\n   * Once OpenVR returns correct hand data in supporting browsers, we can use hand property.\n   * var isPresent = this.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    this.checkControllerPresentAndSetup(this, GAMEPAD_ID_PREFIX, {index: controllerIndex});\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: 0 = right, 1 = left, 2 = anything else.\n      controller: data.hand === 'right' ? 0 : data.hand === 'left' ? 1 : 2,\n      rotationOffset: data.rotationOffset\n    });\n\n    // Load model.\n    if (!this.data.model) { return; }\n    this.el.setAttribute('obj-model', {\n      obj: VIVE_CONTROLLER_MODEL_OBJ_URL,\n      mtl: VIVE_CONTROLLER_MODEL_OBJ_MTL\n    });\n  },\n\n  addControllersUpdateListener: function () {\n    this.el.sceneEl.addEventListener('controllersupdated', this.onControllersUpdate, false);\n  },\n\n  removeControllersUpdateListener: function () {\n    this.el.sceneEl.removeEventListener('controllersupdated', this.onControllersUpdate, false);\n  },\n\n  onControllersUpdate: function () {\n    this.checkIfControllerPresent();\n  },\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\n    if (!button) { 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\n  onModelLoaded: function (evt) {\n    var buttonMeshes;\n    var controllerObject3D = evt.detail.model;\n    var self = this;\n\n    if (!this.data.model) { return; }\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\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\n  onAxisMoved: function (evt) {\n    this.emitIfAxesChanged(this, this.mapping.axes, evt);\n  },\n\n  onButtonEvent: function (id, evtName) {\n    var buttonName = this.mapping.buttons[id];\n    var color;\n    var i;\n    var isTouch = evtName.indexOf('touch') !== -1;\n\n    // Emit events.\n    if (Array.isArray(buttonName)) {\n      for (i = 0; i < buttonName.length; i++) {\n        this.el.emit(buttonName[i] + evtName);\n      }\n    } else {\n      this.el.emit(buttonName + evtName);\n    }\n\n    if (!this.data.model) { return; }\n\n    // Don't change color for trackpad touch.\n    if (isTouch) { return; }\n\n    // Update colors.\n    color = evtName === 'up' ? this.data.buttonColor : this.data.buttonHighlightColor;\n    if (Array.isArray(buttonName)) {\n      for (i = 0; i < buttonName.length; i++) {\n        this.setButtonColor(buttonName[i], color);\n      }\n    } else {\n      this.setButtonColor(buttonName, color);\n    }\n  },\n\n  setButtonColor: function (buttonName, color) {\n    var buttonMeshes = this.buttonMeshes;\n\n    if (!buttonMeshes) { return; }\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},{\"../core/component\":125,\"../utils/\":195}],113:[function(_dereq_,module,exports){\nvar KEYCODE_TO_CODE = _dereq_('../constants').keyboardevent.KEYCODE_TO_CODE;\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar THREE = _dereq_('../lib/three');\nvar utils = _dereq_('../utils/');\n\nvar bind = utils.bind;\nvar shouldCaptureKeyEvent = utils.shouldCaptureKeyEvent;\n\nvar CLAMP_VELOCITY = 0.00001;\nvar MAX_DELTA = 0.2;\nvar KEYS = [\n  'KeyW', 'KeyA', 'KeyS', 'KeyD',\n  'ArrowUp', 'ArrowLeft', 'ArrowRight', 'ArrowDown'\n];\n\n/**\n * WASD component to control entities using WASD keys.\n */\nmodule.exports.Component = registerComponent('wasd-controls', {\n  schema: {\n    acceleration: {default: 65},\n    adAxis: {default: 'x', oneOf: ['x', 'y', 'z']},\n    adEnabled: {default: true},\n    adInverted: {default: false},\n    easing: {default: 20},\n    enabled: {default: true},\n    fly: {default: false},\n    wsAxis: {default: 'z', oneOf: ['x', 'y', 'z']},\n    wsEnabled: {default: true},\n    wsInverted: {default: false}\n  },\n\n  init: function () {\n    // To keep track of the pressed keys.\n    this.keys = {};\n\n    this.position = {};\n    this.velocity = new THREE.Vector3();\n\n    // Bind methods and add event listeners.\n    this.onBlur = bind(this.onBlur, this);\n    this.onFocus = bind(this.onFocus, this);\n    this.onKeyDown = bind(this.onKeyDown, this);\n    this.onKeyUp = bind(this.onKeyUp, this);\n    this.onVisibilityChange = bind(this.onVisibilityChange, this);\n    this.attachVisibilityEventListeners();\n  },\n\n  tick: function (time, delta) {\n    var currentPosition;\n    var data = this.data;\n    var el = this.el;\n    var movementVector;\n    var position = this.position;\n    var velocity = this.velocity;\n\n    if (!velocity[data.adAxis] && !velocity[data.wsAxis] &&\n        isEmptyObject(this.keys)) { return; }\n\n    // Update velocity.\n    delta = delta / 1000;\n    this.updateVelocity(delta);\n\n    if (!velocity[data.adAxis] && !velocity[data.wsAxis]) { return; }\n\n    // Get movement vector and translate position.\n    currentPosition = el.getAttribute('position');\n    movementVector = this.getMovementVector(delta);\n    position.x = currentPosition.x + movementVector.x;\n    position.y = currentPosition.y + movementVector.y;\n    position.z = currentPosition.z + movementVector.z;\n    el.setAttribute('position', position);\n  },\n\n  remove: function () {\n    this.removeKeyEventListeners();\n    this.removeVisibilityEventListeners();\n  },\n\n  play: function () {\n    this.attachKeyEventListeners();\n  },\n\n  pause: function () {\n    this.keys = {};\n    this.removeKeyEventListeners();\n  },\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\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    // Decay velocity.\n    if (velocity[adAxis] !== 0) {\n      velocity[adAxis] -= velocity[adAxis] * data.easing * delta;\n    }\n    if (velocity[wsAxis] !== 0) {\n      velocity[wsAxis] -= velocity[wsAxis] * data.easing * delta;\n    }\n\n    // Clamp velocity easing.\n    if (Math.abs(velocity[adAxis]) < CLAMP_VELOCITY) { velocity[adAxis] = 0; }\n    if (Math.abs(velocity[wsAxis]) < CLAMP_VELOCITY) { velocity[wsAxis] = 0; }\n\n    if (!data.enabled) { return; }\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) { velocity[adAxis] -= adSign * acceleration * delta; }\n      if (keys.KeyD || keys.ArrowRight) { velocity[adAxis] += adSign * acceleration * delta; }\n    }\n    if (data.wsEnabled) {\n      wsSign = data.wsInverted ? -1 : 1;\n      if (keys.KeyW || keys.ArrowUp) { velocity[wsAxis] -= wsSign * acceleration * delta; }\n      if (keys.KeyS || keys.ArrowDown) { 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\n    return function (delta) {\n      var rotation = this.el.getAttribute('rotation');\n      var velocity = this.velocity;\n      var xRotation;\n\n      directionVector.copy(velocity);\n      directionVector.multiplyScalar(delta);\n\n      // Absolute.\n      if (!rotation) { return directionVector; }\n\n      xRotation = this.data.fly ? rotation.x : 0;\n\n      // Transform direction relative to heading.\n      rotationEuler.set(THREE.Math.degToRad(xRotation), THREE.Math.degToRad(rotation.y), 0);\n      directionVector.applyEuler(rotationEuler);\n      return directionVector;\n    };\n  })(),\n\n  attachVisibilityEventListeners: function () {\n    window.addEventListener('blur', this.onBlur);\n    window.addEventListener('focus', this.onFocus);\n    document.addEventListener('visibilitychange', this.onVisibilityChange);\n  },\n\n  removeVisibilityEventListeners: function () {\n    window.removeEventListener('blur', this.onBlur);\n    window.removeEventListener('focus', this.onFocus);\n    document.removeEventListener('visibilitychange', this.onVisibilityChange);\n  },\n\n  attachKeyEventListeners: function () {\n    window.addEventListener('keydown', this.onKeyDown);\n    window.addEventListener('keyup', this.onKeyUp);\n  },\n\n  removeKeyEventListeners: function () {\n    window.removeEventListener('keydown', this.onKeyDown);\n    window.removeEventListener('keyup', this.onKeyUp);\n  },\n\n  onBlur: function () {\n    this.pause();\n  },\n\n  onFocus: function () {\n    this.play();\n  },\n\n  onVisibilityChange: function () {\n    if (document.hidden) {\n      this.onBlur();\n    } else {\n      this.onFocus();\n    }\n  },\n\n  onKeyDown: function (event) {\n    var code;\n    if (!shouldCaptureKeyEvent(event)) { return; }\n    code = event.code || KEYCODE_TO_CODE[event.keyCode];\n    if (KEYS.indexOf(code) !== -1) { 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});\n\nfunction isEmptyObject (keys) {\n  var key;\n  for (key in keys) { return false; }\n  return true;\n}\n\n},{\"../constants\":116,\"../core/component\":125,\"../lib/three\":173,\"../utils/\":195}],114:[function(_dereq_,module,exports){\n/* global THREE */\nvar bind = _dereq_('../utils/bind');\nvar registerComponent = _dereq_('../core/component').registerComponent;\nvar controllerUtils = _dereq_('../utils/tracked-controls');\nvar utils = _dereq_('../utils/');\n\nvar debug = utils.debug('components:windows-motion-controls:debug');\nvar warn = utils.debug('components:windows-motion-controls:warn');\n\nvar DEFAULT_HANDEDNESS = _dereq_('../constants').DEFAULT_HANDEDNESS;\n\nvar MODEL_BASE_URL = 'https://cdn.aframe.io/controllers/microsoft/';\nvar MODEL_FILENAMES = { left: 'left.glb', right: 'right.glb', default: 'universal.glb' };\n\nvar GAMEPAD_ID_PREFIX = 'Spatial Controller (Spatial Interaction Source) ';\nvar GAMEPAD_ID_PATTERN = /([0-9a-zA-Z]+-[0-9a-zA-Z]+)$/;\n\n/**\n * Windows Motion Controller Controls Component\n * Interfaces with Windows Motion Controller controllers and maps Gamepad events to\n * common controller buttons: trackpad, trigger, grip, menu and system\n * It loads a controller model and transforms the pressed buttons\n */\nmodule.exports.Component = registerComponent('windows-motion-controls', {\n  schema: {\n    hand: {default: DEFAULT_HANDEDNESS},\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: {default: 0},\n    // If true, loads the controller glTF asset.\n    model: {default: true},\n    // If true, will hide the model from the scene if no matching gamepad (based on ID & hand) is connected.\n    hideDisconnected: {default: true}\n  },\n\n  mapping: {\n    // A-Frame specific semantic axis names\n    axes: {'thumbstick': [0, 1], 'trackpad': [2, 3]},\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: [\n      'THUMBSTICK_X',\n      'THUMBSTICK_Y',\n      'TOUCHPAD_TOUCH_X',\n      'TOUCHPAD_TOUCH_Y'\n    ],\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  },\n\n  bindMethods: function () {\n    this.onModelError = bind(this.onModelError, this);\n    this.onModelLoaded = bind(this.onModelLoaded, this);\n    this.onControllersUpdate = bind(this.onControllersUpdate, this);\n    this.checkIfControllerPresent = bind(this.checkIfControllerPresent, this);\n    this.onAxisMoved = bind(this.onAxisMoved, this);\n  },\n\n  init: function () {\n    var self = this;\n    var el = this.el;\n    this.onButtonChanged = bind(this.onButtonChanged, this);\n    this.onButtonDown = function (evt) { self.onButtonEvent(evt, 'down'); };\n    this.onButtonUp = function (evt) { self.onButtonEvent(evt, 'up'); };\n    this.onButtonTouchStart = function (evt) { self.onButtonEvent(evt, 'touchstart'); };\n    this.onButtonTouchEnd = function (evt) { self.onButtonEvent(evt, 'touchend'); };\n    this.onControllerConnected = function () { self.setModelVisibility(true); };\n    this.onControllerDisconnected = function () { self.setModelVisibility(false); };\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\n    // Stored on object to allow for mocking in tests\n    this.emitIfAxesChanged = controllerUtils.emitIfAxesChanged;\n    this.checkControllerPresentAndSetup = controllerUtils.checkControllerPresentAndSetup;\n\n    el.addEventListener('controllerconnected', this.onControllerConnected);\n    el.addEventListener('controllerdisconnected', this.onControllerDisconnected);\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    el.addEventListener('model-error', this.onModelError);\n    el.addEventListener('model-loaded', this.onModelLoaded);\n    this.controllerEventsActive = true;\n  },\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\n  checkIfControllerPresent: function () {\n    this.checkControllerPresentAndSetup(this, GAMEPAD_ID_PREFIX, {\n      hand: this.data.hand,\n      index: this.data.pair\n    });\n  },\n\n  play: function () {\n    this.checkIfControllerPresent();\n    this.addControllersUpdateListener();\n  },\n\n  pause: function () {\n    this.removeEventListeners();\n    this.removeControllersUpdateListener();\n  },\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\n    var sourceUrl = this.createControllerModelUrl();\n    this.loadModel(sourceUrl);\n  },\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\n    if (controller) {\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\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\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\n    this.updateControllerModel();\n  },\n\n  addControllersUpdateListener: function () {\n    this.el.sceneEl.addEventListener('controllersupdated', this.onControllersUpdate, false);\n  },\n\n  removeControllersUpdateListener: function () {\n    this.el.sceneEl.removeEventListener('controllersupdated', this.onControllersUpdate, false);\n  },\n\n  onControllersUpdate: function () {\n    this.checkIfControllerPresent();\n  },\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\n  loadModel: function (url) {\n    // The model is loaded by the gltf-model compoent 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\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\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\n        mesh = rootNode.getObjectByName(meshName);\n        if (!mesh) {\n          warn('Missing button mesh with name: ' + meshName);\n          continue;\n        }\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 +\n            '(VALUE: ' + !!meshInfo.value +\n            ', PRESSED: ' + !!meshInfo.pressed +\n            ', UNPRESSED:' + !!meshInfo.unpressed +\n            ')');\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\n        mesh = rootNode.getObjectByName(meshName);\n        if (!mesh) {\n          warn('Missing axis mesh with name: ' + meshName);\n          continue;\n        }\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 +\n            '(VALUE: ' + !!meshInfo.value +\n            ', MIN: ' + !!meshInfo.min +\n            ', MAX:' + !!meshInfo.max +\n            ')');\n        }\n      }\n\n      this.calculateRayOriginFromMesh(rootNode);\n      // Determine if the model has to be visible or not.\n      this.setModelVisibility();\n    }\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\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\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\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\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\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\n      var min = buttonMeshInfo.unpressed;\n      var max = buttonMeshInfo.pressed;\n      var target = buttonMeshInfo.value;\n\n      target.setRotationFromQuaternion(quaternion.copy(min.quaternion).slerp(max.quaternion, buttonValue));\n      target.position.lerpVectors(min.position, max.position, buttonValue);\n    };\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\n  onButtonChanged: function (evt) {\n    var buttonName = this.mapping.buttons[evt.detail.id];\n\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\n  onButtonEvent: function (evt, evtName) {\n    var buttonName = this.mapping.buttons[evt.detail.id];\n    debug('onButtonEvent(' + evt.detail.id + ', ' + evtName + ')');\n\n    if (buttonName) {\n      // Only emit events for buttons that we know how to map from index to name\n      this.el.emit(buttonName + evtName);\n    }\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\n    this.emitIfAxesChanged(this, this.mapping.axes, evt);\n  },\n\n  setModelVisibility: function (visible) {\n    var model = this.el.getObject3D('mesh');\n    visible = visible !== undefined ? visible : this.modelVisible;\n    this.modelVisible = visible;\n    if (!model) { return; }\n    model.visible = visible;\n  }\n});\n\n},{\"../constants\":116,\"../core/component\":125,\"../utils/\":195,\"../utils/bind\":189,\"../utils/tracked-controls\":199}],115:[function(_dereq_,module,exports){\n/**\n * Animation configuration options for TWEEN.js animations.\n * Used by `<a-animation>`.\n */\nvar TWEEN = _dereq_('@tweenjs/tween.js');\n\nvar DIRECTIONS = {\n  alternate: 'alternate',\n  alternateReverse: 'alternate-reverse',\n  normal: 'normal',\n  reverse: 'reverse'\n};\n\nvar EASING_FUNCTIONS = {\n  'linear': TWEEN.Easing.Linear.None,\n\n  'ease': TWEEN.Easing.Cubic.InOut,\n  'ease-in': TWEEN.Easing.Cubic.In,\n  'ease-out': TWEEN.Easing.Cubic.Out,\n  'ease-in-out': TWEEN.Easing.Cubic.InOut,\n\n  'ease-cubic': TWEEN.Easing.Cubic.In,\n  'ease-in-cubic': TWEEN.Easing.Cubic.In,\n  'ease-out-cubic': TWEEN.Easing.Cubic.Out,\n  'ease-in-out-cubic': TWEEN.Easing.Cubic.InOut,\n\n  'ease-quad': TWEEN.Easing.Quadratic.InOut,\n  'ease-in-quad': TWEEN.Easing.Quadratic.In,\n  'ease-out-quad': TWEEN.Easing.Quadratic.Out,\n  'ease-in-out-quad': TWEEN.Easing.Quadratic.InOut,\n\n  'ease-quart': TWEEN.Easing.Quartic.InOut,\n  'ease-in-quart': TWEEN.Easing.Quartic.In,\n  'ease-out-quart': TWEEN.Easing.Quartic.Out,\n  'ease-in-out-quart': TWEEN.Easing.Quartic.InOut,\n\n  'ease-quint': TWEEN.Easing.Quintic.InOut,\n  'ease-in-quint': TWEEN.Easing.Quintic.In,\n  'ease-out-quint': TWEEN.Easing.Quintic.Out,\n  'ease-in-out-quint': TWEEN.Easing.Quintic.InOut,\n\n  'ease-sine': TWEEN.Easing.Sinusoidal.InOut,\n  'ease-in-sine': TWEEN.Easing.Sinusoidal.In,\n  'ease-out-sine': TWEEN.Easing.Sinusoidal.Out,\n  'ease-in-out-sine': TWEEN.Easing.Sinusoidal.InOut,\n\n  'ease-expo': TWEEN.Easing.Exponential.InOut,\n  'ease-in-expo': TWEEN.Easing.Exponential.In,\n  'ease-out-expo': TWEEN.Easing.Exponential.Out,\n  'ease-in-out-expo': TWEEN.Easing.Exponential.InOut,\n\n  'ease-circ': TWEEN.Easing.Circular.InOut,\n  'ease-in-circ': TWEEN.Easing.Circular.In,\n  'ease-out-circ': TWEEN.Easing.Circular.Out,\n  'ease-in-out-circ': TWEEN.Easing.Circular.InOut,\n\n  'ease-elastic': TWEEN.Easing.Elastic.InOut,\n  'ease-in-elastic': TWEEN.Easing.Elastic.In,\n  'ease-out-elastic': TWEEN.Easing.Elastic.Out,\n  'ease-in-out-elastic': TWEEN.Easing.Elastic.InOut,\n\n  'ease-back': TWEEN.Easing.Back.InOut,\n  'ease-in-back': TWEEN.Easing.Back.In,\n  'ease-out-back': TWEEN.Easing.Back.Out,\n  'ease-in-out-back': TWEEN.Easing.Back.InOut,\n\n  'ease-bounce': TWEEN.Easing.Bounce.InOut,\n  'ease-in-bounce': TWEEN.Easing.Bounce.In,\n  'ease-out-bounce': TWEEN.Easing.Bounce.Out,\n  'ease-in-out-bounce': TWEEN.Easing.Bounce.InOut\n};\n\nvar FILLS = {\n  backwards: 'backwards',\n  both: 'both',\n  forwards: 'forwards',\n  none: 'none'\n};\n\nvar REPEATS = {\n  indefinite: 'indefinite'\n};\n\nvar DEFAULTS = {\n  attribute: 'rotation',\n  begin: '',\n  end: '',\n  delay: 0,\n  dur: 1000,\n  easing: 'ease',\n  direction: DIRECTIONS.normal,\n  fill: FILLS.forwards,\n  from: undefined,\n  repeat: 0,\n  to: undefined\n};\n\nmodule.exports.defaults = DEFAULTS;\nmodule.exports.directions = DIRECTIONS;\nmodule.exports.easingFunctions = EASING_FUNCTIONS;\nmodule.exports.fills = FILLS;\nmodule.exports.repeats = REPEATS;\n\n},{\"@tweenjs/tween.js\":1}],116:[function(_dereq_,module,exports){\nmodule.exports = {\n  AFRAME_INJECTED: 'aframe-injected',\n  DEFAULT_CAMERA_HEIGHT: 1.6,\n  DEFAULT_HANDEDNESS: 'right',\n  animation: _dereq_('./animation'),\n  keyboardevent: _dereq_('./keyboardevent')\n};\n\n},{\"./animation\":115,\"./keyboardevent\":117}],117:[function(_dereq_,module,exports){\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},{}],118:[function(_dereq_,module,exports){\nvar ANode = _dereq_('./a-node');\nvar animationConstants = _dereq_('../constants/animation');\nvar coordinates = _dereq_('../utils/').coordinates;\nvar parseProperty = _dereq_('./schema').parseProperty;\nvar registerElement = _dereq_('./a-register-element').registerElement;\nvar TWEEN = _dereq_('@tweenjs/tween.js');\nvar THREE = _dereq_('../lib/three');\nvar utils = _dereq_('../utils/');\nvar bind = utils.bind;\n\nvar getComponentProperty = utils.entity.getComponentProperty;\nvar DEFAULTS = animationConstants.defaults;\nvar DIRECTIONS = animationConstants.directions;\nvar EASING_FUNCTIONS = animationConstants.easingFunctions;\nvar FILLS = animationConstants.fills;\nvar REPEATS = animationConstants.repeats;\nvar isCoordinates = coordinates.isCoordinates;\n\n/**\n * Animation element that applies Tween animation to parent element (entity).\n * Takes after the Web Animations spec.\n *\n * @member {number} count - Decrementing counter for how many cycles of animations left to\n *         run.\n * @member {Element} el - Entity which the animation is modifying.\n * @member initialValue - Value before animation started. Used to restore state.\n * @member {bool} isRunning - Whether animation is currently running.\n * @member {function} partialSetAttribute -\n *   setAttribute function that is agnostic to whether we are setting an attribute value\n *   or a component property value. The el and the attribute names are bundled with\n *   the function.\n * @member {object} tween - tween.js object.\n */\nmodule.exports.AAnimation = registerElement('a-animation', {\n  prototype: Object.create(ANode.prototype, {\n    createdCallback: {\n      value: function () {\n        this.bindMethods();\n        this.isRunning = false;\n        this.partialSetAttribute = function () { /* no-op */ };\n        this.tween = null;\n      }\n    },\n\n    attachedCallback: {\n      value: function () {\n        this.el = this.parentNode;\n        this.handleMixinUpdate();\n        this.update();\n        this.load();\n      }\n    },\n\n    attributeChangedCallback: {\n      value: function (attr, oldVal, newVal) {\n        if (!this.hasLoaded || !this.isRunning) { return; }\n        this.stop();\n        this.handleMixinUpdate();\n        this.update();\n      }\n    },\n\n    detachedCallback: {\n      value: function () {\n        if (!this.isRunning) { return; }\n        this.stop();\n      }\n    },\n\n    /**\n     * Builds a Tween object to handle animations.\n     * Uses tween.js's from, to, delay, easing, repeat, onUpdate, and onComplete.\n     * Note: tween.js takes objects for its `from` and `to` values.\n     *\n     * @returns {object}\n     */\n    getTween: {\n      value: function () {\n        var self = this;\n        var data = self.data;\n        var el = self.el;\n        var animationValues;\n        var attribute = data.attribute;\n        var delay = parseInt(data.delay, 10);\n        var currentValue = getComponentProperty(el, attribute);\n        var direction = self.getDirection(data.direction);\n        var easing = EASING_FUNCTIONS[data.easing];\n        var fill = data.fill;\n        var from;\n        var repeat = data.repeat === REPEATS.indefinite ? Infinity : 0;\n        var to;\n        var toTemp;\n        var yoyo = false;\n\n        animationValues = getAnimationValues(el, attribute, data.from || self.initialValue, data.to, currentValue);\n        from = animationValues.from;\n        to = animationValues.to;\n        self.partialSetAttribute = animationValues.partialSetAttribute;\n\n        if (self.count === undefined) {\n          self.count = repeat === Infinity ? 0 : parseInt(data.repeat, 10);\n        }\n\n        if (isNaN(delay)) { delay = 0; }\n\n        // Store initial state.\n        self.initialValue = self.initialValue || cloneValue(currentValue);\n\n        // Handle indefinite + forwards + alternate yoyo edge-case (#405).\n        if (repeat === Infinity && fill === FILLS.forwards &&\n            [DIRECTIONS.alternate,\n              DIRECTIONS.alternateReverse].indexOf(data.direction) !== -1) {\n          yoyo = true;\n        }\n\n        // If reversing, swap from and to.\n        if (direction === DIRECTIONS.reverse) {\n          toTemp = to;\n          to = cloneValue(from);\n          from = cloneValue(toTemp);\n        }\n\n        // If fill is backwards or both, start animation at the specified from.\n        if ([FILLS.backwards, FILLS.both].indexOf(fill) !== -1) {\n          self.partialSetAttribute(from);\n        }\n\n        // Create Tween.\n        return new TWEEN.Tween(cloneValue(from))\n          .to(to, data.dur)\n          .delay(delay)\n          .easing(easing)\n          .repeat(repeat)\n          .yoyo(yoyo)\n          .onUpdate(function () {\n            self.partialSetAttribute(this);\n          })\n          .onComplete(bind(self.onCompleted, self));\n      }\n    },\n\n    /**\n     * Animation parameters changed. Stop current animation, get a new one, and start it.\n     */\n    update: {\n      value: function () {\n        var data = this.data;\n        // Terminology warning if infinite used instead of indefinite\n        if (data.repeat === 'infinite') {\n          console.warn(\"Using 'infinite' as 'repeat' value is invalid.  Use 'indefinite' instead.\");\n        }\n        // Deprecation warning for begin when used as a delay.\n        if (data.begin !== '' && !isNaN(data.begin)) {\n          console.warn(\"Using 'begin' to specify a delay is deprecated. Use 'delay' instead.\");\n          data.delay = data.begin;\n          data.begin = '';\n        }\n        var begin = data.begin;\n        var end = data.end;\n        // Cancel previous event listeners\n        if (this.evt) { this.removeEventListeners(this.evt); }\n        // Store new event name.\n        this.evt = {begin: begin, end: end};\n        // Add new event listeners\n        this.addEventListeners(this.evt);\n        // If `begin` is not defined, start the animation right away.\n        if (begin === '') {\n          this.stop();\n          this.start();\n        }\n      },\n      writable: window.debug\n    },\n\n    /**\n     * Callback for when a cycle of an animation is complete. Handles when to completely\n     * finish the animation.\n     *\n     * If `repeat` is set to a value, this method is called after each repeat. Repeats are\n     * handled by ending the current animation and creating a new one with `count` updated.\n     * Note that this method is *not* called if repeat is set to `indefinite`.\n     */\n    onCompleted: {\n      value: function () {\n        var data = this.data;\n        this.isRunning = false;\n        if ([FILLS.backwards, FILLS.none].indexOf(data.fill) !== -1) {\n          this.partialSetAttribute(this.initialValue);\n        }\n        if (this.count === 0) {\n          this.count = undefined;\n          this.emit('animationend');\n          return;\n        }\n        this.isRunning = false;\n        this.count--;\n        this.start();\n      }\n    },\n\n    start: {\n      value: function () {\n        var self = this;\n        // Postpone animation start until the entity has loaded\n        if (!this.el.hasLoaded) {\n          this.el.addEventListener('loaded', function () { self.start(); });\n          return;\n        }\n        if (this.isRunning || !this.el.isPlaying) { return; }\n        this.tween = this.getTween();\n        this.isRunning = true;\n        this.tween.start();\n        this.emit('animationstart');\n      },\n      writable: true\n    },\n\n    stop: {\n      value: function () {\n        var tween = this.tween;\n        if (!tween) { return; }\n        tween.stop();\n        this.isRunning = false;\n        if ([FILLS.backwards, FILLS.none].indexOf(this.data.fill) !== -1) {\n          this.partialSetAttribute(this.initialValue);\n        }\n        this.emit('animationstop');\n      },\n      writable: true\n    },\n\n    /**\n     * Handle alternating directions. Given the current direction, calculate the next one,\n     * and store the current one.\n     *\n     * @param {string} direction\n     * @returns {string} Direction that the next individual cycle of the animation will go\n     *          towards.\n     */\n    getDirection: {\n      value: function (direction) {\n        if (direction === DIRECTIONS.alternate) {\n          this.prevDirection =\n            this.prevDirection === DIRECTIONS.normal ? DIRECTIONS.reverse : DIRECTIONS.normal;\n          return this.prevDirection;\n        }\n        if (direction === DIRECTIONS.alternateReverse) {\n          this.prevDirection =\n            this.prevDirection === DIRECTIONS.reverse ? DIRECTIONS.normal : DIRECTIONS.reverse;\n          return this.prevDirection;\n        }\n        return direction;\n      }\n    },\n\n    /**\n     * Preemptive binding to attach/detach event listeners (see `update`).\n     */\n    bindMethods: {\n      value: function () {\n        this.start = bind(this.start, this);\n        this.stop = bind(this.stop, this);\n        this.onStateAdded = bind(this.onStateAdded, this);\n        this.onStateRemoved = bind(this.onStateRemoved, this);\n      }\n    },\n\n    addEventListeners: {\n      value: function (evts) {\n        var el = this.el;\n        var self = this;\n        utils.splitString(evts.begin).forEach(function (evt) {\n          el.addEventListener(evt, self.start);\n        });\n        utils.splitString(evts.end).forEach(function (evt) {\n          el.addEventListener(evt, self.stop);\n        });\n        // If \"begin\" is an event name, wait. If it is not defined, start.\n        if (evts.begin === '') { el.addEventListener('play', this.start); }\n        el.addEventListener('pause', this.stop);\n        el.addEventListener('stateadded', this.onStateAdded);\n        el.addEventListener('stateremoved', this.onStateRemoved);\n      }\n    },\n\n    removeEventListeners: {\n      value: function (evts) {\n        var el = this.el;\n        var start = this.start;\n        var stop = this.stop;\n        utils.splitString(evts.begin).forEach(function (evt) {\n          el.removeEventListener(evt, start);\n        });\n        utils.splitString(evts.end).forEach(function (evt) {\n          el.removeEventListener(evt, stop);\n        });\n        el.removeEventListener('stateadded', this.onStateAdded);\n        el.removeEventListener('stateremoved', this.onStateRemoved);\n      }\n    },\n\n    onStateAdded: {\n      value: function (evt) {\n        if (evt.detail.state === this.data.begin) { this.start(); }\n      },\n      writable: true\n    },\n\n    onStateRemoved: {\n      value: function (evt) {\n        if (evt.detail.state === this.data.begin) { this.stop(); }\n      },\n      writable: true\n    },\n\n    /**\n     * Applies animation data from a mixin element.\n     * Works the same as component mixins but reimplemented because animations\n     * aren't components.\n     */\n    handleMixinUpdate: {\n      value: function () {\n        var data = {};\n        var elData;\n        var mixinData;\n        var mixinEl;\n\n        // Get mixin data.\n        mixinEl = document.querySelector('#' + this.getAttribute('mixin'));\n        mixinData = mixinEl ? utils.getElData(mixinEl, DEFAULTS) : {};\n\n        elData = utils.getElData(this, DEFAULTS);\n        utils.extend(data, DEFAULTS, mixinData, elData);\n        this.data = data;\n      }\n    }\n  })\n});\n\nfunction cloneValue (val) {\n  return utils.extend({}, val);\n}\n\n/**\n * Deduces different animation values based on whether we are:\n *   - animating an inner attribute of a component.\n *   - animating a coordinate component.\n *   - animating a boolean.\n *   - animating a number.\n *\n * @param {Element} el\n * @param {string} attribute - Tells what to animate based on whether it is dot-separated.\n * @param {string} dataFrom - Data `from` value.\n * @param {string} dataTo - Data `to` value.\n * @param currentValue\n * @returns {object}\n *   Object with keys [from, to, partialSetAttribute].\n *     `from` and `to`\n *        Objects where key is attribute being animated and value is value.\n *     `partialSetAttribute`\n *        Closured-function that tells tween how to update the component.\n */\nfunction getAnimationValues (el, attribute, dataFrom, dataTo, currentValue) {\n  var attributeSplit = attribute.split('.');\n  var schema;\n  var component;\n  var componentPropName;\n  var componentName;\n  var from = {};\n  var partialSetAttribute;\n  var to = {};\n  if (attributeSplit.length === 2) {\n    if (isColor()) {\n      getForColorComponent();\n    } else {\n      getForComponentAttribute();\n    }\n  } else if (dataTo && isCoordinates(dataTo)) {\n    getForCoordinateComponent();\n  } else if (['true', 'false'].indexOf(dataTo) !== -1) {\n    getForBoolean();\n  } else if (isNaN(dataTo)) {\n    getForColorComponent();\n  } else {\n    getForNumber();\n  }\n  return {\n    from: from,\n    partialSetAttribute: partialSetAttribute,\n    to: to\n  };\n\n  /**\n   * Match the schema type to color\n   * @return {bool} if the schema is of type color\n   */\n  function isColor () {\n    var componentName = attributeSplit[0];\n    var propertyName = attributeSplit[1];\n    var component = el.components[componentName];\n    var schema = component && component.schema;\n    return schema && schema[propertyName] && schema[propertyName].type === 'color';\n  }\n\n  /**\n   * Animating a component that has multiple attributes (e.g., geometry.width).\n   */\n  function getForComponentAttribute () {\n    componentName = attributeSplit[0];\n    componentPropName = attributeSplit[1];\n    component = el.components[componentName];\n    if (!component) {\n      el.setAttribute(componentName, '');\n      component = el.components[componentName];\n    }\n    schema = component.schema;\n    if (dataFrom === undefined) {  // dataFrom can be 0.\n      from[attribute] = getComponentProperty(el, attribute);\n    } else {\n      from[attribute] = dataFrom;\n    }\n    from[attribute] = parseProperty(from[attribute], schema[componentPropName]);\n    to[attribute] = parseProperty(dataTo, schema[componentPropName]);\n    partialSetAttribute = function (value) {\n      if (!(attribute in value)) { return; }\n      el.setAttribute(componentName, componentPropName, value[attribute]);\n    };\n  }\n\n  /**\n   * Animating a component that is an XYZ coordinate (e.g., position).\n   * Will be tweening {x, y, z} all at once.\n   */\n  function getForCoordinateComponent () {\n    from = dataFrom ? coordinates.parse(dataFrom) : currentValue;\n    to = coordinates.parse(dataTo);\n    partialSetAttribute = function (value) {\n      el.setAttribute(attribute, value);\n    };\n  }\n\n  /**\n   * Animation a boolean (e.g., visible).\n   * Have to convert from boolean to an integer (0 is false, > 0 is true) for tween.\n   */\n  function getForBoolean () {\n    if (dataFrom === undefined) {\n      from[attribute] = false;\n    } else {\n      from[attribute] = strToBool(dataFrom);\n    }\n    from[attribute] = boolToNum(from[attribute]);\n    to[attribute] = boolToNum(strToBool(dataTo));\n    partialSetAttribute = function (value) {\n      el.setAttribute(attribute, !!value[attribute]);\n    };\n  }\n\n  /**\n   * Animating a color component\n   *   Will convert a hex value to a THREE.Color\n   *   Then converts to hex for the setAttribute\n   */\n  function getForColorComponent () {\n    from = new THREE.Color(dataFrom || el.getAttribute(attribute));\n    to = new THREE.Color(dataTo);\n    partialSetAttribute = function (value) {\n      if (attributeSplit.length > 1) {\n        el.setAttribute(attributeSplit[0], attributeSplit[1], rgbVectorToHex(value));\n      }\n      el.setAttribute(attribute, rgbVectorToHex(value));\n    };\n  }\n\n  /**\n   * Animating a numbered attribute (e.g., opacity).\n   */\n  function getForNumber () {\n    if (dataFrom === undefined) {  // dataFrom can be 0.\n      from[attribute] = parseFloat(el.getAttribute(attribute));\n    } else {\n      from[attribute] = parseFloat(dataFrom);\n    }\n    to[attribute] = parseFloat(dataTo);\n    partialSetAttribute = function (value) {\n      el.setAttribute(attribute, value[attribute]);\n    };\n  }\n}\nmodule.exports.getAnimationValues = getAnimationValues;\n\n/**\n * Converts string to bool.\n *\n * @param {string} str - `true` or `false`.\n * @returns {bool}\n */\nfunction strToBool (str) {\n  if (str === 'true') { return true; }\n  return false;\n}\n\n/**\n * Converts boolean to number.\n *\n * @param {bool}\n * @returns {number}\n */\nfunction boolToNum (bool) {\n  return bool ? 1 : 0;\n}\n\n/**\n * Converts a number 0-255 to hex\n * @param {number} color number 0 - 255\n * @returns {string} hex value of number bassed\n */\nfunction componentToHex (color) {\n  var hex = color.toString(16);\n  return hex.length === 1 ? '0' + hex : hex;\n}\n\n/**\n * Clamps a number to 0-1\n * Then converts that number to 0-255\n * @param {number} color number 0 - 1\n * @returns {number} color number 0 - 255\n */\nfunction convertToIntegerColor (color) {\n  return Math.floor(Math.min(Math.abs(color), 1) * 255);\n}\n\n/**\n * Converts a rgb object into a hex string\n * @param {object} color { r: 1, g: 1, b: 1 }\n * @returns {string} hex value #ffffff\n */\nfunction rgbVectorToHex (color) {\n  return '#' + ['r', 'g', 'b'].map(function (prop) {\n    return componentToHex(convertToIntegerColor(color[prop]));\n  }).join('');\n}\n\n},{\"../constants/animation\":115,\"../lib/three\":173,\"../utils/\":195,\"./a-node\":123,\"./a-register-element\":124,\"./schema\":133,\"@tweenjs/tween.js\":1}],119:[function(_dereq_,module,exports){\nvar ANode = _dereq_('./a-node');\nvar bind = _dereq_('../utils/bind');\nvar debug = _dereq_('../utils/debug');\nvar registerElement = _dereq_('./a-register-element').registerElement;\nvar THREE = _dereq_('../lib/three');\n\nvar fileLoader = new THREE.FileLoader();\nvar warn = debug('core:a-assets:warn');\n\n/**\n * Asset management system. Handles blocking on asset loading.\n */\nmodule.exports = registerElement('a-assets', {\n  prototype: Object.create(ANode.prototype, {\n    createdCallback: {\n      value: function () {\n        this.isAssets = true;\n        this.fileLoader = fileLoader;\n        this.timeout = null;\n      }\n    },\n\n    attachedCallback: {\n      value: function () {\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\n        if (!this.parentNode.isScene) {\n          throw new Error('<a-assets> must be a child of a <a-scene>.');\n        }\n\n        // Wait for <img>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.files[imgEls[i].getAttribute('src')] = imgEl;\n            imgEl.onload = resolve;\n            imgEl.onerror = reject;\n          }));\n        }\n\n        // Wait for <audio>s and <video>s.\n        mediaEls = this.querySelectorAll('audio, video');\n        for (i = 0; i < mediaEls.length; i++) {\n          mediaEl = fixUpMediaElement(mediaEls[i]);\n          loaded.push(mediaElementLoaded(mediaEl));\n        }\n\n        // Trigger loaded for scene to start rendering.\n        Promise.all(loaded).then(bind(this.load, this));\n\n        // Timeout to start loading anyways.\n        timeout = parseInt(this.getAttribute('timeout'), 10) || 3000;\n        this.timeout = setTimeout(function () {\n          if (self.hasLoaded) { return; }\n          warn('Asset loading timed out in ', timeout, 'ms');\n          self.emit('timeout');\n          self.load();\n        }, timeout);\n      }\n    },\n\n    detachedCallback: {\n      value: function () {\n        if (this.timeout) { clearTimeout(this.timeout); }\n      }\n    },\n\n    load: {\n      value: function () {\n        ANode.prototype.load.call(this, null, function waitOnFilter (el) {\n          return el.isAssetItem && el.hasAttribute('src');\n        });\n      }\n    }\n  })\n});\n\n/**\n * Preload using XHRLoader for any type of asset.\n */\nregisterElement('a-asset-item', {\n  prototype: Object.create(ANode.prototype, {\n    createdCallback: {\n      value: function () {\n        this.data = null;\n        this.isAssetItem = true;\n      }\n    },\n\n    attachedCallback: {\n      value: function () {\n        var self = this;\n        var src = this.getAttribute('src');\n        fileLoader.setResponseType(\n          this.getAttribute('response-type') || inferResponseType(src));\n        fileLoader.load(src, function handleOnLoad (response) {\n          self.data = response;\n          /*\n            Workaround for a Chrome bug. If another XHR is sent to the same url before the\n            previous one closes, the second request never finishes.\n            setTimeout finishes the first request and lets the logic triggered by load open\n            subsequent requests.\n            setTimeout can be removed once the fix for the bug below ships:\n            https://bugs.chromium.org/p/chromium/issues/detail?id=633696&q=component%3ABlink%3ENetwork%3EXHR%20&colspec=ID%20Pri%20M%20Stars%20ReleaseBlock%20Component%20Status%20Owner%20Summary%20OS%20Modified\n          */\n          setTimeout(function load () { ANode.prototype.load.call(self); });\n        }, function handleOnProgress (xhr) {\n          self.emit('progress', {\n            loadedBytes: xhr.loaded,\n            totalBytes: xhr.total,\n            xhr: xhr\n          });\n        }, function handleOnError (xhr) {\n          self.emit('error', {xhr: xhr});\n        });\n      }\n    }\n  })\n});\n\n/**\n * Create a Promise that resolves once the media element has finished buffering.\n *\n * @param {Element} el - HTMLMediaElement.\n * @returns {Promise}\n */\nfunction mediaElementLoaded (el) {\n  if (!el.hasAttribute('autoplay') && el.getAttribute('preload') !== 'auto') {\n    return;\n  }\n\n  // If media specifies autoplay or preload, wait until media is completely buffered.\n  return new Promise(function (resolve, reject) {\n    if (el.readyState === 4) { return resolve(); }  // Already loaded.\n    if (el.error) { return reject(); }  // Error.\n\n    el.addEventListener('loadeddata', checkProgress, false);\n    el.addEventListener('progress', checkProgress, false);\n    el.addEventListener('error', reject, false);\n\n    function checkProgress () {\n      // Add up the seconds buffered.\n      var secondsBuffered = 0;\n      for (var i = 0; i < el.buffered.length; i++) {\n        secondsBuffered += el.buffered.end(i) - el.buffered.start(i);\n      }\n\n      // Compare seconds buffered to media duration.\n      if (secondsBuffered >= el.duration) {\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.files[el.getAttribute('src')] = el;\n        resolve();\n      }\n    }\n  });\n}\n\n/**\n * Automatically add attributes to media elements where convenient.\n * crossorigin, playsinline.\n */\nfunction fixUpMediaElement (mediaEl) {\n  // Cross-origin.\n  var newMediaEl = setCrossOrigin(mediaEl);\n\n  // Plays inline for mobile.\n  if (newMediaEl.tagName && newMediaEl.tagName.toLowerCase() === 'video') {\n    newMediaEl.setAttribute('playsinline', '');\n    newMediaEl.setAttribute('webkit-playsinline', '');\n  }\n\n  if (newMediaEl !== mediaEl) {\n    mediaEl.parentNode.appendChild(newMediaEl);\n    mediaEl.parentNode.removeChild(mediaEl);\n  }\n  return newMediaEl;\n}\n\n/**\n * Automatically set `crossorigin` if not defined on the media element.\n * If it is not defined, we must create and re-append a new media element <img> and\n * have the browser re-request it with `crossorigin` set.\n *\n * @param {Element} Media element (e.g., <img>, <audio>, <video>).\n * @returns {Element} Media element to be used to listen to for loaded events.\n */\nfunction setCrossOrigin (mediaEl) {\n  var newMediaEl;\n  var src;\n\n  // Already has crossorigin set.\n  if (mediaEl.hasAttribute('crossorigin')) { return mediaEl; }\n\n  src = mediaEl.getAttribute('src');\n\n  if (src !== null) {\n    // Does not have protocol.\n    if (src.indexOf('://') === -1) { return mediaEl; }\n\n    // Determine if cross origin is actually needed.\n    if (extractDomain(src) === window.location.host) { return mediaEl; }\n  }\n\n  warn('Cross-origin element (e.g., <img>) was requested without `crossorigin` set. ' +\n       'A-Frame will re-request the asset with `crossorigin` attribute set. ' +\n       'Please set `crossorigin` on the element (e.g., <img crossorigin=\"anonymous\">)', src);\n  mediaEl.crossOrigin = 'anonymous';\n  newMediaEl = mediaEl.cloneNode(true);\n  return newMediaEl;\n}\n\n/**\n * Extract domain out of URL.\n *\n * @param {string} url\n * @returns {string}\n */\nfunction extractDomain (url) {\n  // Find and remove protocol (e.g., http, ftp, etc.) to get domain.\n  var domain = url.indexOf('://') > -1 ? url.split('/')[2] : url.split('/')[0];\n\n  // Find and remove port number.\n  return domain.split(':')[0];\n}\n\n/**\n * Infer response-type attribute from src.\n * Default is text(default XMLHttpRequest.responseType)\n * but we use arraybuffer for .gltf and .glb files\n * because of THREE.GLTFLoader specification.\n *\n * @param {string} src\n * @returns {string}\n */\nfunction inferResponseType (src) {\n  var dotLastIndex = src.lastIndexOf('.');\n  if (dotLastIndex >= 0) {\n    var extension = src.slice(dotLastIndex, src.length);\n    if (extension === '.gltf' || extension === '.glb') {\n      return 'arraybuffer';\n    }\n  }\n  return 'text';\n}\nmodule.exports.inferResponseType = inferResponseType;\n\n},{\"../lib/three\":173,\"../utils/bind\":189,\"../utils/debug\":191,\"./a-node\":123,\"./a-register-element\":124}],120:[function(_dereq_,module,exports){\nvar debug = _dereq_('../utils/debug');\nvar registerElement = _dereq_('./a-register-element').registerElement;\n\nvar warn = debug('core:cubemap:warn');\n\n/**\n * Cubemap element that handles validation and exposes list of URLs.\n * Does not listen to updates.\n */\nmodule.exports = registerElement('a-cubemap', {\n  prototype: Object.create(window.HTMLElement.prototype, {\n    /**\n     * Calculates this.srcs.\n     */\n    attachedCallback: {\n      value: function () {\n        this.srcs = this.validate();\n      },\n      writable: window.debug\n    },\n\n    /**\n     * Checks for exactly six elements with [src].\n     * Does not check explicitly for <img>s in case user does not want\n     * prefetching.\n     *\n     * @returns {Array|null} - six URLs if valid, else null.\n     */\n    validate: {\n      value: function () {\n        var elements = this.querySelectorAll('[src]');\n        var i;\n        var srcs = [];\n        if (elements.length === 6) {\n          for (i = 0; i < elements.length; i++) {\n            srcs.push(elements[i].getAttribute('src'));\n          }\n          return srcs;\n        }\n        // Else if there are not six elements, throw a warning.\n        warn(\n          '<a-cubemap> did not contain exactly six elements each with a ' +\n          '`src` attribute.');\n      },\n      writable: window.debug\n    }\n  })\n});\n\n},{\"../utils/debug\":191,\"./a-register-element\":124}],121:[function(_dereq_,module,exports){\nvar ANode = _dereq_('./a-node');\nvar COMPONENTS = _dereq_('./component').components;\nvar registerElement = _dereq_('./a-register-element').registerElement;\nvar THREE = _dereq_('../lib/three');\nvar utils = _dereq_('../utils/');\n\nvar AEntity;\nvar bind = utils.bind;\nvar debug = utils.debug('core:a-entity:debug');\nvar warn = utils.debug('core:a-entity:warn');\n\nvar MULTIPLE_COMPONENT_DELIMITER = '__';\n\n/**\n * Entity is a container object that components are plugged into to comprise everything in\n * the scene. In A-Frame, they inherently have position, rotation, and scale.\n *\n * To be able to take components, the scene element inherits from the entity definition.\n *\n * @member {object} components - entity's currently initialized components.\n * @member {object} object3D - three.js object.\n * @member {array} states\n * @member {boolean} isPlaying - false if dynamic behavior of the entity is paused.\n */\nvar proto = Object.create(ANode.prototype, {\n  defaultComponents: {\n    value: {\n      position: '',\n      rotation: '',\n      scale: '',\n      visible: ''\n    }\n  },\n\n  createdCallback: {\n    value: function () {\n      this.components = {};\n      // To avoid double initializations and infinite loops.\n      this.initializingComponents = {};\n      this.isEntity = true;\n      this.isPlaying = false;\n      this.object3D = new THREE.Group();\n      this.object3D.el = this;\n      this.object3DMap = {};\n      this.parentEl = null;\n      this.states = [];\n    }\n  },\n\n  /**\n   * Handle changes coming from the browser DOM inspector.\n   */\n  attributeChangedCallback: {\n    value: function (attr, oldVal, newVal) {\n      var component = this.components[attr];\n      // If the empty string is passed by the component initialization\n      // logic we ignore the component update.\n      if (component && component.justInitialized && newVal === '') {\n        delete component.justInitialized;\n        return;\n      }\n      // When a component is removed after calling el.removeAttribute('material')\n      if (!component && newVal === null) { return; }\n      this.setEntityAttribute(attr, oldVal, newVal);\n    }\n  },\n\n  /**\n   * Add to parent, load, play.\n   */\n  attachedCallback: {\n    value: function () {\n      var assetsEl;  // Asset management system element.\n      var sceneEl = this.sceneEl;\n      var self = this;  // Component.\n\n      this.addToParent();\n\n      // Don't .load() scene on attachedCallback.\n      if (this.isScene) { return; }\n\n      // Gracefully not error when outside of <a-scene> (e.g., tests).\n      if (!sceneEl) {\n        this.load();\n        return;\n      }\n\n      // Wait for asset management system to finish before loading.\n      assetsEl = sceneEl.querySelector('a-assets');\n      if (assetsEl && !assetsEl.hasLoaded) {\n        assetsEl.addEventListener('loaded', function () { self.load(); });\n        return;\n      }\n      this.load();\n    }\n  },\n\n  /**\n   * Tell parent to remove this element's object3D from its object3D.\n   * Do not call on scene element because that will cause a call to document.body.remove().\n   */\n  detachedCallback: {\n    value: function () {\n      var componentName;\n\n      if (!this.parentEl) { return; }\n\n      // Remove components.\n      for (componentName in this.components) { this.removeComponent(componentName); }\n\n      if (this.isScene) { return; }\n\n      this.removeFromParent();\n      ANode.prototype.detachedCallback.call(this);\n\n      // Remove cyclic reference.\n      this.object3D.el = null;\n    }\n  },\n\n  /**\n   * Apply mixin to component.\n   */\n  handleMixinUpdate: {\n    value: function (attrName) {\n      if (!attrName) {\n        this.updateComponents();\n        return;\n      }\n      this.updateComponent(attrName, this.getDOMAttribute(attrName));\n    }\n  },\n\n  /**\n   * Add new mixin for each mixin with state suffix.\n   */\n  mapStateMixins: {\n    value: function (state, op) {\n      var mixins;\n      var mixinIds;\n      var i;\n\n      mixins = this.getAttribute('mixin');\n\n      if (!mixins) { return; }\n      mixinIds = mixins.split(' ');\n      for (i = 0; i < mixinIds.length; i++) {\n        op(mixinIds[i] + '-' + state);\n      }\n      this.updateComponents();\n    }\n  },\n\n  /**\n   * Handle update of mixin states (e.g., `box-hovered` where `box` is the mixin ID and\n   * `hovered` is the entity state.\n   */\n  updateStateMixins: {\n    value: function (newMixins, oldMixins) {\n      var diff;\n      var newMixinIds;\n      var oldMixinIds;\n      var i;\n      var j;\n      var stateMixinEls;\n\n      newMixinIds = newMixins.split(' ');\n      oldMixinIds = (oldMixins || '') ? oldMixins.split(' ') : [];\n\n      // List of mixins that might have been removed on update.\n      diff = oldMixinIds.filter(function (i) { return newMixinIds.indexOf(i) < 0; });\n\n      // Remove removed mixins.\n      for (i = 0; i < diff.length; i++) {\n        stateMixinEls = document.querySelectorAll('[id^=' + diff[i] + '-]');\n        for (j = 0; j < stateMixinEls.length; j++) {\n          this.unregisterMixin(stateMixinEls[j].id);\n        }\n      }\n\n      // Add new mixins.\n      for (i = 0; i < this.states.length; i++) {\n        for (j = 0; j < newMixinIds.length; j++) {\n          this.registerMixin(newMixinIds[j] + '-' + this.states[i]);\n        }\n      }\n    }\n  },\n\n  getObject3D: {\n    value: function (type) {\n      return this.object3DMap[type];\n    }\n  },\n\n  /**\n   * Set a THREE.Object3D into the map.\n   *\n   * @param {string} type - Developer-set name of the type of object, will be unique per type.\n   * @param {object} obj - A THREE.Object3D.\n   */\n  setObject3D: {\n    value: function (type, obj) {\n      var oldObj;\n      var self = this;\n\n      if (!(obj instanceof THREE.Object3D)) {\n        throw new Error(\n          '`Entity.setObject3D` was called with an object that was not an instance of ' +\n          'THREE.Object3D.'\n        );\n      }\n\n      // Remove existing object of the type.\n      oldObj = this.getObject3D(type);\n      if (oldObj) { this.object3D.remove(oldObj); }\n\n      // Set references to A-Frame entity.\n      obj.el = this;\n      if (obj.children.length) {\n        obj.traverse(function bindEl (child) {\n          child.el = self;\n        });\n      }\n\n      // Add.\n      this.object3D.add(obj);\n      this.object3DMap[type] = obj;\n      this.emit('object3dset', {object: obj, type: type});\n    }\n  },\n\n  /**\n   * Remove object from scene and entity object3D map.\n   */\n  removeObject3D: {\n    value: function (type) {\n      var obj = this.getObject3D(type);\n      if (!obj) {\n        warn('Tried to remove `Object3D` of type:', type, 'which was not defined.');\n        return;\n      }\n      this.object3D.remove(obj);\n      delete this.object3DMap[type];\n      this.emit('object3dremove', {type: type});\n    }\n  },\n\n  /**\n   * Gets or creates an object3D of a given type.\n   *\n   * @param {string} type - Type of the object3D.\n   * @param {string} Constructor - Constructor to use to create the object3D if needed.\n   * @returns {object}\n   */\n  getOrCreateObject3D: {\n    value: function (type, Constructor) {\n      var object3D = this.getObject3D(type);\n      if (!object3D && Constructor) {\n        object3D = new Constructor();\n        this.setObject3D(type, object3D);\n      }\n      return object3D;\n    }\n  },\n\n  /**\n   * Add child entity.\n   *\n   * @param {Element} el - Child entity.\n   */\n  add: {\n    value: function (el) {\n      if (!el.object3D) {\n        throw new Error(\"Trying to add an element that doesn't have an `object3D`\");\n      }\n      this.object3D.add(el.object3D);\n      this.emit('child-attached', {el: el});\n    }\n  },\n\n  /**\n   * Tell parentNode to add this entity to itself.\n   */\n  addToParent: {\n    value: function () {\n      var parentNode = this.parentEl = this.parentNode;\n\n      // `!parentNode` check primarily for unit tests.\n      if (!parentNode || !parentNode.add || this.attachedToParent) { return; }\n\n      parentNode.add(this);\n      this.attachedToParent = true;  // To prevent multiple attachments to same parent.\n    }\n  },\n\n  /**\n   * Tell parentNode to remove this entity from itself.\n   */\n  removeFromParent: {\n    value: function () {\n      var parentEl = this.parentEl;\n      this.parentEl.remove(this);\n      this.attachedToParent = false;\n      this.parentEl = this.parentNode = null;\n      parentEl.emit('child-detached', {el: this});\n    }\n  },\n\n  load: {\n    value: function () {\n      var self = this;\n\n      if (this.hasLoaded || !this.parentEl) { return; }\n\n      ANode.prototype.load.call(this, function entityLoadCallback () {\n        // Check if entity was detached while it was waiting to load.\n        if (!self.parentEl) { return; }\n\n        self.updateComponents();\n        if (self.isScene || self.parentEl.isPlaying) { self.play(); }\n      });\n    },\n    writable: window.debug\n  },\n\n  /**\n   * Remove child entity.\n   *\n   * @param {Element} el - Child entity.\n   */\n  remove: {\n    value: function (el) {\n      this.object3D.remove(el.object3D);\n    }\n  },\n\n  /**\n   * @returns {array} Direct children that are entities.\n   */\n  getChildEntities: {\n    value: function () {\n      var children = this.children;\n      var childEntities = [];\n\n      for (var i = 0; i < children.length; i++) {\n        var child = children[i];\n        if (child instanceof AEntity) {\n          childEntities.push(child);\n        }\n      }\n\n      return childEntities;\n    }\n  },\n\n  /**\n   * Initialize component.\n   *\n   * @param {string} attrName - Attribute name asociated to the component.\n   * @param {object} data - Component data\n   * @param {boolean} isDependency - True if the component is a dependency.\n   */\n  initComponent: {\n    value: function (attrName, data, isDependency) {\n      var component;\n      var componentInfo = attrName.split(MULTIPLE_COMPONENT_DELIMITER);\n      var componentId = componentInfo[1];\n      var componentName = componentInfo[0];\n      var isComponentDefined = checkComponentDefined(this, attrName) || data !== undefined;\n\n      // Not a registered component.\n      if (!COMPONENTS[componentName]) { return; }\n\n      // Component is not a dependency and is undefined.\n      // If a component is a dependency, then it is okay to have no data.\n      if (!isComponentDefined && !isDependency) { return; }\n\n      // Component already initialized.\n      if (attrName in this.components) { return; }\n\n      // Initialize dependencies first\n      this.initComponentDependencies(componentName);\n\n      // If component name has an id we check component type multiplic\n      if (componentId && !COMPONENTS[componentName].multiple) {\n        throw new Error('Trying to initialize multiple ' +\n                        'components of type `' + componentName +\n                        '`. There can only be one component of this type per entity.');\n      }\n      component = new COMPONENTS[componentName].Component(this, data, componentId);\n      if (this.isPlaying) { component.play(); }\n\n      // Components are reflected in the DOM as attributes but the state is not shown\n      // hence we set the attribute to empty string.\n      // The flag justInitialized is for attributeChangedCallback to not overwrite\n      // the component with the empty string.\n      if (!this.hasAttribute(attrName)) {\n        component.justInitialized = true;\n        window.HTMLElement.prototype.setAttribute.call(this, attrName, '');\n      }\n\n      debug('Component initialized: %s', attrName);\n    },\n    writable: window.debug\n  },\n\n  /**\n   * Initialize dependencies of a component.\n   *\n   * @param {string} name - Root component name.\n   */\n  initComponentDependencies: {\n    value: function (name) {\n      var self = this;\n      var component = COMPONENTS[name];\n      var dependencies;\n      var i;\n\n      // Not a component.\n      if (!component) { return; }\n\n      // No dependencies.\n      dependencies = COMPONENTS[name].dependencies;\n\n      if (!dependencies) { return; }\n\n      // Initialize dependencies.\n      for (i = 0; i < dependencies.length; i++) {\n        // Call getAttribute to initialize the data from the DOM.\n        self.initComponent(\n          dependencies[i],\n          window.HTMLElement.prototype.getAttribute.call(self, dependencies[i]) || undefined,\n          true\n        );\n      }\n    }\n  },\n\n  removeComponent: {\n    value: function (name) {\n      var component;\n      var isDefault;\n      var isMixedIn;\n\n      // Don't remove default or mixed-in components.\n      isDefault = name in this.defaultComponents;\n      isMixedIn = isComponentMixedIn(name, this.mixinEls);\n      if (isDefault || isMixedIn) { return; }\n\n      component = this.components[name];\n      if (!component) { return; }\n\n      // Wait for component to initialize.\n      if (!component.initialized) {\n        this.addEventListener('componentinitialized', function tryRemoveLater (evt) {\n          if (evt.detail.name !== name) { return; }\n          this.removeComponent(name);\n          this.removeEventListener('componentinitialized', tryRemoveLater);\n        });\n        return;\n      }\n\n      component.pause();\n      component.remove();\n      delete this.components[name];\n      this.emit('componentremoved', component.evtDetail);\n    },\n    writable: window.debug\n  },\n\n  /**\n   * Initialize or update all components.\n   * Build data using initial components, defined attributes, mixins, and defaults.\n   * Update default components before the rest.\n   *\n   * @member {function} getExtraComponents - Can be implemented to include component data\n   *   from other sources (e.g., implemented by primitives).\n   */\n  updateComponents: {\n    value: (function () {\n      var componentsToUpdate = {};\n\n      return function () {\n        var data;\n        var extraComponents;\n        var i;\n        var name;\n\n        if (!this.hasLoaded) { return; }\n\n        // Gather mixin-defined components.\n        for (i = 0; i < this.mixinEls.length; i++) {\n          for (name in this.mixinEls[i].componentCache) {\n            if (isComponent(name)) { componentsToUpdate[name] = true; }\n          }\n        }\n\n        // Gather from extra initial component data if defined (e.g., primitives).\n        if (this.getExtraComponents) {\n          extraComponents = this.getExtraComponents();\n          for (name in extraComponents) {\n            if (isComponent(name)) { componentsToUpdate[name] = true; }\n          }\n        }\n\n        // Gather entity-defined components.\n        for (i = 0; i < this.attributes.length; ++i) {\n          name = this.attributes[i].name;\n          if (isComponent(name)) { componentsToUpdate[name] = true; }\n        }\n\n        // Initialze or update default components first.\n        for (name in this.defaultComponents) {\n          data = mergeComponentData(this.getDOMAttribute(name),\n                                    extraComponents && extraComponents[name]);\n          this.updateComponent(name, data);\n          delete componentsToUpdate[name];\n        }\n\n        // Initialize or update rest of components.\n        for (name in componentsToUpdate) {\n          data = mergeComponentData(this.getDOMAttribute(name),\n                                    extraComponents && extraComponents[name]);\n          this.updateComponent(name, data);\n          delete componentsToUpdate[name];\n        }\n      };\n    })(),\n    writable: window.debug\n  },\n\n  /**\n   * Initialize, update, or remove a single component.\n   *\n   * When initializing, we set the component on `this.components`.\n   *\n   * @param {string} attr - Component name.\n   * @param {object} attrValue - Value of the DOM attribute.\n   * @param {boolean} clobber - If new attrValue completely replaces previous properties.\n   */\n  updateComponent: {\n    value: function (attr, attrValue, clobber) {\n      var component = this.components[attr];\n      var isDefault = attr in this.defaultComponents;\n      if (component) {\n        // Remove component.\n        if (attrValue === null && !isDefault) {\n          this.removeComponent(attr);\n          return;\n        }\n        // Component already initialized. Update component.\n        component.updateProperties(attrValue, clobber);\n        return;\n      }\n\n      // Component not yet initialized. Initialize component.\n      this.initComponent(attr, attrValue, false);\n    }\n  },\n\n  /**\n   * If `attr` is a component name, detach the component from the entity.\n   *\n   * If `propertyName` is given, reset the component property value to its default.\n   *\n   * @param {string} attr - Attribute name, which could also be a component name.\n   * @param {string} propertyName - Component prop name, if resetting an individual prop.\n   */\n  removeAttribute: {\n    value: function (attr, propertyName) {\n      var component = this.components[attr];\n\n      // Remove component.\n      if (component && propertyName === undefined) {\n        this.setEntityAttribute(attr, undefined, null);\n        // Do not remove the component from the DOM if default component.\n        if (this.components[attr]) { return; }\n      }\n\n      // Reset component property value.\n      if (component && propertyName !== undefined) {\n        component.resetProperty(propertyName);\n        return;\n      }\n\n      // Remove mixins.\n      if (attr === 'mixin') {\n        this.mixinUpdate('');\n      }\n\n      window.HTMLElement.prototype.removeAttribute.call(this, attr);\n    }\n  },\n\n  /**\n   * Start dynamic behavior associated with entity such as dynamic components and animations.\n   * Tell all children entities to also play.\n   */\n  play: {\n    value: function () {\n      var entities;\n      var i;\n      var key;\n\n      // Already playing.\n      if (this.isPlaying || !this.hasLoaded) { return; }\n      this.isPlaying = true;\n\n      // Wake up all components.\n      for (key in this.components) { this.components[key].play(); }\n\n      // Tell all child entities to play.\n      entities = this.getChildEntities();\n      for (i = 0; i < entities.length; i++) { entities[i].play(); }\n\n      this.emit('play');\n    },\n    writable: true\n  },\n\n  /**\n   * Pause dynamic behavior associated with entity such as dynamic components and animations.\n   * Tell all children entities to also pause.\n   */\n  pause: {\n    value: function () {\n      var entities;\n      var i;\n      var key;\n\n      if (!this.isPlaying) { return; }\n      this.isPlaying = false;\n\n      // Sleep all components.\n      for (key in this.components) { this.components[key].pause(); }\n\n      // Tell all child entities to pause.\n      entities = this.getChildEntities();\n      for (i = 0; i < entities.length; i++) { entities[i].pause(); }\n\n      this.emit('pause');\n    },\n    writable: true\n  },\n\n  /**\n   * Deals with updates on entity-specific attributes (i.e., components and mixins).\n   *\n   * @param {string} attr\n   * @param {string} oldVal\n   * @param {string|object} newVal\n   */\n  setEntityAttribute: {\n    value: function (attr, oldVal, newVal) {\n      if (COMPONENTS[attr] || this.components[attr]) {\n        this.updateComponent(attr, newVal);\n        return;\n      }\n      if (attr === 'mixin') {\n        this.mixinUpdate(newVal, oldVal);\n        return;\n      }\n    }\n  },\n\n  mixinUpdate: {\n    value: function (newMixins, oldMixins) {\n      oldMixins = oldMixins || this.getAttribute('mixin');\n      this.updateMixins(newMixins, oldMixins);\n      this.updateStateMixins(newMixins, oldMixins);\n      this.updateComponents();\n    }\n  },\n\n  /**\n   * setAttribute can:\n   *\n   * 1. Set a single property of a multi-property component.\n   * 2. Set multiple properties of a multi-property component.\n   * 3. Replace properties of a multi-property component.\n   * 4. Set a value for a single-property component, mixin, or normal HTML attribute.\n   *\n   * @param {string} attrName - Component or attribute name.\n   * @param {*} arg1 - Can be a value, property name, CSS-style property string, or\n   *   object of properties.\n   * @param {*|bool} arg2 - If arg1 is a property name, this should be a value. Otherwise,\n   *   it is a boolean indicating whether to clobber previous values (defaults to false).\n   */\n  setAttribute: {\n    value: function (attrName, arg1, arg2) {\n      var newAttrValue;\n      var clobber;\n      var componentName;\n      var delimiterIndex;\n      var isDebugMode;\n\n      delimiterIndex = attrName.indexOf(MULTIPLE_COMPONENT_DELIMITER);\n      componentName = delimiterIndex > 0 ? attrName.substring(0, delimiterIndex) : attrName;\n\n      // Not a component. Normal set attribute.\n      if (!COMPONENTS[componentName]) {\n        ANode.prototype.setAttribute.call(this, attrName, arg1);\n        if (attrName === 'mixin') { this.mixinUpdate(arg1); }\n        return;\n      }\n\n      // Initialize component first if not yet initialized.\n      if (!this.components[attrName] && this.hasAttribute(attrName)) {\n        this.updateComponent(attrName,\n                             window.HTMLElement.prototype.getAttribute.call(this, attrName));\n      }\n\n      // Determine new attributes from the arguments\n      if (typeof arg2 !== 'undefined' &&\n          typeof arg1 === 'string' &&\n          arg1.length > 0 &&\n          typeof utils.styleParser.parse(arg1) === 'string') {\n        // Update a single property of a multi-property component\n        newAttrValue = {};\n        newAttrValue[arg1] = arg2;\n        clobber = false;\n      } else {\n        // Update with a value, object, or CSS-style property string, with the possiblity\n        // of clobbering previous values.\n        newAttrValue = arg1;\n        clobber = (arg2 === true);\n      }\n\n      // Update component\n      this.updateComponent(attrName, newAttrValue, clobber);\n\n      // In debug mode, write component data up to the DOM.\n      isDebugMode = this.sceneEl && this.sceneEl.getAttribute('debug');\n      if (isDebugMode) { this.components[attrName].flushToDOM(); }\n    },\n    writable: window.debug\n  },\n\n  /**\n   * Reflect component data in the DOM (as seen from the browser DOM Inspector).\n   *\n   * @param {bool} recursive - Also flushToDOM on the children.\n   **/\n  flushToDOM: {\n    value: function (recursive) {\n      var components = this.components;\n      var defaultComponents = this.defaultComponents;\n      var child;\n      var children = this.children;\n      var i;\n      var key;\n\n      // Flush entity's components to DOM.\n      for (key in components) {\n        components[key].flushToDOM(key in defaultComponents);\n      }\n\n      // Recurse.\n      if (!recursive) { return; }\n      for (i = 0; i < children.length; ++i) {\n        child = children[i];\n        if (!child.flushToDOM) { continue; }\n        child.flushToDOM(recursive);\n      }\n    }\n  },\n\n  /**\n   * If `attr` is a component, returns ALL component data including applied mixins and\n   * defaults.\n   *\n   * If `attr` is not a component, fall back to HTML getAttribute.\n   *\n   * @param {string} attr\n   * @returns {object|string} Object if component, else string.\n   */\n  getAttribute: {\n    value: function (attr) {\n      // If component, return component data.\n      var component = this.components[attr];\n      if (component) { return component.data; }\n      return window.HTMLElement.prototype.getAttribute.call(this, attr);\n    },\n    writable: window.debug\n  },\n\n  /**\n   * `getAttribute` used to be `getDOMAttribute` and `getComputedAttribute` used to be\n   * what `getAttribute` is now. Now legacy code.\n   *\n   * @param {string} attr\n   * @returns {object|string} Object if component, else string.\n   */\n  getComputedAttribute: {\n    value: function (attr) {\n      warn('`getComputedAttribute` is deprecated. Use `getAttribute` instead.');\n      return this.getAttribute(attr);\n    }\n  },\n\n  /**\n   * If `attr` is a component, returns JUST the component data defined on the entity.\n   * Like a partial version of `getComputedAttribute` as returned component data\n   * does not include applied mixins or defaults.\n   *\n   * If `attr` is not a component, fall back to HTML getAttribute.\n   *\n   * @param {string} attr\n   * @returns {object|string} Object if component, else string.\n   */\n  getDOMAttribute: {\n    value: function (attr) {\n      // If cached value exists, return partial component data.\n      var component = this.components[attr];\n      if (component) { return component.attrValue; }\n      return window.HTMLElement.prototype.getAttribute.call(this, attr);\n    },\n    writable: window.debug\n  },\n\n  addState: {\n    value: function (state) {\n      if (this.is(state)) { return; }\n      this.states.push(state);\n      this.mapStateMixins(state, bind(this.registerMixin, this));\n      this.emit('stateadded', {state: state});\n    }\n  },\n\n  removeState: {\n    value: function (state) {\n      var stateIndex = this.states.indexOf(state);\n      if (stateIndex === -1) { return; }\n      this.states.splice(stateIndex, 1);\n      this.mapStateMixins(state, bind(this.unregisterMixin, this));\n      this.emit('stateremoved', {state: state});\n    }\n  },\n\n  /**\n   * Checks if the element is in a given state. e.g. el.is('alive');\n   * @type {string} state - Name of the state we want to check\n   */\n  is: {\n    value: function (state) {\n      return this.states.indexOf(state) !== -1;\n    }\n  }\n});\n\n/**\n * Check if a component is *defined* for an entity, including defaults and mixins.\n * Does not check whether the component has been *initialized* for an entity.\n *\n * @param {string} el - Entity.\n * @param {string} name - Component name.\n * @returns {boolean}\n */\nfunction checkComponentDefined (el, name) {\n  // Check if default components contain the component.\n  if (el.defaultComponents[name] !== undefined) { return true; }\n\n  // Check if element contains the component.\n  if (el.components[name] && el.components[name].attrValue) { return true; }\n\n  return isComponentMixedIn(name, el.mixinEls);\n}\n\n/**\n * Check if any mixins contains a component.\n *\n * @param {string} name - Component name.\n * @param {array} mixinEls - Array of <a-mixin>s.\n */\nfunction isComponentMixedIn (name, mixinEls) {\n  var i;\n  var inMixin = false;\n  for (i = 0; i < mixinEls.length; ++i) {\n    inMixin = mixinEls[i].hasAttribute(name);\n    if (inMixin) { break; }\n  }\n  return inMixin;\n}\n\n/**\n * Given entity defined value, merge in extra data if necessary.\n * Handle both single and multi-property components.\n *\n * @param {string} attrValue - Entity data.\n * @param extraData - Entity data from another source to merge in.\n */\nfunction mergeComponentData (attrValue, extraData) {\n  // Extra data not defined, just return attrValue.\n  if (!extraData) { return attrValue; }\n\n  // Merge multi-property data.\n  if (extraData.constructor === Object) {\n    return utils.extend(extraData, utils.styleParser.parse(attrValue || {}));\n  }\n\n  // Return data, precendence to the defined value.\n  return attrValue || extraData;\n}\n\nfunction isComponent (componentName) {\n  if (componentName.indexOf(MULTIPLE_COMPONENT_DELIMITER) !== -1) {\n    componentName = componentName.split(MULTIPLE_COMPONENT_DELIMITER)[0];\n  }\n  if (!COMPONENTS[componentName]) { return false; }\n  return true;\n}\n\nAEntity = registerElement('a-entity', {prototype: proto});\nmodule.exports = AEntity;\n\n},{\"../lib/three\":173,\"../utils/\":195,\"./a-node\":123,\"./a-register-element\":124,\"./component\":125}],122:[function(_dereq_,module,exports){\nvar ANode = _dereq_('./a-node');\nvar registerElement = _dereq_('./a-register-element').registerElement;\nvar components = _dereq_('./component').components;\n\nvar MULTIPLE_COMPONENT_DELIMITER = '__';\n\n/**\n * @member {object} componentCache - Cache of pre-parsed values. An object where the keys\n *         are component names and the values are already parsed by the component.\n */\nmodule.exports = registerElement('a-mixin', {\n  prototype: Object.create(ANode.prototype, {\n    createdCallback: {\n      value: function () {\n        this.componentCache = {};\n        this.id = this.getAttribute('id');\n      }\n    },\n\n    attributeChangedCallback: {\n      value: function (attr, oldVal, newVal) {\n        this.cacheAttribute(attr, newVal);\n      }\n    },\n\n    attachedCallback: {\n      value: function () {\n        this.sceneEl = this.closestScene();\n        this.cacheAttributes();\n        this.updateEntities();\n        this.load();\n      }\n    },\n\n    /**\n     * setAttribute that parses and caches component values.\n     */\n    setAttribute: {\n      value: function (attr, value) {\n        this.cacheAttribute(attr, value);\n        window.HTMLElement.prototype.setAttribute.call(this, attr, value);\n      }\n    },\n\n    /**\n     * If `attr` is a component, then parse the value using the schema and store it.\n     */\n    cacheAttribute: {\n      value: function (attr, value) {\n        var componentName = attr.split(MULTIPLE_COMPONENT_DELIMITER)[0];\n        var component = components[componentName];\n        if (!component) { return; }\n        if (value === undefined) {\n          value = window.HTMLElement.prototype.getAttribute.call(this, attr);\n        }\n        this.componentCache[attr] = component.parseAttrValueForCache(value);\n      }\n    },\n\n    /**\n     * If `attr` is a component, then grab pre-parsed value from the cache.\n     * Else do a normal getAttribute.\n     */\n    getAttribute: {\n      value: function (attr) {\n        return this.componentCache[attr] ||\n               window.HTMLElement.prototype.getAttribute.call(this, attr);\n      }\n    },\n\n    /**\n     * Parse and cache every component defined on the mixin.\n     */\n    cacheAttributes: {\n      value: function () {\n        var attributes = this.attributes;\n        var attrName;\n        var i;\n        for (i = 0; i < attributes.length; i++) {\n          attrName = attributes[i].name;\n          this.cacheAttribute(attrName);\n        }\n      }\n    },\n\n    /**\n     * For entities that already have been loaded by the time the mixin was attached, tell\n     * those entities to register the mixin and refresh their component data.\n     */\n    updateEntities: {\n      value: function () {\n        if (!this.sceneEl) { return; }\n        var entities = this.sceneEl.querySelectorAll('[mixin~=' + this.id + ']');\n        for (var i = 0; i < entities.length; i++) {\n          var entity = entities[i];\n          if (!entity.hasLoaded) { continue; }\n          entity.registerMixin(this.id);\n          Object.keys(this.componentCache).forEach(function updateComponent (componentName) {\n            entity.updateComponent(componentName);\n          });\n        }\n      }\n    }\n  })\n});\n\n},{\"./a-node\":123,\"./a-register-element\":124,\"./component\":125}],123:[function(_dereq_,module,exports){\n/* global MutationObserver */\nvar registerElement = _dereq_('./a-register-element').registerElement;\nvar isNode = _dereq_('./a-register-element').isNode;\nvar utils = _dereq_('../utils/');\n\nvar bind = utils.bind;\nvar warn = utils.debug('core:a-node:warn');\n\n/**\n * Base class for A-Frame that manages loading of objects.\n *\n * Nodes can be modified using mixins.\n * Nodes emit a `loaded` event when they and their children have initialized.\n */\nmodule.exports = registerElement('a-node', {\n  prototype: Object.create(window.HTMLElement.prototype, {\n    createdCallback: {\n      value: function () {\n        this.hasLoaded = false;\n        this.isNode = true;\n        this.mixinEls = [];\n        this.mixinObservers = {};\n      },\n      writable: window.debug\n    },\n\n    attachedCallback: {\n      value: function () {\n        var mixins;\n        this.sceneEl = this.closestScene();\n\n        if (!this.sceneEl) {\n          warn('You are attempting to attach <' + this.tagName + '> outside of an A-Frame ' +\n               'scene. Append this element to `<a-scene>` instead.');\n        }\n\n        this.hasLoaded = false;\n        this.emit('nodeready', {}, false);\n\n        mixins = this.getAttribute('mixin');\n        if (mixins) { this.updateMixins(mixins); }\n      },\n      writable: window.debug\n    },\n\n    attributeChangedCallback: {\n      value: function (attr, oldVal, newVal) {\n        if (attr === 'mixin') { this.updateMixins(newVal, oldVal); }\n      }\n    },\n\n   /**\n    * Returns the first scene by traversing up the tree starting from and\n    * including receiver element.\n    */\n    closestScene: {\n      value: function closest () {\n        var element = this;\n        while (element) {\n          if (element.isScene) { break; }\n          element = element.parentElement;\n        }\n        return element;\n      }\n    },\n\n    /**\n     * Returns first element matching a selector by traversing up the tree starting\n     * from and including receiver element.\n     *\n     * @param {string} selector - Selector of element to find.\n     */\n    closest: {\n      value: function closest (selector) {\n        var matches = this.matches || this.mozMatchesSelector ||\n          this.msMatchesSelector || this.oMatchesSelector || this.webkitMatchesSelector;\n        var element = this;\n        while (element) {\n          if (matches.call(element, selector)) { break; }\n          element = element.parentElement;\n        }\n        return element;\n      }\n    },\n\n    detachedCallback: {\n      value: function () {\n        this.hasLoaded = false;\n      }\n    },\n\n    /**\n     * Wait for children to load, if any.\n     * Then emit `loaded` event and set `hasLoaded`.\n     */\n    load: {\n      value: function (cb, childFilter) {\n        var children;\n        var childrenLoaded;\n        var self = this;\n\n        if (this.hasLoaded) { return; }\n\n        // Default to waiting for all nodes.\n        childFilter = childFilter || isNode;\n        // Wait for children to load (if any), then load.\n        children = this.getChildren();\n        childrenLoaded = children.filter(childFilter).map(function (child) {\n          return new Promise(function waitForLoaded (resolve) {\n            if (child.hasLoaded) { return resolve(); }\n            child.addEventListener('loaded', resolve);\n          });\n        });\n\n        Promise.all(childrenLoaded).then(function emitLoaded () {\n          self.hasLoaded = true;\n          if (cb) { cb(); }\n          self.emit('loaded', undefined, false);\n        });\n      },\n      writable: true\n    },\n\n    getChildren: {\n      value: function () {\n        return Array.prototype.slice.call(this.children, 0);\n      }\n    },\n\n    /**\n     * Remove old mixins and mixin listeners.\n     * Add new mixins and mixin listeners.\n     */\n    updateMixins: {\n      value: function (newMixins, oldMixins) {\n        var newMixinIds = newMixins ? newMixins.trim().split(/\\s+/) : [];\n        var oldMixinIds = oldMixins ? oldMixins.trim().split(/\\s+/) : [];\n\n        // Unregister old mixins.\n        oldMixinIds.filter(function (i) {\n          return newMixinIds.indexOf(i) < 0;\n        }).forEach(bind(this.unregisterMixin, this));\n\n        // Register new mixins.\n        this.mixinEls = [];\n        newMixinIds.forEach(bind(this.registerMixin, this));\n      }\n    },\n\n    registerMixin: {\n      value: function (mixinId) {\n        if (!this.sceneEl) { return; }\n        var mixinEl = this.sceneEl.querySelector('a-mixin#' + mixinId);\n        if (!mixinEl) { return; }\n        this.attachMixinListener(mixinEl);\n        this.mixinEls.push(mixinEl);\n      }\n    },\n\n    setAttribute: {\n      value: function (attr, newValue) {\n        if (attr === 'mixin') { this.updateMixins(newValue); }\n        window.HTMLElement.prototype.setAttribute.call(this, attr, newValue);\n      }\n    },\n\n    unregisterMixin: {\n      value: function (mixinId) {\n        var mixinEls = this.mixinEls;\n        var mixinEl;\n        var i;\n        for (i = 0; i < mixinEls.length; ++i) {\n          mixinEl = mixinEls[i];\n          if (mixinId === mixinEl.id) {\n            mixinEls.splice(i, 1);\n            break;\n          }\n        }\n        this.removeMixinListener(mixinId);\n      }\n    },\n\n    removeMixinListener: {\n      value: function (mixinId) {\n        var observer = this.mixinObservers[mixinId];\n        if (!observer) { return; }\n        observer.disconnect();\n        this.mixinObservers[mixinId] = null;\n      }\n    },\n\n    attachMixinListener: {\n      value: function (mixinEl) {\n        var self = this;\n        var mixinId = mixinEl.id;\n        var currentObserver = this.mixinObservers[mixinId];\n        if (!mixinEl) { return; }\n        if (currentObserver) { return; }\n        var observer = new MutationObserver(function (mutations) {\n          var attr = mutations[0].attributeName;\n          self.handleMixinUpdate(attr);\n        });\n        var config = { attributes: true };\n        observer.observe(mixinEl, config);\n        this.mixinObservers[mixinId] = observer;\n      }\n    },\n\n    handleMixinUpdate: {\n      value: function () { /* no-op */ }\n    },\n\n    /**\n     * Emit a DOM event.\n     *\n     * @param {string} name - Name of event.\n     * @param {object} [detail={}] - Custom data to pass as `detail` to the event.\n     * @param {boolean} [bubbles=true] - Whether the event should bubble.\n     * @param {object} [extraData] - Extra data to pass to the event, if any.\n     */\n    emit: {\n      value: function (name, detail, bubbles, extraData) {\n        var data;\n        var self = this;\n        if (bubbles === undefined) { bubbles = true; }\n        data = {bubbles: !!bubbles, detail: detail};\n        if (extraData) { utils.extend(data, extraData); }\n        return utils.fireEvent(self, name, data);\n      },\n      writable: window.debug\n    },\n\n    /**\n     * Return a closure that emits a DOM event.\n     *\n     * @param {String} name\n     *   Name of event (use a space-delimited string for multiple events).\n     * @param {Object} detail\n     *   Custom data (optional) to pass as `detail` if the event is to\n     *   be a `CustomEvent`.\n     * @param {Boolean} bubbles\n     *   Whether the event should be bubble.\n     */\n    emitter: {\n      value: function (name, detail, bubbles) {\n        var self = this;\n        return function () {\n          self.emit(name, detail, bubbles);\n        };\n      }\n    }\n  })\n});\n\n},{\"../utils/\":195,\"./a-register-element\":124}],124:[function(_dereq_,module,exports){\n/*\n  ------------------------------------------------------------\n  ------------- WARNING WARNING WARNING WARNING --------------\n  ------------------------------------------------------------\n\n  This module wraps registerElement to deal with components that inherit from\n  `ANode` and `AEntity`.  It's a pass through in any other case.\n\n  It wraps some of the prototype methods of the created element to make sure\n  that the corresponding functions in the base prototypes (`AEntity` and `ANode`)\n  are also invoked. The method in the base prototype is always called before the one\n  in the derived prototype.\n*/\n\n// Polyfill `document.registerElement`.\n_dereq_('document-register-element');\n\nvar ANode;  // Must declare before AEntity. Initialized at the bottom.\nvar AEntity;\nvar knownTags = module.exports.knownTags = {};\n\nfunction addTagName (tagName) {\n  knownTags[tagName.toLowerCase()] = true;\n}\n\n/**\n * Return whether the element type is one of our known registered ones.\n *\n * @param {string} node - The name of the tag to register.\n * @returns {boolean} Whether the tag name matches that of our registered custom elements.\n */\nmodule.exports.isNode = function (node) {\n  return node.tagName.toLowerCase() in knownTags || node.isNode;\n};\n\n/**\n * @param {string} tagName - The name of the tag to register.\n * @param {object} obj - The prototype of the new element.\n * @returns {object} The prototype of the new element.\n */\nmodule.exports.registerElement = function (tagName, obj) {\n  var proto = Object.getPrototypeOf(obj.prototype);\n  var newObj = obj;\n  var isANode = ANode && proto === ANode.prototype;\n  var isAEntity = AEntity && proto === AEntity.prototype;\n\n  if (isANode || isAEntity) { addTagName(tagName); }\n\n  // Wrap if element inherits from `ANode`.\n  if (isANode) {\n    newObj = wrapANodeMethods(obj.prototype);\n    newObj = {prototype: Object.create(proto, newObj)};\n  }\n\n  // Wrap if element inherits from `AEntity`.\n  if (isAEntity) {\n    newObj = wrapAEntityMethods(obj.prototype);\n    newObj = {prototype: Object.create(proto, newObj)};\n  }\n\n  return document.registerElement(tagName, newObj);\n};\n\n/**\n * Wrap some obj methods to call those on `ANode` base prototype.\n *\n * @param {object} obj - Object that contains the methods that will be wrapped.\n * @return {object} An object with the same properties as the input parameter but\n * with some of methods wrapped.\n */\nfunction wrapANodeMethods (obj) {\n  var newObj = {};\n  var ANodeMethods = [\n    'attachedCallback',\n    'attributeChangedCallback',\n    'createdCallback'\n  ];\n  wrapMethods(newObj, ANodeMethods, obj, ANode.prototype);\n  copyProperties(obj, newObj);\n  return newObj;\n}\n\n/**\n * This wraps some of the obj methods to call those on `AEntity` base prototype.\n *\n * @param {object} obj - The objects that contains the methods that will be wrapped.\n * @return {object} - An object with the same properties as the input parameter but\n * with some of methods wrapped.\n */\nfunction wrapAEntityMethods (obj) {\n  var newObj = {};\n  var ANodeMethods = [\n    'attachedCallback',\n    'attributeChangedCallback',\n    'createdCallback'\n  ];\n  var AEntityMethods = [\n    'attachedCallback',\n    'attributeChangedCallback',\n    'createdCallback',\n    'detachedCallback'\n  ];\n\n  wrapMethods(newObj, ANodeMethods, obj, ANode.prototype);\n  wrapMethods(newObj, AEntityMethods, obj, AEntity.prototype);\n  // Copies the remaining properties into the new object.\n  copyProperties(obj, newObj);\n  return newObj;\n}\n\n/**\n * Wrap a list a methods to ensure that those in the base prototype are called\n * before the derived one.\n *\n * @param {object} targetObj - Object that will contain the wrapped methods.\n * @param {array} methodList - List of methods from the derivedObj that will be wrapped.\n * @param {object} derivedObject - Object that inherits from the baseObj.\n * @param {object} baseObj - Object that derivedObj inherits from.\n */\nfunction wrapMethods (targetObj, methodList, derivedObj, baseObj) {\n  methodList.forEach(function (methodName) {\n    wrapMethod(targetObj, methodName, derivedObj, baseObj);\n  });\n}\nmodule.exports.wrapMethods = wrapMethods;\n\n/**\n * Wrap one method to ensure that the one in the base prototype is called before\n * the one in the derived one.\n *\n * @param {object} obj - Object that will contain the wrapped method.\n * @param {string} methodName - The name of the method that will be wrapped.\n * @param {object} derivedObject - Object that inherits from the baseObj.\n * @param {object} baseObj - Object that derivedObj inherits from.\n */\nfunction wrapMethod (obj, methodName, derivedObj, baseObj) {\n  var derivedMethod = derivedObj[methodName];\n  var baseMethod = baseObj[methodName];\n\n  // Derived prototype does not define method, no need to wrap.\n  if (!derivedMethod || !baseMethod) { return; }\n\n  // Derived prototype doesn't override the one in the base one, no need to wrap.\n  if (derivedMethod === baseMethod) { return; }\n\n  // Wrap to ensure the base method is called before the one in the derived prototype.\n  obj[methodName] = {\n    value: function wrappedMethod () {\n      baseMethod.apply(this, arguments);\n      return derivedMethod.apply(this, arguments);\n    },\n    writable: window.debug\n  };\n}\n\n/**\n * It copies the properties from source to destination object if they don't\n * exist already.\n *\n * @param {object} source - The object where properties are copied from.\n * @param {type} destination - The object where properties are copied to.\n */\nfunction copyProperties (source, destination) {\n  var props = Object.getOwnPropertyNames(source);\n  props.forEach(function (prop) {\n    var desc;\n    if (!destination[prop]) {\n      desc = Object.getOwnPropertyDescriptor(source, prop);\n      destination[prop] = {value: source[prop], writable: desc.writable};\n    }\n  });\n}\n\nANode = _dereq_('./a-node');\nAEntity = _dereq_('./a-entity');\n\n},{\"./a-entity\":121,\"./a-node\":123,\"document-register-element\":13}],125:[function(_dereq_,module,exports){\n/* global Node */\nvar schema = _dereq_('./schema');\nvar scenes = _dereq_('./scene/scenes');\nvar systems = _dereq_('./system');\nvar utils = _dereq_('../utils/');\n\nvar components = module.exports.components = {};  // Keep track of registered components.\nvar parseProperties = schema.parseProperties;\nvar parseProperty = schema.parseProperty;\nvar processSchema = schema.process;\nvar isSingleProp = schema.isSingleProperty;\nvar stringifyProperties = schema.stringifyProperties;\nvar stringifyProperty = schema.stringifyProperty;\nvar styleParser = utils.styleParser;\nvar warn = utils.debug('core:component:warn');\n\nvar aframeScript = document.currentScript;\nvar upperCaseRegExp = new RegExp('[A-Z]+');\n\n/**\n * Component class definition.\n *\n * Components configure appearance, modify behavior, or add functionality to\n * entities. The behavior and appearance of an entity can be changed at runtime\n * by adding, removing, or updating components. Entities do not share instances\n * of components.\n *\n * @member {object} el - Reference to the entity element.\n * @member {string} attrValue - Value of the corresponding HTML attribute.\n * @member {object} data - Component data populated by parsing the\n *         mapped attribute of the component plus applying defaults and mixins.\n */\nvar Component = module.exports.Component = function (el, attrValue, id) {\n  var self = this;\n  this.el = el;\n  this.id = id;\n  this.attrName = this.name + (id ? '__' + id : '');\n  this.evtDetail = {id: this.id, name: this.name};\n  this.initialized = false;\n  this.el.components[this.attrName] = this;\n\n  // Store component data from previous update call.\n  this.oldData = undefined;\n\n  // Last value passed to updateProperties.\n  this.previousAttrValue = undefined;\n  this.throttledEmitComponentChanged = utils.throttle(function emitChange () {\n    el.emit('componentchanged', self.evtDetail, false);\n  }, 200);\n  this.updateProperties(attrValue);\n};\n\nComponent.prototype = {\n  /**\n   * Contains the type schema and defaults for the data values.\n   * Data is coerced into the types of the values of the defaults.\n   */\n  schema: {},\n\n  /**\n   * Init handler. Similar to attachedCallback.\n   * Called during component initialization and is only run once.\n   * Components can use this to set initial state.\n   */\n  init: function () { /* no-op */ },\n\n  /**\n   * Update handler. Similar to attributeChangedCallback.\n   * Called whenever component's data changes.\n   * Also called on component initialization when the component receives initial data.\n   *\n   * @param {object} prevData - Previous attributes of the component.\n   */\n  update: function (prevData) { /* no-op */ },\n\n  updateSchema: undefined,\n\n  /**\n   * Tick handler.\n   * Called on each tick of the scene render loop.\n   * Affected by play and pause.\n   *\n   * @param {number} time - Scene tick time.\n   * @param {number} timeDelta - Difference in current render time and previous render time.\n   */\n  tick: undefined,\n\n  /**\n   * Tock handler.\n   * Called on each tock of the scene render loop.\n   * Affected by play and pause.\n   *\n   * @param {number} time - Scene tick time.\n   * @param {number} timeDelta - Difference in current render time and previous render time.\n   */\n  tock: undefined,\n\n  /**\n   * Called to start any dynamic behavior (e.g., animation, AI, events, physics).\n   */\n  play: function () { /* no-op */ },\n\n  /**\n   * Called to stop any dynamic behavior (e.g., animation, AI, events, physics).\n   */\n  pause: function () { /* no-op */ },\n\n  /**\n   * Remove handler. Similar to detachedCallback.\n   * Called whenever component is removed from the entity (i.e., removeAttribute).\n   * Components can use this to reset behavior on the entity.\n   */\n  remove: function () { /* no-op */ },\n\n  /**\n   * Parses each property based on property type.\n   * If component is single-property, then parses the single property value.\n   *\n   * @param {string} value - HTML attribute value.\n   * @param {boolean} silent - Suppress warning messages.\n   * @returns {object} Component data.\n   */\n  parse: function (value, silent) {\n    var schema = this.schema;\n    if (isSingleProp(schema)) { return parseProperty(value, schema); }\n    return parseProperties(styleParser.parse(value), schema, true, this.name, silent);\n  },\n\n  /**\n   * Stringify properties if necessary.\n   *\n   * Only called from `Entity.setAttribute` for properties whose parsers accept a non-string\n   * value (e.g., selector, vec3 property types).\n   *\n   * @param {object} data - Complete component data.\n   * @returns {string}\n   */\n  stringify: function (data) {\n    var schema = this.schema;\n    if (typeof data === 'string') { return data; }\n    if (isSingleProp(schema)) { return stringifyProperty(data, schema); }\n    data = stringifyProperties(data, schema);\n    return styleParser.stringify(data);\n  },\n\n  /**\n   * Update the cache of the pre-parsed attribute value.\n   *\n   * @param {string} value - New data.\n   * @param {boolean } clobber - Whether to wipe out and replace previous data.\n   */\n  updateCachedAttrValue: function (value, clobber) {\n    var attrValue = this.parseAttrValueForCache(value);\n    var isSinglePropSchema = isSingleProp(this.schema);\n    var property;\n    if (value === undefined) { return; }\n\n    // Merge new data with previous `attrValue` if updating and not clobbering.\n    if (!isSinglePropSchema && !clobber && this.attrValue) {\n      for (property in this.attrValue) {\n        if (!(property in attrValue)) {\n          attrValue[property] = this.attrValue[property];\n        }\n      }\n    }\n\n    this.attrValue = extendProperties({}, attrValue, isSinglePropSchema);\n  },\n\n  /**\n   * Given an HTML attribute value parses the string\n   * based on the component schema. To avoid double parsings of\n   * strings into strings we store the original instead\n   * of the parsed one\n   *\n   * @param {string} value - HTML attribute value\n   */\n  parseAttrValueForCache: function (value) {\n    var parsedValue;\n    if (typeof value !== 'string') { return value; }\n    if (isSingleProp(this.schema)) {\n      parsedValue = this.schema.parse(value);\n      /**\n       * To avoid bogus double parsings. Cached values will be parsed when building\n       * component data. For instance when parsing a src id to its url, we want to cache\n       * original string and not the parsed one (#monster -> models/monster.dae)\n       * so when building data we parse the expected value.\n       */\n      if (typeof parsedValue === 'string') { parsedValue = value; }\n    } else {\n      // Parse using the style parser to avoid double parsing of individual properties.\n      parsedValue = styleParser.parse(value);\n    }\n    return parsedValue;\n  },\n\n  /**\n   * Write cached attribute data to the entity DOM element.\n   *\n   * @param {boolean} isDefault - Whether component is a default component. Always flush for\n   *   default components.\n   */\n  flushToDOM: function (isDefault) {\n    var attrValue = isDefault ? this.data : this.attrValue;\n    if (!attrValue) { return; }\n    window.HTMLElement.prototype.setAttribute.call(this.el, this.attrName,\n                                            this.stringify(attrValue));\n  },\n\n  /**\n   * Apply new component data if data has changed.\n   *\n   * @param {string} attrValue - HTML attribute value.\n   *        If undefined, use the cached attribute value and continue updating properties.\n   * @param {boolean} clobber - The previous component data is overwritten by the atrrValue\n   */\n  updateProperties: function (attrValue, clobber) {\n    var el = this.el;\n    var isSinglePropSchema;\n    var skipTypeChecking;\n    var oldData = this.oldData;\n\n    // Just cache the attribute if the entity has not loaded\n    // Components are not initialized until the entity has loaded\n    if (!el.hasLoaded) {\n      this.updateCachedAttrValue(attrValue);\n      return;\n    }\n\n    isSinglePropSchema = isSingleProp(this.schema);\n    // Disable type checking if the passed attribute is an object and has not changed.\n    skipTypeChecking = attrValue !== null && typeof this.previousAttrValue === 'object' &&\n                       attrValue === this.previousAttrValue;\n    // Cache previously passed attribute to decide if we skip type checking.\n    this.previousAttrValue = attrValue;\n\n    attrValue = this.parseAttrValueForCache(attrValue);\n    if (this.updateSchema) { this.updateSchema(this.buildData(attrValue, false, true)); }\n    this.data = this.buildData(attrValue, clobber, false, skipTypeChecking);\n\n    // Cache current attrValue for future updates.\n    this.updateCachedAttrValue(attrValue, clobber);\n\n    if (!this.initialized) {\n      // Component is being already initialized.\n      if (el.initializingComponents[this.name]) { return; }\n      // Prevent infinite loop in case of init method setting same component on the entity.\n      el.initializingComponents[this.name] = true;\n      // Initialize component.\n      this.init();\n      this.initialized = true;\n      delete el.initializingComponents[this.name];\n      // For oldData, pass empty object to multiple-prop schemas or object single-prop schema.\n      // Pass undefined to rest of types.\n      oldData = (!isSinglePropSchema ||\n                 typeof parseProperty(undefined, this.schema) === 'object') ? {} : undefined;\n      // Store current data as previous data for future updates.\n      this.oldData = extendProperties({}, this.data, isSinglePropSchema);\n      this.update(oldData);\n      // Play the component if the entity is playing.\n      if (el.isPlaying) { this.play(); }\n      el.emit('componentinitialized', this.evtDetail, false);\n    } else {\n      // Don't update if properties haven't changed\n      if (utils.deepEqual(this.oldData, this.data)) { return; }\n     // Store current data as previous data for future updates.\n      this.oldData = extendProperties({}, this.data, isSinglePropSchema);\n      // Update component.\n      this.update(oldData);\n      this.throttledEmitComponentChanged();\n    }\n  },\n\n  /**\n   * Reset value of a property to the property's default value.\n   * If single-prop component, reset value to component's default value.\n   *\n   * @param {string} propertyName - Name of property to reset.\n   */\n  resetProperty: function (propertyName) {\n    if (isSingleProp(this.schema)) {\n      this.attrValue = undefined;\n    } else {\n      if (!(propertyName in this.attrValue)) { return; }\n      delete this.attrValue[propertyName];\n    }\n    this.updateProperties(this.attrValue);\n  },\n\n  /**\n   * Extend schema of component given a partial schema.\n   *\n   * Some components might want to mutate their schema based on certain properties.\n   * e.g., Material component changes its schema based on `shader` to account for different\n   * uniforms\n   *\n   * @param {object} schemaAddon - Schema chunk that extend base schema.\n   */\n  extendSchema: function (schemaAddon) {\n    // Clone base schema.\n    var extendedSchema = utils.extend({}, components[this.name].schema);\n    // Extend base schema with new schema chunk.\n    utils.extend(extendedSchema, schemaAddon);\n    this.schema = processSchema(extendedSchema);\n    this.el.emit('schemachanged', {component: this.name});\n  },\n\n  /**\n   * Builds component data from the current state of the entity, ultimately\n   * updating this.data.\n   *\n   * If the component was detached completely, set data to null.\n   *\n   * Precedence:\n   * 1. Defaults data\n   * 2. Mixin data.\n   * 3. Attribute data.\n   *\n   * Finally coerce the data to the types of the defaults.\n   *\n   * @param {object} newData - Element new data.\n   * @param {boolean} clobber - The previous data is completely replaced by the new one.\n   * @param {boolean} silent - Suppress warning messages.\n   * @param {boolean} skipTypeChecking - Skip type checking and cohercion.\n   * @return {object} The component data\n   */\n  buildData: function (newData, clobber, silent, skipTypeChecking) {\n    var componentDefined = newData !== undefined && newData !== null;\n    var data;\n    var defaultValue;\n    var keys;\n    var keysLength;\n    var mixinData;\n    var schema = this.schema;\n    var i;\n    var isSinglePropSchema = isSingleProp(schema);\n    var mixinEls = this.el.mixinEls;\n    var previousData;\n    // 1. Default values (lowest precendence).\n    if (isSinglePropSchema) {\n      // Clone default value if plain object so components don't share the same object\n      // that might be modified by the user.\n      data = (schema.default && schema.default.constructor === Object) ? utils.clone(schema.default) : schema.default;\n    } else {\n      // Preserve previously set properties if clobber not enabled.\n      previousData = !clobber && this.attrValue;\n      // Clone previous data to prevent sharing references with attrValue that might be\n      // modified by the user.\n      data = typeof previousData === 'object' ? cloneData(previousData) : {};\n\n      // Apply defaults.\n      for (i = 0, keys = Object.keys(schema), keysLength = keys.length; i < keysLength; i++) {\n        defaultValue = schema[keys[i]].default;\n        if (data[keys[i]] !== undefined) { continue; }\n        // Clone default value if object so components don't share object\n        data[keys[i]] = defaultValue && defaultValue.constructor === Object\n          ? utils.clone(defaultValue)\n          : defaultValue;\n      }\n    }\n\n    // 2. Mixin values.\n    for (i = 0; i < mixinEls.length; i++) {\n      mixinData = mixinEls[i].getAttribute(this.attrName);\n      if (mixinData) {\n        data = extendProperties(data, mixinData, isSinglePropSchema);\n      }\n    }\n\n    // 3. Attribute values (highest precendence).\n    if (componentDefined) {\n      if (isSinglePropSchema) {\n        if (skipTypeChecking === true) { return newData; }\n        return parseProperty(newData, schema);\n      }\n      data = extendProperties(data, newData, isSinglePropSchema);\n    } else {\n      if (skipTypeChecking === true) { return data; }\n      // Parse and coerce using the schema.\n      if (isSinglePropSchema) { return parseProperty(data, schema); }\n    }\n\n    if (skipTypeChecking === true) { return data; }\n    return parseProperties(data, schema, undefined, this.name, silent);\n  }\n};\n\n// For testing.\nif (window.debug) {\n  var registrationOrderWarnings = module.exports.registrationOrderWarnings = {};\n}\n\n/**\n * Registers a component to A-Frame.\n *\n * @param {string} name - Component name.\n * @param {object} definition - Component schema and lifecycle method handlers.\n * @returns {object} Component.\n */\nmodule.exports.registerComponent = function (name, definition) {\n  var NewComponent;\n  var proto = {};\n\n  // Warning if component is statically registered after the scene.\n  if (document.currentScript && document.currentScript !== aframeScript) {\n    scenes.forEach(function checkPosition (sceneEl) {\n      // Okay to register component after the scene at runtime.\n      if (sceneEl.hasLoaded) { return; }\n\n      // Check that component is declared before the scene.\n      if (document.currentScript.compareDocumentPosition(sceneEl) ===\n          Node.DOCUMENT_POSITION_FOLLOWING) { return; }\n\n      warn('The component `' + name + '` was registered in a <script> tag after the scene. ' +\n           'Component <script> tags in an HTML file should be declared *before* the scene ' +\n           'such that the component is available to entities during scene initialization.');\n\n      // For testing.\n      if (window.debug) { registrationOrderWarnings[name] = true; }\n    });\n  }\n\n  if (upperCaseRegExp.test(name) === true) {\n    warn('The component name `' + name + '` contains uppercase characters, but ' +\n         'HTML will ignore the capitalization of attribute names. ' +\n         'Change the name to be lowercase: `' + name.toLowerCase() + '`');\n  }\n\n  if (name.indexOf('__') !== -1) {\n    throw new Error('The component name `' + name + '` is not allowed. ' +\n                    'The sequence __ (double underscore) is reserved to specify an id' +\n                    ' for multiple components of the same type');\n  }\n\n  // Format definition object to prototype object.\n  Object.keys(definition).forEach(function (key) {\n    proto[key] = {\n      value: definition[key],\n      writable: true\n    };\n  });\n\n  if (components[name]) {\n    throw new Error('The component `' + name + '` has been already registered. ' +\n                    'Check that you are not loading two versions of the same component ' +\n                    'or two different components of the same name.');\n  }\n  NewComponent = function (el, attr, id) {\n    Component.call(this, el, attr, id);\n  };\n\n  NewComponent.prototype = Object.create(Component.prototype, proto);\n  NewComponent.prototype.name = name;\n  NewComponent.prototype.constructor = NewComponent;\n  NewComponent.prototype.system = systems && systems.systems[name];\n  NewComponent.prototype.play = wrapPlay(NewComponent.prototype.play);\n  NewComponent.prototype.pause = wrapPause(NewComponent.prototype.pause);\n\n  components[name] = {\n    Component: NewComponent,\n    dependencies: NewComponent.prototype.dependencies,\n    isSingleProp: isSingleProp(NewComponent.prototype.schema),\n    multiple: NewComponent.prototype.multiple,\n    parse: NewComponent.prototype.parse,\n    parseAttrValueForCache: NewComponent.prototype.parseAttrValueForCache,\n    schema: utils.extend(processSchema(NewComponent.prototype.schema, NewComponent.prototype.name)),\n    stringify: NewComponent.prototype.stringify,\n    type: NewComponent.prototype.type\n  };\n  return NewComponent;\n};\n\n/**\n* Clone component data.\n* Clone only the properties that are plain objects while keeping a reference for the rest.\n*\n* @param data - Component data to clone.\n* @returns Cloned data.\n*/\nfunction cloneData (data) {\n  var clone = {};\n  var parsedProperty;\n  var key;\n  for (key in data) {\n    parsedProperty = data[key];\n    clone[key] = parsedProperty && parsedProperty.constructor === Object\n      ? utils.clone(parsedProperty)\n      : parsedProperty;\n  }\n  return clone;\n}\n\n/**\n* Object extending with checking for single-property schema.\n*\n* @param dest - Destination object or value.\n* @param source - Source object or value\n* @param {boolean} isSinglePropSchema - Whether or not schema is only a single property.\n* @returns Overridden object or value.\n*/\nfunction extendProperties (dest, source, isSinglePropSchema) {\n  if (isSinglePropSchema && (source === null || typeof source !== 'object')) { return source; }\n  return utils.extend(dest, source);\n}\n\n/**\n * Checks if a component has defined a method that needs to run every frame.\n */\nfunction hasBehavior (component) {\n  return component.tick || component.tock;\n}\n\n/**\n * Wrapper for user defined pause method\n * Pause component by removing tick behavior and calling user's pause method.\n *\n * @param pauseMethod {function} - user defined pause method\n */\nfunction wrapPause (pauseMethod) {\n  return function pause () {\n    var sceneEl = this.el.sceneEl;\n    if (!this.isPlaying) { return; }\n    pauseMethod.call(this);\n    this.isPlaying = false;\n    // Remove tick behavior.\n    if (!hasBehavior(this)) { return; }\n    sceneEl.removeBehavior(this);\n  };\n}\n\n/**\n * Wrapper for user defined play method\n * Play component by adding tick behavior and calling user's play method.\n *\n * @param playMethod {function} - user defined play method\n *\n */\nfunction wrapPlay (playMethod) {\n  return function play () {\n    var sceneEl = this.el.sceneEl;\n    var shouldPlay = this.el.isPlaying && !this.isPlaying;\n    if (!this.initialized || !shouldPlay) { return; }\n    playMethod.call(this);\n    this.isPlaying = true;\n    // Add tick behavior.\n    if (!hasBehavior(this)) { return; }\n    sceneEl.addBehavior(this);\n  };\n}\n\n},{\"../utils/\":195,\"./scene/scenes\":131,\"./schema\":133,\"./system\":135}],126:[function(_dereq_,module,exports){\nvar schema = _dereq_('./schema');\n\nvar processSchema = schema.process;\nvar geometries = module.exports.geometries = {};  // Registered geometries.\nvar geometryNames = module.exports.geometryNames = [];  // Names of registered geometries.\nvar THREE = _dereq_('../lib/three');\n\n/**\n * Geometry class definition.\n *\n * Geometries extend the geometry component API to create and register geometry types.\n */\nvar Geometry = module.exports.Geometry = function () {};\n\nGeometry.prototype = {\n  /**\n   * Contains the type schema and defaults for the data values.\n   * Data is coerced into the types of the values of the defaults.\n   */\n  schema: {},\n\n  /**\n   * Init handler. Similar to attachedCallback.\n   * Called during shader initialization and is only run once.\n   */\n  init: function (data) {\n    this.geometry = new THREE.Geometry();\n    return this.geometry;\n  },\n\n  /**\n   * Update handler. Similar to attributeChangedCallback.\n   * Called whenever the associated geometry data changes.\n   *\n   * @param {object} data - New geometry data.\n   */\n  update: function (data) { /* no-op */ }\n};\n\n/**\n * Registers a geometry to A-Frame.\n *\n * @param {string} name - Geometry name.\n * @param {object} definition - Geometry property and methods.\n * @returns {object} Geometry.\n */\nmodule.exports.registerGeometry = function (name, definition) {\n  var NewGeometry;\n  var proto = {};\n\n  // Format definition object to prototype object.\n  Object.keys(definition).forEach(function expandDefinition (key) {\n    proto[key] = {\n      value: definition[key],\n      writable: true\n    };\n  });\n\n  if (geometries[name]) {\n    throw new Error('The geometry `' + name + '` has been already registered');\n  }\n  NewGeometry = function () { Geometry.call(this); };\n  NewGeometry.prototype = Object.create(Geometry.prototype, proto);\n  NewGeometry.prototype.name = name;\n  NewGeometry.prototype.constructor = NewGeometry;\n  geometries[name] = {\n    Geometry: NewGeometry,\n    schema: processSchema(NewGeometry.prototype.schema)\n  };\n  geometryNames.push(name);\n  return NewGeometry;\n};\n\n},{\"../lib/three\":173,\"./schema\":133}],127:[function(_dereq_,module,exports){\nvar coordinates = _dereq_('../utils/coordinates');\nvar debug = _dereq_('debug');\n\nvar error = debug('core:propertyTypes:warn');\nvar warn = debug('core:propertyTypes:warn');\n\nvar propertyTypes = module.exports.propertyTypes = {};\nvar nonCharRegex = /[,> .[\\]:]/;\n\n// Built-in property types.\nregisterPropertyType('audio', '', assetParse);\nregisterPropertyType('array', [], arrayParse, arrayStringify);\nregisterPropertyType('asset', '', assetParse);\nregisterPropertyType('boolean', false, boolParse);\nregisterPropertyType('color', '#FFF', defaultParse, defaultStringify);\nregisterPropertyType('int', 0, intParse);\nregisterPropertyType('number', 0, numberParse);\nregisterPropertyType('map', '', assetParse);\nregisterPropertyType('model', '', assetParse);\nregisterPropertyType('selector', null, selectorParse, selectorStringify);\nregisterPropertyType('selectorAll', null, selectorAllParse, selectorAllStringify);\nregisterPropertyType('src', '', srcParse);\nregisterPropertyType('string', '', defaultParse, defaultStringify);\nregisterPropertyType('time', 0, intParse);\nregisterPropertyType('vec2', {x: 0, y: 0}, vecParse, coordinates.stringify);\nregisterPropertyType('vec3', {x: 0, y: 0, z: 0}, vecParse, coordinates.stringify);\nregisterPropertyType('vec4', {x: 0, y: 0, z: 0, w: 0}, vecParse, coordinates.stringify);\n\n/**\n * Register a parser for re-use such that when someone uses `type` in the schema,\n * `schema.process` will set the property `parse` and `stringify`.\n *\n * @param {string} type - Type name.\n * @param [defaultValue=null] -\n *   Default value to use if component does not define default value.\n * @param {function} [parse=defaultParse] - Parse string function.\n * @param {function} [stringify=defaultStringify] - Stringify to DOM function.\n */\nfunction registerPropertyType (type, defaultValue, parse, stringify) {\n  if ('type' in propertyTypes) {\n    error('Property type ' + type + ' is already registered.');\n    return;\n  }\n\n  propertyTypes[type] = {\n    default: defaultValue,\n    parse: parse || defaultParse,\n    stringify: stringify || defaultStringify\n  };\n}\nmodule.exports.registerPropertyType = registerPropertyType;\n\nfunction arrayParse (value) {\n  if (Array.isArray(value)) { return value; }\n  if (!value || typeof value !== 'string') { return []; }\n  return value.split(',').map(trim);\n  function trim (str) { return str.trim(); }\n}\n\nfunction arrayStringify (value) {\n  return value.join(', ');\n}\n\n/**\n * For general assets.\n *\n * @param {string} value - Can either be `url(<value>)`, an ID selector to an asset, or\n *   just string.\n * @returns {string} Parsed value from `url(<value>)`, src from `<someasset src>`, or\n *   just string.\n */\nfunction assetParse (value) {\n  var el;\n  var parsedUrl;\n\n  // If an element was provided (e.g. canvas or video), just return it.\n  if (typeof value !== 'string') { return value; }\n\n  // Wrapped `url()` in case of data URI.\n  parsedUrl = value.match(/\\url\\((.+)\\)/);\n  if (parsedUrl) { return parsedUrl[1]; }\n\n  // ID.\n  if (value.charAt(0) === '#') {\n    el = document.getElementById(value.substring(1));\n    if (el) {\n      // Pass through media elements. If we have the elements, we don't have to call\n      // three.js loaders which would re-request the assets.\n      if (el.tagName === 'CANVAS' || el.tagName === 'VIDEO' || el.tagName === 'IMG') {\n        return el;\n      }\n      return el.getAttribute('src');\n    }\n    warn('\"' + value + '\" asset not found.');\n    return;\n  }\n\n  // Non-wrapped url().\n  return value;\n}\n\nfunction defaultParse (value) {\n  return value;\n}\n\nfunction defaultStringify (value) {\n  if (value === null) { return 'null'; }\n  return value.toString();\n}\n\nfunction boolParse (value) {\n  return value !== 'false' && value !== false;\n}\n\nfunction intParse (value) {\n  return parseInt(value, 10);\n}\n\nfunction numberParse (value) {\n  return parseFloat(value, 10);\n}\n\nfunction selectorParse (value) {\n  if (!value) { return null; }\n  if (typeof value !== 'string') { return value; }\n  if (value[0] === '#' && !nonCharRegex.test(value)) {\n    // When selecting element by ID only, use getElementById for better performance.\n    // Don't match like #myId .child.\n    return document.getElementById(value.substring(1));\n  }\n  return document.querySelector(value);\n}\n\nfunction selectorAllParse (value) {\n  if (!value) { return null; }\n  if (typeof value !== 'string') { return value; }\n  return Array.prototype.slice.call(document.querySelectorAll(value), 0);\n}\n\nfunction selectorStringify (value) {\n  if (value.getAttribute) {\n    return '#' + value.getAttribute('id');\n  }\n  return defaultStringify(value);\n}\n\nfunction selectorAllStringify (value) {\n  if (value instanceof Array) {\n    return value.map(function (element) {\n      return '#' + element.getAttribute('id');\n    }).join(', ');\n  }\n  return defaultStringify(value);\n}\n\nfunction srcParse (value) {\n  warn('`src` property type is deprecated. Use `asset` instead.');\n  return assetParse(value);\n}\n\nfunction vecParse (value) {\n  return coordinates.parse(value, this.default);\n}\n\n/**\n * Validate the default values in a schema to match their type.\n *\n * @param {string} type - Property type name.\n * @param defaultVal - Property type default value.\n * @returns {boolean} Whether default value is accurate given the type.\n */\nfunction isValidDefaultValue (type, defaultVal) {\n  if (type === 'audio' && typeof defaultVal !== 'string') { return false; }\n  if (type === 'array' && !Array.isArray(defaultVal)) { return false; }\n  if (type === 'asset' && typeof defaultVal !== 'string') { return false; }\n  if (type === 'boolean' && typeof defaultVal !== 'boolean') { return false; }\n  if (type === 'color' && typeof defaultVal !== 'string') { return false; }\n  if (type === 'int' && typeof defaultVal !== 'number') { return false; }\n  if (type === 'number' && typeof defaultVal !== 'number') { return false; }\n  if (type === 'map' && typeof defaultVal !== 'string') { return false; }\n  if (type === 'model' && typeof defaultVal !== 'string') { return false; }\n  if (type === 'selector' && typeof defaultVal !== 'string' &&\n      defaultVal !== null) { return false; }\n  if (type === 'selectorAll' && typeof defaultVal !== 'string' &&\n      defaultVal !== null) { return false; }\n  if (type === 'src' && typeof defaultVal !== 'string') { return false; }\n  if (type === 'string' && typeof defaultVal !== 'string') { return false; }\n  if (type === 'time' && typeof defaultVal !== 'number') { return false; }\n  if (type === 'vec2') { return isValidDefaultCoordinate(defaultVal, 2); }\n  if (type === 'vec3') { return isValidDefaultCoordinate(defaultVal, 3); }\n  if (type === 'vec4') { return isValidDefaultCoordinate(defaultVal, 4); }\n  return true;\n}\nmodule.exports.isValidDefaultValue = isValidDefaultValue;\n\n/**\n * Checks if default coordinates are valid.\n *\n * @param possibleCoordinates\n * @param {number} dimensions - 2 for 2D Vector, 3 for 3D vector.\n * @returns {boolean} Whether coordinates are parsed correctly.\n */\nfunction isValidDefaultCoordinate (possibleCoordinates, dimensions) {\n  if (possibleCoordinates === null) { return true; }\n  if (typeof possibleCoordinates !== 'object') { return false; }\n\n  if (Object.keys(possibleCoordinates).length !== dimensions) {\n    return false;\n  } else {\n    var x = possibleCoordinates.x;\n    var y = possibleCoordinates.y;\n    var z = possibleCoordinates.z;\n    var w = possibleCoordinates.w;\n\n    if (typeof x !== 'number' || typeof y !== 'number') { return false; }\n    if (dimensions > 2 && typeof z !== 'number') { return false; }\n    if (dimensions > 3 && typeof w !== 'number') { return false; }\n  }\n\n  return true;\n}\nmodule.exports.isValidDefaultCoordinate = isValidDefaultCoordinate;\n\n},{\"../utils/coordinates\":190,\"debug\":10}],128:[function(_dereq_,module,exports){\n/* global Promise, screen */\nvar initMetaTags = _dereq_('./metaTags').inject;\nvar initWakelock = _dereq_('./wakelock');\nvar re = _dereq_('../a-register-element');\nvar scenes = _dereq_('./scenes');\nvar systems = _dereq_('../system').systems;\nvar THREE = _dereq_('../../lib/three');\nvar TWEEN = _dereq_('@tweenjs/tween.js');\nvar utils = _dereq_('../../utils/');\n// Require after.\nvar AEntity = _dereq_('../a-entity');\nvar ANode = _dereq_('../a-node');\nvar initPostMessageAPI = _dereq_('./postMessage');\n\nvar bind = utils.bind;\nvar isIOS = utils.device.isIOS();\nvar isMobile = utils.device.isMobile();\nvar registerElement = re.registerElement;\nvar warn = utils.debug('core:a-scene:warn');\n\n/**\n * Scene element, holds all entities.\n *\n * @member {number} animationFrameID\n * @member {array} behaviors - Component instances that have registered themselves to be\n           updated on every tick.\n * @member {object} camera - three.js Camera object.\n * @member {object} canvas\n * @member {bool} isScene - Differentiates as scene entity as opposed to other entites.\n * @member {bool} isMobile - Whether browser is mobile (via UA detection).\n * @member {object} object3D - Root three.js Scene object.\n * @member {object} renderer\n * @member {bool} renderStarted\n * @member {object} effect - three.js VREffect\n * @member {object} systems - Registered instantiated systems.\n * @member {number} time\n */\nmodule.exports.AScene = registerElement('a-scene', {\n  prototype: Object.create(AEntity.prototype, {\n    defaultComponents: {\n      value: {\n        'inspector': '',\n        'keyboard-shortcuts': '',\n        'screenshot': '',\n        'vr-mode-ui': ''\n      }\n    },\n\n    createdCallback: {\n      value: function () {\n        this.isIOS = isIOS;\n        this.isMobile = isMobile;\n        this.isScene = true;\n        this.object3D = new THREE.Scene();\n        this.render = bind(this.render, this);\n        this.systems = {};\n        this.systemNames = [];\n        this.time = 0;\n        this.init();\n      }\n    },\n\n    init: {\n      value: function () {\n        this.behaviors = {tick: [], tock: []};\n        this.hasLoaded = false;\n        this.isPlaying = false;\n        this.originalHTML = this.innerHTML;\n        this.renderTarget = null;\n        setupCanvas(this);\n        this.setupRenderer();\n        this.resize();\n        this.addFullScreenStyles();\n        initPostMessageAPI(this);\n      },\n      writable: true\n    },\n\n    addFullScreenStyles: {\n      value: function () {\n        var htmlEl = document.documentElement;\n        htmlEl.classList.add('a-html');\n        document.body.classList.add('a-body');\n        this.classList.add('fullscreen');\n      }\n    },\n\n    removeFullScreenStyles: {\n      value: function () {\n        var htmlEl = document.documentElement;\n        htmlEl.classList.remove('a-html');\n        document.body.classList.remove('a-body');\n        this.classList.remove('fullscreen');\n      }\n    },\n\n    attachedCallback: {\n      value: function () {\n        var resize;\n        var self = this;\n\n        initMetaTags(this);\n        initWakelock(this);\n        this.initSystems();\n\n        resize = bind(this.resize, this);\n        window.addEventListener('load', resize);\n        window.addEventListener('resize', resize);\n        this.play();\n\n        // Add to scene index.\n        scenes.push(this);\n\n        // Handler to exit VR (e.g., Oculus Browser back button).\n        this.onVRPresentChangeBound = bind(this.onVRPresentChange, this);\n        window.addEventListener('vrdisplaypresentchange', this.onVRPresentChangeBound);\n\n        // bind functions\n        this.enterVRBound = function () { self.enterVR(); };\n        this.exitVRBound = function () { self.exitVR(); };\n        this.exitVRTrueBound = function () { self.exitVR(true); };\n        this.pointerRestrictedBound = function () { self.pointerRestricted(); };\n        this.pointerUnrestrictedBound = function () { self.pointerUnrestricted(); };\n\n        // Enter VR on `vrdisplayactivate` (e.g. putting on Rift headset).\n        window.addEventListener('vrdisplayactivate', this.enterVRBound);\n\n        // Exit VR on `vrdisplaydeactivate` (e.g. taking off Rift headset).\n        window.addEventListener('vrdisplaydeactivate', this.exitVRBound);\n\n        // Exit VR on `vrdisplaydisconnect` (e.g. unplugging Rift headset).\n        window.addEventListener('vrdisplaydisconnect', this.exitVRTrueBound);\n\n        // Register for mouse restricted events while in VR\n        // (e.g. mouse no longer available on desktop 2D view)\n        window.addEventListener('vrdisplaypointerrestricted', this.pointerRestrictedBound);\n\n        // Register for mouse unrestricted events while in VR\n        // (e.g. mouse once again available on desktop 2D view)\n        window.addEventListener('vrdisplaypointerunrestricted', this.pointerUnrestrictedBound);\n      },\n      writable: window.debug\n    },\n\n    /**\n     * Initialize all systems.\n     */\n    initSystems: {\n      value: function () {\n        Object.keys(systems).forEach(bind(this.initSystem, this));\n      }\n    },\n\n    /**\n     * Initialize a system.\n     */\n    initSystem: {\n      value: function (name) {\n        if (this.systems[name]) { return; }\n        this.systems[name] = new systems[name](this);\n        this.systemNames.push(name);\n      }\n    },\n\n    /**\n     * Shut down scene on detach.\n     */\n    detachedCallback: {\n      value: function () {\n        var sceneIndex;\n\n        if (this.effect && this.effect.cancelAnimationFrame) {\n          this.effect.cancelAnimationFrame(this.animationFrameID);\n        } else {\n          window.cancelAnimationFrame(this.animationFrameID);\n        }\n        this.animationFrameID = null;\n\n        // Remove from scene index.\n        sceneIndex = scenes.indexOf(this);\n        scenes.splice(sceneIndex, 1);\n\n        window.removeEventListener('vrdisplaypresentchange', this.onVRPresentChangeBound);\n        window.removeEventListener('vrdisplayactivate', this.enterVRBound);\n        window.removeEventListener('vrdisplaydeactivate', this.exitVRBound);\n        window.removeEventListener('vrdisplayconnect', this.enterVRBound);\n        window.removeEventListener('vrdisplaydisconnect', this.exitVRTrueBound);\n        window.removeEventListener('vrdisplaypointerrestricted', this.pointerRestrictedBound);\n        window.removeEventListener('vrdisplaypointerunrestricted', this.pointerUnrestrictedBound);\n      }\n    },\n\n    /**\n     * Add ticks and tocks.\n     *\n     * @param {object} behavior - Generally a component. Must implement a .update() method\n     *   to be called on every tick.\n     */\n    addBehavior: {\n      value: function (behavior) {\n        var self = this;\n        var behaviors = this.behaviors;\n        // Check if behavior has tick and/or tock and add the behavior to the appropriate list.\n        Object.keys(behaviors).forEach(function (behaviorType) {\n          if (!behavior[behaviorType]) { return; }\n          var behaviorArr = self.behaviors[behaviorType];\n          if (behaviorArr.indexOf(behavior) === -1) {\n            behaviorArr.push(behavior);\n          }\n        });\n      }\n    },\n\n    /**\n     * For tests.\n     */\n    getPointerLockElement: {\n      value: function () {\n        return document.pointerLockElement;\n      },\n      writable: window.debug\n    },\n\n    /**\n     * For tests.\n     */\n    checkHeadsetConnected: {\n      value: utils.device.checkHeadsetConnected,\n      writable: window.debug\n    },\n\n    /**\n     * Call `requestPresent` if WebVR or WebVR polyfill.\n     * Call `requestFullscreen` on desktop.\n     * Handle events, states, fullscreen styles.\n     *\n     * @param {bool} fromExternal - Whether exiting VR due to an external event (e.g.,\n     *   manually calling requestPresent via WebVR API directly).\n     * @returns {Promise}\n     */\n    enterVR: {\n      value: function (fromExternal) {\n        var self = this;\n        var effect = this.effect;\n\n        // Don't enter VR if already in VR.\n        if (this.is('vr-mode')) { return Promise.resolve('Already in VR.'); }\n\n        // Enter VR via WebVR API.\n        if (!fromExternal && (this.checkHeadsetConnected() || this.isMobile)) {\n          return effect && effect.requestPresent().then(enterVRSuccess, enterVRFailure) || Promise.reject(new Error('VREffect not initialized'));\n        }\n\n        // Either entered VR already via WebVR API or VR not supported.\n        enterVRSuccess();\n        return Promise.resolve();\n\n        function enterVRSuccess () {\n          self.addState('vr-mode');\n          self.emit('enter-vr', {target: self});\n\n          // Lock to landscape orientation on mobile.\n          if (self.isMobile && screen.orientation && screen.orientation.lock) {\n            screen.orientation.lock('landscape');\n          }\n          self.addFullScreenStyles();\n\n          // On mobile, the polyfill handles fullscreen.\n          // TODO: 07/16 Chromium builds break when `requestFullscreen`ing on a canvas\n          // that we are also `requestPresent`ing. Until then, don't fullscreen if headset\n          // connected.\n          if (!self.isMobile && !self.checkHeadsetConnected()) {\n            requestFullscreen(self.canvas);\n          }\n          self.resize();\n        }\n\n        function enterVRFailure (err) {\n          if (err && err.message) {\n            throw new Error('Failed to enter VR mode (`requestPresent`): ' + err.message);\n          } else {\n            throw new Error('Failed to enter VR mode (`requestPresent`).');\n          }\n        }\n      },\n      writable: window.debug\n    },\n     /**\n     * Call `exitPresent` if WebVR or WebVR polyfill.\n     * Handle events, states, fullscreen styles.\n     *\n     * @param {bool} fromExternal - Whether exiting VR due to an external event (e.g.,\n     *   Oculus Browser GearVR back button).\n     * @returns {Promise}\n     */\n    exitVR: {\n      value: function (fromExternal) {\n        var self = this;\n\n        // Don't exit VR if not in VR.\n        if (!this.is('vr-mode')) { return Promise.resolve('Not in VR.'); }\n\n        exitFullscreen();\n\n        // Handle exiting VR if not yet already and in a headset or polyfill.\n        if (!fromExternal && (this.checkHeadsetConnected() || this.isMobile)) {\n          return this.effect.exitPresent().then(exitVRSuccess, exitVRFailure);\n        }\n\n        // Handle exiting VR in all other cases (2D fullscreen, external exit VR event).\n        exitVRSuccess();\n\n        return Promise.resolve();\n\n        function exitVRSuccess () {\n          self.removeState('vr-mode');\n          // Lock to landscape orientation on mobile.\n          if (self.isMobile && screen.orientation && screen.orientation.unlock) {\n            screen.orientation.unlock();\n          }\n          // Exiting VR in embedded mode, no longer need fullscreen styles.\n          if (self.hasAttribute('embedded')) { self.removeFullScreenStyles(); }\n          self.resize();\n          if (self.isIOS) { utils.forceCanvasResizeSafariMobile(this.canvas); }\n          self.emit('exit-vr', {target: self});\n        }\n\n        function exitVRFailure (err) {\n          if (err && err.message) {\n            throw new Error('Failed to exit VR mode (`exitPresent`): ' + err.message);\n          } else {\n            throw new Error('Failed to exit VR mode (`exitPresent`).');\n          }\n        }\n      },\n      writable: window.debug\n    },\n\n    pointerRestricted: {\n      value: function () {\n        if (this.canvas) {\n          var pointerLockElement = this.getPointerLockElement();\n          if (pointerLockElement && pointerLockElement !== this.canvas && document.exitPointerLock) {\n            // Recreate pointer lock on the canvas, if taken on another element.\n            document.exitPointerLock();\n          }\n\n          if (this.canvas.requestPointerLock) {\n            this.canvas.requestPointerLock();\n          }\n        }\n      }\n    },\n\n    pointerUnrestricted: {\n      value: function () {\n        var pointerLockElement = this.getPointerLockElement();\n        if (pointerLockElement && pointerLockElement === this.canvas && document.exitPointerLock) {\n          document.exitPointerLock();\n        }\n      }\n    },\n\n    /**\n     * Handle `vrdisplaypresentchange` event for exiting VR through other means than\n     * `<ESC>` key. For example, GearVR back button on Oculus Browser.\n     */\n    onVRPresentChange: {\n      value: function (evt) {\n        // Polyfill places display inside the detail property\n        var display = evt.display || evt.detail.display;\n        // Entering VR.\n        if (display.isPresenting) {\n          this.enterVR(true);\n          return;\n        }\n        // Exiting VR.\n        this.exitVR(true);\n      }\n    },\n\n    /**\n     * Wraps Entity.getAttribute to take into account for systems.\n     * If system exists, then return system data rather than possible component data.\n     */\n    getAttribute: {\n      value: function (attr) {\n        var system = this.systems[attr];\n        if (system) { return system.data; }\n        return AEntity.prototype.getAttribute.call(this, attr);\n      }\n    },\n\n    /**\n     * `getAttribute` used to be `getDOMAttribute` and `getComputedAttribute` used to be\n     * what `getAttribute` is now. Now legacy code.\n     */\n    getComputedAttribute: {\n      value: function (attr) {\n        warn('`getComputedAttribute` is deprecated. Use `getAttribute` instead.');\n        this.getAttribute(attr);\n      }\n    },\n\n    /**\n     * Wraps Entity.getDOMAttribute to take into account for systems.\n     * If system exists, then return system data rather than possible component data.\n     */\n    getDOMAttribute: {\n      value: function (attr) {\n        var system = this.systems[attr];\n        if (system) { return system.data; }\n        return AEntity.prototype.getDOMAttribute.call(this, attr);\n      }\n    },\n\n    /**\n     * Wrap Entity.setAttribute to take into account for systems.\n     * If system exists, then skip component initialization checks and do a normal\n     * setAttribute.\n     */\n    setAttribute: {\n      value: function (attr, value, componentPropValue) {\n        var system = this.systems[attr];\n        if (system) {\n          ANode.prototype.setAttribute.call(this, attr, value);\n          system.updateProperties(value);\n          return;\n        }\n        AEntity.prototype.setAttribute.call(this, attr, value, componentPropValue);\n      }\n    },\n\n    /**\n     * @param {object} behavior - Generally a component. Has registered itself to behaviors.\n     */\n    removeBehavior: {\n      value: function (behavior) {\n        var self = this;\n        var behaviors = this.behaviors;\n        // Check if behavior has tick and/or tock and remove the behavior from the appropriate array.\n        Object.keys(behaviors).forEach(function (behaviorType) {\n          if (!behavior[behaviorType]) { return; }\n          var behaviorArr = self.behaviors[behaviorType];\n          var index = behaviorArr.indexOf(behavior);\n          if (index !== -1) {\n            behaviorArr.splice(index, 1);\n          }\n        });\n      }\n    },\n\n    resize: {\n      value: function () {\n        var camera = this.camera;\n        var canvas = this.canvas;\n        var embedded = this.getAttribute('embedded') && !this.is('vr-mode');\n        var size;\n        var isEffectPresenting = this.effect && this.effect.isPresenting;\n        // Do not update renderer, if a camera or a canvas have not been injected.\n        // In VR mode, VREffect handles canvas resize based on the dimensions returned by\n        // the getEyeParameters function of the WebVR API. These dimensions are independent of\n        // the window size, therefore should not be overwritten with the window's width and height,\n        // except when in fullscreen mode.\n        if (!camera || !canvas || (this.is('vr-mode') && (this.isMobile || isEffectPresenting))) { return; }\n        // Update camera.\n        size = getCanvasSize(canvas, embedded);\n        camera.aspect = size.width / size.height;\n        camera.updateProjectionMatrix();\n        // Notify renderer of size change.\n        this.renderer.setSize(size.width, size.height);\n      },\n      writable: window.debug\n    },\n\n    setupRenderer: {\n      value: function () {\n        var renderer;\n\n        renderer = this.renderer = new THREE.WebGLRenderer({\n          canvas: this.canvas,\n          antialias: shouldAntiAlias(this),\n          alpha: true\n        });\n        renderer.setPixelRatio(window.devicePixelRatio);\n        renderer.sortObjects = false;\n        this.effect = new THREE.VREffect(renderer);\n        this.effect.autoSubmitFrame = false;\n      },\n      writable: window.debug\n    },\n\n    /**\n     * Handler attached to elements to help scene know when to kick off.\n     * Scene waits for all entities to load.\n     */\n    play: {\n      value: function () {\n        var self = this;\n        if (this.renderStarted) {\n          AEntity.prototype.play.call(this);\n          return;\n        }\n\n        this.addEventListener('loaded', function () {\n          AEntity.prototype.play.call(this);  // .play() *before* render.\n\n          // Wait for camera if necessary before rendering.\n          if (this.camera) {\n            startRender(this);\n            return;\n          }\n          this.addEventListener('camera-set-active', function () { startRender(this); });\n\n          function startRender (sceneEl) {\n            if (sceneEl.renderStarted) { return; }\n\n            sceneEl.resize();\n\n            // Kick off render loop.\n            if (sceneEl.renderer) {\n              if (window.performance) {\n                window.performance.mark('render-started');\n              }\n              sceneEl.clock = new THREE.Clock();\n              sceneEl.render();\n              sceneEl.renderStarted = true;\n              sceneEl.emit('renderstart');\n            }\n          }\n        });\n\n        // setTimeout to wait for all nodes to attach and run their callbacks.\n        setTimeout(function () {\n          AEntity.prototype.load.call(self);\n        });\n      }\n    },\n\n    /**\n     * Reload the scene to the original DOM content.\n     *\n     * @param {bool} doPause - Whether to reload the scene with all dynamic behavior paused.\n     */\n    reload: {\n      value: function (doPause) {\n        var self = this;\n        if (doPause) { this.pause(); }\n        this.innerHTML = this.originalHTML;\n        this.init();\n        ANode.prototype.load.call(this, play);\n        function play () {\n          if (!self.isPlaying) { return; }\n          AEntity.prototype.play.call(self);\n        }\n      }\n    },\n\n    /**\n     * Wrap `updateComponent` to not initialize the component if the component has a system\n     * (aframevr/aframe#2365).\n     */\n    updateComponent: {\n      value: function (componentName) {\n        if (componentName in systems) { return; }\n        AEntity.prototype.updateComponent.apply(this, arguments);\n      }\n    },\n\n    /**\n     * Behavior-updater meant to be called from scene render.\n     * Abstracted to a different function to facilitate unit testing (`scene.tick()`) without\n     * needing to render.\n     */\n    tick: {\n      value: function (time, timeDelta) {\n        var i;\n        var systems = this.systems;\n\n        // Animations.\n        TWEEN.update();\n\n        // Components.\n        for (i = 0; i < this.behaviors.tick.length; i++) {\n          if (!this.behaviors.tick[i].el.isPlaying) { continue; }\n          this.behaviors.tick[i].tick(time, timeDelta);\n        }\n\n        // Systems.\n        for (i = 0; i < this.systemNames.length; i++) {\n          if (!systems[this.systemNames[i]].tick) { continue; }\n          systems[this.systemNames[i]].tick(time, timeDelta);\n        }\n      }\n    },\n\n    /**\n     * Behavior-updater meant to be called after scene render for post processing purposes.\n     * Abstracted to a different function to facilitate unit testing (`scene.tock()`) without\n     * needing to render.\n     */\n    tock: {\n      value: function (time, timeDelta) {\n        var i;\n        var systems = this.systems;\n\n        // Components.\n        for (i = 0; i < this.behaviors.tock.length; i++) {\n          if (!this.behaviors.tock[i].el.isPlaying) { continue; }\n          this.behaviors.tock[i].tock(time, timeDelta);\n        }\n\n        // Systems.\n        for (i = 0; i < this.systemNames.length; i++) {\n          if (!systems[this.systemNames[i]].tock) { continue; }\n          systems[this.systemNames[i]].tock(time, timeDelta);\n        }\n      }\n    },\n\n    /**\n     * The render loop.\n     *\n     * Updates animations.\n     * Updates behaviors.\n     * Renders with request animation frame.\n     */\n    render: {\n      value: function () {\n        var effect = this.effect;\n        var delta = this.clock.getDelta() * 1000;\n        this.time = this.clock.elapsedTime * 1000;\n\n        if (this.isPlaying) { this.tick(this.time, delta); }\n\n        this.animationFrameID = effect.requestAnimationFrame(this.render);\n        effect.render(this.object3D, this.camera, this.renderTarget);\n\n        if (this.isPlaying) { this.tock(this.time, delta); }\n\n        this.effect.submitFrame();\n      },\n      writable: true\n    }\n  })\n});\n\n/**\n * Return the canvas size where the scene will be rendered\n * It will be always the window size except when the scene\n * is embedded. The parent size will be returned in that case\n *\n * @param {object} canvasEl - the canvas element\n * @param {boolean} embedded - Is the scene embedded?\n */\nfunction getCanvasSize (canvasEl, embedded) {\n  if (embedded) {\n    return {\n      height: canvasEl.parentElement.offsetHeight,\n      width: canvasEl.parentElement.offsetWidth\n    };\n  }\n  return {\n    height: window.innerHeight,\n    width: window.innerWidth\n  };\n}\n\nfunction requestFullscreen (canvas) {\n  var requestFullscreen =\n    canvas.requestFullscreen ||\n    canvas.webkitRequestFullscreen ||\n    canvas.mozRequestFullScreen ||  // The capitalized `S` is not a typo.\n    canvas.msRequestFullscreen;\n  requestFullscreen.apply(canvas);\n}\n\nfunction exitFullscreen () {\n  if (document.exitFullscreen) {\n    document.exitFullscreen();\n  } else if (document.mozCancelFullScreen) {\n    document.mozCancelFullScreen();\n  } else if (document.webkitExitFullscreen) {\n    document.webkitExitFullscreen();\n  }\n}\n\n/**\n * Determines if renderer anti-aliasing should be enabled.\n * Enabled by default if has native WebVR or is desktop.\n *\n * @returns {bool}\n */\nfunction shouldAntiAlias (sceneEl) {\n  // Explicitly set.\n  if (sceneEl.getAttribute('antialias') !== null) {\n    return sceneEl.getAttribute('antialias') === 'true';\n  }\n\n  // Default not AA for mobile.\n  return !sceneEl.isMobile;\n}\nmodule.exports.shouldAntiAlias = shouldAntiAlias;  // For testing.\n\nfunction setupCanvas (sceneEl) {\n  var canvasEl;\n\n  canvasEl = document.createElement('canvas');\n  canvasEl.classList.add('a-canvas');\n  // Mark canvas as provided/injected by A-Frame.\n  canvasEl.dataset.aframeCanvas = true;\n  sceneEl.appendChild(canvasEl);\n\n  document.addEventListener('fullscreenchange', onFullScreenChange);\n  document.addEventListener('mozfullscreenchange', onFullScreenChange);\n  document.addEventListener('webkitfullscreenchange', onFullScreenChange);\n\n  // Prevent overscroll on mobile.\n  canvasEl.addEventListener('touchmove', function (event) { event.preventDefault(); });\n\n  // Set canvas on scene.\n  sceneEl.canvas = canvasEl;\n  sceneEl.emit('render-target-loaded', {target: canvasEl});\n  // For unknown reasons a synchronous resize does not work on desktop when\n  // entering/exiting fullscreen.\n  setTimeout(bind(sceneEl.resize, sceneEl), 0);\n\n  function onFullScreenChange () {\n    var fullscreenEl =\n      document.fullscreenElement ||\n      document.mozFullScreenElement ||\n      document.webkitFullscreenElement;\n    // No fullscren element === exit fullscreen\n    if (!fullscreenEl) { sceneEl.exitVR(); }\n    document.activeElement.blur();\n    document.body.focus();\n  }\n}\nmodule.exports.setupCanvas = setupCanvas;  // For testing.\n\n},{\"../../lib/three\":173,\"../../utils/\":195,\"../a-entity\":121,\"../a-node\":123,\"../a-register-element\":124,\"../system\":135,\"./metaTags\":129,\"./postMessage\":130,\"./scenes\":131,\"./wakelock\":132,\"@tweenjs/tween.js\":1}],129:[function(_dereq_,module,exports){\nvar constants = _dereq_('../../constants/');\nvar extend = _dereq_('../../utils').extend;\n\nvar MOBILE_HEAD_TAGS = module.exports.MOBILE_HEAD_TAGS = [\n  Meta({name: 'viewport', content: 'width=device-width,initial-scale=1,maximum-scale=1,shrink-to-fit=no,user-scalable=no,minimal-ui'}),\n\n  // W3C-standardised meta tags.\n  Meta({name: 'mobile-web-app-capable', content: 'yes'}),\n  Meta({name: 'theme-color', content: 'black'})\n];\n\nvar MOBILE_IOS_HEAD_TAGS = [\n  // iOS-specific meta tags for fullscreen when pinning to homescreen.\n  Meta({name: 'apple-mobile-web-app-capable', content: 'yes'}),\n  Meta({name: 'apple-mobile-web-app-status-bar-style', content: 'black'}),\n  Link({rel: 'apple-touch-icon', href: 'https://aframe.io/images/aframe-logo-152.png'})\n];\n\nfunction Meta (attrs) {\n  return {\n    tagName: 'meta',\n    attributes: attrs,\n    exists: function () { return document.querySelector('meta[name=\"' + attrs.name + '\"]'); }\n  };\n}\n\nfunction Link (attrs) {\n  return {\n    tagName: 'link',\n    attributes: attrs,\n    exists: function () { return document.querySelector('link[rel=\"' + attrs.rel + '\"]'); }\n  };\n}\n\n/**\n * Injects the necessary metatags in the document for mobile support:\n * 1. Prevent the user to zoom in the document.\n * 2. Ensure that window.innerWidth and window.innerHeight have the correct\n *    values and the canvas is properly scaled.\n * 3. To allow fullscreen mode when pinning a web app on the home screen on\n *    iOS.\n * Adapted from https://www.reddit.com/r/web_design/comments/3la04p/\n *\n * @param {object} scene - Scene element\n * @returns {Array}\n */\nmodule.exports.inject = function injectHeadTags (scene) {\n  var headEl = document.head;\n  var headScriptEl = headEl.querySelector('script');\n  var tag;\n  var headTags = [];\n  MOBILE_HEAD_TAGS.forEach(createAndInjectTag);\n  if (scene.isIOS) {\n    MOBILE_IOS_HEAD_TAGS.forEach(createAndInjectTag);\n  }\n  return headTags;\n\n  function createAndInjectTag (tagObj) {\n    if (!tagObj || tagObj.exists()) { return; }\n\n    tag = createTag(tagObj);\n    if (!tag) { return; }\n\n    if (headScriptEl) {\n      headScriptEl.parentNode.insertBefore(tag, headScriptEl);\n    } else {\n      headEl.appendChild(tag);\n    }\n\n    headTags.push(tag);\n  }\n};\n\nfunction createTag (tagObj) {\n  if (!tagObj || !tagObj.tagName) { return; }\n  var meta = document.createElement(tagObj.tagName);\n  meta.setAttribute(constants.AFRAME_INJECTED, '');\n  return extend(meta, tagObj.attributes);\n}\n\n},{\"../../constants/\":116,\"../../utils\":195}],130:[function(_dereq_,module,exports){\nvar bind = _dereq_('../../utils/bind');\nvar isIframed = _dereq_('../../utils/').isIframed;\n\n/**\n * Provides a post message API for scenes contained\n * in an iframe.\n */\nmodule.exports = function initPostMessageAPI (scene) {\n  // Handles fullscreen behavior when inside an iframe.\n  if (!isIframed()) { return; }\n  // postMessage API handler\n  window.addEventListener('message', bind(postMessageAPIHandler, scene));\n};\n\nfunction postMessageAPIHandler (event) {\n  var scene = this;\n  if (!event.data) { return; }\n\n  switch (event.data.type) {\n    case 'vr': {\n      switch (event.data.data) {\n        case 'enter':\n          scene.enterVR();\n          break;\n        case 'exit':\n          scene.exitVR();\n          break;\n      }\n    }\n  }\n}\n\n},{\"../../utils/\":195,\"../../utils/bind\":189}],131:[function(_dereq_,module,exports){\n/*\n  Scene index for keeping track of created scenes.\n*/\nmodule.exports = [];\n\n},{}],132:[function(_dereq_,module,exports){\nvar Wakelock = _dereq_('../../../vendor/wakelock/wakelock');\n\nmodule.exports = function initWakelock (scene) {\n  if (!scene.isMobile) { return; }\n\n  var wakelock = scene.wakelock = new Wakelock();\n  scene.addEventListener('enter-vr', function () { wakelock.request(); });\n  scene.addEventListener('exit-vr', function () { wakelock.release(); });\n};\n\n},{\"../../../vendor/wakelock/wakelock\":205}],133:[function(_dereq_,module,exports){\nvar utils = _dereq_('../utils/');\nvar PropertyTypes = _dereq_('./propertyTypes');\n\nvar debug = utils.debug;\nvar isValidDefaultValue = PropertyTypes.isValidDefaultValue;\nvar propertyTypes = PropertyTypes.propertyTypes;\n\nvar warn = debug('core:schema:warn');\n\n/**\n * A schema is classified as a schema for a single property if:\n * - `type` is defined on the schema as a string.\n * - OR `default` is defined on the schema, as a reserved keyword.\n * - OR schema is empty.\n */\nfunction isSingleProperty (schema) {\n  if ('type' in schema) {\n    return typeof schema.type === 'string';\n  }\n  return 'default' in schema;\n}\nmodule.exports.isSingleProperty = isSingleProperty;\n\n/**\n * Build step to schema to use `type` to inject default value, parser, and stringifier.\n *\n * @param {object} schema\n * @param {string} componentName\n * @returns {object} Schema.\n */\nmodule.exports.process = function (schema, componentName) {\n  // For single property schema, run processPropDefinition over the whole schema.\n  if (isSingleProperty(schema)) {\n    return processPropertyDefinition(schema, componentName);\n  }\n\n  // For multi-property schema, run processPropDefinition over each property definition.\n  Object.keys(schema).forEach(function (propName) {\n    schema[propName] = processPropertyDefinition(schema[propName], componentName);\n  });\n  return schema;\n};\n\n/**\n * Inject default value, parser, stringifier for single property.\n *\n * @param {object} propDefinition\n * @param {string} componentName\n */\nfunction processPropertyDefinition (propDefinition, componentName) {\n  var defaultVal = propDefinition.default;\n  var isCustomType;\n  var propType;\n  var typeName = propDefinition.type;\n\n  // Type inference.\n  if (!propDefinition.type) {\n    if (defaultVal !== undefined && ['boolean', 'number'].indexOf(typeof defaultVal) !== -1) {\n      // Type inference.\n      typeName = typeof defaultVal;\n    } else if (Array.isArray(defaultVal)) {\n      typeName = 'array';\n    } else {\n      // Fall back to string.\n      typeName = 'string';\n    }\n  } else if (propDefinition.type === 'bool') {\n    typeName = 'boolean';\n  } else if (propDefinition.type === 'float') {\n    typeName = 'number';\n  }\n\n  propType = propertyTypes[typeName];\n  if (!propType) {\n    warn('Unknown property type for component `' + componentName + '`: ' + typeName);\n  }\n\n  // Fill in parse and stringify using property types.\n  isCustomType = !!propDefinition.parse;\n  propDefinition.parse = propDefinition.parse || propType.parse;\n  propDefinition.stringify = propDefinition.stringify || propType.stringify;\n\n  // Fill in type name.\n  propDefinition.type = typeName;\n\n  // Check that default value exists.\n  if ('default' in propDefinition) {\n    // Check that default values are valid.\n    if (!isCustomType && !isValidDefaultValue(typeName, defaultVal)) {\n      warn('Default value `' + defaultVal + '` does not match type `' + typeName +\n           '` in component `' + componentName + '`');\n    }\n  } else {\n    // Fill in default value.\n    propDefinition.default = propType.default;\n  }\n\n  return propDefinition;\n}\nmodule.exports.processPropertyDefinition = processPropertyDefinition;\n\n/**\n * Parse propData using schema. Use default values if not existing in propData.\n *\n * @param {object} propData - Unparsed properties.\n * @param {object} schema - Property types definition.\n * @param {boolean} getPartialData - Whether to return full component data or just the data\n *        with keys in `propData`.\n * @param {string } componentName - Name of the component, used for the property warning.\n * @param {boolean} silent - Suppress warning messages.\n */\nmodule.exports.parseProperties = function (propData, schema, getPartialData, componentName,\n                                           silent) {\n  var propNames = Object.keys(getPartialData ? propData : schema);\n\n  if (propData === null || typeof propData !== 'object') { return propData; }\n\n  // Validation errors.\n  Object.keys(propData).forEach(function (propName) {\n    if (!schema[propName] && !silent) {\n      warn('Unknown property `' + propName +\n           '` for component/system `' + componentName + '`.');\n    }\n  });\n\n  propNames.forEach(function parse (propName) {\n    var propDefinition = schema[propName];\n    var propValue = propData[propName];\n    if (!(schema[propName])) { return; }\n    propData[propName] = parseProperty(propValue, propDefinition);\n  });\n\n  return propData;\n};\n\n/**\n * Deserialize a single property.\n */\nfunction parseProperty (value, propDefinition) {\n  // Use default value if value is falsy.\n  if (value === undefined || value === null || value === '') {\n    value = propDefinition.default;\n    if (Array.isArray(value)) { value = value.slice(); }\n  }\n  // Invoke property type parser.\n  return propDefinition.parse(value, propDefinition.default);\n}\nmodule.exports.parseProperty = parseProperty;\n\n/**\n * Serialize a group of properties.\n */\nmodule.exports.stringifyProperties = function (propData, schema) {\n  var stringifiedData = {};\n  Object.keys(propData).forEach(function (propName) {\n    var propDefinition = schema[propName];\n    var propValue = propData[propName];\n    var value = propValue;\n    if (typeof value === 'object') {\n      value = stringifyProperty(propValue, propDefinition);\n      if (!propDefinition) { warn('Unknown component property: ' + propName); }\n    }\n    stringifiedData[propName] = value;\n  });\n  return stringifiedData;\n};\n\n/**\n * Serialize a single property.\n */\nfunction stringifyProperty (value, propDefinition) {\n  // This function stringifies but it's used in a context where\n  // there's always second stringification pass. By returning the original\n  // value when it's not an object we save one unnecessary call\n  // to JSON.stringify.\n  if (typeof value !== 'object') { return value; }\n  // if there's no schema for the property we use standar JSON stringify\n  if (!propDefinition || value === null) { return JSON.stringify(value); }\n  return propDefinition.stringify(value);\n}\nmodule.exports.stringifyProperty = stringifyProperty;\n\n},{\"../utils/\":195,\"./propertyTypes\":127}],134:[function(_dereq_,module,exports){\nvar schema = _dereq_('./schema');\n\nvar processSchema = schema.process;\nvar shaders = module.exports.shaders = {};  // Keep track of registered shaders.\nvar shaderNames = module.exports.shaderNames = [];  // Keep track of the names of registered shaders.\nvar THREE = _dereq_('../lib/three');\nvar utils = _dereq_('../utils');\n\n// A-Frame properties to three.js uniform types.\nvar propertyToThreeMapping = {\n  array: 'v3',\n  color: 'v3',\n  int: 'i',\n  number: 'f',\n  map: 't',\n  time: 'f',\n  vec2: 'v2',\n  vec3: 'v3',\n  vec4: 'v4'\n};\n\n/**\n * Shader class definition.\n *\n * Shaders extend the material component API so you can create your own library\n * of customized materials\n *\n */\nvar Shader = module.exports.Shader = function () {};\n\nShader.prototype = {\n  /**\n   * Contains the type schema and defaults for the data values.\n   * Data is coerced into the types of the values of the defaults.\n   */\n  schema: {},\n\n  vertexShader:\n    'void main() {' +\n      'gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);' +\n    '}',\n\n  fragmentShader:\n    'void main() {' +\n      'gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);' +\n    '}',\n\n  /**\n   * Init handler. Similar to attachedCallback.\n   * Called during shader initialization and is only run once.\n   */\n  init: function (data) {\n    this.attributes = this.initVariables(data, 'attribute');\n    this.uniforms = this.initVariables(data, 'uniform');\n    this.material = new (this.raw ? THREE.RawShaderMaterial : THREE.ShaderMaterial)({\n      // attributes: this.attributes,\n      uniforms: this.uniforms,\n      vertexShader: this.vertexShader,\n      fragmentShader: this.fragmentShader\n    });\n    return this.material;\n  },\n\n  initVariables: function (data, type) {\n    var variables = {};\n    var schema = this.schema;\n    Object.keys(schema).forEach(function processSchema (key) {\n      if (schema[key].is !== type) { return; }\n      var varType = propertyToThreeMapping[schema[key].type];\n      variables[key] = {\n        type: varType,\n        value: undefined  // Let updateVariables handle setting these.\n      };\n    });\n    return variables;\n  },\n\n  /**\n   * Update handler. Similar to attributeChangedCallback.\n   * Called whenever the associated material data changes.\n   *\n   * @param {object} data - New material data.\n   */\n  update: function (data) {\n    this.updateVariables(data, 'attribute');\n    this.updateVariables(data, 'uniform');\n  },\n\n  updateVariables: function (data, type) {\n    var self = this;\n    var variables = type === 'uniform' ? this.uniforms : this.attributes;\n    var schema = this.schema;\n    Object.keys(data).forEach(function processData (key) {\n      var materialKey;\n      if (!schema[key] || schema[key].is !== type) { return; }\n\n      if (schema[key].type === 'map') {\n        // If data unchanged, get out early.\n        if (!variables[key] || variables[key].value === data[key]) { return; }\n\n        // Special handling is needed for textures.\n        materialKey = '_texture_' + key;\n\n        // We can't actually set the variable correctly until we've loaded the texture.\n        self.el.addEventListener('materialtextureloaded', function () {\n          variables[key].value = self.material[materialKey];\n          variables[key].needsUpdate = true;\n        });\n\n        // Kick off the texture update now that handler is added.\n        utils.material.updateMapMaterialFromData(materialKey, key, self, data);\n        return;\n      }\n      variables[key].value = self.parseValue(schema[key].type, data[key]);\n      variables[key].needsUpdate = true;\n    });\n  },\n\n  parseValue: function (type, value) {\n    var color;\n    switch (type) {\n      case 'vec2': {\n        return new THREE.Vector2(value.x, value.y);\n      }\n      case 'vec3': {\n        return new THREE.Vector3(value.x, value.y, value.z);\n      }\n      case 'vec4': {\n        return new THREE.Vector4(value.x, value.y, value.z, value.w);\n      }\n      case 'color': {\n        color = new THREE.Color(value);\n        return new THREE.Vector3(color.r, color.g, color.b);\n      }\n      case 'map': {\n        return THREE.ImageUtils.loadTexture(value);\n      }\n      default: {\n        return value;\n      }\n    }\n  }\n};\n\n/**\n * Registers a shader to A-Frame.\n *\n * @param {string} name - shader name.\n * @param {object} definition - shader property and methods.\n * @returns {object} Shader.\n */\nmodule.exports.registerShader = function (name, definition) {\n  var NewShader;\n  var proto = {};\n\n  // Format definition object to prototype object.\n  Object.keys(definition).forEach(function (key) {\n    proto[key] = {\n      value: definition[key],\n      writable: true\n    };\n  });\n\n  if (shaders[name]) {\n    throw new Error('The shader ' + name + ' has been already registered');\n  }\n  NewShader = function () { Shader.call(this); };\n  NewShader.prototype = Object.create(Shader.prototype, proto);\n  NewShader.prototype.name = name;\n  NewShader.prototype.constructor = NewShader;\n  shaders[name] = {\n    Shader: NewShader,\n    schema: processSchema(NewShader.prototype.schema)\n  };\n  shaderNames.push(name);\n  return NewShader;\n};\n\n},{\"../lib/three\":173,\"../utils\":195,\"./schema\":133}],135:[function(_dereq_,module,exports){\nvar components = _dereq_('./component');\nvar schema = _dereq_('./schema');\nvar utils = _dereq_('../utils/');\n\nvar parseProperties = schema.parseProperties;\nvar parseProperty = schema.parseProperty;\nvar processSchema = schema.process;\nvar isSingleProp = schema.isSingleProperty;\nvar styleParser = utils.styleParser;\n\nvar systems = module.exports.systems = {};  // Keep track of registered systems.\n\n/**\n * System class definition.\n *\n * Systems provide global scope and services to a group of instantiated components of the\n * same class. They can also help abstract logic away from components such that components\n * only have to worry about data.\n *\n * For example, a physics component that creates a physics world that oversees\n * all entities with a physics or rigid body component.\n *\n * TODO: Have the System prototype reuse the Component prototype. Most code is copied\n * and some pieces are missing from the Component facilities (e.g., attribute caching,\n * setAttribute behavior).\n *\n * @member {string} name - Name that system is registered under.\n * @member {Element} sceneEl - Handle to the scene element where system applies to.\n */\nvar System = module.exports.System = function (sceneEl) {\n  var component = components && components.components[this.name];\n\n  // Set reference to scene.\n  this.el = sceneEl;\n  this.sceneEl = sceneEl;\n\n  // Set reference to matching component (if exists).\n  if (component) { component.Component.prototype.system = this; }\n\n  // Process system configuration.\n  this.buildData();\n  this.init();\n  this.update({});\n};\n\nSystem.prototype = {\n  /**\n   * Schema to configure system.\n   */\n  schema: {},\n\n  /**\n   * Init handler. Called during scene initialization and is only run once.\n   * Systems can use this to set initial state.\n   */\n  init: function () { /* no-op */ },\n\n  /**\n   * Update handler. Called during scene attribute updates.\n   * Systems can use this to dynamically update their state.\n   */\n  update: function (oldData) { /* no-op */ },\n\n  /**\n   * Build data and call update handler.\n   *\n   * @private\n   */\n  updateProperties: function (rawData) {\n    var oldData = this.data;\n    if (!Object.keys(schema).length) { return; }\n    this.buildData(rawData);\n    this.update(oldData);\n  },\n\n  /**\n   * Parse data.\n   */\n  buildData: function (rawData) {\n    var schema = this.schema;\n    if (!Object.keys(schema).length) { return; }\n    rawData = rawData || window.HTMLElement.prototype.getAttribute.call(this.sceneEl, this.name);\n    if (isSingleProp(schema)) {\n      this.data = parseProperty(rawData, schema);\n    } else {\n      this.data = parseProperties(styleParser.parse(rawData) || {}, schema);\n    }\n  },\n\n  /**\n   * Tick handler.\n   * Called on each tick of the scene render loop.\n   * Affected by play and pause.\n   *\n   * @param {number} time - Scene tick time.\n   * @param {number} timeDelta - Difference in current render time and previous render time.\n   */\n  tick: undefined,\n\n  /**\n   * Tock handler.\n   * Called on each tock of the scene render loop.\n   * Affected by play and pause.\n   *\n   * @param {number} time - Scene tick time.\n   * @param {number} timeDelta - Difference in current render time and previous render time.\n   */\n  tock: undefined,\n\n  /**\n   * Called to start any dynamic behavior (e.g., animation, AI, events, physics).\n   */\n  play: function () { /* no-op */ },\n\n  /**\n   * Called to stop any dynamic behavior (e.g., animation, AI, events, physics).\n   */\n  pause: function () { /* no-op */ }\n};\n\n/**\n * Registers a system to A-Frame.\n *\n * @param {string} name - Component name.\n * @param {object} definition - Component property and methods.\n * @returns {object} Component.\n */\nmodule.exports.registerSystem = function (name, definition) {\n  var i;\n  var NewSystem;\n  var proto = {};\n  var scenes = utils.findAllScenes(document);\n\n  // Format definition object to prototype object.\n  Object.keys(definition).forEach(function (key) {\n    proto[key] = {\n      value: definition[key],\n      writable: true\n    };\n  });\n\n  if (systems[name]) {\n    throw new Error('The system `' + name + '` has been already registered. ' +\n                    'Check that you are not loading two versions of the same system ' +\n                    'or two different systems of the same name.');\n  }\n  NewSystem = function (sceneEl) { System.call(this, sceneEl); };\n  NewSystem.prototype = Object.create(System.prototype, proto);\n  NewSystem.prototype.name = name;\n  NewSystem.prototype.constructor = NewSystem;\n  NewSystem.prototype.schema = utils.extend(processSchema(NewSystem.prototype.schema));\n  systems[name] = NewSystem;\n\n  // Initialize systems for existing scenes\n  for (i = 0; i < scenes.length; i++) { scenes[i].initSystem(name); }\n};\n\n},{\"../utils/\":195,\"./component\":125,\"./schema\":133}],136:[function(_dereq_,module,exports){\n_dereq_('./pivot');\n\n},{\"./pivot\":137}],137:[function(_dereq_,module,exports){\nvar registerComponent = _dereq_('../../core/component').registerComponent;\nvar THREE = _dereq_('../../lib/three');\n\nvar originalPosition = new THREE.Vector3();\nvar originalRotation = new THREE.Vector3();\n\n/**\n * Wrap el.object3D within an outer group. Apply pivot to el.object3D as position.\n */\nregisterComponent('pivot', {\n  dependencies: ['position'],\n\n  schema: {type: 'vec3'},\n\n  init: function () {\n    var data = this.data;\n    var el = this.el;\n    var originalParent = el.object3D.parent;\n    var originalGroup = el.object3D;\n    var outerGroup = new THREE.Group();\n\n    originalPosition.copy(originalGroup.position);\n    originalRotation.copy(originalGroup.rotation);\n\n    // Detach current group from parent.\n    originalParent.remove(originalGroup);\n    outerGroup.add(originalGroup);\n\n    // Set new group as the outer group.\n    originalParent.add(outerGroup);\n\n    // Set outer group as new object3D.\n    el.object3D = outerGroup;\n\n    // Apply pivot to original group.\n    originalGroup.position.set(-1 * data.x, -1 * data.y, -1 * data.z);\n\n    // Offset the pivot so that world position not affected.\n    // And restore position onto outer group.\n    outerGroup.position.set(data.x + originalPosition.x, data.y + originalPosition.y,\n                            data.z + originalPosition.z);\n\n    // Transfer rotation to outer group.\n    outerGroup.rotation.copy(originalGroup.rotation);\n    originalGroup.rotation.set(0, 0, 0);\n  }\n});\n\n},{\"../../core/component\":125,\"../../lib/three\":173}],138:[function(_dereq_,module,exports){\n/**\n * Common mesh defaults, mappings, and transforms.\n */\nvar components = _dereq_('../../core/component').components;\nvar shaders = _dereq_('../../core/shader').shaders;\nvar utils = _dereq_('../../utils/');\n\nvar materialMappings = {};\nObject.keys(components.material.schema).forEach(addMapping);\nObject.keys(shaders.standard.schema).forEach(addMapping);\n\nfunction addMapping (prop) {\n  // To hyphenated.\n  var htmlAttrName = prop.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();\n  if (prop === 'fog') { htmlAttrName = 'material-fog'; }\n  if (prop === 'visible') { htmlAttrName = 'material-visible'; }\n  materialMappings[htmlAttrName] = 'material.' + prop;\n}\n\nmodule.exports = function getMeshMixin () {\n  return {\n    defaultComponents: {material: {}},\n    mappings: utils.extend({}, materialMappings)\n  };\n};\n\n},{\"../../core/component\":125,\"../../core/shader\":134,\"../../utils/\":195}],139:[function(_dereq_,module,exports){\n_dereq_('./primitives/a-camera');\n_dereq_('./primitives/a-collada-model');\n_dereq_('./primitives/a-cursor');\n_dereq_('./primitives/a-curvedimage');\n_dereq_('./primitives/a-gltf-model');\n_dereq_('./primitives/a-image');\n_dereq_('./primitives/a-light');\n_dereq_('./primitives/a-link');\n_dereq_('./primitives/a-obj-model');\n_dereq_('./primitives/a-sky');\n_dereq_('./primitives/a-sound');\n_dereq_('./primitives/a-text');\n_dereq_('./primitives/a-video');\n_dereq_('./primitives/a-videosphere');\n_dereq_('./primitives/meshPrimitives');\n\n},{\"./primitives/a-camera\":141,\"./primitives/a-collada-model\":142,\"./primitives/a-cursor\":143,\"./primitives/a-curvedimage\":144,\"./primitives/a-gltf-model\":145,\"./primitives/a-image\":146,\"./primitives/a-light\":147,\"./primitives/a-link\":148,\"./primitives/a-obj-model\":149,\"./primitives/a-sky\":150,\"./primitives/a-sound\":151,\"./primitives/a-text\":152,\"./primitives/a-video\":153,\"./primitives/a-videosphere\":154,\"./primitives/meshPrimitives\":155}],140:[function(_dereq_,module,exports){\nvar AEntity = _dereq_('../../core/a-entity');\nvar components = _dereq_('../../core/component').components;\nvar registerElement = _dereq_('../../core/a-register-element').registerElement;\nvar utils = _dereq_('../../utils/');\n\nvar debug = utils.debug;\nvar setComponentProperty = utils.entity.setComponentProperty;\nvar log = debug('extras:primitives:debug');\nvar warn = debug('extras:primitives:warn');\n\nvar primitives = module.exports.primitives = {};\n\nmodule.exports.registerPrimitive = function registerPrimitive (name, definition) {\n  name = name.toLowerCase();\n  log('Registering <%s>', name);\n\n  // Deprecation warning for defaultAttributes usage.\n  if (definition.defaultAttributes) {\n    warn(\"The 'defaultAttributes' object is deprecated. Use 'defaultComponents' instead.\");\n  }\n\n  var primitive = registerElement(name, {\n    prototype: Object.create(AEntity.prototype, {\n      defaultComponentsFromPrimitive: {\n        value: definition.defaultComponents || definition.defaultAttributes || {}\n      },\n      deprecated: {value: definition.deprecated || null},\n      deprecatedMappings: {value: definition.deprecatedMappings || {}},\n      mappings: {value: definition.mappings || {}},\n\n      createdCallback: {\n        value: function () {\n          if (definition.deprecated) { console.warn(definition.deprecated); }\n          this.resolveMappingCollisions();\n        }\n      },\n\n      /**\n       * If a mapping collides with a registered component name\n       * it renames the mapping to componentname-property\n       */\n      resolveMappingCollisions: {\n        value: function () {\n          var mappings = this.mappings;\n          var self = this;\n          Object.keys(mappings).forEach(function resolveCollision (key) {\n            var newAttribute;\n            if (key !== key.toLowerCase()) { warn('Mapping keys should be specified in lower case. The mapping key ' + key + ' may not be recognized'); }\n            if (components[key]) {\n              newAttribute = mappings[key].replace('.', '-');\n              mappings[newAttribute] = mappings[key];\n              delete mappings[key];\n              console.warn('The primitive ' + self.tagName.toLowerCase() + ' has a mapping collision. ' +\n                           'The attribute ' + key + ' has the same name as a registered component and' +\n                           ' has been renamed to ' + newAttribute);\n            }\n          });\n        }\n      },\n\n      getExtraComponents: {\n        value: function () {\n          var attr;\n          var data;\n          var i;\n          var mapping;\n          var mixins;\n          var path;\n          var self = this;\n\n          // Gather component data from default components.\n          data = utils.clone(this.defaultComponentsFromPrimitive);\n\n          // Factor in mixins to overwrite default components.\n          mixins = this.getAttribute('mixin');\n          if (mixins) {\n            mixins = mixins.trim().split(' ');\n            mixins.forEach(function applyMixin (mixinId) {\n              var mixinComponents = self.sceneEl.querySelector('#' + mixinId).componentCache;\n              Object.keys(mixinComponents).forEach(function setComponent (name) {\n                data[name] = extend(data[name], mixinComponents[name]);\n              });\n            });\n          }\n\n          // Gather component data from mappings.\n          for (i = 0; i < this.attributes.length; i++) {\n            attr = this.attributes[i];\n            mapping = this.mappings[attr.name];\n            if (mapping) {\n              path = utils.entity.getComponentPropertyPath(mapping);\n              if (path.constructor === Array) {\n                data[path[0]] = data[path[0]] || {};\n                data[path[0]][path[1]] = attr.value;\n              } else {\n                data[path] = attr.value;\n              }\n              continue;\n            }\n          }\n\n          return data;\n\n          /**\n           * For the base to be extensible, both objects must be pure JavaScript objects.\n           * The function assumes that base is undefined, or null or a pure object.\n           */\n          function extend (base, extension) {\n            if (isUndefined(base)) {\n              return copy(extension);\n            }\n            if (isUndefined(extension)) {\n              return copy(base);\n            }\n            if (isPureObject(base) && isPureObject(extension)) {\n              return utils.extendDeep(base, extension);\n            }\n            return copy(extension);\n          }\n\n          function isUndefined (value) {\n            return typeof value === 'undefined';\n          }\n\n          function copy (value) {\n            if (isPureObject(value)) {\n              return utils.extendDeep({}, value);\n            }\n            return value;\n          }\n\n          function isPureObject (value) {\n            return value !== null && value.constructor === Object;\n          }\n        }\n      },\n\n      /**\n       * Sync to attribute to component property whenever mapped attribute changes.\n       * If attribute is mapped to a component property, set the component property using\n       * the attribute value.\n       */\n      attributeChangedCallback: {\n        value: function (attr, oldVal, value) {\n          var componentName = this.mappings[attr];\n\n          if (attr in this.deprecatedMappings) {\n            console.warn(this.deprecatedMappings[attr]);\n          }\n\n          if (!attr || !componentName) { return; }\n\n          // Set value.\n          setComponentProperty(this, componentName, value);\n        }\n      }\n    })\n  });\n\n  // Store.\n  primitives[name] = primitive;\n  return primitive;\n};\n\n/**\n * Add component mappings using schema.\n */\nfunction addComponentMapping (componentName, mappings) {\n  var schema = components[componentName].schema;\n  Object.keys(schema).map(function (prop) {\n    // Hyphenate where there is camelCase.\n    var attrName = prop.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();\n    // If there is a mapping collision, prefix with component name and hyphen.\n    if (mappings[attrName] !== undefined) { attrName = componentName + '-' + prop; }\n    mappings[attrName] = componentName + '.' + prop;\n  });\n}\n\n/**\n * Helper to define a primitive, building mappings using a component schema.\n */\nfunction definePrimitive (tagName, defaultComponents, mappings) {\n  // If no initial mappings provided, start from empty map.\n  mappings = mappings || {};\n\n  // From the default components, add mapping automagically.\n  Object.keys(defaultComponents).map(function buildMappings (componentName) {\n    addComponentMapping(componentName, mappings);\n  });\n\n  // Register the primitive.\n  module.exports.registerPrimitive(tagName, utils.extendDeep({}, null, {\n    defaultComponents: defaultComponents,\n    mappings: mappings\n  }));\n}\nmodule.exports.definePrimitive = definePrimitive;\n\n},{\"../../core/a-entity\":121,\"../../core/a-register-element\":124,\"../../core/component\":125,\"../../utils/\":195}],141:[function(_dereq_,module,exports){\nvar DEFAULT_CAMERA_HEIGHT = _dereq_('../../../constants/').DEFAULT_CAMERA_HEIGHT;\nvar registerPrimitive = _dereq_('../primitives').registerPrimitive;\n\nregisterPrimitive('a-camera', {\n  defaultComponents: {\n    camera: {\n      userHeight: DEFAULT_CAMERA_HEIGHT\n    },\n    'look-controls': {},\n    'wasd-controls': {}\n  },\n\n  mappings: {\n    active: 'camera.active',\n    far: 'camera.far',\n    fov: 'camera.fov',\n    'look-controls-enabled': 'look-controls.enabled',\n    near: 'camera.near',\n    'wasd-controls-enabled': 'wasd-controls.enabled',\n    'reverse-mouse-drag': 'look-controls.reverseMouseDrag',\n    'user-height': 'camera.userHeight',\n    zoom: 'camera.zoom'\n  },\n\n  deprecatedMappings: {\n    'cursor-color': 'a-camera[cursor-color] has been removed. Use a-cursor[color] instead.',\n    'cursor-maxdistance': 'a-camera[cursor-maxdistance] has been removed. Use a-cursor[max-distance] instead.',\n    'cursor-offset': 'a-camera[cursor-offset] has been removed. Use a-cursor[position] instead.',\n    'cursor-opacity': 'a-camera[cursor-offset] has been removed. Use a-cursor[opacity] instead.',\n    'cursor-scale': 'a-camera[cursor-scale] has been removed. Use a-cursor[scale] instead.',\n    'cursor-visible': 'a-camera[cursor-visible] has been removed. Use a-cursor[visible] instead.'\n  }\n});\n\n},{\"../../../constants/\":116,\"../primitives\":140}],142:[function(_dereq_,module,exports){\nvar registerPrimitive = _dereq_('../primitives').registerPrimitive;\n\nregisterPrimitive('a-collada-model', {\n  mappings: {\n    src: 'collada-model'\n  }\n});\n\n},{\"../primitives\":140}],143:[function(_dereq_,module,exports){\nvar getMeshMixin = _dereq_('../getMeshMixin');\nvar registerPrimitive = _dereq_('../primitives').registerPrimitive;\nvar utils = _dereq_('../../../utils/');\n\nregisterPrimitive('a-cursor', utils.extendDeep({}, getMeshMixin(), {\n  defaultComponents: {\n    cursor: {},\n    geometry: {\n      primitive: 'ring',\n      radiusOuter: 0.016,\n      radiusInner: 0.01,\n      segmentsTheta: 32\n    },\n    material: {\n      color: '#000',\n      shader: 'flat',\n      opacity: 0.8\n    },\n    position: {\n      x: 0,\n      y: 0,\n      z: -1\n    }\n  },\n\n  mappings: {\n    far: 'raycaster.far',\n    fuse: 'cursor.fuse',\n    'fuse-timeout': 'cursor.fuseTimeout',\n    interval: 'raycaster.interval',\n    objects: 'raycaster.objects'\n  }\n}));\n\n},{\"../../../utils/\":195,\"../getMeshMixin\":138,\"../primitives\":140}],144:[function(_dereq_,module,exports){\nvar getMeshMixin = _dereq_('../getMeshMixin');\nvar registerPrimitive = _dereq_('../primitives').registerPrimitive;\nvar utils = _dereq_('../../../utils/');\n\nregisterPrimitive('a-curvedimage', utils.extendDeep({}, getMeshMixin(), {\n  defaultComponents: {\n    geometry: {\n      height: 1,\n      primitive: 'cylinder',\n      radius: 2,\n      segmentsRadial: 48,\n      thetaLength: 270,\n      openEnded: true,\n      thetaStart: 0\n    },\n    material: {\n      color: '#FFF',\n      shader: 'flat',\n      side: 'double',\n      transparent: true,\n      repeat: '-1 1'\n    }\n  },\n\n  mappings: {\n    height: 'geometry.height',\n    'open-ended': 'geometry.openEnded',\n    radius: 'geometry.radius',\n    segments: 'geometry.segmentsRadial',\n    start: 'geometry.thetaStart',\n    'theta-length': 'geometry.thetaLength',\n    'theta-start': 'geometry.thetaStart',\n    'width': 'geometry.thetaLength'\n  }\n}));\n\n},{\"../../../utils/\":195,\"../getMeshMixin\":138,\"../primitives\":140}],145:[function(_dereq_,module,exports){\nvar registerPrimitive = _dereq_('../primitives').registerPrimitive;\n\nregisterPrimitive('a-gltf-model', {\n  mappings: {\n    src: 'gltf-model'\n  }\n});\n\n},{\"../primitives\":140}],146:[function(_dereq_,module,exports){\nvar getMeshMixin = _dereq_('../getMeshMixin');\nvar registerPrimitive = _dereq_('../primitives').registerPrimitive;\nvar utils = _dereq_('../../../utils/');\n\nregisterPrimitive('a-image', utils.extendDeep({}, getMeshMixin(), {\n  defaultComponents: {\n    geometry: {\n      primitive: 'plane'\n    },\n    material: {\n      color: '#FFF',\n      shader: 'flat',\n      side: 'double',\n      transparent: true\n    }\n  },\n\n  mappings: {\n    height: 'geometry.height',\n    width: 'geometry.width'\n  }\n}));\n\n},{\"../../../utils/\":195,\"../getMeshMixin\":138,\"../primitives\":140}],147:[function(_dereq_,module,exports){\nvar registerPrimitive = _dereq_('../primitives').registerPrimitive;\n\nregisterPrimitive('a-light', {\n  defaultComponents: {\n    light: {}\n  },\n\n  mappings: {\n    angle: 'light.angle',\n    color: 'light.color',\n    'ground-color': 'light.groundColor',\n    decay: 'light.decay',\n    distance: 'light.distance',\n    intensity: 'light.intensity',\n    penumbra: 'light.penumbra',\n    type: 'light.type',\n    target: 'light.target'\n  }\n});\n\n},{\"../primitives\":140}],148:[function(_dereq_,module,exports){\nvar registerPrimitive = _dereq_('../primitives').registerPrimitive;\n\nregisterPrimitive('a-link', {\n  defaultComponents: {},\n\n  mappings: {\n    href: 'link.href',\n    image: 'link.image',\n    title: 'link.title'\n  }\n});\n\n},{\"../primitives\":140}],149:[function(_dereq_,module,exports){\nvar meshMixin = _dereq_('../getMeshMixin')();\nvar registerPrimitive = _dereq_('../primitives').registerPrimitive;\nvar utils = _dereq_('../../../utils/');\n\nregisterPrimitive('a-obj-model', utils.extendDeep({}, meshMixin, {\n  defaultComponents: {\n    'obj-model': {}\n  },\n\n  mappings: {\n    src: 'obj-model.obj',\n    mtl: 'obj-model.mtl'\n  }\n}));\n\n},{\"../../../utils/\":195,\"../getMeshMixin\":138,\"../primitives\":140}],150:[function(_dereq_,module,exports){\nvar getMeshMixin = _dereq_('../getMeshMixin');\nvar registerPrimitive = _dereq_('../primitives').registerPrimitive;\nvar utils = _dereq_('../../../utils/');\nvar meshPrimitives = _dereq_('./meshPrimitives');\n\nregisterPrimitive('a-sky', utils.extendDeep({}, getMeshMixin(), {\n  defaultComponents: {\n    geometry: {\n      primitive: 'sphere',\n      radius: 5000,\n      segmentsWidth: 64,\n      segmentsHeight: 32\n    },\n    material: {\n      color: '#FFF',\n      shader: 'flat',\n      npot: true\n    },\n    scale: '-1 1 1'\n  },\n\n  mappings: utils.extendDeep({}, meshPrimitives['a-sphere'].prototype.mappings)\n}));\n\n},{\"../../../utils/\":195,\"../getMeshMixin\":138,\"../primitives\":140,\"./meshPrimitives\":155}],151:[function(_dereq_,module,exports){\nvar registerPrimitive = _dereq_('../primitives').registerPrimitive;\n\nregisterPrimitive('a-sound', {\n  defaultComponents: {\n    sound: {}\n  },\n\n  mappings: {\n    src: 'sound.src',\n    on: 'sound.on',\n    autoplay: 'sound.autoplay',\n    loop: 'sound.loop',\n    volume: 'sound.volume'\n  }\n});\n\n},{\"../primitives\":140}],152:[function(_dereq_,module,exports){\n// <a-text> using `definePrimitive` helper.\nvar definePrimitive = _dereq_('../primitives').definePrimitive;\ndefinePrimitive('a-text', {text: {anchor: 'align', width: 5}});\n\n},{\"../primitives\":140}],153:[function(_dereq_,module,exports){\nvar getMeshMixin = _dereq_('../getMeshMixin');\nvar registerPrimitive = _dereq_('../primitives').registerPrimitive;\nvar utils = _dereq_('../../../utils/');\n\nregisterPrimitive('a-video', utils.extendDeep({}, getMeshMixin(), {\n  defaultComponents: {\n    geometry: {\n      primitive: 'plane'\n    },\n    material: {\n      color: '#FFF',\n      shader: 'flat',\n      side: 'double',\n      transparent: true\n    }\n  },\n\n  mappings: {\n    height: 'geometry.height',\n    width: 'geometry.width'\n  }\n}));\n\n},{\"../../../utils/\":195,\"../getMeshMixin\":138,\"../primitives\":140}],154:[function(_dereq_,module,exports){\nvar getMeshMixin = _dereq_('../getMeshMixin');\nvar registerPrimitive = _dereq_('../primitives').registerPrimitive;\nvar utils = _dereq_('../../../utils/');\n\nregisterPrimitive('a-videosphere', utils.extendDeep({}, getMeshMixin(), {\n  defaultComponents: {\n    geometry: {\n      primitive: 'sphere',\n      radius: 5000,\n      segmentsWidth: 64,\n      segmentsHeight: 32\n    },\n    material: {\n      color: '#FFF',\n      shader: 'flat',\n      npot: true\n    },\n    scale: '-1 1 1'\n  },\n\n  mappings: {\n    radius: 'geometry.radius',\n    'segments-height': 'geometry.segmentsHeight',\n    'segments-width': 'geometry.segmentsWidth'\n  }\n}));\n\n},{\"../../../utils/\":195,\"../getMeshMixin\":138,\"../primitives\":140}],155:[function(_dereq_,module,exports){\n/**\n * Automated mesh primitive registration.\n */\nvar getMeshMixin = _dereq_('../getMeshMixin');\nvar geometries = _dereq_('../../../core/geometry').geometries;\nvar geometryNames = _dereq_('../../../core/geometry').geometryNames;\nvar registerPrimitive = _dereq_('../primitives').registerPrimitive;\nvar utils = _dereq_('../../../utils/');\n\n// For testing.\nvar meshPrimitives = module.exports = {};\n\n// Generate primitive for each geometry type.\ngeometryNames.forEach(function registerMeshPrimitive (geometryName) {\n  var geometry = geometries[geometryName];\n  var geometryHyphened = unCamelCase(geometryName);\n\n  // Generate mappings.\n  var mappings = {};\n  Object.keys(geometry.schema).forEach(function createMapping (property) {\n    mappings[unCamelCase(property)] = 'geometry.' + property;\n  });\n\n  // Register.\n  var tagName = 'a-' + geometryHyphened;\n  var primitive = registerPrimitive(tagName, utils.extendDeep({}, getMeshMixin(), {\n    defaultComponents: {geometry: {primitive: geometryName}},\n    mappings: mappings\n  }));\n  meshPrimitives[tagName] = primitive;\n});\n\n/**\n * camelCase to hyphened-string.\n */\nfunction unCamelCase (str) {\n  return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();\n}\n\n},{\"../../../core/geometry\":126,\"../../../utils/\":195,\"../getMeshMixin\":138,\"../primitives\":140}],156:[function(_dereq_,module,exports){\nvar registerGeometry = _dereq_('../core/geometry').registerGeometry;\nvar THREE = _dereq_('../lib/three');\n\nregisterGeometry('box', {\n  schema: {\n    depth: {default: 1, min: 0},\n    height: {default: 1, min: 0},\n    width: {default: 1, min: 0},\n    segmentsHeight: {default: 1, min: 1, max: 20, type: 'int'},\n    segmentsWidth: {default: 1, min: 1, max: 20, type: 'int'},\n    segmentsDepth: {default: 1, min: 1, max: 20, type: 'int'}\n  },\n\n  init: function (data) {\n    this.geometry = new THREE.BoxGeometry(\n      data.width, data.height, data.depth,\n      data.segmentsWidth, data.segmentsHeight, data.segmentsDepth);\n  }\n});\n\n},{\"../core/geometry\":126,\"../lib/three\":173}],157:[function(_dereq_,module,exports){\nvar registerGeometry = _dereq_('../core/geometry').registerGeometry;\nvar THREE = _dereq_('../lib/three');\n\nvar degToRad = THREE.Math.degToRad;\n\nregisterGeometry('circle', {\n  schema: {\n    radius: {default: 1, min: 0},\n    segments: {default: 32, min: 3, type: 'int'},\n    thetaLength: {default: 360, min: 0},\n    thetaStart: {default: 0}\n  },\n\n  init: function (data) {\n    this.geometry = new THREE.CircleGeometry(\n      data.radius, data.segments, degToRad(data.thetaStart), degToRad(data.thetaLength));\n  }\n});\n\n},{\"../core/geometry\":126,\"../lib/three\":173}],158:[function(_dereq_,module,exports){\nvar registerGeometry = _dereq_('../core/geometry').registerGeometry;\nvar THREE = _dereq_('../lib/three');\n\nvar degToRad = THREE.Math.degToRad;\n\nregisterGeometry('cone', {\n  schema: {\n    height: {default: 1, min: 0},\n    openEnded: {default: false},\n    radiusBottom: {default: 1, min: 0},\n    radiusTop: {default: 0.01, min: 0},\n    segmentsHeight: {default: 18, min: 1, type: 'int'},\n    segmentsRadial: {default: 36, min: 3, type: 'int'},\n    thetaLength: {default: 360, min: 0},\n    thetaStart: {default: 0}\n  },\n\n  init: function (data) {\n    this.geometry = new THREE.CylinderGeometry(\n        data.radiusTop, data.radiusBottom, data.height, data.segmentsRadial,\n        data.segmentsHeight, data.openEnded, degToRad(data.thetaStart),\n        degToRad(data.thetaLength));\n  }\n});\n\n},{\"../core/geometry\":126,\"../lib/three\":173}],159:[function(_dereq_,module,exports){\nvar registerGeometry = _dereq_('../core/geometry').registerGeometry;\nvar THREE = _dereq_('../lib/three');\n\nvar degToRad = THREE.Math.degToRad;\n\nregisterGeometry('cylinder', {\n  schema: {\n    height: {default: 1, min: 0},\n    openEnded: {default: false},\n    radius: {default: 1, min: 0},\n    segmentsHeight: {default: 18, min: 1, type: 'int'},\n    segmentsRadial: {default: 36, min: 3, type: 'int'},\n    thetaLength: {default: 360, min: 0},\n    thetaStart: {default: 0}\n  },\n\n  init: function (data) {\n    this.geometry = new THREE.CylinderGeometry(\n        data.radius, data.radius, data.height, data.segmentsRadial, data.segmentsHeight,\n        data.openEnded, degToRad(data.thetaStart), degToRad(data.thetaLength));\n  }\n});\n\n},{\"../core/geometry\":126,\"../lib/three\":173}],160:[function(_dereq_,module,exports){\nvar registerGeometry = _dereq_('../core/geometry').registerGeometry;\nvar THREE = _dereq_('../lib/three');\n\nregisterGeometry('dodecahedron', {\n  schema: {\n    detail: {default: 0, min: 0, max: 5, type: 'int'},\n    radius: {default: 1, min: 0}\n  },\n\n  init: function (data) {\n    this.geometry = new THREE.DodecahedronGeometry(data.radius, data.detail);\n  }\n});\n\n},{\"../core/geometry\":126,\"../lib/three\":173}],161:[function(_dereq_,module,exports){\nvar registerGeometry = _dereq_('../core/geometry').registerGeometry;\nvar THREE = _dereq_('../lib/three');\n\nregisterGeometry('icosahedron', {\n  schema: {\n    detail: {default: 0, min: 0, max: 5, type: 'int'},\n    radius: {default: 1, min: 0}\n  },\n\n  init: function (data) {\n    this.geometry = new THREE.IcosahedronGeometry(data.radius, data.detail);\n  }\n});\n\n},{\"../core/geometry\":126,\"../lib/three\":173}],162:[function(_dereq_,module,exports){\n_dereq_('./box.js');\n_dereq_('./circle.js');\n_dereq_('./cone.js');\n_dereq_('./cylinder.js');\n_dereq_('./dodecahedron.js');\n_dereq_('./icosahedron.js');\n_dereq_('./octahedron.js');\n_dereq_('./plane.js');\n_dereq_('./ring.js');\n_dereq_('./sphere.js');\n_dereq_('./tetrahedron.js');\n_dereq_('./torus.js');\n_dereq_('./torusKnot.js');\n_dereq_('./triangle.js');\n\n},{\"./box.js\":156,\"./circle.js\":157,\"./cone.js\":158,\"./cylinder.js\":159,\"./dodecahedron.js\":160,\"./icosahedron.js\":161,\"./octahedron.js\":163,\"./plane.js\":164,\"./ring.js\":165,\"./sphere.js\":166,\"./tetrahedron.js\":167,\"./torus.js\":168,\"./torusKnot.js\":169,\"./triangle.js\":170}],163:[function(_dereq_,module,exports){\nvar registerGeometry = _dereq_('../core/geometry').registerGeometry;\nvar THREE = _dereq_('../lib/three');\n\nregisterGeometry('octahedron', {\n  schema: {\n    detail: {default: 0, min: 0, max: 5, type: 'int'},\n    radius: {default: 1, min: 0}\n  },\n\n  init: function (data) {\n    this.geometry = new THREE.OctahedronGeometry(data.radius, data.detail);\n  }\n});\n\n},{\"../core/geometry\":126,\"../lib/three\":173}],164:[function(_dereq_,module,exports){\nvar registerGeometry = _dereq_('../core/geometry').registerGeometry;\nvar THREE = _dereq_('../lib/three');\n\nregisterGeometry('plane', {\n  schema: {\n    height: {default: 1, min: 0},\n    width: {default: 1, min: 0},\n    segmentsHeight: {default: 1, min: 1, max: 20, type: 'int'},\n    segmentsWidth: {default: 1, min: 1, max: 20, type: 'int'}\n  },\n\n  init: function (data) {\n    this.geometry = new THREE.PlaneGeometry(data.width, data.height, data.segmentsWidth, data.segmentsHeight);\n  }\n});\n\n},{\"../core/geometry\":126,\"../lib/three\":173}],165:[function(_dereq_,module,exports){\nvar registerGeometry = _dereq_('../core/geometry').registerGeometry;\nvar THREE = _dereq_('../lib/three');\n\nvar degToRad = THREE.Math.degToRad;\n\nregisterGeometry('ring', {\n  schema: {\n    radiusInner: {default: 0.8, min: 0},\n    radiusOuter: {default: 1.2, min: 0},\n    segmentsPhi: {default: 10, min: 1, type: 'int'},\n    segmentsTheta: {default: 32, min: 3, type: 'int'},\n    thetaLength: {default: 360, min: 0},\n    thetaStart: {default: 0}\n  },\n\n  init: function (data) {\n    this.geometry = new THREE.RingGeometry(\n        data.radiusInner, data.radiusOuter, data.segmentsTheta, data.segmentsPhi,\n        degToRad(data.thetaStart), degToRad(data.thetaLength));\n  }\n});\n\n},{\"../core/geometry\":126,\"../lib/three\":173}],166:[function(_dereq_,module,exports){\nvar registerGeometry = _dereq_('../core/geometry').registerGeometry;\nvar THREE = _dereq_('../lib/three');\n\nvar degToRad = THREE.Math.degToRad;\n\nregisterGeometry('sphere', {\n  schema: {\n    radius: {default: 1, min: 0},\n    phiLength: {default: 360},\n    phiStart: {default: 0, min: 0},\n    thetaLength: {default: 180, min: 0},\n    thetaStart: {default: 0},\n    segmentsHeight: {default: 18, min: 2, type: 'int'},\n    segmentsWidth: {default: 36, min: 3, type: 'int'}\n  },\n\n  init: function (data) {\n    this.geometry = new THREE.SphereGeometry(\n      data.radius, data.segmentsWidth, data.segmentsHeight, degToRad(data.phiStart),\n      degToRad(data.phiLength), degToRad(data.thetaStart), degToRad(data.thetaLength));\n  }\n});\n\n},{\"../core/geometry\":126,\"../lib/three\":173}],167:[function(_dereq_,module,exports){\nvar registerGeometry = _dereq_('../core/geometry').registerGeometry;\nvar THREE = _dereq_('../lib/three');\n\nregisterGeometry('tetrahedron', {\n  schema: {\n    detail: {default: 0, min: 0, max: 5, type: 'int'},\n    radius: {default: 1, min: 0}\n  },\n\n  init: function (data) {\n    this.geometry = new THREE.TetrahedronGeometry(data.radius, data.detail);\n  }\n});\n\n},{\"../core/geometry\":126,\"../lib/three\":173}],168:[function(_dereq_,module,exports){\nvar registerGeometry = _dereq_('../core/geometry').registerGeometry;\nvar THREE = _dereq_('../lib/three');\n\nvar degToRad = THREE.Math.degToRad;\n\nregisterGeometry('torus', {\n  schema: {\n    arc: {default: 360},\n    radius: {default: 1, min: 0},\n    radiusTubular: {default: 0.2, min: 0},\n    segmentsRadial: {default: 36, min: 2, type: 'int'},\n    segmentsTubular: {default: 32, min: 3, type: 'int'}\n  },\n\n  init: function (data) {\n    this.geometry = new THREE.TorusGeometry(\n      data.radius, data.radiusTubular * 2, data.segmentsRadial, data.segmentsTubular,\n      degToRad(data.arc));\n  }\n});\n\n},{\"../core/geometry\":126,\"../lib/three\":173}],169:[function(_dereq_,module,exports){\nvar registerGeometry = _dereq_('../core/geometry').registerGeometry;\nvar THREE = _dereq_('../lib/three');\n\nregisterGeometry('torusKnot', {\n  schema: {\n    p: {default: 2, min: 1},\n    q: {default: 3, min: 1},\n    radius: {default: 1, min: 0},\n    radiusTubular: {default: 0.2, min: 0},\n    segmentsRadial: {default: 8, min: 3, type: 'int'},\n    segmentsTubular: {default: 100, min: 3, type: 'int'}\n  },\n\n  init: function (data) {\n    this.geometry = new THREE.TorusKnotGeometry(\n      data.radius, data.radiusTubular * 2, data.segmentsTubular, data.segmentsRadial,\n      data.p, data.q);\n  }\n});\n\n},{\"../core/geometry\":126,\"../lib/three\":173}],170:[function(_dereq_,module,exports){\nvar registerGeometry = _dereq_('../core/geometry').registerGeometry;\nvar THREE = _dereq_('../lib/three');\n\nvar quaternion = new THREE.Quaternion();\nvar rotateVector = new THREE.Vector3(0, 0, 1);\nvar uvMinVector = new THREE.Vector2();\nvar uvMaxVector = new THREE.Vector2();\nvar uvScaleVector = new THREE.Vector2();\n\nregisterGeometry('triangle', {\n  schema: {\n    vertexA: {type: 'vec3', default: {x: 0, y: 0.5, z: 0}},\n    vertexB: {type: 'vec3', default: {x: -0.5, y: -0.5, z: 0}},\n    vertexC: {type: 'vec3', default: {x: 0.5, y: -0.5, z: 0}}\n  },\n\n  init: function (data) {\n    var geometry;\n    var normal;\n    var triangle;\n    var uvA;\n    var uvB;\n    var uvC;\n\n    triangle = new THREE.Triangle();\n    triangle.a.set(data.vertexA.x, data.vertexA.y, data.vertexA.z);\n    triangle.b.set(data.vertexB.x, data.vertexB.y, data.vertexB.z);\n    triangle.c.set(data.vertexC.x, data.vertexC.y, data.vertexC.z);\n    normal = triangle.normal();\n\n    // Rotate the 3D triangle to be parallel to XY plane.\n    quaternion.setFromUnitVectors(normal, rotateVector);\n    uvA = triangle.a.clone().applyQuaternion(quaternion);\n    uvB = triangle.b.clone().applyQuaternion(quaternion);\n    uvC = triangle.c.clone().applyQuaternion(quaternion);\n\n    // Compute UVs.\n    // Normalize x/y values of UV so they are within 0 to 1.\n    uvMinVector.set(Math.min(uvA.x, uvB.x, uvC.x), Math.min(uvA.y, uvB.y, uvC.y));\n    uvMaxVector.set(Math.max(uvA.x, uvB.x, uvC.x), Math.max(uvA.y, uvB.y, uvC.y));\n    uvScaleVector.set(0, 0).subVectors(uvMaxVector, uvMinVector);\n    uvA = new THREE.Vector2().subVectors(uvA, uvMinVector).divide(uvScaleVector);\n    uvB = new THREE.Vector2().subVectors(uvB, uvMinVector).divide(uvScaleVector);\n    uvC = new THREE.Vector2().subVectors(uvC, uvMinVector).divide(uvScaleVector);\n\n    geometry = this.geometry = new THREE.Geometry();\n    geometry.vertices.push(triangle.a);\n    geometry.vertices.push(triangle.b);\n    geometry.vertices.push(triangle.c);\n    geometry.faces.push(new THREE.Face3(0, 1, 2, normal));\n    geometry.faceVertexUvs[0] = [[uvA, uvB, uvC]];\n  }\n});\n\n},{\"../core/geometry\":126,\"../lib/three\":173}],171:[function(_dereq_,module,exports){\nvar utils = _dereq_('./utils/');\n\nvar debug = utils.debug;\nvar error = debug('A-Frame:error');\nvar warn = debug('A-Frame:warn');\n\nif (window.document.currentScript && window.document.currentScript.parentNode !==\n    window.document.head && !window.debug) {\n  warn('Put the A-Frame <script> tag in the <head> of the HTML *before* the scene to ' +\n       'ensure everything for A-Frame is properly registered before they are used from ' +\n       'HTML.');\n}\n\n// Error if not using a server.\nif (window.location.protocol === 'file:') {\n  error(\n    'This HTML file is currently being served via the file:// protocol. ' +\n    'Assets, textures, and models WILL NOT WORK due to cross-origin policy! ' +\n    'Please use a local or hosted server: ' +\n    'https://aframe.io/docs/0.5.0/introduction/getting-started.html#using-a-local-server.');\n}\n\n// Polyfill `Promise`.\nwindow.Promise = window.Promise || _dereq_('promise-polyfill');\n\n// Check before the polyfill runs.\nwindow.hasNativeWebVRImplementation = !!window.navigator.getVRDisplays || !!window.navigator.getVRDevices;\n\nwindow.WebVRConfig = window.WebVRConfig || {\n  BUFFER_SCALE: 1,\n  CARDBOARD_UI_DISABLED: true,\n  ROTATE_INSTRUCTIONS_DISABLED: true,\n  TOUCH_PANNER_DISABLED: true,\n  MOUSE_KEYBOARD_CONTROLS_DISABLED: true\n};\n\n// Workaround for iOS Safari canvas sizing issues in stereo (webvr-polyfill/issues/102).\n// Only for iOS on versions older than 10.\nif (utils.device.isIOSOlderThan10(window.navigator.userAgent)) {\n  window.WebVRConfig.BUFFER_SCALE = 1 / window.devicePixelRatio;\n}\n\n// WebVR polyfill\n_dereq_('webvr-polyfill');\n\n_dereq_('present'); // Polyfill `performance.now()`.\n\n// CSS.\nif (utils.device.isBrowserEnvironment) {\n  _dereq_('./style/aframe.css');\n  _dereq_('./style/rStats.css');\n}\n\n// Required before `AEntity` so that all components are registered.\nvar AScene = _dereq_('./core/scene/a-scene').AScene;\nvar components = _dereq_('./core/component').components;\nvar registerComponent = _dereq_('./core/component').registerComponent;\nvar registerGeometry = _dereq_('./core/geometry').registerGeometry;\nvar registerPrimitive = _dereq_('./extras/primitives/primitives').registerPrimitive;\nvar registerShader = _dereq_('./core/shader').registerShader;\nvar registerSystem = _dereq_('./core/system').registerSystem;\nvar shaders = _dereq_('./core/shader').shaders;\nvar systems = _dereq_('./core/system').systems;\n// Exports THREE to window so three.js can be used without alteration.\nvar THREE = window.THREE = _dereq_('./lib/three');\nvar TWEEN = window.TWEEN = _dereq_('@tweenjs/tween.js');\n\nvar pkg = _dereq_('../package');\n\n_dereq_('./components/index'); // Register standard components.\n_dereq_('./geometries/index'); // Register standard geometries.\n_dereq_('./shaders/index'); // Register standard shaders.\n_dereq_('./systems/index'); // Register standard systems.\nvar ANode = _dereq_('./core/a-node');\nvar AEntity = _dereq_('./core/a-entity'); // Depends on ANode and core components.\n\n_dereq_('./core/a-animation');\n_dereq_('./core/a-assets');\n_dereq_('./core/a-cubemap');\n_dereq_('./core/a-mixin');\n\n// Extras.\n_dereq_('./extras/components/');\n_dereq_('./extras/primitives/');\n\nconsole.log('A-Frame Version: 0.7.1 (Date 18-10-2017, Commit #0da6cf4)');\nconsole.log('three Version:', pkg.dependencies['three']);\nconsole.log('WebVR Polyfill Version:', pkg.dependencies['webvr-polyfill']);\n\nmodule.exports = window.AFRAME = {\n  AComponent: _dereq_('./core/component').Component,\n  AEntity: AEntity,\n  ANode: ANode,\n  AScene: AScene,\n  components: components,\n  geometries: _dereq_('./core/geometry').geometries,\n  registerComponent: registerComponent,\n  registerElement: _dereq_('./core/a-register-element').registerElement,\n  registerGeometry: registerGeometry,\n  registerPrimitive: registerPrimitive,\n  registerShader: registerShader,\n  registerSystem: registerSystem,\n  primitives: {\n    getMeshMixin: _dereq_('./extras/primitives/getMeshMixin'),\n    primitives: _dereq_('./extras/primitives/primitives').primitives\n  },\n  scenes: _dereq_('./core/scene/scenes'),\n  schema: _dereq_('./core/schema'),\n  shaders: shaders,\n  systems: systems,\n  THREE: THREE,\n  TWEEN: TWEEN,\n  utils: utils,\n  version: pkg.version\n};\n\n},{\"../package\":76,\"./components/index\":85,\"./core/a-animation\":118,\"./core/a-assets\":119,\"./core/a-cubemap\":120,\"./core/a-entity\":121,\"./core/a-mixin\":122,\"./core/a-node\":123,\"./core/a-register-element\":124,\"./core/component\":125,\"./core/geometry\":126,\"./core/scene/a-scene\":128,\"./core/scene/scenes\":131,\"./core/schema\":133,\"./core/shader\":134,\"./core/system\":135,\"./extras/components/\":136,\"./extras/primitives/\":139,\"./extras/primitives/getMeshMixin\":138,\"./extras/primitives/primitives\":140,\"./geometries/index\":162,\"./lib/three\":173,\"./shaders/index\":175,\"./style/aframe.css\":180,\"./style/rStats.css\":181,\"./systems/index\":184,\"./utils/\":195,\"@tweenjs/tween.js\":1,\"present\":33,\"promise-polyfill\":34,\"webvr-polyfill\":61}],172:[function(_dereq_,module,exports){\nwindow.aframeStats = function (scene) {\n  var _rS = null;\n  var _scene = scene;\n  var _values = {\n    te: {\n      caption: 'Entities'\n    },\n    lt: {\n      caption: 'Load Time'\n    }\n  };\n  var _groups = [ {\n    caption: 'A-Frame',\n    values: [ 'te', 'lt' ]\n  } ];\n\n  function _update () {\n    _rS('te').set(getEntityCount());\n    if (window.performance.getEntriesByName) {\n      _rS('lt').set(window.performance.getEntriesByName('render-started')[0].startTime.toFixed(0));\n    }\n  }\n\n  function getEntityCount () {\n    var elements = _scene.querySelectorAll('*');\n    Array.prototype.slice.call(elements).filter(function (el) {\n      return el.isEntity;\n    });\n    return elements.length;\n  }\n\n  function _start () {}\n\n  function _end () {}\n\n  function _attach (r) {\n    _rS = r;\n  }\n\n  return {\n    update: _update,\n    start: _start,\n    end: _end,\n    attach: _attach,\n    values: _values,\n    groups: _groups,\n    fractions: []\n  };\n};\n\nif (typeof module === 'object') {\n  module.exports = {\n    aframeStats: window.aframeStats\n  };\n}\n\n},{}],173:[function(_dereq_,module,exports){\n(function (global){\nvar THREE = global.THREE = _dereq_('three');\n\n// Allow cross-origin images to be loaded.\n\n// This should not be on `THREE.Loader` nor `THREE.ImageUtils`.\n// Must be on `THREE.TextureLoader`.\nif (THREE.TextureLoader) {\n  THREE.TextureLoader.prototype.crossOrigin = 'anonymous';\n}\n\n// This is for images loaded from the model loaders.\nif (THREE.ImageLoader) {\n  THREE.ImageLoader.prototype.crossOrigin = 'anonymous';\n}\n\n// In-memory caching for XHRs (for images, audio files, textures, etc.).\nif (THREE.Cache) {\n  THREE.Cache.enabled = true;\n}\n\n// TODO: Eventually include these only if they are needed by a component.\n_dereq_('three/examples/js/loaders/GLTFLoader');  // THREE.GLTFLoader\n_dereq_('three/examples/js/loaders/OBJLoader');  // THREE.OBJLoader\n_dereq_('three/examples/js/loaders/MTLLoader');  // THREE.MTLLoader\n_dereq_('three/examples/js/loaders/ColladaLoader');  // THREE.ColladaLoader\n_dereq_('../../vendor/VRControls');  // THREE.VRControls\n_dereq_('../../vendor/VREffect');  // THREE.VREffect\n\nTHREE.ColladaLoader.prototype.crossOrigin = 'anonymous';\nTHREE.GLTFLoader.prototype.crossOrigin = 'anonymous';\nTHREE.MTLLoader.prototype.crossOrigin = 'anonymous';\nTHREE.OBJLoader.prototype.crossOrigin = 'anonymous';\n\nmodule.exports = THREE;\n\n}).call(this,typeof global !== \"undefined\" ? global : typeof self !== \"undefined\" ? self : typeof window !== \"undefined\" ? window : {})\n\n},{\"../../vendor/VRControls\":200,\"../../vendor/VREffect\":201,\"three\":41,\"three/examples/js/loaders/ColladaLoader\":42,\"three/examples/js/loaders/GLTFLoader\":43,\"three/examples/js/loaders/MTLLoader\":44,\"three/examples/js/loaders/OBJLoader\":45}],174:[function(_dereq_,module,exports){\nvar registerShader = _dereq_('../core/shader').registerShader;\nvar THREE = _dereq_('../lib/three');\nvar utils = _dereq_('../utils/');\n\n/**\n * Flat shader using THREE.MeshBasicMaterial.\n */\nmodule.exports.Shader = registerShader('flat', {\n  schema: {\n    color: {type: 'color'},\n    fog: {default: true},\n    height: {default: 256},\n    offset: {type: 'vec2', default: {x: 0, y: 0}},\n    repeat: {type: 'vec2', default: {x: 1, y: 1}},\n    src: {type: 'map'},\n    width: {default: 512},\n    wireframe: {default: false},\n    wireframeLinewidth: {default: 2}\n  },\n\n  /**\n   * Initializes the shader.\n   * Adds a reference from the scene to this entity as the camera.\n   */\n  init: function (data) {\n    this.textureSrc = null;\n    this.material = new THREE.MeshBasicMaterial(getMaterialData(data));\n    utils.material.updateMap(this, data);\n  },\n\n  update: function (data) {\n    this.updateMaterial(data);\n    utils.material.updateMap(this, data);\n  },\n\n  /**\n   * Updating existing material.\n   *\n   * @param {object} data - Material component data.\n   */\n  updateMaterial: function (data) {\n    var material = this.material;\n    data = getMaterialData(data);\n    Object.keys(data).forEach(function (key) {\n      material[key] = data[key];\n    });\n  }\n});\n\n/**\n * Builds and normalize material data, normalizing stuff along the way.\n *\n * @param {object} data - Material data.\n * @returns {object} data - Processed material data.\n */\nfunction getMaterialData (data) {\n  return {\n    fog: data.fog,\n    color: new THREE.Color(data.color),\n    wireframe: data.wireframe,\n    wireframeLinewidth: data.wireframeLinewidth\n  };\n}\n\n},{\"../core/shader\":134,\"../lib/three\":173,\"../utils/\":195}],175:[function(_dereq_,module,exports){\n_dereq_('./flat');\n_dereq_('./standard');\n_dereq_('./sdf');\n_dereq_('./msdf');\n_dereq_('./ios10hls');\n\n},{\"./flat\":174,\"./ios10hls\":176,\"./msdf\":177,\"./sdf\":178,\"./standard\":179}],176:[function(_dereq_,module,exports){\nvar registerShader = _dereq_('../core/shader').registerShader;\n\n/**\n * Custom shader for iOS 10 HTTP Live Streaming (HLS).\n * For more information on HLS, see https://datatracker.ietf.org/doc/draft-pantos-http-live-streaming/\n */\nmodule.exports.Shader = registerShader('ios10hls', {\n  schema: {\n    src: {type: 'map', is: 'uniform'},\n    opacity: {type: 'number', is: 'uniform', default: 1}\n  },\n\n  vertexShader: [\n    'varying vec2 vUV;',\n    'void main(void) {',\n    '  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);',\n    '  vUV = uv;',\n    '}'\n  ].join('\\n'),\n\n  fragmentShader: [\n    'uniform sampler2D src;',\n    'uniform float opacity;',\n    'varying vec2 vUV;',\n    'void main() {',\n    '  vec2 offset = vec2(0, 0);',\n    '  vec2 repeat = vec2(1, 1);',\n    '  vec4 color = texture2D(src, vec2(vUV.x / repeat.x + offset.x, (1.0 - vUV.y) / repeat.y + offset.y)).bgra;',\n    '  gl_FragColor = vec4(color.rgb, opacity);',\n    '}'\n  ].join('\\n')\n});\n\n\n},{\"../core/shader\":134}],177:[function(_dereq_,module,exports){\nvar registerShader = _dereq_('../core/shader').registerShader;\n\n/**\n * Multi-channel signed distance field.\n * Used by text component.\n */\nmodule.exports.Shader = registerShader('msdf', {\n  schema: {\n    alphaTest: {type: 'number', is: 'uniform', default: 0.5},\n    color: {type: 'color', is: 'uniform', default: 'white'},\n    map: {type: 'map', is: 'uniform'},\n    opacity: {type: 'number', is: 'uniform', default: 1.0}\n  },\n\n  raw: true,\n\n  vertexShader: [\n    'attribute vec2 uv;',\n    'attribute vec3 position;',\n    'uniform mat4 projectionMatrix;',\n    'uniform mat4 modelViewMatrix;',\n    'varying vec2 vUV;',\n    'void main(void) {',\n    '  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);',\n    '  vUV = uv;',\n    '}'\n  ].join('\\n'),\n\n  fragmentShader: [\n    '#ifdef GL_OES_standard_derivatives',\n    '#extension GL_OES_standard_derivatives: enable',\n    '#endif',\n\n    'precision highp float;',\n    // FIXME: Experimentally determined constants.\n    '#define BIG_ENOUGH 0.001',\n    '#define MODIFIED_ALPHATEST (0.02 * isBigEnough / BIG_ENOUGH)',\n    '#define ALL_SMOOTH 0.4',\n    '#define ALL_ROUGH 0.02',\n    '#define DISCARD_ALPHA (alphaTest / (2.2 - 1.2 * ratio))',\n    'uniform sampler2D map;',\n    'uniform vec3 color;',\n    'uniform float opacity;',\n    'uniform float alphaTest;',\n    'varying vec2 vUV;',\n\n    'float median(float r, float g, float b) {',\n    '  return max(min(r, g), min(max(r, g), b));',\n    '}',\n    'void main() {',\n    '  vec3 sample = 1.0 - texture2D(map, vUV).rgb;',\n    '  float sigDist = median(sample.r, sample.g, sample.b) - 0.5;',\n    '  float alpha = clamp(sigDist/fwidth(sigDist) + 0.5, 0.0, 1.0);',\n    '  float dscale = 0.353505;',\n    '  vec2 duv = dscale * (dFdx(vUV) + dFdy(vUV));',\n    '  float isBigEnough = max(abs(duv.x), abs(duv.y));',\n    // When texel is too small, blend raw alpha value rather than supersampling.\n    // FIXME: Experimentally determined constant.\n    '  if (isBigEnough > BIG_ENOUGH) {',\n    '    float ratio = BIG_ENOUGH / isBigEnough;',\n    '    alpha = ratio * alpha + (1.0 - ratio) * (sigDist + 0.5);',\n    '  }',\n    // When texel is big enough, do standard alpha test.\n    // FIXME: Experimentally determined constant.\n    // Looks much better if we *don't* do this, but do we get Z fighting?\n    '  if (isBigEnough <= BIG_ENOUGH && alpha < alphaTest) { discard; return; }',\n    // Else, do modified alpha test.\n    // FIXME: Experimentally determined constant.\n    '  if (alpha < alphaTest * MODIFIED_ALPHATEST) { discard; return; }',\n    '  gl_FragColor = vec4(color.xyz, alpha * opacity);',\n    '}'\n  ].join('\\n')\n});\n\n},{\"../core/shader\":134}],178:[function(_dereq_,module,exports){\nvar registerShader = _dereq_('../core/shader').registerShader;\n\n/**\n * Signed distance field.\n * Used by text component.\n */\nmodule.exports.Shader = registerShader('sdf', {\n  schema: {\n    alphaTest: {type: 'number', is: 'uniform', default: 0.5},\n    color: {type: 'color', is: 'uniform', default: 'white'},\n    map: {type: 'map', is: 'uniform'},\n    opacity: {type: 'number', is: 'uniform', default: 1.0}\n  },\n\n  raw: true,\n\n  vertexShader: [\n    'attribute vec2 uv;',\n    'attribute vec3 position;',\n    'uniform mat4 projectionMatrix;',\n    'uniform mat4 modelViewMatrix;',\n    'varying vec2 vUV;',\n    'void main(void) {',\n    '  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);',\n    '  vUV = uv;',\n    '}'\n  ].join('\\n'),\n\n  fragmentShader: [\n    '#ifdef GL_OES_standard_derivatives',\n    '#extension GL_OES_standard_derivatives: enable',\n    '#endif',\n\n    'precision highp float;',\n    // FIXME: experimentally determined constants\n    '#define BIG_ENOUGH 0.001',\n    '#define MODIFIED_ALPHATEST (0.02 * isBigEnough / BIG_ENOUGH)',\n    '#define ALL_SMOOTH 0.4',\n    '#define ALL_ROUGH 0.02',\n    '#define DISCARD_ALPHA (alphaTest / (2.2 - 1.2 * ratio))',\n    'uniform sampler2D map;',\n    'uniform vec3 color;',\n    'uniform float opacity;',\n    'uniform float alphaTest;',\n    'varying vec2 vUV;',\n    '#ifdef GL_OES_standard_derivatives',\n    'float contour(float width, float value) {',\n    '  return smoothstep(0.5 - value, 0.5 + value, width);',\n    '}',\n    '#else',\n    'float aastep(float value, float afwidth) {',\n    '  return smoothstep(0.5 - afwidth, 0.5 + afwidth, value);',\n    '}',\n    '#endif',\n    'void main() {',\n    '#ifdef GL_OES_standard_derivatives',\n    // when we have derivatives and can get texel size etc., that allows supersampling etc.\n    '  vec2 uv = vUV;',\n    '  vec4 texColor = texture2D(map, uv);',\n    '  float dist = texColor.a;',\n    '  float width = fwidth(dist);',\n    '  float alpha = contour(dist, width);',\n    '  float dscale = 0.353505;',\n    '  vec2 duv = dscale * (dFdx(uv) + dFdy(uv));',\n    '  float isBigEnough = max(abs(duv.x), abs(duv.y));',\n    // when texel is too small, blend raw alpha value rather than supersampling etc.\n    // FIXME: experimentally determined constant\n    '  if (isBigEnough > BIG_ENOUGH) {',\n    '    float ratio = BIG_ENOUGH / isBigEnough;',\n    '    alpha = ratio * alpha + (1.0 - ratio) * dist;',\n    '  }',\n    // otherwise do weighted supersampling\n    // FIXME: why this weighting?\n    '  else if (isBigEnough <= BIG_ENOUGH) {',\n    '    vec4 box = vec4 (uv - duv, uv + duv);',\n    '    alpha = (alpha + 0.5 * (',\n    '      contour(texture2D(map, box.xy).a, width)',\n    '      + contour(texture2D(map, box.zw).a, width)',\n    '      + contour(texture2D(map, box.xw).a, width)',\n    '      + contour(texture2D(map, box.zy).a, width)',\n    '    )) / 3.0;',\n    '  }',\n    // when texel is big enough, do standard alpha test\n    // FIXME: experimentally determined constant\n    // looks much better if we DON'T do this, but do we get Z fighting etc.?\n    '  if (isBigEnough <= BIG_ENOUGH && alpha < alphaTest) { discard; return; }',\n    // else do modified alpha test\n    // FIXME: experimentally determined constant\n    '  if (alpha < alphaTest * MODIFIED_ALPHATEST) { discard; return; }',\n    '#else',\n    '  vec4 texColor = texture2D(map, vUV);',\n    '  float value = texColor.a;',\n    // when we don't have derivatives, use approximations\n    // FIXME: if we understood font pixel dimensions, this could probably be improved\n    '  float afwidth = (1.0 / 32.0) * (1.4142135623730951 / (2.0 * gl_FragCoord.w));',\n    '  float alpha = aastep(value, afwidth);',\n    // use gl_FragCoord.w to guess when we should blend\n    // FIXME: if we understood font pixel dimensions, this could probably be improved\n    '  float ratio = (gl_FragCoord.w >= ALL_SMOOTH) ? 1.0 : (gl_FragCoord.w < ALL_ROUGH) ? 0.0 : (gl_FragCoord.w - ALL_ROUGH) / (ALL_SMOOTH - ALL_ROUGH);',\n    '  if (alpha < alphaTest) { if (ratio >= 1.0) { discard; return; } alpha = 0.0; }',\n    '  alpha = alpha * ratio + (1.0 - ratio) * value;',\n    '  if (ratio < 1.0)',\n    '    if (alpha <= DISCARD_ALPHA) { discard; return; }',\n    '#endif',\n    '  gl_FragColor = vec4(color, opacity * alpha);',\n    '}'\n  ].join('\\n')\n});\n\n},{\"../core/shader\":134}],179:[function(_dereq_,module,exports){\nvar registerShader = _dereq_('../core/shader').registerShader;\nvar THREE = _dereq_('../lib/three');\nvar utils = _dereq_('../utils/');\n\nvar CubeLoader = new THREE.CubeTextureLoader();\nvar texturePromises = {};\n\n/**\n * Standard (physically-based) shader using THREE.MeshStandardMaterial.\n */\nmodule.exports.Shader = registerShader('standard', {\n  schema: {\n    ambientOcclusionMap: {type: 'map'},\n    ambientOcclusionMapIntensity: {default: 1},\n    ambientOcclusionTextureOffset: {type: 'vec2'},\n    ambientOcclusionTextureRepeat: {type: 'vec2', default: {x: 1, y: 1}},\n\n    color: {type: 'color'},\n\n    displacementMap: {type: 'map'},\n    displacementScale: {default: 1},\n    displacementBias: {default: 0.5},\n    displacementTextureOffset: {type: 'vec2'},\n    displacementTextureRepeat: {type: 'vec2', default: {x: 1, y: 1}},\n    emissive: {type: 'color', default: '#000'},\n    emissiveIntensity: {default: 1},\n    envMap: {default: ''},\n\n    fog: {default: true},\n    height: {default: 256},\n    metalness: {default: 0.0, min: 0.0, max: 1.0},\n\n    normalMap: {type: 'map'},\n    normalScale: {type: 'vec2', default: {x: 1, y: 1}},\n    normalTextureOffset: {type: 'vec2'},\n    normalTextureRepeat: {type: 'vec2', default: {x: 1, y: 1}},\n\n    offset: {type: 'vec2', default: {x: 0, y: 0}},\n    repeat: {type: 'vec2', default: {x: 1, y: 1}},\n    roughness: {default: 0.5, min: 0.0, max: 1.0},\n    sphericalEnvMap: {type: 'map'},\n    src: {type: 'map'},\n    width: {default: 512},\n    wireframe: {default: false},\n    wireframeLinewidth: {default: 2}\n  },\n\n  /**\n   * Initializes the shader.\n   * Adds a reference from the scene to this entity as the camera.\n   */\n  init: function (data) {\n    this.material = new THREE.MeshStandardMaterial(getMaterialData(data));\n    utils.material.updateMap(this, data);\n    if (data.normalMap) { utils.material.updateDistortionMap('normal', this, data); }\n    if (data.displacementMap) { utils.material.updateDistortionMap('displacement', this, data); }\n    if (data.ambientOcclusionMap) { utils.material.updateDistortionMap('ambientOcclusion', this, data); }\n    this.updateEnvMap(data);\n  },\n\n  update: function (data) {\n    this.updateMaterial(data);\n    utils.material.updateMap(this, data);\n    if (data.normalMap) { utils.material.updateDistortionMap('normal', this, data); }\n    if (data.displacementMap) { utils.material.updateDistortionMap('displacement', this, data); }\n    if (data.ambientOcclusionMap) { utils.material.updateDistortionMap('ambientOcclusion', this, data); }\n    this.updateEnvMap(data);\n  },\n\n  /**\n   * Updating existing material.\n   *\n   * @param {object} data - Material component data.\n   * @returns {object} Material.\n   */\n  updateMaterial: function (data) {\n    var material = this.material;\n    data = getMaterialData(data);\n    Object.keys(data).forEach(function (key) {\n      material[key] = data[key];\n    });\n  },\n\n  /**\n   * Handle environment cubemap. Textures are cached in texturePromises.\n   */\n  updateEnvMap: function (data) {\n    var self = this;\n    var material = this.material;\n    var envMap = data.envMap;\n    var sphericalEnvMap = data.sphericalEnvMap;\n\n    // No envMap defined or already loading.\n    if ((!envMap && !sphericalEnvMap) || this.isLoadingEnvMap) {\n      material.envMap = null;\n      material.needsUpdate = true;\n      return;\n    }\n    this.isLoadingEnvMap = true;\n\n    // if a spherical env map is defined then use it.\n    if (sphericalEnvMap) {\n      this.el.sceneEl.systems.material.loadTexture(sphericalEnvMap, {src: sphericalEnvMap}, function textureLoaded (texture) {\n        self.isLoadingEnvMap = false;\n        texture.mapping = THREE.SphericalReflectionMapping;\n        material.envMap = texture;\n        utils.material.handleTextureEvents(self.el, texture);\n        material.needsUpdate = true;\n      });\n      return;\n    }\n\n    // Another material is already loading this texture. Wait on promise.\n    if (texturePromises[envMap]) {\n      texturePromises[envMap].then(function (cube) {\n        self.isLoadingEnvMap = false;\n        material.envMap = cube;\n        utils.material.handleTextureEvents(self.el, cube);\n        material.needsUpdate = true;\n      });\n      return;\n    }\n\n    // Material is first to load this texture. Load and resolve texture.\n    texturePromises[envMap] = new Promise(function (resolve) {\n      utils.srcLoader.validateCubemapSrc(envMap, function loadEnvMap (urls) {\n        CubeLoader.load(urls, function (cube) {\n          // Texture loaded.\n          self.isLoadingEnvMap = false;\n          material.envMap = cube;\n          utils.material.handleTextureEvents(self.el, cube);\n          resolve(cube);\n        });\n      });\n    });\n  }\n});\n\n/**\n * Builds and normalize material data, normalizing stuff along the way.\n *\n * @param {object} data - Material data.\n * @returns {object} data - Processed material data.\n */\nfunction getMaterialData (data) {\n  var newData = {\n    color: new THREE.Color(data.color),\n    emissive: new THREE.Color(data.emissive),\n    emissiveIntensity: data.emissiveIntensity,\n    fog: data.fog,\n    metalness: data.metalness,\n    roughness: data.roughness,\n    wireframe: data.wireframe,\n    wireframeLinewidth: data.wireframeLinewidth\n  };\n\n  if (data.normalMap) { newData.normalScale = data.normalScale; }\n\n  if (data.ambientOcclusionMap) { newData.aoMapIntensity = data.ambientOcclusionMapIntensity; }\n\n  if (data.displacementMap) {\n    newData.displacementScale = data.displacementScale;\n    newData.displacementBias = data.displacementBias;\n  }\n\n  return newData;\n}\n\n},{\"../core/shader\":134,\"../lib/three\":173,\"../utils/\":195}],180:[function(_dereq_,module,exports){\nvar css = \".a-html{bottom:0;left:0;position:fixed;right:0;top:0}.a-body{height:100%;margin:0;overflow:hidden;padding:0;width:100%}:-webkit-full-screen{background-color:transparent}.a-hidden{display:none!important}.a-canvas{height:100%;left:0;position:absolute;top:0;width:100%}.a-canvas.a-grab-cursor:hover{cursor:grab;cursor:-moz-grab;cursor:-webkit-grab}.a-canvas.a-grab-cursor:active,.a-grabbing{cursor:grabbing;cursor:-moz-grabbing;cursor:-webkit-grabbing}// Class is removed when doing <a-scene embedded>. a-scene.fullscreen .a-canvas{width:100%!important;height:100%!important;top:0!important;left:0!important;right:0!important;bottom:0!important;z-index:999999!important;position:fixed!important}.a-inspector-loader{background-color:#ed3160;position:fixed;left:3px;top:3px;padding:6px 10px;color:#fff;text-decoration:none;font-size:12px;font-family:Roboto,sans-serif;text-align:center;z-index:99999;width:204px}@keyframes dots-1{from{opacity:0}25%{opacity:1}}@keyframes dots-2{from{opacity:0}50%{opacity:1}}@keyframes dots-3{from{opacity:0}75%{opacity:1}}@-webkit-keyframes dots-1{from{opacity:0}25%{opacity:1}}@-webkit-keyframes dots-2{from{opacity:0}50%{opacity:1}}@-webkit-keyframes dots-3{from{opacity:0}75%{opacity:1}}.a-inspector-loader .dots span{animation:dots-1 2s infinite steps(1);-webkit-animation:dots-1 2s infinite steps(1)}.a-inspector-loader .dots span:first-child+span{animation-name:dots-2;-webkit-animation-name:dots-2}.a-inspector-loader .dots span:first-child+span+span{animation-name:dots-3;-webkit-animation-name:dots-3}a-scene{display:block;position:relative;height:100%;width:100%}a-assets,a-scene audio,a-scene img,a-scene video{display:none}.a-enter-vr-modal,.a-orientation-modal{font-family:Consolas,Andale Mono,Courier New,monospace}.a-enter-vr-modal a{border-bottom:1px solid #fff;padding:2px 0;text-decoration:none;transition:.1s color ease-in}.a-enter-vr-modal a:hover{background-color:#fff;color:#111;padding:2px 4px;position:relative;left:-4px}.a-enter-vr{font-family:sans-serif,monospace;font-size:13px;width:100%;font-weight:200;line-height:16px;position:absolute;right:20px;bottom:20px}.a-enter-vr.embedded{right:5px;bottom:5px}.a-enter-vr-button,.a-enter-vr-modal,.a-enter-vr-modal a{color:#fff}.a-enter-vr-button{background:url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20245.82%20141.73%22%3E%3Cdefs%3E%3Cstyle%3E.a%7Bfill%3A%23fff%3Bfill-rule%3Aevenodd%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Emask%3C%2Ftitle%3E%3Cpath%20class%3D%22a%22%20d%3D%22M175.56%2C111.37c-22.52%2C0-40.77-18.84-40.77-42.07S153%2C27.24%2C175.56%2C27.24s40.77%2C18.84%2C40.77%2C42.07S198.08%2C111.37%2C175.56%2C111.37ZM26.84%2C69.31c0-23.23%2C18.25-42.07%2C40.77-42.07s40.77%2C18.84%2C40.77%2C42.07-18.26%2C42.07-40.77%2C42.07S26.84%2C92.54%2C26.84%2C69.31ZM27.27%2C0C11.54%2C0%2C0%2C12.34%2C0%2C28.58V110.9c0%2C16.24%2C11.54%2C30.83%2C27.27%2C30.83H99.57c2.17%2C0%2C4.19-1.83%2C5.4-3.7L116.47%2C118a8%2C8%2C0%2C0%2C1%2C12.52-.18l11.51%2C20.34c1.2%2C1.86%2C3.22%2C3.61%2C5.39%2C3.61h72.29c15.74%2C0%2C27.63-14.6%2C27.63-30.83V28.58C245.82%2C12.34%2C233.93%2C0%2C218.19%2C0H27.27Z%22%2F%3E%3C%2Fsvg%3E) 50% 50%/70% 70% no-repeat rgba(0,0,0,.35);border:0;bottom:0;cursor:pointer;min-width:50px;min-height:30px;padding-right:5%;padding-top:4%;position:absolute;right:0;transition:background-color .05s ease;-webkit-transition:background-color .05s ease;z-index:9999}.a-enter-vr-button:active,.a-enter-vr-button:hover{background-color:#666}[data-a-enter-vr-no-webvr] .a-enter-vr-button{border-color:#666;opacity:.65}[data-a-enter-vr-no-webvr] .a-enter-vr-button:active,[data-a-enter-vr-no-webvr] .a-enter-vr-button:hover{background-color:rgba(0,0,0,.35);cursor:not-allowed}.a-enter-vr-modal{background-color:#666;border-radius:0;display:none;min-height:32px;margin-right:70px;padding:9px;width:280px;right:2%;position:absolute}.a-enter-vr-modal:after{border-bottom:10px solid transparent;border-left:10px solid #666;border-top:10px solid transparent;display:inline-block;content:'';position:absolute;right:-5px;top:5px;width:0;height:0}.a-enter-vr-modal a,.a-enter-vr-modal p{display:inline}.a-enter-vr-modal p{margin:0}.a-enter-vr-modal p:after{content:' '}[data-a-enter-vr-no-headset].a-enter-vr:hover .a-enter-vr-modal,[data-a-enter-vr-no-webvr].a-enter-vr:hover .a-enter-vr-modal{display:block}.a-orientation-modal{background:url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20xmlns%3Axlink%3D%22http%3A//www.w3.org/1999/xlink%22%20version%3D%221.1%22%20x%3D%220px%22%20y%3D%220px%22%20viewBox%3D%220%200%2090%2090%22%20enable-background%3D%22new%200%200%2090%2090%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%220%2C0%200%2C0%200%2C0%20%22%3E%3C/polygon%3E%3Cg%3E%3Cpath%20d%3D%22M71.545%2C48.145h-31.98V20.743c0-2.627-2.138-4.765-4.765-4.765H18.456c-2.628%2C0-4.767%2C2.138-4.767%2C4.765v42.789%20%20%20c0%2C2.628%2C2.138%2C4.766%2C4.767%2C4.766h5.535v0.959c0%2C2.628%2C2.138%2C4.765%2C4.766%2C4.765h42.788c2.628%2C0%2C4.766-2.137%2C4.766-4.765V52.914%20%20%20C76.311%2C50.284%2C74.173%2C48.145%2C71.545%2C48.145z%20M18.455%2C16.935h16.344c2.1%2C0%2C3.808%2C1.708%2C3.808%2C3.808v27.401H37.25V22.636%20%20%20c0-0.264-0.215-0.478-0.479-0.478H16.482c-0.264%2C0-0.479%2C0.214-0.479%2C0.478v36.585c0%2C0.264%2C0.215%2C0.478%2C0.479%2C0.478h7.507v7.644%20%20%20h-5.534c-2.101%2C0-3.81-1.709-3.81-3.81V20.743C14.645%2C18.643%2C16.354%2C16.935%2C18.455%2C16.935z%20M16.96%2C23.116h19.331v25.031h-7.535%20%20%20c-2.628%2C0-4.766%2C2.139-4.766%2C4.768v5.828h-7.03V23.116z%20M71.545%2C73.064H28.757c-2.101%2C0-3.81-1.708-3.81-3.808V52.914%20%20%20c0-2.102%2C1.709-3.812%2C3.81-3.812h42.788c2.1%2C0%2C3.809%2C1.71%2C3.809%2C3.812v16.343C75.354%2C71.356%2C73.645%2C73.064%2C71.545%2C73.064z%22%3E%3C/path%3E%3Cpath%20d%3D%22M28.919%2C58.424c-1.466%2C0-2.659%2C1.193-2.659%2C2.66c0%2C1.466%2C1.193%2C2.658%2C2.659%2C2.658c1.468%2C0%2C2.662-1.192%2C2.662-2.658%20%20%20C31.581%2C59.617%2C30.387%2C58.424%2C28.919%2C58.424z%20M28.919%2C62.786c-0.939%2C0-1.703-0.764-1.703-1.702c0-0.939%2C0.764-1.704%2C1.703-1.704%20%20%20c0.94%2C0%2C1.705%2C0.765%2C1.705%2C1.704C30.623%2C62.022%2C29.858%2C62.786%2C28.919%2C62.786z%22%3E%3C/path%3E%3Cpath%20d%3D%22M69.654%2C50.461H33.069c-0.264%2C0-0.479%2C0.215-0.479%2C0.479v20.288c0%2C0.264%2C0.215%2C0.478%2C0.479%2C0.478h36.585%20%20%20c0.263%2C0%2C0.477-0.214%2C0.477-0.478V50.939C70.131%2C50.676%2C69.917%2C50.461%2C69.654%2C50.461z%20M69.174%2C51.417V70.75H33.548V51.417H69.174z%22%3E%3C/path%3E%3Cpath%20d%3D%22M45.201%2C30.296c6.651%2C0%2C12.233%2C5.351%2C12.551%2C11.977l-3.033-2.638c-0.193-0.165-0.507-0.142-0.675%2C0.048%20%20%20c-0.174%2C0.198-0.153%2C0.501%2C0.045%2C0.676l3.883%2C3.375c0.09%2C0.075%2C0.198%2C0.115%2C0.312%2C0.115c0.141%2C0%2C0.273-0.061%2C0.362-0.166%20%20%20l3.371-3.877c0.173-0.2%2C0.151-0.502-0.047-0.675c-0.194-0.166-0.508-0.144-0.676%2C0.048l-2.592%2C2.979%20%20%20c-0.18-3.417-1.629-6.605-4.099-9.001c-2.538-2.461-5.877-3.817-9.404-3.817c-0.264%2C0-0.479%2C0.215-0.479%2C0.479%20%20%20C44.72%2C30.083%2C44.936%2C30.296%2C45.201%2C30.296z%22%3E%3C/path%3E%3C/g%3E%3C/svg%3E) center/50% 50% no-repeat rgba(244,244,244,1);bottom:0;font-size:14px;font-weight:600;left:0;line-height:20px;right:0;position:fixed;top:0;z-index:9999999}.a-orientation-modal:after{color:#666;content:\\\"Insert phone into Cardboard holder.\\\";display:block;position:absolute;text-align:center;top:70%;transform:translateY(-70%);width:100%}.a-orientation-modal button{background:url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20xmlns%3Axlink%3D%22http%3A//www.w3.org/1999/xlink%22%20version%3D%221.1%22%20x%3D%220px%22%20y%3D%220px%22%20viewBox%3D%220%200%20100%20100%22%20enable-background%3D%22new%200%200%20100%20100%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23000000%22%20d%3D%22M55.209%2C50l17.803-17.803c1.416-1.416%2C1.416-3.713%2C0-5.129c-1.416-1.417-3.713-1.417-5.129%2C0L50.08%2C44.872%20%20L32.278%2C27.069c-1.416-1.417-3.714-1.417-5.129%2C0c-1.417%2C1.416-1.417%2C3.713%2C0%2C5.129L44.951%2C50L27.149%2C67.803%20%20c-1.417%2C1.416-1.417%2C3.713%2C0%2C5.129c0.708%2C0.708%2C1.636%2C1.062%2C2.564%2C1.062c0.928%2C0%2C1.856-0.354%2C2.564-1.062L50.08%2C55.13l17.803%2C17.802%20%20c0.708%2C0.708%2C1.637%2C1.062%2C2.564%2C1.062s1.856-0.354%2C2.564-1.062c1.416-1.416%2C1.416-3.713%2C0-5.129L55.209%2C50z%22%3E%3C/path%3E%3C/svg%3E) no-repeat;border:none;height:50px;text-indent:-9999px;width:50px}\"; (_dereq_(\"browserify-css\").createStyle(css, { \"href\": \"src\\\\style\\\\aframe.css\"})); module.exports = css;\n},{\"browserify-css\":5}],181:[function(_dereq_,module,exports){\nvar css = \".rs-base{background-color:#333;color:#fafafa;border-radius:0;font:10px monospace;left:5px;line-height:1em;opacity:.85;overflow:hidden;padding:10px;position:fixed;top:5px;width:300px;z-index:10000}.rs-base div.hidden{display:none}.rs-base h1{color:#fff;cursor:pointer;font-size:1.4em;font-weight:300;margin:0 0 5px;padding:0}.rs-group{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-flex-direction:column-reverse;flex-direction:column-reverse;margin-bottom:5px}.rs-group:last-child{margin-bottom:0}.rs-counter-base{align-items:center;display:-webkit-box;display:-webkit-flex;display:flex;height:10px;-webkit-justify-content:space-between;justify-content:space-between;margin:2px 0}.rs-counter-base.alarm{color:#b70000;text-shadow:0 0 0 #b70000,0 0 1px #fff,0 0 1px #fff,0 0 2px #fff,0 0 2px #fff,0 0 3px #fff,0 0 3px #fff,0 0 4px #fff,0 0 4px #fff}.rs-counter-id{font-weight:300;-webkit-box-ordinal-group:0;-webkit-order:0;order:0;width:54px}.rs-counter-value{font-weight:300;-webkit-box-ordinal-group:1;-webkit-order:1;order:1;text-align:right;width:35px}.rs-canvas{-webkit-box-ordinal-group:2;-webkit-order:2;order:2}@media (min-width:480px){.rs-base{left:20px;top:20px}}\"; (_dereq_(\"browserify-css\").createStyle(css, { \"href\": \"src\\\\style\\\\rStats.css\"})); module.exports = css;\n},{\"browserify-css\":5}],182:[function(_dereq_,module,exports){\nvar bind = _dereq_('../utils/bind');\nvar constants = _dereq_('../constants/');\nvar registerSystem = _dereq_('../core/system').registerSystem;\n\nvar DEFAULT_CAMERA_ATTR = 'data-aframe-default-camera';\n\n/**\n * Camera system. Manages which camera is active among multiple cameras in scene.\n *\n * @member {object} activeCameraEl - Active camera entity.\n */\nmodule.exports.System = registerSystem('camera', {\n  init: function () {\n    this.activeCameraEl = null;\n    // Wait for all entities to fully load before checking for existence of camera.\n    // Since entities wait for <a-assets> to load, any cameras attaching to the scene\n    // will do so asynchronously.\n    this.sceneEl.addEventListener('loaded', bind(this.setupDefaultCamera, this));\n  },\n\n  /**\n   * Create a default camera if user has not added one during the initial scene traversal.\n   *\n   * Default camera offset height is at average eye level (~1.6m).\n   */\n  setupDefaultCamera: function () {\n    var sceneEl = this.sceneEl;\n    var defaultCameraEl;\n\n    // Camera already defined.\n    if (sceneEl.camera) {\n      sceneEl.emit('camera-ready', {cameraEl: sceneEl.camera.el});\n      return;\n    }\n\n    // Set up default camera.\n    defaultCameraEl = document.createElement('a-entity');\n    defaultCameraEl.setAttribute('position', '0 0 0');\n    defaultCameraEl.setAttribute(DEFAULT_CAMERA_ATTR, '');\n    defaultCameraEl.setAttribute('camera', {active: true, userHeight: constants.DEFAULT_CAMERA_HEIGHT});\n    defaultCameraEl.setAttribute('wasd-controls', '');\n    defaultCameraEl.setAttribute('look-controls', '');\n    defaultCameraEl.setAttribute(constants.AFRAME_INJECTED, '');\n    sceneEl.appendChild(defaultCameraEl);\n    sceneEl.addEventListener('enter-vr', this.removeDefaultOffset);\n    sceneEl.addEventListener('exit-vr', this.addDefaultOffset);\n    sceneEl.emit('camera-ready', {cameraEl: defaultCameraEl});\n  },\n\n  /**\n   * Set a different active camera.\n   * When we choose a (sort of) random scene camera as the replacement, set its `active` to\n   * true. The camera component will call `setActiveCamera` and handle passing the torch to\n   * the new camera.\n   */\n  disableActiveCamera: function () {\n    var cameraEls = this.sceneEl.querySelectorAll('[camera]');\n    var newActiveCameraEl = cameraEls[cameraEls.length - 1];\n    newActiveCameraEl.setAttribute('camera', 'active', true);\n  },\n\n  /**\n   * Set active camera to be used by renderer.\n   * Removes the default camera (if present).\n   * Disables all other cameras in the scene.\n   *\n   * @param {Element} newCameraEl - Entity with camera component.\n   */\n  setActiveCamera: function (newCameraEl) {\n    var cameraEl;\n    var cameraEls;\n    var i;\n    var newCamera;\n    var previousCamera = this.activeCameraEl;\n    var sceneEl = this.sceneEl;\n\n    // Same camera.\n    newCamera = newCameraEl.getObject3D('camera');\n    if (!newCamera || newCameraEl === this.activeCameraEl) { return; }\n\n    // Grab the default camera.\n    var defaultCameraWrapper = sceneEl.querySelector('[' + DEFAULT_CAMERA_ATTR + ']');\n    var defaultCameraEl = defaultCameraWrapper &&\n                          defaultCameraWrapper.querySelector('[camera]');\n\n    // Remove default camera if new camera is not the default camera.\n    if (newCameraEl !== defaultCameraEl) { removeDefaultCamera(sceneEl); }\n\n    // Make new camera active.\n    this.activeCameraEl = newCameraEl;\n    this.activeCameraEl.play();\n    sceneEl.camera = newCamera;\n\n    // Disable current camera\n    if (previousCamera) {\n      previousCamera.setAttribute('camera', 'active', false);\n    }\n\n    // Disable other cameras in the scene\n    cameraEls = sceneEl.querySelectorAll('[camera]');\n    for (i = 0; i < cameraEls.length; i++) {\n      cameraEl = cameraEls[i];\n      if (newCameraEl === cameraEl) { continue; }\n      cameraEl.setAttribute('camera', 'active', false);\n      cameraEl.pause();\n    }\n    sceneEl.emit('camera-set-active', {cameraEl: newCameraEl});\n  }\n});\n\n/**\n * Remove injected default camera from scene, if present.\n *\n * @param {Element} sceneEl\n */\nfunction removeDefaultCamera (sceneEl) {\n  var defaultCamera;\n  var camera = sceneEl.camera;\n  if (!camera) { return; }\n\n  // Remove default camera if present.\n  defaultCamera = sceneEl.querySelector('[' + DEFAULT_CAMERA_ATTR + ']');\n  if (!defaultCamera) { return; }\n  sceneEl.removeChild(defaultCamera);\n}\n\n},{\"../constants/\":116,\"../core/system\":135,\"../utils/bind\":189}],183:[function(_dereq_,module,exports){\nvar geometries = _dereq_('../core/geometry').geometries;\nvar registerSystem = _dereq_('../core/system').registerSystem;\nvar THREE = _dereq_('../lib/three');\n\n/**\n * System for geometry component.\n * Handle geometry caching.\n *\n * @member {object} cache - Mapping of stringified component data to THREE.Geometry objects.\n * @member {object} cacheCount - Keep track of number of entities using a geometry to\n *         know whether to dispose on removal.\n */\nmodule.exports.System = registerSystem('geometry', {\n  init: function () {\n    this.cache = {};\n    this.cacheCount = {};\n  },\n\n  /**\n   * Reset cache. Mainly for testing.\n   */\n  clearCache: function () {\n    this.cache = {};\n    this.cacheCount = {};\n  },\n\n  /**\n   * Attempt to retrieve from cache.\n   *\n   * @returns {Object|null} A geometry if it exists, else null.\n   */\n  getOrCreateGeometry: function (data) {\n    var cache = this.cache;\n    var cachedGeometry;\n    var hash;\n\n    // Skip all caching logic.\n    if (data.skipCache || data.mergeTo) { return createGeometry(data); }\n\n    // Try to retrieve from cache first.\n    hash = this.hash(data);\n    cachedGeometry = cache[hash];\n    incrementCacheCount(this.cacheCount, hash);\n\n    if (cachedGeometry) { return cachedGeometry; }\n\n    // Create geometry.\n    cachedGeometry = createGeometry(data);\n\n    // Cache and return geometry.\n    cache[hash] = cachedGeometry;\n    return cachedGeometry;\n  },\n\n  /**\n   * Let system know that an entity is no longer using a geometry.\n   */\n  unuseGeometry: function (data) {\n    var cache = this.cache;\n    var cacheCount = this.cacheCount;\n    var geometry;\n    var hash;\n\n    if (data.skipCache || data.mergeTo) { return; }\n\n    hash = this.hash(data);\n\n    if (!cache[hash]) { return; }\n\n    decrementCacheCount(cacheCount, hash);\n\n    // Another entity is still using this geometry. No need to do anything.\n    if (cacheCount[hash] > 0) { return; }\n\n    // No more entities are using this geometry. Dispose.\n    geometry = cache[hash];\n    geometry.dispose();\n    delete cache[hash];\n    delete cacheCount[hash];\n  },\n\n  /**\n   * Use JSON.stringify to turn component data into hash.\n   * Should be deterministic within a single browser engine.\n   * If not, then look into json-stable-stringify.\n   */\n  hash: function (data) {\n    return JSON.stringify(data);\n  }\n});\n\n/**\n * Create geometry using component data.\n *\n * @param {object} data - Component data.\n * @returns {object} Geometry.\n */\nfunction createGeometry (data) {\n  var geometryType = data.primitive;\n  var GeometryClass = geometries[geometryType] && geometries[geometryType].Geometry;\n  var geometryInstance = new GeometryClass();\n\n  if (!GeometryClass) { throw new Error('Unknown geometry `' + geometryType + '`'); }\n\n  geometryInstance.init(data);\n  return toBufferGeometry(geometryInstance.geometry, data.buffer);\n}\n\n/**\n * Decreate count of entity using a geometry.\n */\nfunction decrementCacheCount (cacheCount, hash) {\n  cacheCount[hash]--;\n}\n\n/**\n * Increase count of entity using a geometry.\n */\nfunction incrementCacheCount (cacheCount, hash) {\n  cacheCount[hash] = cacheCount[hash] === undefined ? 1 : cacheCount[hash] + 1;\n}\n\n/**\n * Transform geometry to BufferGeometry if `doBuffer`.\n *\n * @param {object} geometry\n * @param {boolean} doBuffer\n * @returns {object} Geometry.\n */\nfunction toBufferGeometry (geometry, doBuffer) {\n  var bufferGeometry;\n  if (!doBuffer) { return geometry; }\n\n  bufferGeometry = new THREE.BufferGeometry().fromGeometry(geometry);\n  bufferGeometry.metadata = {type: geometry.type, parameters: geometry.parameters || {}};\n  geometry.dispose();  // Dispose no longer needed non-buffer geometry.\n  return bufferGeometry;\n}\n\n},{\"../core/geometry\":126,\"../core/system\":135,\"../lib/three\":173}],184:[function(_dereq_,module,exports){\n_dereq_('./camera');\n_dereq_('./geometry');\n_dereq_('./light');\n_dereq_('./material');\n_dereq_('./shadow');\n_dereq_('./tracked-controls');\n\n\n},{\"./camera\":182,\"./geometry\":183,\"./light\":185,\"./material\":186,\"./shadow\":187,\"./tracked-controls\":188}],185:[function(_dereq_,module,exports){\nvar registerSystem = _dereq_('../core/system').registerSystem;\nvar bind = _dereq_('../utils/bind');\nvar constants = _dereq_('../constants/');\n\nvar DEFAULT_LIGHT_ATTR = 'data-aframe-default-light';\n\n/**\n * Light system.\n *\n * Prescribes default lighting if not specified (one ambient, one directional).\n * Removes default lighting from the scene when a new light is added.\n *\n * @param {bool} defaultLights - Whether default lighting are defined.\n * @param {bool} userDefinedLights - Whether user lighting is defined.\n */\nmodule.exports.System = registerSystem('light', {\n  schema: {\n    defaultLightsEnabled: {default: true}\n  },\n\n  init: function () {\n    this.defaultLights = false;\n    this.userDefinedLights = false;\n    // Wait for all entities to fully load before checking for existence of lights.\n    // Since entities wait for <a-assets> to load, any lights attaching to the scene\n    // will do so asynchronously.\n    this.sceneEl.addEventListener('loaded', bind(this.setupDefaultLights, this));\n  },\n\n  /**\n   * Notify scene that light has been added and to remove the default.\n   *\n   * @param {object} el - element holding the light component.\n   */\n  registerLight: function (el) {\n    if (!el.hasAttribute(DEFAULT_LIGHT_ATTR)) {\n      // User added a light, remove default lights through DOM.\n      this.removeDefaultLights();\n      this.userDefinedLights = true;\n    }\n  },\n\n  removeDefaultLights: function () {\n    var defaultLights;\n    var sceneEl = this.sceneEl;\n\n    if (!this.defaultLights) { return; }\n    defaultLights = document.querySelectorAll('[' + DEFAULT_LIGHT_ATTR + ']');\n    for (var i = 0; i < defaultLights.length; i++) {\n      sceneEl.removeChild(defaultLights[i]);\n    }\n    this.defaultLights = false;\n  },\n\n  /**\n   * Prescibe default lights to the scene.\n   * Does so by injecting markup such that this state is not invisible.\n   * These lights are removed if the user adds any lights.\n   */\n  setupDefaultLights: function () {\n    var sceneEl = this.sceneEl;\n    var ambientLight;\n    var directionalLight;\n\n    if (this.userDefinedLights || this.defaultLights || !this.data.defaultLightsEnabled) {\n      return;\n    }\n\n    ambientLight = document.createElement('a-entity');\n    ambientLight.setAttribute('light', {color: '#BBB', type: 'ambient'});\n    ambientLight.setAttribute(DEFAULT_LIGHT_ATTR, '');\n    ambientLight.setAttribute(constants.AFRAME_INJECTED, '');\n    sceneEl.appendChild(ambientLight);\n\n    directionalLight = document.createElement('a-entity');\n    directionalLight.setAttribute('light', {color: '#FFF', intensity: 0.6, castShadow: true});\n    directionalLight.setAttribute('position', {x: -0.5, y: 1, z: 1});\n    directionalLight.setAttribute(DEFAULT_LIGHT_ATTR, '');\n    directionalLight.setAttribute(constants.AFRAME_INJECTED, '');\n    sceneEl.appendChild(directionalLight);\n\n    this.defaultLights = true;\n  }\n});\n\n},{\"../constants/\":116,\"../core/system\":135,\"../utils/bind\":189}],186:[function(_dereq_,module,exports){\nvar registerSystem = _dereq_('../core/system').registerSystem;\nvar THREE = _dereq_('../lib/three');\nvar utils = _dereq_('../utils/');\nvar isHLS = _dereq_('../utils/material').isHLS;\n\nvar bind = utils.bind;\nvar debug = utils.debug;\nvar error = debug('components:texture:error');\nvar TextureLoader = new THREE.TextureLoader();\nvar warn = debug('components:texture:warn');\n\nTextureLoader.setCrossOrigin('anonymous');\n\n/**\n * System for material component.\n * Handle material registration, updates (for fog), and texture caching.\n *\n * @member {object} materials - Registered materials.\n * @member {object} textureCounts - Number of times each texture is used. Tracked\n *         separately from textureCache, because the cache (1) is populated in\n *         multiple places, and (2) may be cleared at any time.\n * @member {object} textureCache - Texture cache for:\n *   - Images: textureCache has mapping of src -> repeat -> cached three.js texture.\n *   - Videos: textureCache has mapping of videoElement -> cached three.js texture.\n */\nmodule.exports.System = registerSystem('material', {\n  init: function () {\n    this.materials = {};\n    this.textureCounts = {};\n    this.textureCache = {};\n\n    this.sceneEl.addEventListener(\n      'materialtextureloaded',\n      bind(this.onMaterialTextureLoaded, this)\n    );\n  },\n\n  clearTextureCache: function () {\n    this.textureCache = {};\n  },\n\n  /**\n   * Determine whether `src` is a image or video. Then try to load the asset, then call back.\n   *\n   * @param {string, or element} src - Texture URL or element.\n   * @param {string} data - Relevant texture data used for caching.\n   * @param {function} cb - Callback to pass texture to.\n   */\n  loadTexture: function (src, data, cb) {\n    var self = this;\n\n    // Canvas.\n    if (src.tagName === 'CANVAS') {\n      this.loadCanvas(src, data, cb);\n      return;\n    }\n\n    // Video element.\n    if (src.tagName === 'VIDEO') {\n      if (!src.hasAttribute('src') && !src.hasAttribute('srcObject')) {\n        warn('Video element was defined without `src` nor `srcObject` attributes.');\n      }\n      this.loadVideo(src, data, cb);\n      return;\n    }\n\n    utils.srcLoader.validateSrc(src, loadImageCb, loadVideoCb);\n    function loadImageCb (src) { self.loadImage(src, data, cb); }\n    function loadVideoCb (src) { self.loadVideo(src, data, cb); }\n  },\n\n  /**\n   * High-level function for loading image textures (THREE.Texture).\n   *\n   * @param {Element|string} src - Texture source.\n   * @param {object} data - Texture data.\n   * @param {function} cb - Callback to pass texture to.\n   */\n  loadImage: function (src, data, handleImageTextureLoaded) {\n    var hash = this.hash(data);\n    var textureCache = this.textureCache;\n\n    // Texture already being loaded or already loaded. Wait on promise.\n    if (textureCache[hash]) {\n      textureCache[hash].then(handleImageTextureLoaded);\n      return;\n    }\n\n    // Texture not yet being loaded. Start loading it.\n    textureCache[hash] = loadImageTexture(src, data);\n    textureCache[hash].then(handleImageTextureLoaded);\n  },\n\n  /**\n   * High-level function for loading canvas textures (THREE.Texture).\n   *\n   * @param {Element|string} src - Texture source.\n   * @param {object} data - Texture data.\n   * @param {function} cb - Callback to pass texture to.\n   */\n  loadCanvas: function (src, data, cb) {\n    // Hack readyState and HAVE_CURRENT_DATA on canvas to work with THREE.VideoTexture\n    src.readyState = 2;\n    src.HAVE_CURRENT_DATA = 2;\n    this.loadVideo(src, data, cb);\n  },\n\n    /**\n   * Load video texture (THREE.VideoTexture).\n   * Which is just an image texture that RAFs + needsUpdate.\n   * Note that creating a video texture is synchronous unlike loading an image texture.\n   * Made asynchronous to be consistent with image textures.\n   *\n   * @param {Element|string} src - Texture source.\n   * @param {object} data - Texture data.\n   * @param {function} cb - Callback to pass texture to.\n   */\n  loadVideo: function (src, data, cb) {\n    var hash;\n    var texture;\n    var textureCache = this.textureCache;\n    var videoEl;\n    var videoTextureResult;\n\n    function handleVideoTextureLoaded (result) {\n      result.texture.needsUpdate = true;\n      cb(result.texture, result.videoEl);\n    }\n\n    // Video element provided.\n    if (typeof src !== 'string') {\n      // Check cache before creating texture.\n      videoEl = src;\n      hash = this.hashVideo(data, videoEl);\n      if (textureCache[hash]) {\n        textureCache[hash].then(handleVideoTextureLoaded);\n        return;\n      }\n      // If not in cache, fix up the attributes then start to create the texture.\n      fixVideoAttributes(videoEl);\n    }\n\n    // Only URL provided. Use video element to create texture.\n    videoEl = videoEl || createVideoEl(src, data.width, data.height);\n\n    // Generated video element already cached. Use that.\n    hash = this.hashVideo(data, videoEl);\n    if (textureCache[hash]) {\n      textureCache[hash].then(handleVideoTextureLoaded);\n      return;\n    }\n\n    // Create new video texture.\n    texture = new THREE.VideoTexture(videoEl);\n    texture.minFilter = THREE.LinearFilter;\n    setTextureProperties(texture, data);\n\n    // If iOS and video is HLS, do some hacks.\n    if (this.sceneEl.isIOS &&\n        isHLS(videoEl.src || videoEl.getAttribute('src'),\n              videoEl.type || videoEl.getAttribute('type'))) {\n      // Actually BGRA. Tell shader to correct later.\n      texture.format = THREE.RGBAFormat;\n      texture.needsCorrectionBGRA = true;\n      // Apparently needed for HLS. Tell shader to correct later.\n      texture.flipY = false;\n      texture.needsCorrectionFlipY = true;\n    }\n\n    // Cache as promise to be consistent with image texture caching.\n    videoTextureResult = {texture: texture, videoEl: videoEl};\n    textureCache[hash] = Promise.resolve(videoTextureResult);\n    handleVideoTextureLoaded(videoTextureResult);\n  },\n\n  /**\n   * Create a hash of the material properties for texture cache key.\n   */\n  hash: function (data) {\n    if (data.src.tagName) {\n      // Since `data.src` can be an element, parse out the string if necessary for the hash.\n      data = utils.extendDeep({}, data);\n      data.src = data.src.getAttribute('src');\n    }\n    return JSON.stringify(data);\n  },\n\n  hashVideo: function (data, videoEl) {\n    return calculateVideoCacheHash(data, videoEl);\n  },\n\n  /**\n   * Keep track of material in case an update trigger is needed (e.g., fog).\n   *\n   * @param {object} material\n   */\n  registerMaterial: function (material) {\n    this.materials[material.uuid] = material;\n  },\n\n  /**\n   * Stop tracking material, and dispose of any textures not being used by\n   * another material component.\n   *\n   * @param {object} material\n   */\n  unregisterMaterial: function (material) {\n    delete this.materials[material.uuid];\n\n    // If any textures on this material are no longer in use, dispose of them.\n    var textureCounts = this.textureCounts;\n    Object.keys(material)\n      .filter(function (propName) {\n        return material[propName] && material[propName].isTexture;\n      })\n      .forEach(function (mapName) {\n        textureCounts[material[mapName].uuid]--;\n        if (textureCounts[material[mapName].uuid] <= 0) {\n          material[mapName].dispose();\n        }\n      });\n  },\n\n  /**\n   * Trigger update to all registered materials.\n   */\n  updateMaterials: function (material) {\n    var materials = this.materials;\n    Object.keys(materials).forEach(function (uuid) {\n      materials[uuid].needsUpdate = true;\n    });\n  },\n\n  /**\n   * Track textures used by material components, so that they can be safely\n   * disposed when no longer in use. Textures must be registered here, and not\n   * through registerMaterial(), because textures may not be attached at the\n   * time the material is registered.\n   *\n   * @param {Event} e\n   */\n  onMaterialTextureLoaded: function (e) {\n    if (!this.textureCounts[e.detail.texture.uuid]) {\n      this.textureCounts[e.detail.texture.uuid] = 0;\n    }\n    this.textureCounts[e.detail.texture.uuid]++;\n  }\n});\n\n/**\n * Calculates consistent hash from a video element using its attributes.\n * If the video element has an ID, use that.\n * Else build a hash that looks like `src:myvideo.mp4;height:200;width:400;`.\n *\n * @param data {object} - Texture data such as repeat.\n * @param videoEl {Element} - Video element.\n * @returns {string}\n */\nfunction calculateVideoCacheHash (data, videoEl) {\n  var i;\n  var id = videoEl.getAttribute('id');\n  var hash;\n  var videoAttributes;\n\n  if (id) { return id; }\n\n  // Calculate hash using sorted video attributes.\n  hash = '';\n  videoAttributes = data || {};\n  for (i = 0; i < videoEl.attributes.length; i++) {\n    videoAttributes[videoEl.attributes[i].name] = videoEl.attributes[i].value;\n  }\n  Object.keys(videoAttributes).sort().forEach(function (name) {\n    hash += name + ':' + videoAttributes[name] + ';';\n  });\n\n  return hash;\n}\n\n/**\n * Load image texture.\n *\n * @private\n * @param {string|object} src - An <img> element or url to an image file.\n * @param {object} data - Data to set texture properties like `repeat`.\n * @returns {Promise} Resolves once texture is loaded.\n */\nfunction loadImageTexture (src, data) {\n  return new Promise(doLoadImageTexture);\n\n  function doLoadImageTexture (resolve, reject) {\n    var isEl = typeof src !== 'string';\n\n    function resolveTexture (texture) {\n      setTextureProperties(texture, data);\n      texture.needsUpdate = true;\n      resolve(texture);\n    }\n\n    // Create texture from an element.\n    if (isEl) {\n      resolveTexture(new THREE.Texture(src));\n      return;\n    }\n\n    // Request and load texture from src string. THREE will create underlying element.\n    // Use THREE.TextureLoader (src, onLoad, onProgress, onError) to load texture.\n    TextureLoader.load(\n      src,\n      resolveTexture,\n      function () { /* no-op */ },\n      function (xhr) {\n        error('`$s` could not be fetched (Error code: %s; Response: %s)', xhr.status,\n              xhr.statusText);\n      }\n    );\n  }\n}\n\n/**\n * Set texture properties such as repeat and offset.\n *\n * @param {object} data - With keys like `repeat`.\n */\nfunction setTextureProperties (texture, data) {\n  var offset = data.offset || {x: 0, y: 0};\n  var repeat = data.repeat || {x: 1, y: 1};\n  var npot = data.npot || false;\n\n  // To support NPOT textures, wrap must be ClampToEdge (not Repeat),\n  // and filters must not use mipmaps (i.e. Nearest or Linear).\n  if (npot) {\n    texture.wrapS = THREE.ClampToEdgeWrapping;\n    texture.wrapT = THREE.ClampToEdgeWrapping;\n    texture.magFilter = THREE.LinearFilter;\n    texture.minFilter = THREE.LinearFilter;\n  }\n\n  // Don't bother setting repeat if it is 1/1. Power-of-two is required to repeat.\n  if (repeat.x !== 1 || repeat.y !== 1) {\n    texture.wrapS = THREE.RepeatWrapping;\n    texture.wrapT = THREE.RepeatWrapping;\n    texture.repeat.set(repeat.x, repeat.y);\n  }\n  // Don't bother setting offset if it is 0/0.\n  if (offset.x !== 0 || offset.y !== 0) {\n    texture.offset.set(offset.x, offset.y);\n  }\n}\n\n/**\n * Create video element to be used as a texture.\n *\n * @param {string} src - Url to a video file.\n * @param {number} width - Width of the video.\n * @param {number} height - Height of the video.\n * @returns {Element} Video element.\n */\nfunction createVideoEl (src, width, height) {\n  var videoEl = document.createElement('video');\n  videoEl.width = width;\n  videoEl.height = height;\n  // Support inline videos for iOS webviews.\n  videoEl.setAttribute('playsinline', '');\n  videoEl.setAttribute('webkit-playsinline', '');\n  videoEl.autoplay = true;\n  videoEl.loop = true;\n  videoEl.crossOrigin = 'anonymous';\n  videoEl.addEventListener('error', function () {\n    warn('`$s` is not a valid video', src);\n  }, true);\n  videoEl.src = src;\n  return videoEl;\n}\n\n/**\n * Fixes a video element's attributes to prevent developers from accidentally passing the\n * wrong attribute values to commonly misused video attributes.\n *\n * <video> does not treat `autoplay`, `controls`, `crossorigin`, `loop`, and `preload` as\n * as booleans. Existence of those attributes will mean truthy.\n *\n * For example, translates <video loop=\"false\"> to <video>.\n *\n * @see https://developer.mozilla.org/docs/Web/HTML/Element/video#Attributes\n * @param {Element} videoEl - Video element.\n * @returns {Element} Video element with the correct properties updated.\n */\nfunction fixVideoAttributes (videoEl) {\n  videoEl.autoplay = videoEl.hasAttribute('autoplay') && videoEl.getAttribute('autoplay') !== 'false';\n  videoEl.controls = videoEl.hasAttribute('controls') && videoEl.getAttribute('controls') !== 'false';\n  if (videoEl.getAttribute('loop') === 'false') {\n    videoEl.removeAttribute('loop');\n  }\n  if (videoEl.getAttribute('preload') === 'false') {\n    videoEl.preload = 'none';\n  }\n  videoEl.crossOrigin = videoEl.crossOrigin || 'anonymous';\n  // To support inline videos in iOS webviews.\n  videoEl.setAttribute('playsinline', '');\n  videoEl.setAttribute('webkit-playsinline', '');\n  return videoEl;\n}\n\n},{\"../core/system\":135,\"../lib/three\":173,\"../utils/\":195,\"../utils/material\":196}],187:[function(_dereq_,module,exports){\nvar registerSystem = _dereq_('../core/system').registerSystem;\nvar bind = _dereq_('../utils/bind');\nvar THREE = _dereq_('../lib/three');\n\nvar SHADOW_MAP_TYPE_MAP = {\n  basic: THREE.BasicShadowMap,\n  pcf: THREE.PCFShadowMap,\n  pcfsoft: THREE.PCFSoftShadowMap\n};\n\n/**\n * Shadow system.\n *\n * Enabled automatically when one or more shadow components are added to the scene, the system sets\n * options on the WebGLRenderer for configuring shadow appearance.\n */\nmodule.exports.System = registerSystem('shadow', {\n  schema: {\n    type: {default: 'pcf', oneOf: ['basic', 'pcf', 'pcfsoft']},\n    renderReverseSided: {default: true},\n    renderSingleSided: {default: true}\n  },\n\n  init: function () {\n    var sceneEl = this.sceneEl;\n    var data = this.data;\n\n    this.shadowMapEnabled = false;\n\n    sceneEl.addEventListener('render-target-loaded', bind(function () {\n      // Renderer is not initialized in most tests.\n      if (!sceneEl.renderer) { return; }\n      sceneEl.renderer.shadowMap.type = SHADOW_MAP_TYPE_MAP[data.type];\n      sceneEl.renderer.shadowMap.renderReverseSided = data.renderReverseSided;\n      sceneEl.renderer.shadowMap.renderSingleSided = data.renderSingleSided;\n      this.setShadowMapEnabled(this.shadowMapEnabled);\n    }, this));\n  },\n\n  /**\n   * Enables/disables the renderer shadow map.\n   * @param {boolean} enabled\n   */\n  setShadowMapEnabled: function (enabled) {\n    var renderer = this.sceneEl.renderer;\n    this.shadowMapEnabled = enabled;\n    if (renderer) {\n      renderer.shadowMap.enabled = enabled;\n    }\n  }\n});\n\n},{\"../core/system\":135,\"../lib/three\":173,\"../utils/bind\":189}],188:[function(_dereq_,module,exports){\nvar registerSystem = _dereq_('../core/system').registerSystem;\n\n/**\n * Tracked controls system.\n * Maintain list with available tracked controllers.\n */\nmodule.exports.System = registerSystem('tracked-controls', {\n  init: function () {\n    var self = this;\n\n    this.controllers = [];\n\n    this.updateControllerList();\n\n    if (!navigator.getVRDisplays) { return; }\n\n    this.sceneEl.addEventListener('enter-vr', function () {\n      navigator.getVRDisplays().then(function (displays) {\n        if (displays.length) { self.vrDisplay = displays[0]; }\n      });\n    });\n  },\n\n  tick: function () {\n    this.updateControllerList();\n  },\n\n  /**\n   * Update controller list.\n   */\n  updateControllerList: function () {\n    var controllers = this.controllers;\n    var gamepad;\n    var gamepads;\n    var i;\n    var prevCount;\n\n    gamepads = navigator.getGamepads && navigator.getGamepads();\n    if (!gamepads) { return; }\n\n    prevCount = controllers.length;\n    controllers.length = 0;\n    for (i = 0; i < gamepads.length; ++i) {\n      gamepad = gamepads[i];\n      if (gamepad && gamepad.pose) {\n        controllers.push(gamepad);\n      }\n    }\n\n    if (controllers.length !== prevCount) {\n      this.el.emit('controllersupdated', undefined, false);\n    }\n  }\n});\n\n},{\"../core/system\":135}],189:[function(_dereq_,module,exports){\n/**\n * Faster version of Function.prototype.bind\n * @param {Function} fn - Function to wrap.\n * @param {Object} ctx - What to bind as context.\n * @param {...*} arguments - Arguments to pass through.\n */\nmodule.exports = function bind (fn, ctx/* , arg1, arg2 */) {\n  return (function (prependedArgs) {\n    return function bound () {\n      // Concat the bound function arguments with those passed to original bind\n      var args = prependedArgs.concat(Array.prototype.slice.call(arguments, 0));\n      return fn.apply(ctx, args);\n    };\n  })(Array.prototype.slice.call(arguments, 2));\n};\n\n},{}],190:[function(_dereq_,module,exports){\n/* global THREE */\nvar debug = _dereq_('./debug');\nvar extend = _dereq_('object-assign');\n\nvar warn = debug('utils:coordinates:warn');\n\n// Coordinate string regex. Handles negative, positive, and decimals.\nvar regex = /^\\s*((-?\\d*\\.{0,1}\\d+(e-?\\d+)?)\\s+){2,3}(-?\\d*\\.{0,1}\\d+(e-?\\d+)?)\\s*$/;\nmodule.exports.regex = regex;\n\n/**\n * Parses coordinates from an \"x y z\" string.\n * Example: \"3 10 -5\" to {x: 3, y: 10, z: -5}.\n *\n * @param {string} val - An \"x y z\" string.\n * @param {string} defaults - fallback value.\n * @returns {object} An object with keys [x, y, z].\n */\nfunction parse (value, defaultVec) {\n  var coordinate;\n  var vec;\n\n  if (value && value instanceof Object) {\n    if (defaultVec) {\n      value.x = value.x === undefined ? defaultVec.x : value.x;\n      value.y = value.y === undefined ? defaultVec.y : value.y;\n      value.z = value.z === undefined ? defaultVec.z : value.z;\n      value.w = value.w === undefined ? defaultVec.w : value.w;\n    }\n    return vecParseFloat(value);\n  }\n\n  if (value === null || value === undefined) {\n    return typeof defaultVec === 'object' ? extend({}, defaultVec) : defaultVec;\n  }\n\n  coordinate = value.trim().replace(/\\s+/g, ' ').split(' ');\n  vec = {};\n  vec.x = coordinate[0] || defaultVec && defaultVec.x;\n  vec.y = coordinate[1] || defaultVec && defaultVec.y;\n  vec.z = coordinate[2] || defaultVec && defaultVec.z;\n  vec.w = coordinate[3] || defaultVec && defaultVec.w;\n  return vecParseFloat(vec);\n}\nmodule.exports.parse = parse;\n\n/**\n * Stringify coordinates from an object with keys [x y z].\n * Example: {x: 3, y: 10, z: -5} to \"3 10 -5\".\n *\n * @param {object|string} data - An object with keys [x y z].\n * @returns {string} An \"x y z\" string.\n */\nfunction stringify (data) {\n  if (typeof data !== 'object') { return data; }\n  return [data.x, data.y, data.z, data.w].join(' ').trim();\n}\nmodule.exports.stringify = stringify;\n\n/**\n * @returns {bool}\n */\nfunction isCoordinates (value) {\n  return regex.test(value);\n}\nmodule.exports.isCoordinates = isCoordinates;\n\nmodule.exports.isCoordinate = function (value) {\n  warn('`AFRAME.utils.isCoordinate` has been renamed to `AFRAME.utils.isCoordinates`');\n  return isCoordinates(value);\n};\n\nfunction vecParseFloat (vec) {\n  var key;\n  for (key in vec) {\n    if (vec[key] === undefined) {\n      delete vec[key];\n      continue;\n    }\n    if (vec[key].constructor === String) {\n      vec[key] = parseFloat(vec[key], 10);\n    }\n  }\n  return vec;\n}\n\n/**\n * Convert {x, y, z} object to three.js Vector3.\n */\nmodule.exports.toVector3 = function (vec3) {\n  return new THREE.Vector3(vec3.x, vec3.y, vec3.z);\n};\n\n},{\"./debug\":191,\"object-assign\":26}],191:[function(_dereq_,module,exports){\n(function (process){\nvar debugLib = _dereq_('debug');\nvar extend = _dereq_('object-assign');\n\nvar settings = {\n  colors: {\n    debug: 'gray',\n    error: 'red',\n    info: 'gray',\n    warn: 'orange'\n  }\n};\n\n/**\n * Monkeypatches `debug` so we can colorize error/warning messages.\n *\n * (See issue: https://github.com/visionmedia/debug/issues/137)\n */\nvar debug = function (namespace) {\n  var d = debugLib(namespace);\n\n  d.color = getDebugNamespaceColor(namespace);\n\n  return d;\n};\nextend(debug, debugLib);\n\n/**\n * Returns the type of the namespace (e.g., `error`, `warn`).\n *\n * @param {String} namespace\n *   The debug logger's namespace (e.g., `components:geometry:warn`).\n * @returns {String} The type of the namespace (e.g., `warn`).\n * @api private\n */\nfunction getDebugNamespaceType (namespace) {\n  var chunks = namespace.split(':');\n\n  return chunks[chunks.length - 1];  // Return the last one\n}\n\n/**\n * Returns the color of the namespace (e.g., `orange`).\n *\n * @param {String} namespace\n *   The debug logger's namespace (e.g., `components:geometry:warn`).\n * @returns {String} The color of the namespace (e.g., `orange`).\n * @api private\n */\nfunction getDebugNamespaceColor (namespace) {\n  var type = getDebugNamespaceType(namespace);\n\n  var color = settings.colors && settings.colors[type];\n\n  return color || null;\n}\n\n/**\n * Returns `localStorage` if possible.\n *\n * This is necessary because Safari throws when a user disables\n * cookies or `localStorage` and you attempt to access it.\n *\n * @returns {localStorage}\n * @api private\n */\nfunction storage () {\n  try {\n    return window.localStorage;\n  } catch (e) {\n  }\n}\n\n/**\n * To enable console logging, type this in the Console of your Dev Tools:\n *\n *   localStorage.logs = 1\n *\n * To disable console logging:\n *\n *   localStorage.logs = 0\n *\n */\nvar ls = storage();\nif (ls && (parseInt(ls.logs, 10) || ls.logs === 'true')) {\n  debug.enable('*');\n} else {\n  debug.enable('*:error,*:info,*:warn');\n}\n\nif (process.browser) { window.logs = debug; }\n\nmodule.exports = debug;\n\n}).call(this,_dereq_('_process'))\n\n},{\"_process\":6,\"debug\":10,\"object-assign\":26}],192:[function(_dereq_,module,exports){\n(function (process){\nvar THREE = _dereq_('../lib/three');\nvar dolly = new THREE.Object3D();\nvar controls = new THREE.VRControls(dolly);\n\n/**\n * Determine if a headset is connected by checking if the orientation is available.\n */\nfunction checkHeadsetConnected () {\n  var orientation;\n  var vrDisplay = controls.getVRDisplay();\n\n  // If `isConnected` is available, just use that.\n  if (vrDisplay && 'isConnected' in vrDisplay) { return vrDisplay.isConnected; }\n\n  controls.update();\n  orientation = dolly.quaternion;\n  if (orientation._x !== 0 || orientation._y !== 0 || orientation._z !== 0) {\n    return true;\n  }\n  return false;\n}\nmodule.exports.checkHeadsetConnected = checkHeadsetConnected;\n\n/**\n * Check for positional tracking.\n */\nfunction checkHasPositionalTracking () {\n  var vrDisplay = controls.getVRDisplay();\n  if (isMobile() || isGearVR()) { return false; }\n  return vrDisplay && vrDisplay.capabilities.hasPosition;\n}\nmodule.exports.checkHasPositionalTracking = checkHasPositionalTracking;\n\n/**\n * Checks if browser is mobile.\n * @return {Boolean} True if mobile browser detected.\n */\nvar isMobile = (function () {\n  var _isMobile = false;\n  (function (a) {\n    // eslint-disable-next-line no-useless-escape\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))) {\n      _isMobile = true;\n    }\n    if (isIOS() || isTablet()) {\n      _isMobile = true;\n    }\n  })(window.navigator.userAgent || window.navigator.vendor || window.opera);\n\n  return function () { return _isMobile; };\n})();\nmodule.exports.isMobile = isMobile;\n\n/**\n *  Detect tablet devices.\n *  @param {string} mockUserAgent - Allow passing a mock user agent for testing.\n */\nfunction isTablet (mockUserAgent) {\n  var userAgent = mockUserAgent || window.navigator.userAgent;\n  return /ipad|Nexus (7|9)|xoom|sch-i800|playbook|tablet|kindle/i.test(userAgent);\n}\nmodule.exports.isTablet = isTablet;\n\nfunction isIOS () {\n  return /iPad|iPhone|iPod/.test(window.navigator.platform);\n}\nmodule.exports.isIOS = isIOS;\n\nfunction isGearVR () {\n  return /SamsungBrowser.+Mobile VR/i.test(window.navigator.userAgent);\n}\nmodule.exports.isGearVR = isGearVR;\n\n/**\n * Checks mobile device orientation.\n * @return {Boolean} True if landscape orientation.\n */\nmodule.exports.isLandscape = function () {\n  return window.orientation === 90 || window.orientation === -90;\n};\n\n/**\n * Check if device is iOS and older than version 10.\n */\nmodule.exports.isIOSOlderThan10 = function (userAgent) {\n  return /(iphone|ipod|ipad).*os.(7|8|9)/i.test(userAgent);\n};\n\n/**\n * Check if running in a browser or spoofed browser (bundler).\n * We need to check a node api that isn't mocked on either side.\n * `require` and `module.exports` are mocked in browser by bundlers.\n * `window` is mocked in node.\n * `process` is also mocked by browserify, but has custom properties.\n */\nmodule.exports.isBrowserEnvironment = !!(!process || process.browser);\n\n/**\n * Check if running in node on the server.\n */\nmodule.exports.isNodeEnvironment = !module.exports.isBrowserEnvironment;\n\n}).call(this,_dereq_('_process'))\n\n},{\"../lib/three\":173,\"_process\":6}],193:[function(_dereq_,module,exports){\n/**\n * Split a delimited component property string (e.g., `material.color`) to an object\n * containing `component` name and `property` name. If there is no delimiter, just return the\n * string back.\n */\nmodule.exports.getComponentPropertyPath = function (str, delimiter) {\n  delimiter = delimiter || '.';\n  if (str.indexOf(delimiter) === -1) { return str; }\n  return str.split(delimiter);\n};\n\n/**\n * Get component property using encoded component name + component property name with a\n * delimiter.\n */\nmodule.exports.getComponentProperty = function (el, name, delimiter) {\n  var splitName;\n  delimiter = delimiter || '.';\n  if (name.indexOf(delimiter) !== -1) {\n    splitName = name.split(delimiter);\n    return el.getAttribute(splitName[0])[splitName[1]];\n  }\n  return el.getAttribute(name);\n};\n\n/**\n * Set component property using encoded component name + component property name with a\n * delimiter.\n */\nmodule.exports.setComponentProperty = function (el, name, value, delimiter) {\n  var data = {};\n  var splitName;\n  delimiter = delimiter || '.';\n  if (name.indexOf(delimiter) !== -1) {\n    splitName = name.split(delimiter);\n    data[splitName[1]] = value;\n    el.setAttribute(splitName[0], data);\n    return;\n  }\n  el.setAttribute(name, value);\n};\n\n},{}],194:[function(_dereq_,module,exports){\nmodule.exports = function forceCanvasResizeSafariMobile (canvasEl) {\n  var width = canvasEl.style.width;\n  var height = canvasEl.style.height;\n  // Taken from webvr-polyfill (https://github.com/borismus/webvr-polyfill/blob/85f657cd502ec9417bf26b87c3cb2afa6a70e079/src/util.js#L200)\n  // iOS only workaround for https://bugs.webkit.org/show_bug.cgi?id=152556\n  // By changing the size 1 pixel and restoring the previous value\n  // we trigger a size recalculation cycle.\n  canvasEl.style.width = (parseInt(width, 10) + 1) + 'px';\n  canvasEl.style.height = (parseInt(height, 10) + 1) + 'px';\n  setTimeout(function () {\n    canvasEl.style.width = width;\n    canvasEl.style.height = height;\n  }, 200);\n};\n\n},{}],195:[function(_dereq_,module,exports){\n/* global CustomEvent, location */\n/* Centralized place to reference utilities since utils is exposed to the user. */\nvar debug = _dereq_('./debug');\nvar deepAssign = _dereq_('deep-assign');\nvar device = _dereq_('./device');\nvar objectAssign = _dereq_('object-assign');\n\nvar warn = debug('utils:warn');\n\nmodule.exports.bind = _dereq_('./bind');\nmodule.exports.coordinates = _dereq_('./coordinates');\nmodule.exports.debug = debug;\nmodule.exports.device = device;\nmodule.exports.entity = _dereq_('./entity');\nmodule.exports.forceCanvasResizeSafariMobile = _dereq_('./forceCanvasResizeSafariMobile');\nmodule.exports.material = _dereq_('./material');\nmodule.exports.styleParser = _dereq_('./styleParser');\nmodule.exports.trackedControls = _dereq_('./tracked-controls');\n\nmodule.exports.checkHeadsetConnected = function () {\n  warn('`utils.checkHeadsetConnected` has moved to `utils.device.checkHeadsetConnected`');\n  return device.checkHeadsetConnected(arguments);\n};\nmodule.exports.isGearVR = function () {\n  warn('`utils.isGearVR` has moved to `utils.device.isGearVR`');\n  return device.isGearVR(arguments);\n};\nmodule.exports.isIOS = function () {\n  warn('`utils.isIOS` has moved to `utils.device.isIOS`');\n  return device.isIOS(arguments);\n};\nmodule.exports.isMobile = function () {\n  warn('`utils.isMobile has moved to `utils.device.isMobile`');\n  return device.isMobile(arguments);\n};\n\n/**\n * Returns throttle function that gets called at most once every interval.\n *\n * @param {function} functionToThrottle\n * @param {number} minimumInterval - Minimal interval between calls (milliseconds).\n * @param {object} optionalContext - If given, bind function to throttle to this context.\n * @returns {function} Throttled function.\n */\nmodule.exports.throttle = function (functionToThrottle, minimumInterval, optionalContext) {\n  var lastTime;\n  if (optionalContext) {\n    functionToThrottle = module.exports.bind(functionToThrottle, optionalContext);\n  }\n  return function () {\n    var time = Date.now();\n    var sinceLastTime = typeof lastTime === 'undefined' ? minimumInterval : time - lastTime;\n    if (typeof lastTime === 'undefined' || (sinceLastTime >= minimumInterval)) {\n      lastTime = time;\n      functionToThrottle.apply(null, arguments);\n    }\n  };\n};\n\n/**\n * Returns throttle function that gets called at most once every interval.\n * Uses the time/timeDelta timestamps provided by the global render loop for better perf.\n *\n * @param {function} functionToThrottle\n * @param {number} minimumInterval - Minimal interval between calls (milliseconds).\n * @param {object} optionalContext - If given, bind function to throttle to this context.\n * @returns {function} Throttled function.\n */\nmodule.exports.throttleTick = function (functionToThrottle, minimumInterval, optionalContext) {\n  var lastTime;\n  if (optionalContext) {\n    functionToThrottle = module.exports.bind(functionToThrottle, optionalContext);\n  }\n  return function (time, delta) {\n    var sinceLastTime = typeof lastTime === 'undefined' ? delta : time - lastTime;\n    if (typeof lastTime === 'undefined' || (sinceLastTime >= minimumInterval)) {\n      lastTime = time;\n      functionToThrottle(time, sinceLastTime);\n    }\n  };\n};\n\n/**\n * Returns debounce function that gets called only once after a set of repeated calls.\n *\n * @param {function} functionToDebounce\n * @param {number} wait - Time to wait for repeated function calls (milliseconds).\n * @param {boolean} immediate - Calls the function immediately regardless of if it should be waiting.\n * @returns {function} Debounced function.\n */\nmodule.exports.debounce = function (func, wait, immediate) {\n  var timeout;\n  return function () {\n    var context = this;\n    var args = arguments;\n    var later = function () {\n      timeout = null;\n      if (!immediate) func.apply(context, args);\n    };\n    var callNow = immediate && !timeout;\n    clearTimeout(timeout);\n    timeout = setTimeout(later, wait);\n    if (callNow) func.apply(context, args);\n  };\n};\n\n/**\n * Fires a custom DOM event.\n *\n * @param {Element} el Element on which to fire the event.\n * @param {String} name Name of the event.\n * @param {Object=} [data={bubbles: true, {detail: <el>}}]\n *   Data to pass as `customEventInit` to the event.\n */\nmodule.exports.fireEvent = function (el, name, data) {\n  data = data || {};\n  data.detail = data.detail || {};\n  data.detail.target = data.detail.target || el;\n  var evt = new CustomEvent(name, data);\n  el.dispatchEvent(evt);\n};\n\n/**\n * Mix the properties of source object(s) into a destination object.\n *\n * @param  {object} dest - The object to which properties will be copied.\n * @param  {...object} source - The object(s) from which properties will be copied.\n */\nmodule.exports.extend = objectAssign;\nmodule.exports.extendDeep = deepAssign;\n\nmodule.exports.clone = function (obj) {\n  return JSON.parse(JSON.stringify(obj));\n};\n\n/**\n * Checks if two values are equal.\n * Includes objects and arrays and nested objects and arrays.\n * Try to keep this function performant as it will be called often to see if a component\n * should be updated.\n *\n * @param {object} a - First object.\n * @param {object} b - Second object.\n * @returns {boolean} Whether two objects are deeply equal.\n */\nfunction deepEqual (a, b) {\n  var i;\n  var keysA;\n  var keysB;\n  var valA;\n  var valB;\n\n  // If not objects or arrays, compare as values.\n  if (a === undefined || b === undefined || a === null || b === null ||\n      !(a && b && (a.constructor === Object && b.constructor === Object) ||\n                  (a.constructor === Array && b.constructor === Array))) {\n    return a === b;\n  }\n\n  // Different number of keys, not equal.\n  keysA = Object.keys(a);\n  keysB = Object.keys(b);\n  if (keysA.length !== keysB.length) { return false; }\n\n  // Return `false` at the first sign of inequality.\n  for (i = 0; i < keysA.length; ++i) {\n    valA = a[keysA[i]];\n    valB = b[keysA[i]];\n    // Check nested array and object.\n    if ((typeof valA === 'object' || typeof valB === 'object') ||\n        (Array.isArray(valA) && Array.isArray(valB))) {\n      if (valA === valB) { continue; }\n      if (!deepEqual(valA, valB)) { return false; }\n    } else if (valA !== valB) {\n      return false;\n    }\n  }\n  return true;\n}\nmodule.exports.deepEqual = deepEqual;\n\n/**\n * Computes the difference between two objects.\n *\n * @param {object} a - First object to compare (e.g., oldData).\n * @param {object} b - Second object to compare (e.g., newData).\n * @returns {object}\n *   Difference object where set of keys note which values were not equal, and values are\n *   `b`'s values.\n */\nmodule.exports.diff = function (a, b) {\n  var diff = {};\n  var keys = Object.keys(a);\n  if (!b) { return diff; }\n  Object.keys(b).forEach(function collectKeys (bKey) {\n    if (keys.indexOf(bKey) === -1) {\n      keys.push(bKey);\n    }\n  });\n  keys.forEach(function doDiff (key) {\n    var aVal = a[key];\n    var bVal = b[key];\n    var isComparingObjects = aVal && bVal &&\n                             aVal.constructor === Object && bVal.constructor === Object;\n    if ((isComparingObjects && !deepEqual(aVal, bVal)) ||\n        (!isComparingObjects && aVal !== bVal)) {\n      diff[key] = bVal;\n    }\n  });\n  return diff;\n};\n\n/**\n * Returns whether we should capture this keyboard event for keyboard shortcuts.\n * @param {Event} event Event object.\n * @returns {Boolean} Whether the key event should be captured.\n */\nmodule.exports.shouldCaptureKeyEvent = function (event) {\n  if (event.metaKey) { return false; }\n  return document.activeElement === document.body;\n};\n\n/**\n * Splits a string into an array based on a delimiter.\n *\n * @param   {string=} [str='']        Source string\n * @param   {string=} [delimiter=' '] Delimiter to use\n * @returns {array}                   Array of delimited strings\n */\nmodule.exports.splitString = function (str, delimiter) {\n  if (typeof delimiter === 'undefined') { delimiter = ' '; }\n  // First collapse the whitespace (or whatever the delimiter is).\n  var regex = new RegExp(delimiter, 'g');\n  str = (str || '').replace(regex, delimiter);\n  // Then split.\n  return str.split(delimiter);\n};\n\n/**\n * Extracts data from the element given an object that contains expected keys.\n *\n * @param {Element} Source element.\n * @param {Object} [defaults={}] Object of default key-value pairs.\n * @returns {Object}\n */\nmodule.exports.getElData = function (el, defaults) {\n  defaults = defaults || {};\n  var data = {};\n  Object.keys(defaults).forEach(copyAttribute);\n  function copyAttribute (key) {\n    if (el.hasAttribute(key)) {\n      data[key] = el.getAttribute(key);\n    }\n  }\n  return data;\n};\n\n/**\n * Retrieves querystring value.\n * @param  {String} name Name of querystring key.\n * @return {String}      Value\n */\nmodule.exports.getUrlParameter = function (name) {\n  // eslint-disable-next-line no-useless-escape\n  name = name.replace(/[\\[]/, '\\\\[').replace(/[\\]]/, '\\\\]');\n  var regex = new RegExp('[\\\\?&]' + name + '=([^&#]*)');\n  var results = regex.exec(location.search);\n  return results === null ? '' : decodeURIComponent(results[1].replace(/\\+/g, ' '));\n};\n\n/**\n * Detects whether context is within iframe.\n */\nmodule.exports.isIframed = function () {\n  return window.top !== window.self;\n};\n\n/**\n * Finds all elements under the element that have the isScene\n * property set to true\n */\nmodule.exports.findAllScenes = function (el) {\n  var matchingElements = [];\n  var allElements = el.getElementsByTagName('*');\n  for (var i = 0, n = allElements.length; i < n; i++) {\n    if (allElements[i].isScene) {\n      // Element exists with isScene set.\n      matchingElements.push(allElements[i]);\n    }\n  }\n  return matchingElements;\n};\n\n// Must be at bottom to avoid circular dependency.\nmodule.exports.srcLoader = _dereq_('./src-loader');\n\n},{\"./bind\":189,\"./coordinates\":190,\"./debug\":191,\"./device\":192,\"./entity\":193,\"./forceCanvasResizeSafariMobile\":194,\"./material\":196,\"./src-loader\":197,\"./styleParser\":198,\"./tracked-controls\":199,\"deep-assign\":12,\"object-assign\":26}],196:[function(_dereq_,module,exports){\nvar THREE = _dereq_('../lib/three');\n\nvar HLS_MIMETYPES = ['application/x-mpegurl', 'application/vnd.apple.mpegurl'];\n\n/**\n * Update `material` texture property (usually but not always `map`)\n * from `data` property (usually but not always `src`)\n *\n * @param {object} shader - A-Frame shader instance.\n * @param {object} data\n */\nmodule.exports.updateMapMaterialFromData = function (materialName, dataName, shader, data) {\n  var el = shader.el;\n  var material = shader.material;\n  var src = data[dataName];\n\n  // Because a single material / shader may have multiple textures,\n  // we need to remember the source value for this data property\n  // to avoid redundant operations which can be expensive otherwise\n  // (e.g. video texture loads).\n  if (!shader.materialSrcs) { shader.materialSrcs = {}; }\n\n  if (!src) {\n    // Forget the prior material src.\n    delete shader.materialSrcs[materialName];\n    // Remove the texture.\n    setMap(null);\n    return;\n  }\n\n  // Don't process if material src hasn't changed.\n  if (src === shader.materialSrcs[materialName]) { return; }\n\n  // Remember the new src for this texture (there may be multiple).\n  shader.materialSrcs[materialName] = src;\n\n  // If the new material src is already a texture, just use it.\n  if (src instanceof THREE.Texture) { setMap(src); } else {\n    // Load texture for the new material src.\n    // (And check if we should still use it once available in callback.)\n    el.sceneEl.systems.material.loadTexture(src,\n      {src: src, repeat: data.repeat, offset: data.offset, npot: data.npot},\n      checkSetMap);\n  }\n\n  function checkSetMap (texture) {\n    // If the source has been changed, don't use loaded texture.\n    if (shader.materialSrcs[materialName] !== src) { return; }\n    setMap(texture);\n  }\n\n  function setMap (texture) {\n    material[materialName] = texture;\n    material.needsUpdate = true;\n    handleTextureEvents(el, texture);\n  }\n};\n\n/**\n * Update `material.map` given `data.src`. For standard and flat shaders.\n *\n * @param {object} shader - A-Frame shader instance.\n * @param {object} data\n */\nmodule.exports.updateMap = function (shader, data) {\n  return module.exports.updateMapMaterialFromData('map', 'src', shader, data);\n};\n\n/**\n * Updates the material's maps which give the illusion of extra geometry.\n *\n * @param {string} longType - The friendly name of the map from the component e.g. ambientOcclusionMap becomes aoMap in THREE.js\n * @param {object} shader - A-Frame shader instance\n * @param {object} data\n */\nmodule.exports.updateDistortionMap = function (longType, shader, data) {\n  var shortType = longType;\n  if (longType === 'ambientOcclusion') { shortType = 'ao'; }\n  var el = shader.el;\n  var material = shader.material;\n  var src = data[longType + 'Map'];\n  var info = {};\n  info.src = src;\n\n  // Pass through the repeat and offset to be handled by the material loader.\n  info.offset = data[longType + 'TextureOffset'];\n  info.repeat = data[longType + 'TextureRepeat'];\n  info.wrap = data[longType + 'TextureWrap'];\n\n  if (src) {\n    if (src === shader[longType + 'TextureSrc']) { return; }\n\n    // Texture added or changed.\n    shader[longType + 'TextureSrc'] = src;\n    el.sceneEl.systems.material.loadTexture(src, info, setMap);\n    return;\n  }\n\n  // Texture removed.\n  if (!material.map) { return; }\n  setMap(null);\n\n  function setMap (texture) {\n    material[shortType + 'Map'] = texture;\n    material.needsUpdate = true;\n    handleTextureEvents(el, texture);\n  }\n};\n\n/**\n * Emit event on entities on texture-related events.\n *\n * @param {Element} el - Entity.\n * @param {object} texture - three.js Texture.\n */\nfunction handleTextureEvents (el, texture) {\n  if (!texture) { return; }\n\n  el.emit('materialtextureloaded', {src: texture.image, texture: texture});\n\n  // Video events.\n  if (!texture.image || texture.image.tagName !== 'VIDEO') { return; }\n\n  texture.image.addEventListener('loadeddata', function emitVideoTextureLoadedDataAll () {\n    // Check to see if we need to use iOS 10 HLS shader.\n    // Only override the shader if it is stock shader that we know doesn't correct.\n    if (!el.components || !el.components.material) { return; }\n\n    if (texture.needsCorrectionBGRA && texture.needsCorrectionFlipY &&\n        ['standard', 'flat'].indexOf(el.components.material.data.shader) !== -1) {\n      el.setAttribute('material', 'shader', 'ios10hls');\n    }\n\n    el.emit('materialvideoloadeddata', {src: texture.image, texture: texture});\n  });\n  texture.image.addEventListener('ended', function emitVideoTextureEndedAll () {\n    // Works for non-looping videos only.\n    el.emit('materialvideoended', {src: texture.image, texture: texture});\n  });\n}\nmodule.exports.handleTextureEvents = handleTextureEvents;\n\n/**\n * Given video element src and type, guess whether stream is HLS.\n *\n * @param {string} src - src from video element (generally URL to content).\n * @param {string} type - type from video element (generally MIME type if present).\n */\nmodule.exports.isHLS = function (src, type) {\n  if (type && HLS_MIMETYPES.includes(type.toLowerCase())) { return true; }\n  if (src && src.toLowerCase().indexOf('.m3u8') > 0) { return true; }\n  return false;\n};\n\n},{\"../lib/three\":173}],197:[function(_dereq_,module,exports){\n/* global Image */\nvar debug = _dereq_('./debug');\n\nvar warn = debug('utils:src-loader:warn');\n\n/**\n * Validate a texture, either as a selector or as a URL.\n * Detects whether `src` is pointing to an image or video and invokes the appropriate\n * callback.\n *\n * `src` will be passed into the callback\n *\n * @params {string|Element} src - URL or media element.\n * @params {function} isImageCb - callback if texture is an image.\n * @params {function} isVideoCb - callback if texture is a video.\n */\nfunction validateSrc (src, isImageCb, isVideoCb) {\n  checkIsImage(src, function isAnImageUrl (isImage) {\n    if (isImage) {\n      isImageCb(src);\n      return;\n    }\n    isVideoCb(src);\n  });\n}\n\n/**\n * Validates six images as a cubemap, either as selector or comma-separated\n * URLs.\n *\n * @param {string} src - A selector or comma-separated image URLs. Image URLs\n          must be wrapped by `url()`.\n * @param {string} src - A selector or comma-separated image URLs. Image URLs\n          must be wrapped by `url()`.\n */\nfunction validateCubemapSrc (src, cb) {\n  var aCubemap;\n  var cubemapSrcRegex = '';\n  var i;\n  var urls;\n  var validatedUrls = [];\n\n  for (i = 0; i < 5; i++) {\n    cubemapSrcRegex += '(url\\\\((?:[^\\\\)]+)\\\\),\\\\s*)';\n  }\n  cubemapSrcRegex += '(url\\\\((?:[^\\\\)]+)\\\\)\\\\s*)';\n  urls = src.match(new RegExp(cubemapSrcRegex));\n\n  // `src` is a comma-separated list of URLs.\n  // In this case, re-use validateSrc for each side of the cube.\n  function isImageCb (url) {\n    validatedUrls.push(url);\n    if (validatedUrls.length === 6) {\n      cb(validatedUrls);\n    }\n  }\n  if (urls) {\n    for (i = 1; i < 7; i++) {\n      validateSrc(parseUrl(urls[i]), isImageCb);\n    }\n    return;\n  }\n\n  // `src` is a query selector to <a-cubemap> containing six $([src])s.\n  aCubemap = validateAndGetQuerySelector(src);\n  if (!aCubemap) { return; }\n  if (aCubemap.tagName === 'A-CUBEMAP' && aCubemap.srcs) {\n    return cb(aCubemap.srcs);\n  }\n  // Else if aCubeMap is not a <a-cubemap>.\n  warn('Selector \"%s\" does not point to <a-cubemap>', src);\n}\n\n/**\n * Parses src from `url(src)`.\n * @param  {string} src - String to parse.\n * @return {string} The parsed src, if parseable.\n */\nfunction parseUrl (src) {\n  var parsedSrc = src.match(/\\url\\((.+)\\)/);\n  if (!parsedSrc) { return; }\n  return parsedSrc[1];\n}\n\n/**\n * Call back whether `src` is an image.\n *\n * @param {string|Element} src - URL or element that will be tested.\n * @param {function} onResult - Callback with whether `src` is an image.\n */\nfunction checkIsImage (src, onResult) {\n  if (src.tagName) {\n    onResult(src.tagName === 'IMG');\n    return;\n  }\n\n  var tester = new Image();\n  tester.addEventListener('load', onLoad);\n  function onLoad () { onResult(true); }\n  tester.addEventListener('error', onError);\n  function onError () { onResult(false); }\n  tester.src = src;\n}\n\n/**\n * Query and validate a query selector,\n *\n * @param  {string} selector - DOM selector.\n * @return {object|null|undefined} Selected DOM element if exists.\n           null if query yields no results.\n           undefined if `selector` is not a valid selector.\n */\nfunction validateAndGetQuerySelector (selector) {\n  try {\n    var el = document.querySelector(selector);\n    if (!el) {\n      warn('No element was found matching the selector: \"%s\"', selector);\n    }\n    return el;\n  } catch (e) {  // Capture exception if it's not a valid selector.\n    warn('\"%s\" is not a valid selector', selector);\n    return undefined;\n  }\n}\n\nmodule.exports = {\n  parseUrl: parseUrl,\n  validateSrc: validateSrc,\n  validateCubemapSrc: validateCubemapSrc\n};\n\n},{\"./debug\":191}],198:[function(_dereq_,module,exports){\n/* Utils for parsing style-like strings (e.g., \"primitive: box; width: 5; height: 4.5\"). */\nvar styleParser = _dereq_('style-attr');\n\n/**\n * Deserializes style-like string into an object of properties.\n *\n * @param {string} value - HTML attribute value.\n * @returns {object} Property data.\n */\nmodule.exports.parse = function (value) {\n  var parsedData;\n  if (typeof value !== 'string') { return value; }\n  parsedData = styleParser.parse(value);\n  // The style parser returns an object { \"\" : \"test\"} when fed a string\n  if (parsedData['']) { return value; }\n  return transformKeysToCamelCase(parsedData);\n};\n\n/**\n * Serialize an object of properties into a style-like string.\n *\n * @param {object} data - Property data.\n * @returns {string}\n */\nmodule.exports.stringify = function (data) {\n  if (typeof data === 'string') { return data; }\n  return styleParser.stringify(data);\n};\n\n/**\n * Converts string from hyphen to camelCase.\n *\n * @param {string} str - String to camelCase.\n * @return {string} CamelCased string.\n */\nfunction toCamelCase (str) {\n  return str.replace(/-([a-z])/g, camelCase);\n  function camelCase (g) { return g[1].toUpperCase(); }\n}\nmodule.exports.toCamelCase = toCamelCase;\n\n/**\n * Converts object's keys from hyphens to camelCase (e.g., `max-value` to\n * `maxValue`).\n *\n * @param {object} obj - The object to camelCase keys.\n * @return {object} The object with keys camelCased.\n */\nfunction transformKeysToCamelCase (obj) {\n  var keys = Object.keys(obj);\n  var camelCaseObj = {};\n  keys.forEach(function (key) {\n    var camelCaseKey = toCamelCase(key);\n    camelCaseObj[camelCaseKey] = obj[key];\n  });\n  return camelCaseObj;\n}\nmodule.exports.transformKeysToCamelCase = transformKeysToCamelCase;\n\n},{\"style-attr\":36}],199:[function(_dereq_,module,exports){\nvar DEFAULT_HANDEDNESS = _dereq_('../constants').DEFAULT_HANDEDNESS;\nvar AXIS_LABELS = ['x', 'y', 'z', 'w'];\nvar NUM_HANDS = 2; // Number of hands in a pair. Should always be 2.\n\n/**\n * Called on controller component `.play` handlers.\n * Check if controller matches parameters and inject tracked-controls component.\n * Handle event listeners.\n * Generate controllerconnected or controllerdisconnected events.\n *\n * @param {object} component - Tracked controls component.\n * @param {object} idPrefix - Prefix to match in gamepad id if any.\n * @param {object} queryObject - Map of values to match.\n */\nmodule.exports.checkControllerPresentAndSetup = function (component, idPrefix, queryObject) {\n  var el = component.el;\n  var isPresent = isControllerPresent(component, idPrefix, queryObject);\n\n  // If component was previously paused and now playing, re-add event listeners.\n  // Handle the event listeners here since this helper method is control of calling\n  // `.addEventListeners` and `.removeEventListeners`.\n  if (component.controllerPresent && !component.controllerEventsActive) {\n    component.addEventListeners();\n  }\n\n  // Nothing changed, no need to do anything.\n  if (isPresent === component.controllerPresent) { return isPresent; }\n\n  component.controllerPresent = isPresent;\n\n  // Update controller presence.\n  if (isPresent) {\n    component.injectTrackedControls();\n    component.addEventListeners();\n    el.emit('controllerconnected', {name: component.name, component: component});\n  } else {\n    component.removeEventListeners();\n    el.emit('controllerdisconnected', {name: component.name, component: component});\n  }\n};\n\n/**\n * Enumerate controller (that have pose) and check if they match parameters.\n *\n * @param {object} component - Tracked controls component.\n * @param {object} idPrefix - Prefix to match in gamepad id if any.\n * @param {object} queryObject - Map of values to match.\n */\nfunction isControllerPresent (component, idPrefix, queryObject) {\n  var gamepads;\n  var sceneEl = component.el.sceneEl;\n  var trackedControlsSystem;\n  var filterControllerIndex = queryObject.index || 0;\n\n  if (!idPrefix) { return false; }\n\n  trackedControlsSystem = sceneEl && sceneEl.systems['tracked-controls'];\n  if (!trackedControlsSystem) { return false; }\n\n  gamepads = trackedControlsSystem.controllers;\n  if (!gamepads.length) { return false; }\n\n  return !!findMatchingController(gamepads, null, idPrefix, queryObject.hand, filterControllerIndex);\n}\n\nmodule.exports.isControllerPresent = isControllerPresent;\n\n/**\n * Walk through the given controllers to find any where the device ID equals filterIdExact, or startWith filterIdPrefix.\n * A controller where this considered true is considered a 'match'.\n *\n * For each matching controller:\n *   If filterHand is set, and the controller:\n *     is handed, we further verify that controller.hand equals filterHand.\n *     is unhanded (controller.hand is ''), we skip until we have found a number of matching controllers that equals filterControllerIndex\n *   If filterHand is not set, we skip until we have found the nth matching controller, where n equals filterControllerIndex\n *\n * The method should be called with one of: [filterIdExact, filterIdPrefix] AND one or both of: [filterHand, filterControllerIndex]\n *\n * @param {object} controllers - Array of gamepads to search\n * @param {string} filterIdExact - If set, used to find controllers with id === this value\n * @param {string} filterIdPrefix - If set, used to find controllers with id startsWith this value\n * @param {object} filterHand - If set, further filters controllers with matching 'hand' property\n * @param {object} filterControllerIndex - Find the nth matching controller, where n equals filterControllerIndex. defaults to 0.\n */\nfunction findMatchingController (controllers, filterIdExact, filterIdPrefix, filterHand, filterControllerIndex) {\n  var controller;\n  var i;\n  var matchingControllerOccurence = 0;\n  var targetControllerMatch = filterControllerIndex || 0;\n\n  for (i = 0; i < controllers.length; i++) {\n    controller = controllers[i];\n    // Determine if the controller ID matches our criteria\n    if (filterIdPrefix && controller.id.indexOf(filterIdPrefix) === -1) { continue; }\n    if (!filterIdPrefix && controller.id !== filterIdExact) { continue; }\n\n    // If the hand filter and controller handedness are defined we compare them.\n    if (filterHand && controller.hand && filterHand !== controller.hand) { continue; }\n\n    // If we have detected an unhanded controller and the component was asking for a particular hand,\n    // we need to treat the controllers in the array as pairs of controllers. This effectively means that we\n    // need to skip NUM_HANDS matches for each controller number, instead of 1.\n    if (filterHand && !controller.hand) {\n      targetControllerMatch = NUM_HANDS * filterControllerIndex + ((filterHand === DEFAULT_HANDEDNESS) ? 0 : 1);\n    }\n\n    // We are looking for the nth occurence of a matching controller (n equals targetControllerMatch).\n    if (matchingControllerOccurence === targetControllerMatch) {\n      return controller;\n    }\n    ++matchingControllerOccurence;\n  }\n  return undefined;\n}\n\nmodule.exports.findMatchingController = findMatchingController;\n\n/**\n * Emit specific `moved` event(s) if axes changed based on original axismoved event.\n *\n * @param {object} component - Controller component in use.\n * @param {array} axesMapping - For example `{thumbstick: [0, 1]}`.\n * @param {object} evt - Event to process.\n */\nmodule.exports.emitIfAxesChanged = function (component, axesMapping, evt) {\n  var axes;\n  var buttonTypes;\n  var changed;\n  var detail;\n  var i;\n  var j;\n\n  buttonTypes = Object.keys(axesMapping);\n  for (i = 0; i < buttonTypes.length; i++) {\n    axes = axesMapping[buttonTypes[i]];\n\n    changed = false;\n    for (j = 0; j < axes.length; j++) {\n      if (evt.detail.changed[axes[j]]) { changed = true; }\n    }\n\n    if (!changed) { continue; }\n\n    // Axis has changed. Emit the specific moved event with axis values in detail.\n    detail = {};\n    for (j = 0; j < axes.length; j++) {\n      detail[AXIS_LABELS[j]] = evt.detail.axis[axes[j]];\n    }\n    component.el.emit(buttonTypes[i] + 'moved', detail);\n  }\n};\n\n},{\"../constants\":116}],200:[function(_dereq_,module,exports){\n/**\n * @author dmarcos / https://github.com/dmarcos\n * @author mrdoob / http://mrdoob.com\n */\n\nTHREE.VRControls = function ( object, onError ) {\n\n\tvar scope = this;\n\n\tvar vrDisplay, vrDisplays;\n\n\tvar standingMatrix = new THREE.Matrix4();\n\n\tvar frameData = null;\n\n\tif ( 'VRFrameData' in window ) {\n\n\t\tframeData = new window.VRFrameData();\n\n\t}\n\n\twindow.addEventListener('vrdisplayconnect', function (evt) { vrDisplay = evt.display; });\n\twindow.addEventListener('vrdisplaydisconnect', function () { vrDisplay = undefined });\n\n\tfunction gotVRDisplays( displays ) {\n\n\t\tvrDisplays = displays;\n\n\t\tif ( displays.length > 0 ) {\n\n\t\t\tvrDisplay = displays[ 0 ];\n\n\t\t} else {\n\n\t\t\tif ( onError ) onError( 'VR input not available.' );\n\n\t\t}\n\n\t}\n\n\tif ( navigator.getVRDisplays ) {\n\n\t\tnavigator.getVRDisplays().then( gotVRDisplays ).catch ( function () {\n\n\t\t\tconsole.warn( 'THREE.VRControls: Unable to get VR Displays' );\n\n\t\t} );\n\n\t}\n\n\t// the Rift SDK returns the position in meters\n\t// this scale factor allows the user to define how meters\n\t// are converted to scene units.\n\n\tthis.scale = 1;\n\n\t// If true will use \"standing space\" coordinate system where y=0 is the\n\t// floor and x=0, z=0 is the center of the room.\n\tthis.standing = false;\n\n\t// Distance from the users eyes to the floor in meters. Used when\n\t// standing=true but the VRDisplay doesn't provide stageParameters.\n\tthis.userHeight = 1.6;\n\n\tthis.getVRDisplay = function () {\n\n\t\treturn vrDisplay;\n\n\t};\n\n\tthis.setVRDisplay = function ( value ) {\n\n\t\tvrDisplay = value;\n\n\t};\n\n\tthis.getVRDisplays = function () {\n\n\t\tconsole.warn( 'THREE.VRControls: getVRDisplays() is being deprecated.' );\n\t\treturn vrDisplays;\n\n\t};\n\n\tthis.getStandingMatrix = function () {\n\n\t\treturn standingMatrix;\n\n\t};\n\n\tthis.update = function () {\n\n\t\tif ( vrDisplay ) {\n\n\t\t\tvar pose;\n\n\t\t\tif ( vrDisplay.getFrameData ) {\n\n\t\t\t\tvrDisplay.getFrameData( frameData );\n\t\t\t\tpose = frameData.pose;\n\n\t\t\t} else if ( vrDisplay.getPose ) {\n\n\t\t\t\tpose = vrDisplay.getPose();\n\n\t\t\t}\n\n\t\t\tif ( pose.orientation !== null ) {\n\n\t\t\t\tobject.quaternion.fromArray( pose.orientation );\n\n\t\t\t}\n\n\t\t\tif ( pose.position !== null ) {\n\n\t\t\t\tobject.position.fromArray( pose.position );\n\n\t\t\t} else {\n\n\t\t\t\tobject.position.set( 0, 0, 0 );\n\n\t\t\t}\n\n\t\t\tif ( this.standing ) {\n\n\t\t\t\tif ( vrDisplay.stageParameters ) {\n\n\t\t\t\t\tobject.updateMatrix();\n\n\t\t\t\t\tstandingMatrix.fromArray( vrDisplay.stageParameters.sittingToStandingTransform );\n\t\t\t\t\tobject.applyMatrix( standingMatrix );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tobject.position.setY( object.position.y + this.userHeight );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tobject.position.multiplyScalar( scope.scale );\n\n\t\t}\n\n\t};\n\n\tthis.resetPose = function () {\n\n\t\tif ( vrDisplay ) {\n\n\t\t\tvrDisplay.resetPose();\n\n\t\t}\n\n\t};\n\n\tthis.resetSensor = function () {\n\n\t\tconsole.warn( 'THREE.VRControls: .resetSensor() is now .resetPose().' );\n\t\tthis.resetPose();\n\n\t};\n\n\tthis.zeroSensor = function () {\n\n\t\tconsole.warn( 'THREE.VRControls: .zeroSensor() is now .resetPose().' );\n\t\tthis.resetPose();\n\n\t};\n\n\tthis.dispose = function () {\n\n\t\tvrDisplay = null;\n\n\t};\n\n};\n\n},{}],201:[function(_dereq_,module,exports){\n/**\n * @author dmarcos / https://github.com/dmarcos\n * @author mrdoob / http://mrdoob.com\n *\n * WebVR Spec: http://mozvr.github.io/webvr-spec/webvr.html\n *\n * Firefox: http://mozvr.com/downloads/\n * Chromium: https://webvr.info/get-chrome\n *\n */\n\nTHREE.VREffect = function( renderer, onError ) {\n\n\tvar vrDisplay, vrDisplays;\n\tvar eyeTranslationL = new THREE.Vector3();\n\tvar eyeTranslationR = new THREE.Vector3();\n\tvar renderRectL, renderRectR;\n\n\tvar frameData = null;\n\n\tif ( 'VRFrameData' in window ) {\n\n\t\tframeData = new window.VRFrameData();\n\n\t}\n\n\twindow.addEventListener('vrdisplayconnect', function (evt) { vrDisplay = evt.display; });\n\twindow.addEventListener('vrdisplaydisconnect', function (evt) {\n\t\tvar f;\n\t\t\n\t\tscope.exitPresent();\n\t\t// Cancels current request animation frame.\n\t\tf = scope.cancelAnimationFrame();\n\t\tvrDisplay = undefined;\n\t\t// Resumes the request animation frame.\n\t\tscope.requestAnimationFrame(f);\n\t});\n\n\tfunction gotVRDisplays( displays ) {\n\n\t\tvrDisplays = displays;\n\n\t\tif ( displays.length > 0 ) {\n\n\t\t\tvrDisplay = displays[ 0 ];\n\n\t\t} else {\n\n\t\t\tif ( onError ) onError( 'HMD not available' );\n\n\t\t}\n\n\t}\n\n\tif ( navigator.getVRDisplays ) {\n\n\t\tnavigator.getVRDisplays().then( gotVRDisplays ).catch( function() {\n\n\t\t\tconsole.warn( 'THREE.VREffect: Unable to get VR Displays' );\n\n\t\t} );\n\n\t}\n\n\t//\n\n\tthis.isPresenting = false;\n\n\tvar scope = this;\n\n\tvar rendererSize = renderer.getSize();\n\tvar rendererUpdateStyle = false;\n\tvar rendererPixelRatio = renderer.getPixelRatio();\n\n\tthis.getVRDisplay = function() {\n\n\t\treturn vrDisplay;\n\n\t};\n\n\tthis.setVRDisplay = function( value ) {\n\n\t\tvrDisplay = value;\n\n\t};\n\n\tthis.getVRDisplays = function() {\n\n\t\tconsole.warn( 'THREE.VREffect: getVRDisplays() is being deprecated.' );\n\t\treturn vrDisplays;\n\n\t};\n\n\tthis.setSize = function( width, height, updateStyle ) {\n\n\t\trendererSize = { width: width, height: height };\n\t\trendererUpdateStyle = updateStyle;\n\n\t\tif ( scope.isPresenting ) {\n\n\t\t\tvar eyeParamsL = vrDisplay.getEyeParameters( 'left' );\n\t\t\trenderer.setPixelRatio( 1 );\n\t\t\trenderer.setSize( eyeParamsL.renderWidth * 2, eyeParamsL.renderHeight, false );\n\n\t\t} else {\n\n\t\t\trenderer.setPixelRatio( rendererPixelRatio );\n\t\t\trenderer.setSize( width, height, updateStyle );\n\n\t\t}\n\n\t};\n\n\t// VR presentation\n\n\tvar canvas = renderer.domElement;\n\tvar defaultLeftBounds = [ 0.0, 0.0, 0.5, 1.0 ];\n\tvar defaultRightBounds = [ 0.5, 0.0, 0.5, 1.0 ];\n\n\tfunction onVRDisplayPresentChange() {\n\n\t\tvar wasPresenting = scope.isPresenting;\n\t\tscope.isPresenting = vrDisplay !== undefined && vrDisplay.isPresenting;\n\n\t\tif ( scope.isPresenting ) {\n\n\t\t\tvar eyeParamsL = vrDisplay.getEyeParameters( 'left' );\n\t\t\tvar eyeWidth = eyeParamsL.renderWidth;\n\t\t\tvar eyeHeight = eyeParamsL.renderHeight;\n\n\t\t\tif ( ! wasPresenting ) {\n\n\t\t\t\trendererPixelRatio = renderer.getPixelRatio();\n\t\t\t\trendererSize = renderer.getSize();\n\n\t\t\t\trenderer.setPixelRatio( 1 );\n\t\t\t\trenderer.setSize( eyeWidth * 2, eyeHeight, false );\n\n\t\t\t}\n\n\t\t} else if ( wasPresenting ) {\n\n\t\t\trenderer.setPixelRatio( rendererPixelRatio );\n\t\t\trenderer.setSize( rendererSize.width, rendererSize.height, rendererUpdateStyle );\n\n\t\t}\n\n\t}\n\n\twindow.addEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false );\n\n\tthis.setFullScreen = function( boolean ) {\n\n\t\treturn new Promise( function( resolve, reject ) {\n\n\t\t\tif ( vrDisplay === undefined ) {\n\n\t\t\t\treject( new Error( 'No VR hardware found.' ) );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tif ( scope.isPresenting === boolean ) {\n\n\t\t\t\tresolve();\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tif ( boolean ) {\n\n\t\t\t\tresolve( vrDisplay.requestPresent( [ { source: canvas } ] ) );\n\n\t\t\t} else {\n\n\t\t\t\tresolve( vrDisplay.exitPresent() );\n\n\t\t\t}\n\n\t\t} );\n\n\t};\n\n\tthis.requestPresent = function() {\n\n\t\treturn this.setFullScreen( true );\n\n\t};\n\n\tthis.exitPresent = function() {\n\n\t\treturn this.setFullScreen( false );\n\n\t};\n\n\tthis.requestAnimationFrame = function( f ) {\n\n\t\tvar f = scope.f = f || scope.f;\n\n\t\tif (!f) { return; }\n\n\t\tif ( vrDisplay !== undefined ) {\n\t\t\treturn vrDisplay.requestAnimationFrame( f );\n\t\t} else {\n\n\t\t\treturn window.requestAnimationFrame( f );\n\n\t\t}\n\n\t};\n\n\tthis.cancelAnimationFrame = function( h ) {\n\n\t\tvar f = scope.f;\n\n\t\tscope.f = undefined;\n\n\t\tif ( vrDisplay !== undefined ) {\n\n\t\t\tvrDisplay.cancelAnimationFrame( h );\n\n\t\t} else {\n\n\t\t\twindow.cancelAnimationFrame( h );\n\n\t\t}\n\n\t\treturn f;\n\t};\n\n\tthis.submitFrame = function() {\n\n\t\tif ( vrDisplay !== undefined && scope.isPresenting ) {\n\n\t\t\tvrDisplay.submitFrame();\n\n\t\t}\n\n\t};\n\n\tthis.autoSubmitFrame = true;\n\n\t// render\n\n\tvar cameraL = new THREE.PerspectiveCamera();\n\tcameraL.layers.enable( 1 );\n\n\tvar cameraR = new THREE.PerspectiveCamera();\n\tcameraR.layers.enable( 2 );\n\n\tthis.render = function( scene, camera, renderTarget, forceClear ) {\n\n\t\tif ( vrDisplay && scope.isPresenting ) {\n\n\t\t\tvar autoUpdate = scene.autoUpdate;\n\n\t\t\tif ( autoUpdate ) {\n\n\t\t\t\tscene.updateMatrixWorld();\n\t\t\t\tscene.autoUpdate = false;\n\n\t\t\t}\n\n\t\t\tvar eyeParamsL = vrDisplay.getEyeParameters( 'left' );\n\t\t\tvar eyeParamsR = vrDisplay.getEyeParameters( 'right' );\n\n\t\t\teyeTranslationL.fromArray( eyeParamsL.offset );\n\t\t\teyeTranslationR.fromArray( eyeParamsR.offset );\n\n\t\t\tif ( Array.isArray( scene ) ) {\n\n\t\t\t\tconsole.warn( 'THREE.VREffect.render() no longer supports arrays. Use object.layers instead.' );\n\t\t\t\tscene = scene[ 0 ];\n\n\t\t\t}\n\n\t\t\t// When rendering we don't care what the recommended size is, only what the actual size\n\t\t\t// of the backbuffer is.\n\t\t\tvar size = renderer.getSize();\n\t\t\tvar layers = vrDisplay.getLayers();\n\t\t\tvar leftBounds;\n\t\t\tvar rightBounds;\n\n\t\t\tif ( layers.length ) {\n\n\t\t\t\tvar layer = layers[ 0 ];\n\n\t\t\t\tleftBounds = layer.leftBounds !== null && layer.leftBounds.length === 4 ? layer.leftBounds : defaultLeftBounds;\n\t\t\t\trightBounds = layer.rightBounds !== null && layer.rightBounds.length === 4 ? layer.rightBounds : defaultRightBounds;\n\n\t\t\t} else {\n\n\t\t\t\tleftBounds = defaultLeftBounds;\n\t\t\t\trightBounds = defaultRightBounds;\n\n\t\t\t}\n\n\t\t\trenderRectL = {\n\t\t\t\tx: Math.round( size.width * leftBounds[ 0 ] ),\n\t\t\t\ty: Math.round( size.height * leftBounds[ 1 ] ),\n\t\t\t\twidth: Math.round( size.width * leftBounds[ 2 ] ),\n\t\t\t\theight: Math.round( size.height * leftBounds[ 3 ] )\n\t\t\t};\n\t\t\trenderRectR = {\n\t\t\t\tx: Math.round( size.width * rightBounds[ 0 ] ),\n\t\t\t\ty: Math.round( size.height * rightBounds[ 1 ] ),\n\t\t\t\twidth: Math.round( size.width * rightBounds[ 2 ] ),\n\t\t\t\theight: Math.round( size.height * rightBounds[ 3 ] )\n\t\t\t};\n\n\t\t\tif ( renderTarget ) {\n\n\t\t\t\trenderer.setRenderTarget( renderTarget );\n\t\t\t\trenderTarget.scissorTest = true;\n\n\t\t\t} else {\n\n\t\t\t\trenderer.setRenderTarget( null );\n\t\t\t\trenderer.setScissorTest( true );\n\n\t\t\t}\n\n\t\t\tif ( renderer.autoClear || forceClear ) renderer.clear();\n\n\t\t\tif ( camera.parent === null ) camera.updateMatrixWorld();\n\n\t\t\tcamera.matrixWorld.decompose( cameraL.position, cameraL.quaternion, cameraL.scale );\n\n\t\t\tcameraR.position.copy(cameraL.position);\n\t\t\tcameraR.quaternion.copy(cameraL.quaternion);\n\t\t\tcameraR.scale.copy(cameraL.scale);\n\n\t\t\tcameraL.translateOnAxis( eyeTranslationL, cameraL.scale.x );\n\t\t\tcameraR.translateOnAxis( eyeTranslationR, cameraR.scale.x );\n\n\t\t\tif ( vrDisplay.getFrameData ) {\n\n\t\t\t\tvrDisplay.depthNear = camera.near;\n\t\t\t\tvrDisplay.depthFar = camera.far;\n\n\t\t\t\tvrDisplay.getFrameData( frameData );\n\n\t\t\t\tcameraL.projectionMatrix.elements = frameData.leftProjectionMatrix;\n\t\t\t\tcameraR.projectionMatrix.elements = frameData.rightProjectionMatrix;\n\n\t\t\t} else {\n\n\t\t\t\tcameraL.projectionMatrix = fovToProjection( eyeParamsL.fieldOfView, true, camera.near, camera.far );\n\t\t\t\tcameraR.projectionMatrix = fovToProjection( eyeParamsR.fieldOfView, true, camera.near, camera.far );\n\n\t\t\t}\n\n\t\t\t// render left eye\n\t\t\tif ( renderTarget ) {\n\n\t\t\t\trenderTarget.viewport.set( renderRectL.x, renderRectL.y, renderRectL.width, renderRectL.height );\n\t\t\t\trenderTarget.scissor.set( renderRectL.x, renderRectL.y, renderRectL.width, renderRectL.height );\n\n\t\t\t} else {\n\n\t\t\t\trenderer.setViewport( renderRectL.x, renderRectL.y, renderRectL.width, renderRectL.height );\n\t\t\t\trenderer.setScissor( renderRectL.x, renderRectL.y, renderRectL.width, renderRectL.height );\n\n\t\t\t}\n\t\t\trenderer.render( scene, cameraL, renderTarget, forceClear );\n\n\t\t\t// render right eye\n\t\t\tif ( renderTarget ) {\n\n\t\t\t\trenderTarget.viewport.set( renderRectR.x, renderRectR.y, renderRectR.width, renderRectR.height );\n\t\t\t\trenderTarget.scissor.set( renderRectR.x, renderRectR.y, renderRectR.width, renderRectR.height );\n\n\t\t\t} else {\n\n\t\t\t\trenderer.setViewport( renderRectR.x, renderRectR.y, renderRectR.width, renderRectR.height );\n\t\t\t\trenderer.setScissor( renderRectR.x, renderRectR.y, renderRectR.width, renderRectR.height );\n\n\t\t\t}\n\t\t\trenderer.render( scene, cameraR, renderTarget, forceClear );\n\n\t\t\tif ( renderTarget ) {\n\n\t\t\t\trenderTarget.viewport.set( 0, 0, size.width, size.height );\n\t\t\t\trenderTarget.scissor.set( 0, 0, size.width, size.height );\n\t\t\t\trenderTarget.scissorTest = false;\n\t\t\t\trenderer.setRenderTarget( null );\n\n\t\t\t} else {\n\n\t\t\t\trenderer.setViewport( 0, 0, size.width, size.height );\n\t\t\t\trenderer.setScissorTest( false );\n\n\t\t\t}\n\n\t\t\tif ( autoUpdate ) {\n\n\t\t\t\tscene.autoUpdate = true;\n\n\t\t\t}\n\n\t\t\tif ( scope.autoSubmitFrame ) {\n\n\t\t\t\tscope.submitFrame();\n\n\t\t\t}\n\n\t\t\treturn;\n\n\t\t}\n\n\t\t// Regular render mode if not HMD\n\n\t\trenderer.render( scene, camera, renderTarget, forceClear );\n\n\t};\n\n\tthis.dispose = function() {\n\n\t\twindow.removeEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false );\n\n\t};\n\n\t//\n\n\tfunction fovToNDCScaleOffset( fov ) {\n\n\t\tvar pxscale = 2.0 / ( fov.leftTan + fov.rightTan );\n\t\tvar pxoffset = ( fov.leftTan - fov.rightTan ) * pxscale * 0.5;\n\t\tvar pyscale = 2.0 / ( fov.upTan + fov.downTan );\n\t\tvar pyoffset = ( fov.upTan - fov.downTan ) * pyscale * 0.5;\n\t\treturn { scale: [ pxscale, pyscale ], offset: [ pxoffset, pyoffset ] };\n\n\t}\n\n\tfunction fovPortToProjection( fov, rightHanded, zNear, zFar ) {\n\n\t\trightHanded = rightHanded === undefined ? true : rightHanded;\n\t\tzNear = zNear === undefined ? 0.01 : zNear;\n\t\tzFar = zFar === undefined ? 10000.0 : zFar;\n\n\t\tvar handednessScale = rightHanded ? - 1.0 : 1.0;\n\n\t\t// start with an identity matrix\n\t\tvar mobj = new THREE.Matrix4();\n\t\tvar m = mobj.elements;\n\n\t\t// and with scale/offset info for normalized device coords\n\t\tvar scaleAndOffset = fovToNDCScaleOffset( fov );\n\n\t\t// X result, map clip edges to [-w,+w]\n\t\tm[ 0 * 4 + 0 ] = scaleAndOffset.scale[ 0 ];\n\t\tm[ 0 * 4 + 1 ] = 0.0;\n\t\tm[ 0 * 4 + 2 ] = scaleAndOffset.offset[ 0 ] * handednessScale;\n\t\tm[ 0 * 4 + 3 ] = 0.0;\n\n\t\t// Y result, map clip edges to [-w,+w]\n\t\t// Y offset is negated because this proj matrix transforms from world coords with Y=up,\n\t\t// but the NDC scaling has Y=down (thanks D3D?)\n\t\tm[ 1 * 4 + 0 ] = 0.0;\n\t\tm[ 1 * 4 + 1 ] = scaleAndOffset.scale[ 1 ];\n\t\tm[ 1 * 4 + 2 ] = - scaleAndOffset.offset[ 1 ] * handednessScale;\n\t\tm[ 1 * 4 + 3 ] = 0.0;\n\n\t\t// Z result (up to the app)\n\t\tm[ 2 * 4 + 0 ] = 0.0;\n\t\tm[ 2 * 4 + 1 ] = 0.0;\n\t\tm[ 2 * 4 + 2 ] = zFar / ( zNear - zFar ) * - handednessScale;\n\t\tm[ 2 * 4 + 3 ] = ( zFar * zNear ) / ( zNear - zFar );\n\n\t\t// W result (= Z in)\n\t\tm[ 3 * 4 + 0 ] = 0.0;\n\t\tm[ 3 * 4 + 1 ] = 0.0;\n\t\tm[ 3 * 4 + 2 ] = handednessScale;\n\t\tm[ 3 * 4 + 3 ] = 0.0;\n\n\t\tmobj.transpose();\n\t\treturn mobj;\n\n\t}\n\n\tfunction fovToProjection( fov, rightHanded, zNear, zFar ) {\n\n\t\tvar DEG2RAD = Math.PI / 180.0;\n\n\t\tvar fovPort = {\n\t\t\tupTan: Math.tan( fov.upDegrees * DEG2RAD ),\n\t\t\tdownTan: Math.tan( fov.downDegrees * DEG2RAD ),\n\t\t\tleftTan: Math.tan( fov.leftDegrees * DEG2RAD ),\n\t\t\trightTan: Math.tan( fov.rightDegrees * DEG2RAD )\n\t\t};\n\n\t\treturn fovPortToProjection( fovPort, rightHanded, zNear, zFar );\n\n\t}\n\n};\n\n},{}],202:[function(_dereq_,module,exports){\nwindow.glStats = function () {\n\n    var _rS = null;\n\n    var _totalDrawArraysCalls = 0,\n        _totalDrawElementsCalls = 0,\n        _totalUseProgramCalls = 0,\n        _totalFaces = 0,\n        _totalVertices = 0,\n        _totalPoints = 0,\n        _totalBindTexures = 0;\n\n    function _h ( f, c ) {\n        return function () {\n            c.apply( this, arguments );\n            f.apply( this, arguments );\n        };\n    }\n\n    WebGLRenderingContext.prototype.drawArrays = _h( WebGLRenderingContext.prototype.drawArrays, function () {\n        _totalDrawArraysCalls++;\n        if ( arguments[ 0 ] == this.POINTS ) _totalPoints += arguments[ 2 ];\n        else _totalVertices += arguments[ 2 ];\n    } );\n\n    WebGLRenderingContext.prototype.drawElements = _h( WebGLRenderingContext.prototype.drawElements, function () {\n        _totalDrawElementsCalls++;\n        _totalFaces += arguments[ 1 ] / 3;\n        _totalVertices += arguments[ 1 ];\n    } );\n\n    WebGLRenderingContext.prototype.useProgram = _h( WebGLRenderingContext.prototype.useProgram, function () {\n        _totalUseProgramCalls++;\n    } );\n\n    WebGLRenderingContext.prototype.bindTexture = _h( WebGLRenderingContext.prototype.bindTexture, function () {\n        _totalBindTexures++;\n    } );\n\n    var _values = {\n        allcalls: {\n            over: 3000,\n            caption: 'Calls (hook)'\n        },\n        drawelements: {\n            caption: 'drawElements (hook)'\n        },\n        drawarrays: {\n            caption: 'drawArrays (hook)'\n        }\n    };\n\n    var _groups = [ {\n        caption: 'WebGL',\n        values: [ 'allcalls', 'drawelements', 'drawarrays', 'useprogram', 'bindtexture', 'glfaces', 'glvertices', 'glpoints' ]\n    } ];\n\n    var _fractions = [ {\n        base: 'allcalls',\n        steps: [ 'drawelements', 'drawarrays' ]\n    } ];\n\n    function _update () {\n        _rS( 'allcalls' ).set( _totalDrawArraysCalls + _totalDrawElementsCalls );\n        _rS( 'drawElements' ).set( _totalDrawElementsCalls );\n        _rS( 'drawArrays' ).set( _totalDrawArraysCalls );\n        _rS( 'bindTexture' ).set( _totalBindTexures );\n        _rS( 'useProgram' ).set( _totalUseProgramCalls );\n        _rS( 'glfaces' ).set( _totalFaces );\n        _rS( 'glvertices' ).set( _totalVertices );\n        _rS( 'glpoints' ).set( _totalPoints );\n    }\n\n    function _start () {\n        _totalDrawArraysCalls = 0;\n        _totalDrawElementsCalls = 0;\n        _totalUseProgramCalls = 0;\n        _totalFaces = 0;\n        _totalVertices = 0;\n        _totalPoints = 0;\n        _totalBindTexures = 0;\n    }\n\n    function _end () {}\n\n    function _attach ( r ) {\n        _rS = r;\n    }\n\n    return {\n        update: _update,\n        start: _start,\n        end: _end,\n        attach: _attach,\n        values: _values,\n        groups: _groups,\n        fractions: _fractions\n    };\n\n};\n\nwindow.threeStats = function ( renderer ) {\n\n    var _rS = null;\n\n    var _values = {\n        'renderer.info.memory.geometries': {\n            caption: 'Geometries'\n        },\n        'renderer.info.memory.textures': {\n            caption: 'Textures'\n        },\n        'renderer.info.programs': {\n            caption: 'Programs'\n        },\n        'renderer.info.render.calls': {\n            caption: 'Calls'\n        },\n        'renderer.info.render.faces': {\n            caption: 'Faces',\n            over: 1000\n        },\n        'renderer.info.render.points': {\n            caption: 'Points'\n        },\n        'renderer.info.render.vertices': {\n            caption: 'Vertices'\n        }\n    };\n\n    var _groups = [ {\n        caption: 'Three.js - Memory',\n        values: [ 'renderer.info.memory.geometries', 'renderer.info.programs', 'renderer.info.memory.textures' ]\n    }, {\n        caption: 'Three.js - Render',\n        values: [ 'renderer.info.render.calls', 'renderer.info.render.faces', 'renderer.info.render.points', 'renderer.info.render.vertices' ]\n    } ];\n\n    var _fractions = [];\n\n    function _update () {\n\n        _rS( 'renderer.info.memory.geometries' ).set( renderer.info.memory.geometries );\n        _rS( 'renderer.info.programs' ).set( renderer.info.programs.length );\n        _rS( 'renderer.info.memory.textures' ).set( renderer.info.memory.textures );\n        _rS( 'renderer.info.render.calls' ).set( renderer.info.render.calls );\n        _rS( 'renderer.info.render.faces' ).set( renderer.info.render.faces );\n        _rS( 'renderer.info.render.points' ).set( renderer.info.render.points );\n        _rS( 'renderer.info.render.vertices' ).set( renderer.info.render.vertices );\n\n    }\n\n    function _start () {}\n\n    function _end () {}\n\n    function _attach ( r ) {\n        _rS = r;\n    }\n\n    return {\n        update: _update,\n        start: _start,\n        end: _end,\n        attach: _attach,\n        values: _values,\n        groups: _groups,\n        fractions: _fractions\n    };\n\n};\n\n/*\n *   From https://github.com/paulirish/memory-stats.js\n */\n\nwindow.BrowserStats = function () {\n\n    var _rS = null;\n\n    var _usedJSHeapSize = 0,\n        _totalJSHeapSize = 0;\n\n    if ( window.performance && !performance.memory ) {\n        performance.memory = {\n            usedJSHeapSize: 0,\n            totalJSHeapSize: 0\n        };\n    }\n\n    if ( performance.memory.totalJSHeapSize === 0 ) {\n        console.warn( 'totalJSHeapSize === 0... performance.memory is only available in Chrome .' );\n    }\n\n    var _values = {\n        memory: {\n            caption: 'Used Memory',\n            average: true,\n            avgMs: 1000,\n            over: 22\n        },\n        total: {\n            caption: 'Total Memory'\n        }\n    };\n\n    var _groups = [ {\n        caption: 'Browser',\n        values: [ 'memory', 'total' ]\n    } ];\n\n    var _fractions = [ {\n        base: 'total',\n        steps: [ 'memory' ]\n    } ];\n\n    var log1024 = Math.log( 1024 );\n\n    function _size ( v ) {\n\n        var precision = 100; //Math.pow(10, 2);\n        var i = Math.floor( Math.log( v ) / log1024 );\n        return Math.round( v * precision / Math.pow( 1024, i ) ) / precision; // + ' ' + sizes[i];\n\n    }\n\n    function _update () {\n        _usedJSHeapSize = _size( performance.memory.usedJSHeapSize );\n        _totalJSHeapSize = _size( performance.memory.totalJSHeapSize );\n\n        _rS( 'memory' ).set( _usedJSHeapSize );\n        _rS( 'total' ).set( _totalJSHeapSize );\n    }\n\n    function _start () {\n        _usedJSHeapSize = 0;\n    }\n\n    function _end () {}\n\n    function _attach ( r ) {\n        _rS = r;\n    }\n\n    return {\n        update: _update,\n        start: _start,\n        end: _end,\n        attach: _attach,\n        values: _values,\n        groups: _groups,\n        fractions: _fractions\n    };\n\n};\n\nif (typeof module === 'object') {\n  module.exports = {\n    glStats: window.glStats,\n    threeStats: window.threeStats,\n    BrowserStats: window.BrowserStats\n  };\n}\n\n},{}],203:[function(_dereq_,module,exports){\n// performance.now() polyfill from https://gist.github.com/paulirish/5438650\n'use strict';\n\n( function () {\n\n    if ( 'performance' in window == false ) {\n        window.performance = {};\n    }\n\n    var performance = window.performance;\n\n    if ( 'now' in performance == false ) {\n\n        var nowOffset = Date.now();\n\n        if ( performance.timing && performance.timing.navigationStart ) {\n            nowOffset = performance.timing.navigationStart;\n        }\n\n        performance.now = function now () {\n            return Date.now() - nowOffset;\n        };\n\n    }\n\n    if( !performance.mark ) {\n        performance.mark = function(){}\n    }\n\n    if( !performance.measure ) {\n        performance.measure = function(){}\n    }\n\n} )();\n\nwindow.rStats = function rStats ( settings ) {\n\n    function iterateKeys ( array, callback ) {\n        var keys = Object.keys( array );\n        for ( var j = 0, l = keys.length; j < l; j++ ) {\n            callback( keys[ j ] );\n        }\n    }\n\n    function importCSS ( url ) {\n\n        var element = document.createElement( 'link' );\n        element.href = url;\n        element.rel = 'stylesheet';\n        element.type = 'text/css';\n        document.getElementsByTagName( 'head' )[ 0 ].appendChild( element );\n\n    }\n\n    var _settings = settings || {};\n    var _colours = _settings.colours || [ '#850700', '#c74900', '#fcb300', '#284280', '#4c7c0c' ];\n\n    var _cssFont = 'https://fonts.googleapis.com/css?family=Roboto+Condensed:400,700,300';\n    var _cssRStats = ( _settings.CSSPath ? _settings.CSSPath : '' ) + 'rStats.css';\n\n    var _css = _settings.css || [ _cssFont, _cssRStats ];\n    _css.forEach(function (uri) {\n        importCSS( uri );\n    });\n\n    if ( !_settings.values ) _settings.values = {};\n\n    var _base, _div, _elHeight = 10, _elWidth = 200;\n    var _perfCounters = {};\n\n\n    function Graph ( _dom, _id, _defArg ) {\n\n        var _def = _defArg || {};\n        var _canvas = document.createElement( 'canvas' ),\n            _ctx = _canvas.getContext( '2d' ),\n            _max = 0,\n            _current = 0;\n\n        var c = _def.color ? _def.color : '#666666';\n\n        var _dotCanvas = document.createElement( 'canvas' ),\n            _dotCtx = _dotCanvas.getContext( '2d' );\n        _dotCanvas.width = 1;\n        _dotCanvas.height = 2 * _elHeight;\n        _dotCtx.fillStyle = '#444444';\n        _dotCtx.fillRect( 0, 0, 1, 2 * _elHeight );\n        _dotCtx.fillStyle = c;\n        _dotCtx.fillRect( 0, _elHeight, 1, _elHeight );\n        _dotCtx.fillStyle = '#ffffff';\n        _dotCtx.globalAlpha = 0.5;\n        _dotCtx.fillRect( 0, _elHeight, 1, 1 );\n        _dotCtx.globalAlpha = 1;\n\n        var _alarmCanvas = document.createElement( 'canvas' ),\n            _alarmCtx = _alarmCanvas.getContext( '2d' );\n        _alarmCanvas.width = 1;\n        _alarmCanvas.height = 2 * _elHeight;\n        _alarmCtx.fillStyle = '#444444';\n        _alarmCtx.fillRect( 0, 0, 1, 2 * _elHeight );\n        _alarmCtx.fillStyle = '#b70000';\n        _alarmCtx.fillRect( 0, _elHeight, 1, _elHeight );\n        _alarmCtx.globalAlpha = 0.5;\n        _alarmCtx.fillStyle = '#ffffff';\n        _alarmCtx.fillRect( 0, _elHeight, 1, 1 );\n        _alarmCtx.globalAlpha = 1;\n\n        function _init () {\n\n            _canvas.width = _elWidth;\n            _canvas.height = _elHeight;\n            _canvas.style.width = _canvas.width + 'px';\n            _canvas.style.height = _canvas.height + 'px';\n            _canvas.className = 'rs-canvas';\n            _dom.appendChild( _canvas );\n\n            _ctx.fillStyle = '#444444';\n            _ctx.fillRect( 0, 0, _canvas.width, _canvas.height );\n\n        }\n\n        function _draw ( v, alarm ) {\n            _current += ( v - _current ) * 0.1;\n            _max *= 0.99;\n            if ( _current > _max ) _max = _current;\n            _ctx.drawImage( _canvas, 1, 0, _canvas.width - 1, _canvas.height, 0, 0, _canvas.width - 1, _canvas.height );\n            if ( alarm ) {\n                _ctx.drawImage( _alarmCanvas, _canvas.width - 1, _canvas.height - _current * _canvas.height / _max - _elHeight );\n            } else {\n                _ctx.drawImage( _dotCanvas, _canvas.width - 1, _canvas.height - _current * _canvas.height / _max - _elHeight );\n            }\n        }\n\n        _init();\n\n        return {\n            draw: _draw\n        };\n\n    }\n\n    function StackGraph ( _dom, _num ) {\n\n        var _canvas = document.createElement( 'canvas' ),\n            _ctx = _canvas.getContext( '2d' );\n\n        function _init () {\n\n            _canvas.width = _elWidth;\n            _canvas.height = _elHeight * _num;\n            _canvas.style.width = _canvas.width + 'px';\n            _canvas.style.height = _canvas.height + 'px';\n            _canvas.className = 'rs-canvas';\n            _dom.appendChild( _canvas );\n\n            _ctx.fillStyle = '#444444';\n            _ctx.fillRect( 0, 0, _canvas.width, _canvas.height );\n\n        }\n\n        function _draw ( v ) {\n            _ctx.drawImage( _canvas, 1, 0, _canvas.width - 1, _canvas.height, 0, 0, _canvas.width - 1, _canvas.height );\n            var th = 0;\n            iterateKeys( v, function ( j ) {\n                var h = v[ j ] * _canvas.height;\n                _ctx.fillStyle = _colours[ j ];\n                _ctx.fillRect( _canvas.width - 1, th, 1, h );\n                th += h;\n            } );\n        }\n\n        _init();\n\n        return {\n            draw: _draw\n        };\n\n    }\n\n    function PerfCounter ( id, group ) {\n\n        var _id = id,\n            _time,\n            _value = 0,\n            _total = 0,\n            _averageValue = 0,\n            _accumValue = 0,\n            _accumStart = performance.now(),\n            _accumSamples = 0,\n            _dom = document.createElement( 'div' ),\n            _spanId = document.createElement( 'span' ),\n            _spanValue = document.createElement( 'div' ),\n            _spanValueText = document.createTextNode( '' ),\n            _def = _settings ? _settings.values[ _id.toLowerCase() ] : null,\n            _graph = new Graph( _dom, _id, _def ),\n            _started = false;\n\n        _spanId.className = 'rs-counter-id';\n        _spanId.textContent = ( _def && _def.caption ) ? _def.caption : _id;\n\n        _spanValue.className = 'rs-counter-value';\n        _spanValue.appendChild( _spanValueText );\n\n        _dom.appendChild( _spanId );\n        _dom.appendChild( _spanValue );\n        if ( group ) group.div.appendChild( _dom );\n        else _div.appendChild( _dom );\n\n        _time = performance.now();\n\n        function _average ( v ) {\n            if ( _def && _def.average ) {\n                _accumValue += v;\n                _accumSamples++;\n                var t = performance.now();\n                if ( t - _accumStart >= ( _def.avgMs || 1000 ) ) {\n                    _averageValue = _accumValue / _accumSamples;\n                    _accumValue = 0;\n                    _accumStart = t;\n                    _accumSamples = 0;\n                }\n            }\n        }\n\n        function _start () {\n            _time = performance.now();\n            if( _settings.userTimingAPI ) performance.mark( _id + '-start' );\n            _started = true;\n        }\n\n        function _end () {\n            _value = performance.now() - _time;\n            if( _settings.userTimingAPI ) {\n                performance.mark( _id + '-end' );\n                if( _started ) {\n                    performance.measure( _id, _id + '-start', _id + '-end' );\n                }\n            }\n            _average( _value );\n        }\n\n        function _tick () {\n            _end();\n            _start();\n        }\n\n        function _draw () {\n            var v = ( _def && _def.average ) ? _averageValue : _value;\n            _spanValueText.nodeValue = Math.round( v * 100 ) / 100;\n            var a = ( _def && ( ( _def.below && _value < _def.below ) || ( _def.over && _value > _def.over ) ) );\n            _graph.draw( _value, a );\n            _dom.className = a ? 'rs-counter-base alarm' : 'rs-counter-base';\n\n        }\n\n        function _frame () {\n            var t = performance.now();\n            var e = t - _time;\n            _total++;\n            if ( e > 1000 ) {\n                if ( _def && _def.interpolate === false ) {\n                    _value = _total;\n                } else {\n                    _value = _total * 1000 / e;\n                }\n                _total = 0;\n                _time = t;\n                _average( _value );\n            }\n        }\n\n        function _set ( v ) {\n            _value = v;\n            _average( _value );\n        }\n\n        return {\n            set: _set,\n            start: _start,\n            tick: _tick,\n            end: _end,\n            frame: _frame,\n            value: function () {\n                return _value;\n            },\n            draw: _draw\n        };\n\n    }\n\n    function sample () {\n\n        var _value = 0;\n\n        function _set ( v ) {\n            _value = v;\n        }\n\n        return {\n            set: _set,\n            value: function () {\n                return _value;\n            }\n        };\n\n    }\n\n    function _perf ( idArg ) {\n\n        var id = idArg.toLowerCase();\n        if ( id === undefined ) id = 'default';\n        if ( _perfCounters[ id ] ) return _perfCounters[ id ];\n\n        var group = null;\n        if ( _settings && _settings.groups ) {\n            iterateKeys( _settings.groups, function ( j ) {\n                var g = _settings.groups[ parseInt( j, 10 ) ];\n                if ( !group && g.values.indexOf( id.toLowerCase() ) !== -1 ) {\n                    group = g;\n                }\n            } );\n        }\n\n        var p = new PerfCounter( id, group );\n        _perfCounters[ id ] = p;\n        return p;\n\n    }\n\n    function _init () {\n\n        if ( _settings.plugins ) {\n            if ( !_settings.values ) _settings.values = {};\n            if ( !_settings.groups ) _settings.groups = [];\n            if ( !_settings.fractions ) _settings.fractions = [];\n            for ( var j = 0; j < _settings.plugins.length; j++ ) {\n                _settings.plugins[ j ].attach( _perf );\n                iterateKeys( _settings.plugins[ j ].values, function ( k ) {\n                    _settings.values[ k ] = _settings.plugins[ j ].values[ k ];\n                } );\n                _settings.groups = _settings.groups.concat( _settings.plugins[ j ].groups );\n                _settings.fractions = _settings.fractions.concat( _settings.plugins[ j ].fractions );\n            }\n        } else {\n            _settings.plugins = {};\n        }\n\n        _base = document.createElement( 'div' );\n        _base.className = 'rs-base';\n        _div = document.createElement( 'div' );\n        _div.className = 'rs-container';\n        _div.style.height = 'auto';\n        _base.appendChild( _div );\n        document.body.appendChild( _base );\n\n        if ( !_settings ) return;\n\n        if ( _settings.groups ) {\n            iterateKeys( _settings.groups, function ( j ) {\n                var g = _settings.groups[ parseInt( j, 10 ) ];\n                var div = document.createElement( 'div' );\n                div.className = 'rs-group';\n                g.div = div;\n                var h1 = document.createElement( 'h1' );\n                h1.textContent = g.caption;\n                h1.addEventListener( 'click', function ( e ) {\n                    this.classList.toggle( 'hidden' );\n                    e.preventDefault();\n                }.bind( div ) );\n                _div.appendChild( h1 );\n                _div.appendChild( div );\n            } );\n        }\n\n        if ( _settings.fractions ) {\n            iterateKeys( _settings.fractions, function ( j ) {\n                var f = _settings.fractions[ parseInt( j, 10 ) ];\n                var div = document.createElement( 'div' );\n                div.className = 'rs-fraction';\n                var legend = document.createElement( 'div' );\n                legend.className = 'rs-legend';\n\n                var h = 0;\n                iterateKeys( _settings.fractions[ j ].steps, function ( k ) {\n                    var p = document.createElement( 'p' );\n                    p.textContent = _settings.fractions[ j ].steps[ k ];\n                    p.style.color = _colours[ h ];\n                    legend.appendChild( p );\n                    h++;\n                } );\n                div.appendChild( legend );\n                div.style.height = h * _elHeight + 'px';\n                f.div = div;\n                var graph = new StackGraph( div, h );\n                f.graph = graph;\n                _div.appendChild( div );\n            } );\n        }\n\n    }\n\n    function _update () {\n\n        iterateKeys( _settings.plugins, function ( j ) {\n            _settings.plugins[ j ].update();\n        } );\n\n        iterateKeys( _perfCounters, function ( j ) {\n            _perfCounters[ j ].draw();\n        } );\n\n        if ( _settings && _settings.fractions ) {\n            iterateKeys( _settings.fractions, function ( j ) {\n                var f = _settings.fractions[ parseInt( j, 10 ) ];\n                var v = [];\n                var base = _perfCounters[ f.base.toLowerCase() ];\n                if ( base ) {\n                    base = base.value();\n                    iterateKeys( _settings.fractions[ j ].steps, function ( k ) {\n                        var s = _settings.fractions[ j ].steps[ parseInt( k, 10 ) ].toLowerCase();\n                        var val = _perfCounters[ s ];\n                        if ( val ) {\n                            v.push( val.value() / base );\n                        }\n                    } );\n                }\n                f.graph.draw( v );\n            } );\n        }\n\n        /*if( _height != _div.clientHeight ) {\n            _height = _div.clientHeight;\n            _base.style.height = _height + 2 * _elHeight + 'px';\n        console.log( _base.clientHeight );\n        }*/\n\n    }\n\n    _init();\n\n    return function ( id ) {\n        if ( id ) return _perf( id );\n        return {\n            element: _base,\n            update: _update\n        };\n    };\n\n}\n\nif (typeof module === 'object') {\n  module.exports = window.rStats;\n}\n\n},{}],204:[function(_dereq_,module,exports){\n/*\n * Copyright 2015 Google Inc. All Rights Reserved.\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\nvar Util = {};\n\nUtil.base64 = function(mimeType, base64) {\n  return 'data:' + mimeType + ';base64,' + base64;\n};\n\nUtil.isMobile = function() {\n  var check = false;\n  (function(a){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})(navigator.userAgent||navigator.vendor||window.opera);\n  return check;\n};\n\nUtil.isIOS = function() {\n  return /(iPad|iPhone|iPod)/g.test(navigator.userAgent);\n};\n\nUtil.isIFrame = function() {\n  try {\n    return window.self !== window.top;\n  } catch (e) {\n    return true;\n  }\n};\n\nUtil.appendQueryParameter = function(url, key, value) {\n  // Determine delimiter based on if the URL already GET parameters in it.\n  var delimiter = (url.indexOf('?') < 0 ? '?' : '&');\n  url += delimiter + key + '=' + value;\n  return url;\n};\n\n// From http://goo.gl/4WX3tg\nUtil.getQueryParameter = function(name) {\n  name = name.replace(/[\\[]/, \"\\\\[\").replace(/[\\]]/, \"\\\\]\");\n  var regex = new RegExp(\"[\\\\?&]\" + name + \"=([^&#]*)\"),\n      results = regex.exec(location.search);\n  return results === null ? \"\" : decodeURIComponent(results[1].replace(/\\+/g, \" \"));\n};\n\nUtil.isLandscapeMode = function() {\n  return (window.orientation == 90 || window.orientation == -90);\n};\n\n\nmodule.exports = Util;\n\n},{}],205:[function(_dereq_,module,exports){\n/*\n * Copyright 2015 Google Inc. All Rights Reserved.\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\nvar Util = _dereq_('./util.js');\n\n/**\n * Android and iOS compatible wakelock implementation.\n *\n * Refactored thanks to dkovalev@.\n */\nfunction AndroidWakeLock() {\n  var video = document.createElement('video');\n\n  video.addEventListener('ended', function() {\n    video.play();\n  });\n\n  this.request = function() {\n    if (video.paused) {\n      // Base64 version of videos_src/no-sleep-60s.webm.\n      video.src = Util.base64('video/webm', 'GkXfowEAAAAAAAAfQoaBAUL3gQFC8oEEQvOBCEKChHdlYm1Ch4ECQoWBAhhTgGcBAAAAAAAH4xFNm3RALE27i1OrhBVJqWZTrIHfTbuMU6uEFlSua1OsggEwTbuMU6uEHFO7a1OsggfG7AEAAAAAAACkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVSalmAQAAAAAAAEUq17GDD0JATYCNTGF2ZjU2LjQwLjEwMVdBjUxhdmY1Ni40MC4xMDFzpJAGSJTMbsLpDt/ySkipgX1fRImIQO1MAAAAAAAWVK5rAQAAAAAAADuuAQAAAAAAADLXgQFzxYEBnIEAIrWcg3VuZIaFVl9WUDmDgQEj44OEO5rKAOABAAAAAAAABrCBsLqBkB9DtnUBAAAAAAAAo+eBAKOmgQAAgKJJg0IAAV4BHsAHBIODCoAACmH2MAAAZxgz4dPSTFi5JACjloED6ACmAECSnABMQAADYAAAWi0quoCjloEH0ACmAECSnABNwAADYAAAWi0quoCjloELuACmAECSnABNgAADYAAAWi0quoCjloEPoACmAECSnABNYAADYAAAWi0quoCjloETiACmAECSnABNIAADYAAAWi0quoAfQ7Z1AQAAAAAAAJTnghdwo5aBAAAApgBAkpwATOAAA2AAAFotKrqAo5aBA+gApgBAkpwATMAAA2AAAFotKrqAo5aBB9AApgBAkpwATIAAA2AAAFotKrqAo5aBC7gApgBAkpwATEAAA2AAAFotKrqAo5aBD6AApgDAkpwAQ2AAA2AAAFotKrqAo5aBE4gApgBAkpwATCAAA2AAAFotKrqAH0O2dQEAAAAAAACU54Iu4KOWgQAAAKYAQJKcAEvAAANgAABaLSq6gKOWgQPoAKYAQJKcAEtgAANgAABaLSq6gKOWgQfQAKYAQJKcAEsAAANgAABaLSq6gKOWgQu4AKYAQJKcAEqAAANgAABaLSq6gKOWgQ+gAKYAQJKcAEogAANgAABaLSq6gKOWgROIAKYAQJKcAEnAAANgAABaLSq6gB9DtnUBAAAAAAAAlOeCRlCjloEAAACmAECSnABJgAADYAAAWi0quoCjloED6ACmAECSnABJIAADYAAAWi0quoCjloEH0ACmAMCSnABDYAADYAAAWi0quoCjloELuACmAECSnABI4AADYAAAWi0quoCjloEPoACmAECSnABIoAADYAAAWi0quoCjloETiACmAECSnABIYAADYAAAWi0quoAfQ7Z1AQAAAAAAAJTngl3Ao5aBAAAApgBAkpwASCAAA2AAAFotKrqAo5aBA+gApgBAkpwASAAAA2AAAFotKrqAo5aBB9AApgBAkpwAR8AAA2AAAFotKrqAo5aBC7gApgBAkpwAR4AAA2AAAFotKrqAo5aBD6AApgBAkpwAR2AAA2AAAFotKrqAo5aBE4gApgBAkpwARyAAA2AAAFotKrqAH0O2dQEAAAAAAACU54J1MKOWgQAAAKYAwJKcAENgAANgAABaLSq6gKOWgQPoAKYAQJKcAEbgAANgAABaLSq6gKOWgQfQAKYAQJKcAEagAANgAABaLSq6gKOWgQu4AKYAQJKcAEaAAANgAABaLSq6gKOWgQ+gAKYAQJKcAEZAAANgAABaLSq6gKOWgROIAKYAQJKcAEYAAANgAABaLSq6gB9DtnUBAAAAAAAAlOeCjKCjloEAAACmAECSnABF4AADYAAAWi0quoCjloED6ACmAECSnABFwAADYAAAWi0quoCjloEH0ACmAECSnABFoAADYAAAWi0quoCjloELuACmAECSnABFgAADYAAAWi0quoCjloEPoACmAMCSnABDYAADYAAAWi0quoCjloETiACmAECSnABFYAADYAAAWi0quoAfQ7Z1AQAAAAAAAJTngqQQo5aBAAAApgBAkpwARUAAA2AAAFotKrqAo5aBA+gApgBAkpwARSAAA2AAAFotKrqAo5aBB9AApgBAkpwARQAAA2AAAFotKrqAo5aBC7gApgBAkpwARQAAA2AAAFotKrqAo5aBD6AApgBAkpwAROAAA2AAAFotKrqAo5aBE4gApgBAkpwARMAAA2AAAFotKrqAH0O2dQEAAAAAAACU54K7gKOWgQAAAKYAQJKcAESgAANgAABaLSq6gKOWgQPoAKYAQJKcAESAAANgAABaLSq6gKOWgQfQAKYAwJKcAENgAANgAABaLSq6gKOWgQu4AKYAQJKcAERgAANgAABaLSq6gKOWgQ+gAKYAQJKcAERAAANgAABaLSq6gKOWgROIAKYAQJKcAEQgAANgAABaLSq6gB9DtnUBAAAAAAAAlOeC0vCjloEAAACmAECSnABEIAADYAAAWi0quoCjloED6ACmAECSnABEAAADYAAAWi0quoCjloEH0ACmAECSnABD4AADYAAAWi0quoCjloELuACmAECSnABDwAADYAAAWi0quoCjloEPoACmAECSnABDoAADYAAAWi0quoCjloETiACmAECSnABDgAADYAAAWi0quoAcU7trAQAAAAAAABG7j7OBALeK94EB8YIBd/CBAw==');\n      video.play();\n    }\n  };\n\n  this.release = function() {\n    video.pause();\n    video.src = '';\n  };\n}\n\nfunction iOSWakeLock() {\n  var timer = null;\n\n  this.request = function() {\n    if (!timer) {\n      timer = setInterval(function() {\n        window.location.href = '/';\n        setTimeout(window.stop, 0);\n      }, 15000);\n    }\n  }\n\n  this.release = function() {\n    if (timer) {\n      clearInterval(timer);\n      timer = null;\n    }\n  }\n}\n\n\nfunction getWakeLock() {\n  var userAgent = navigator.userAgent || navigator.vendor || window.opera;\n  if (userAgent.match(/iPhone/i) || userAgent.match(/iPod/i)) {\n    return iOSWakeLock;\n  } else {\n    return AndroidWakeLock;\n  }\n}\n\nmodule.exports = getWakeLock();\n\n},{\"./util.js\":204}]},{},[171])(171)\n});\n//# sourceMappingURL=aframe-v0.7.1.js.map\n"
  },
  {
    "path": "libs/ammo.js/LICENSE",
    "content": "Copyright (c) 2011 ammo.js contributors\r\n\r\nThis software is provided 'as-is', without any express or implied\r\nwarranty.  In no event will the authors be held liable for any damages\r\narising from the use of this software.\r\n\r\nPermission is granted to anyone to use this software for any purpose,\r\nincluding commercial applications, and to alter it and redistribute it\r\nfreely, subject to the following restrictions:\r\n\r\n1. The origin of this software must not be misrepresented; you must not\r\n   claim that you wrote the original software. If you use this software\r\n   in a product, an acknowledgment in the product documentation would be\r\n   appreciated but is not required.\r\n2. Altered source versions must be plainly marked as such, and must not be\r\n   misrepresented as being the original software.\r\n3. This notice may not be removed or altered from any source distribution.\r\n\r\n---\r\n\r\nSee AUTHORS for list of contributors.\r\n"
  },
  {
    "path": "libs/ammo.js/ammo.js",
    "content": "\n// This is ammo.js, a port of Bullet Physics to JavaScript. zlib licensed.\nvar Ammo = function(Ammo) {\n  Ammo = Ammo || {};\n  var Module = Ammo;\n\nvar c;c||(c=eval(\"(function() { try { return Ammo || {} } catch(e) { return {} } })()\"));var aa={},ba;for(ba in c)c.hasOwnProperty(ba)&&(aa[ba]=c[ba]);var ca=!1,da=!1,ea=!1,fa=!1;\nif(c.ENVIRONMENT)if(\"WEB\"===c.ENVIRONMENT)ca=!0;else if(\"WORKER\"===c.ENVIRONMENT)da=!0;else if(\"NODE\"===c.ENVIRONMENT)ea=!0;else if(\"SHELL\"===c.ENVIRONMENT)fa=!0;else throw Error(\"The provided Module['ENVIRONMENT'] value is not valid. It must be one of: WEB|WORKER|NODE|SHELL.\");else ca=\"object\"===typeof window,da=\"function\"===typeof importScripts,ea=\"object\"===typeof process&&\"function\"===typeof require&&!ca&&!da,fa=!ca&&!ea&&!da;\nif(ea){c.print||(c.print=console.log);c.printErr||(c.printErr=console.warn);var ga,ha;c.read=function(a,b){ga||(ga=require(\"fs\"));ha||(ha=require(\"path\"));a=ha.normalize(a);var e=ga.readFileSync(a);return b?e:e.toString()};c.readBinary=function(a){a=c.read(a,!0);a.buffer||(a=new Uint8Array(a));assert(a.buffer);return a};c.load=function(a){ia(read(a))};c.thisProgram||(c.thisProgram=1<process.argv.length?process.argv[1].replace(/\\\\/g,\"/\"):\"unknown-program\");c.arguments=process.argv.slice(2);\"undefined\"!==\ntypeof module&&(module.exports=c);process.on(\"uncaughtException\",function(a){if(!(a instanceof ja))throw a;});c.inspect=function(){return\"[Emscripten Module object]\"}}else if(fa)c.print||(c.print=print),\"undefined\"!=typeof printErr&&(c.printErr=printErr),c.read=\"undefined\"!=typeof read?read:function(){throw\"no read() available\";},c.readBinary=function(a){if(\"function\"===typeof readbuffer)return new Uint8Array(readbuffer(a));a=read(a,\"binary\");assert(\"object\"===typeof a);return a},\"undefined\"!=typeof scriptArgs?\nc.arguments=scriptArgs:\"undefined\"!=typeof arguments&&(c.arguments=arguments),\"function\"===typeof quit&&(c.quit=function(a){quit(a)}),eval(\"if (typeof gc === 'function' && gc.toString().indexOf('[native code]') > 0) var gc = undefined\");else if(ca||da)c.read=function(a){var b=new XMLHttpRequest;b.open(\"GET\",a,!1);b.send(null);return b.responseText},da&&(c.readBinary=function(a){var b=new XMLHttpRequest;b.open(\"GET\",a,!1);b.responseType=\"arraybuffer\";b.send(null);return b.response}),c.readAsync=function(a,\nb,e){var f=new XMLHttpRequest;f.open(\"GET\",a,!0);f.responseType=\"arraybuffer\";f.onload=function(){200==f.status||0==f.status&&f.response?b(f.response):e()};f.onerror=e;f.send(null)},\"undefined\"!=typeof arguments&&(c.arguments=arguments),\"undefined\"!==typeof console?(c.print||(c.print=function(a){console.log(a)}),c.printErr||(c.printErr=function(a){console.warn(a)})):c.print||(c.print=function(){}),da&&(c.load=importScripts),\"undefined\"===typeof c.setWindowTitle&&(c.setWindowTitle=function(a){document.title=\na});else throw\"Unknown runtime environment. Where are we?\";function ia(a){eval.call(null,a)}!c.load&&c.read&&(c.load=function(a){ia(c.read(a))});c.print||(c.print=function(){});c.printErr||(c.printErr=c.print);c.arguments||(c.arguments=[]);c.thisProgram||(c.thisProgram=\"./this.program\");c.quit||(c.quit=function(a,b){throw b;});c.print=c.print;c.i=c.printErr;c.preRun=[];c.postRun=[];for(ba in aa)aa.hasOwnProperty(ba)&&(c[ba]=aa[ba]);\nvar aa=void 0,d={e:function(a){return tempRet0=a},J:function(){return tempRet0},N:function(){return ka},M:function(a){ka=a},s:function(a){switch(a){case \"i1\":case \"i8\":return 1;case \"i16\":return 2;case \"i32\":return 4;case \"i64\":return 8;case \"float\":return 4;case \"double\":return 8;default:return\"*\"===a[a.length-1]?d.j:\"i\"===a[0]?(a=parseInt(a.substr(1)),assert(0===a%8),a/8):0}},H:function(a){return Math.max(d.s(a),d.j)},O:16,$:function(a,b){\"double\"===b||\"i64\"===b?a&7&&(assert(4===(a&7)),a+=4):assert(0===\n(a&3));return a},T:function(a,b,e){return e||\"i64\"!=a&&\"double\"!=a?a?Math.min(b||(a?d.H(a):0),d.j):Math.min(b,8):8},l:function(a,b,e){return e&&e.length?c[\"dynCall_\"+a].apply(null,[b].concat(e)):c[\"dynCall_\"+a].call(null,b)},h:[],v:function(a){for(var b=0;b<d.h.length;b++)if(!d.h[b])return d.h[b]=a,2*(1+b);throw\"Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.\";},L:function(a){d.h[(a-2)/2]=null},f:function(a){d.f.n||(d.f.n={});d.f.n[a]||(d.f.n[a]=1,c.i(a))},\nm:{},V:function(a,b){assert(b);d.m[b]||(d.m[b]={});var e=d.m[b];e[a]||(e[a]=1===b.length?function(){return d.l(b,a)}:2===b.length?function(e){return d.l(b,a,[e])}:function(){return d.l(b,a,Array.prototype.slice.call(arguments))});return e[a]},U:function(){throw\"You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work\";},t:function(a){var b=ka;ka=ka+a|0;ka=ka+15&-16;return b},u:function(a){var b=la;la=la+a|0;la=la+15&-16;return b},\nF:function(a){var b=l[ma>>2];a=(b+a+15|0)&-16;l[ma>>2]=a;if(a=a>=na)oa(),a=!0;return a?(l[ma>>2]=b,0):b},p:function(a,b){return Math.ceil(a/(b?b:16))*(b?b:16)},Z:function(a,b,e){return e?+(a>>>0)+4294967296*+(b>>>0):+(a>>>0)+4294967296*+(b|0)},g:8,j:4,P:0};d.addFunction=d.v;d.removeFunction=d.L;var pa=0;function assert(a,b){a||qa(\"Assertion failed: \"+b)}\nfunction ra(a){var b;b=\"i32\";\"*\"===b.charAt(b.length-1)&&(b=\"i32\");switch(b){case \"i1\":return sa[a>>0];case \"i8\":return sa[a>>0];case \"i16\":return ta[a>>1];case \"i32\":return l[a>>2];case \"i64\":return l[a>>2];case \"float\":return ua[a>>2];case \"double\":return va[a>>3];default:qa(\"invalid type for setValue: \"+b)}return null}\nfunction wa(a,b,e,f){var g,h;\"number\"===typeof a?(g=!0,h=a):(g=!1,h=a.length);var k=\"string\"===typeof b?b:null,m;4==e?m=f:m=[\"function\"===typeof xa?xa:d.u,d.t,d.u,d.F][void 0===e?2:e](Math.max(h,k?1:b.length));if(g){f=m;assert(0==(m&3));for(a=m+(h&-4);f<a;f+=4)l[f>>2]=0;for(a=m+h;f<a;)sa[f++>>0]=0;return m}if(\"i8\"===k)return a.subarray||a.slice?ya.set(a,m):ya.set(new Uint8Array(a),m),m;f=0;for(var v,B;f<h;){var z=a[f];\"function\"===typeof z&&(z=d.W(z));e=k||b[f];if(0===e)f++;else{\"i64\"==e&&(e=\"i32\");\ng=m+f;var T=e,T=T||\"i8\";\"*\"===T.charAt(T.length-1)&&(T=\"i32\");switch(T){case \"i1\":sa[g>>0]=z;break;case \"i8\":sa[g>>0]=z;break;case \"i16\":ta[g>>1]=z;break;case \"i32\":l[g>>2]=z;break;case \"i64\":tempI64=[z>>>0,(tempDouble=z,1<=+za(tempDouble)?0<tempDouble?(Aa(+Ba(tempDouble/4294967296),4294967295)|0)>>>0:~~+Ca((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)];l[g>>2]=tempI64[0];l[g+4>>2]=tempI64[1];break;case \"float\":ua[g>>2]=z;break;case \"double\":va[g>>3]=z;break;default:qa(\"invalid type for setValue: \"+\nT)}B!==e&&(v=d.s(e),B=e);f+=v}}return m}function Da(a){var b;if(0===b||!a)return\"\";for(var e=0,f,g=0;;){f=ya[a+g>>0];e|=f;if(0==f&&!b)break;g++;if(b&&g==b)break}b||(b=g);f=\"\";if(128>e){for(;0<b;)e=String.fromCharCode.apply(String,ya.subarray(a,a+Math.min(b,1024))),f=f?f+e:e,a+=1024,b-=1024;return f}return c.UTF8ToString(a)}var Ea=\"undefined\"!==typeof TextDecoder?new TextDecoder(\"utf8\"):void 0;\nfunction Fa(a,b,e,f){if(0<f){f=e+f-1;for(var g=0;g<a.length;++g){var h=a.charCodeAt(g);55296<=h&&57343>=h&&(h=65536+((h&1023)<<10)|a.charCodeAt(++g)&1023);if(127>=h){if(e>=f)break;b[e++]=h}else{if(2047>=h){if(e+1>=f)break;b[e++]=192|h>>6}else{if(65535>=h){if(e+2>=f)break;b[e++]=224|h>>12}else{if(2097151>=h){if(e+3>=f)break;b[e++]=240|h>>18}else{if(67108863>=h){if(e+4>=f)break;b[e++]=248|h>>24}else{if(e+5>=f)break;b[e++]=252|h>>30;b[e++]=128|h>>24&63}b[e++]=128|h>>18&63}b[e++]=128|h>>12&63}b[e++]=\n128|h>>6&63}b[e++]=128|h&63}}b[e]=0}}function Ga(a){for(var b=0,e=0;e<a.length;++e){var f=a.charCodeAt(e);55296<=f&&57343>=f&&(f=65536+((f&1023)<<10)|a.charCodeAt(++e)&1023);127>=f?++b:b=2047>=f?b+2:65535>=f?b+3:2097151>=f?b+4:67108863>=f?b+5:b+6}return b}\"undefined\"!==typeof TextDecoder&&new TextDecoder(\"utf-16le\");\nfunction Ha(a){return a.replace(/__Z[\\w\\d_]+/g,function(a){var e;a:{var f=c.___cxa_demangle||c.__cxa_demangle;if(f)try{var g=a.substr(1),h=Ga(g)+1,k=xa(h);Fa(g,ya,k,h);var m=xa(4),v=f(k,0,0,m);if(0===ra(m)&&v){e=Da(v);break a}}catch(B){}finally{k&&Ia(k),m&&Ia(m),v&&Ia(v)}else d.f(\"warning: build with  -s DEMANGLE_SUPPORT=1  to link in libcxxabi demangling\");e=a}return a===e?a:a+\" [\"+e+\"]\"})}\nfunction Ja(){var a;a:{a=Error();if(!a.stack){try{throw Error(0);}catch(b){a=b}if(!a.stack){a=\"(no stack trace available)\";break a}}a=a.stack.toString()}c.extraStackTrace&&(a+=\"\\n\"+c.extraStackTrace());return Ha(a)}var buffer,sa,ya,ta,Ka,l,La,ua,va,Ma,la,Na,ka,Oa,Pa,ma;Ma=la=Na=ka=Oa=Pa=ma=0;\nfunction oa(){qa(\"Cannot enlarge memory arrays. Either (1) compile with  -s TOTAL_MEMORY=X  with X higher than the current value \"+na+\", (2) compile with  -s ALLOW_MEMORY_GROWTH=1  which allows increasing the size at runtime but prevents some optimizations, (3) set Module.TOTAL_MEMORY to a higher value before the program runs, or (4) if you want malloc to return NULL (0) instead of this abort, compile with  -s ABORTING_MALLOC=0 \")}var Qa=c.TOTAL_STACK||5242880,na=c.TOTAL_MEMORY||67108864;\nna<Qa&&c.i(\"TOTAL_MEMORY should be larger than TOTAL_STACK, was \"+na+\"! (TOTAL_STACK=\"+Qa+\")\");c.buffer?buffer=c.buffer:buffer=new ArrayBuffer(na);c.HEAP8=sa=new Int8Array(buffer);c.HEAP16=ta=new Int16Array(buffer);c.HEAP32=l=new Int32Array(buffer);c.HEAPU8=ya=new Uint8Array(buffer);c.HEAPU16=Ka=new Uint16Array(buffer);c.HEAPU32=La=new Uint32Array(buffer);c.HEAPF32=ua=new Float32Array(buffer);c.HEAPF64=va=new Float64Array(buffer);l[0]=1668509029;ta[1]=25459;\nif(115!==ya[2]||99!==ya[3])throw\"Runtime error: expected the system to be little-endian!\";c.HEAP=void 0;c.buffer=buffer;c.HEAP8=sa;c.HEAP16=ta;c.HEAP32=l;c.HEAPU8=ya;c.HEAPU16=Ka;c.HEAPU32=La;c.HEAPF32=ua;c.HEAPF64=va;function Ra(a){for(;0<a.length;){var b=a.shift();if(\"function\"==typeof b)b();else{var e=b.G;\"number\"===typeof e?void 0===b.k?c.dynCall_v(e):c.dynCall_vi(e,b.k):e(void 0===b.k?null:b.k)}}}var Sa=[],Ta=[],Ua=[],Va=[],Wa=[],Xa=!1;function Ya(){var a=c.preRun.shift();Sa.unshift(a)}\nfunction Za(a){var b=Array(Ga(a)+1);Fa(a,b,0,b.length);return b}Math.imul&&-5===Math.imul(4294967295,5)||(Math.imul=function(a,b){var e=a&65535,f=b&65535;return e*f+((a>>>16)*f+e*(b>>>16)<<16)|0});Math.X=Math.imul;Math.clz32||(Math.clz32=function(a){a=a>>>0;for(var b=0;32>b;b++)if(a&1<<31-b)return b;return 32});Math.R=Math.clz32;Math.trunc||(Math.trunc=function(a){return 0>a?Math.ceil(a):Math.floor(a)});Math.trunc=Math.trunc;var za=Math.abs,Ca=Math.ceil,Ba=Math.floor,$a=Math.pow,Aa=Math.min;\nc.preloadedImages={};c.preloadedAudios={};var ab=[function(a,b,e,f,g,h,k,m){a=c.getCache(c.ConcreteContactResultCallback)[a];if(!a.hasOwnProperty(\"addSingleResult\"))throw\"a JSImplementation must implement all functions, you forgot ConcreteContactResultCallback::addSingleResult.\";return a.addSingleResult(b,e,f,g,h,k,m)}];Ma=d.g;la=Ma+26336;Ta.push({G:function(){bb()}});\nwa([36,38,0,0,148,39,0,0,24,0,0,0,0,0,0,0,252,37,0,0,180,39,0,0,36,38,0,0,224,39,0,0,48,0,0,0,0,0,0,0,252,37,0,0,15,40,0,0,36,38,0,0,55,40,0,0,72,0,0,0,0,0,0,0,252,37,0,0,77,40,0,0,36,38,0,0,105,40,0,0,96,0,0,0,0,0,0,0,252,37,0,0,128,40,0,0,252,37,0,0,144,40,0,0,36,38,0,0,165,40,0,0,128,0,0,0,0,0,0,0,252,37,0,0,215,40,0,0,36,38,0,0,2,41,0,0,152,0,0,0,0,0,0,0,252,37,0,0,28,41,0,0,36,38,0,0,47,41,0,0,0,4,0,0,0,0,0,0,36,38,0,0,91,41,0,0,192,0,0,0,0,0,0,0,252,37,0,0,150,41,0,0,36,38,0,0,183,41,0,0,192,\n0,0,0,0,0,0,0,36,38,0,0,235,41,0,0,192,0,0,0,0,0,0,0,36,38,0,0,25,42,0,0,192,0,0,0,0,0,0,0,36,38,0,0,11,43,0,0,176,3,0,0,0,0,0,0,36,38,0,0,24,43,0,0,24,1,0,0,0,0,0,0,252,37,0,0,56,43,0,0,252,37,0,0,75,43,0,0,36,38,0,0,96,43,0,0,32,1,0,0,0,0,0,0,36,38,0,0,127,43,0,0,48,8,0,0,0,0,0,0,36,38,0,0,16,44,0,0,104,1,0,0,0,0,0,0,36,38,0,0,242,43,0,0,176,7,0,0,0,0,0,0,36,38,0,0,50,44,0,0,24,1,0,0,0,0,0,0,36,38,0,0,83,44,0,0,24,1,0,0,0,0,0,0,36,38,0,0,118,44,0,0,24,1,0,0,0,0,0,0,36,38,0,0,152,44,0,0,104,1,0,\n0,0,0,0,0,36,38,0,0,186,44,0,0,184,1,0,0,0,0,0,0,252,37,0,0,218,44,0,0,36,38,0,0,230,45,0,0,184,1,0,0,0,0,0,0,36,38,0,0,41,45,0,0,208,7,0,0,0,0,0,0,36,38,0,0,250,44,0,0,120,7,0,0,0,0,0,0,252,37,0,0,12,45,0,0,36,38,0,0,201,45,0,0,208,7,0,0,0,0,0,0,36,38,0,0,154,46,0,0,96,2,0,0,0,0,0,0,36,38,0,0,75,46,0,0,40,2,0,0,0,0,0,0,36,38,0,0,101,46,0,0,56,2,0,0,0,0,0,0,252,37,0,0,127,46,0,0,36,38,0,0,181,46,0,0,184,1,0,0,0,0,0,0,36,38,0,0,233,46,0,0,176,3,0,0,0,0,0,0,36,38,0,0,153,48,0,0,128,2,0,0,0,0,0,0,36,\n38,0,0,123,47,0,0,112,0,0,0,0,0,0,0,36,38,0,0,179,48,0,0,40,5,0,0,0,0,0,0,36,38,0,0,197,48,0,0,160,2,0,0,0,0,0,0,252,37,0,0,227,48,0,0,36,38,0,0,81,49,0,0,184,2,0,0,0,0,0,0,76,38,0,0,45,49,0,0,0,0,0,0,1,0,0,0,208,2,0,0,2,4,0,0,252,37,0,0,65,49,0,0,36,38,0,0,141,49,0,0,168,2,0,0,0,0,0,0,36,38,0,0,206,49,0,0,184,2,0,0,0,0,0,0,36,38,0,0,26,50,0,0,184,2,0,0,0,0,0,0,36,38,0,0,73,50,0,0,184,2,0,0,0,0,0,0,36,38,0,0,124,50,0,0,184,2,0,0,0,0,0,0,36,38,0,0,218,50,0,0,56,3,0,0,0,0,0,0,252,37,0,0,0,51,0,0,36,\n38,0,0,21,51,0,0,80,3,0,0,0,0,0,0,252,37,0,0,40,51,0,0,36,38,0,0,60,51,0,0,104,0,0,0,0,0,0,0,36,38,0,0,134,51,0,0,136,3,0,0,0,0,0,0,36,38,0,0,88,51,0,0,112,0,0,0,0,0,0,0,36,38,0,0,167,51,0,0,80,3,0,0,0,0,0,0,36,38,0,0,200,51,0,0,168,3,0,0,0,0,0,0,252,37,0,0,225,51,0,0,252,37,0,0,11,52,0,0,36,38,0,0,31,52,0,0,176,3,0,0,0,0,0,0,36,38,0,0,47,52,0,0,184,3,0,0,0,0,0,0,36,38,0,0,120,52,0,0,136,9,0,0,0,0,0,0,36,38,0,0,74,52,0,0,248,3,0,0,0,0,0,0,252,37,0,0,100,52,0,0,36,38,0,0,144,52,0,0,16,4,0,0,0,0,0,\n0,252,37,0,0,178,52,0,0,36,38,0,0,205,52,0,0,192,0,0,0,0,0,0,0,36,38,0,0,253,52,0,0,192,0,0,0,0,0,0,0,36,38,0,0,40,53,0,0,192,0,0,0,0,0,0,0,36,38,0,0,91,53,0,0,192,0,0,0,0,0,0,0,36,38,0,0,140,53,0,0,192,0,0,0,0,0,0,0,36,38,0,0,173,53,0,0,192,0,0,0,0,0,0,0,36,38,0,0,225,53,0,0,192,0,0,0,0,0,0,0,36,38,0,0,22,54,0,0,192,0,0,0,0,0,0,0,36,38,0,0,67,54,0,0,192,0,0,0,0,0,0,0,36,38,0,0,124,54,0,0,192,0,0,0,0,0,0,0,252,37,0,0,174,54,0,0,36,38,0,0,245,54,0,0,184,1,0,0,0,0,0,0,36,38,0,0,208,55,0,0,56,10,0,0,\n0,0,0,0,36,38,0,0,23,55,0,0,208,7,0,0,0,0,0,0,36,38,0,0,181,55,0,0,208,7,0,0,0,0,0,0,36,38,0,0,244,55,0,0,56,10,0,0,0,0,0,0,36,38,0,0,17,56,0,0,32,5,0,0,0,0,0,0,252,37,0,0,36,56,0,0,252,37,0,0,203,59,0,0,36,38,0,0,187,58,0,0,40,2,0,0,0,0,0,0,36,38,0,0,144,56,0,0,48,0,0,0,0,0,0,0,36,38,0,0,21,57,0,0,24,1,0,0,0,0,0,0,36,38,0,0,147,57,0,0,152,9,0,0,0,0,0,0,36,38,0,0,40,58,0,0,152,9,0,0,0,0,0,0,76,38,0,0,209,58,0,0,0,0,0,0,2,0,0,0,208,7,0,0,2,0,0,0,216,7,0,0,2,4,0,0,36,38,0,0,242,59,0,0,128,0,0,0,0,0,\n0,0,36,38,0,0,143,60,0,0,168,9,0,0,0,0,0,0,36,38,0,0,64,61,0,0,168,9,0,0,0,0,0,0,36,38,0,0,255,61,0,0,40,2,0,0,0,0,0,0,36,38,0,0,49,62,0,0,56,2,0,0,0,0,0,0,36,38,0,0,23,62,0,0,16,5,0,0,0,0,0,0,36,38,0,0,75,62,0,0,56,10,0,0,0,0,0,0,36,38,0,0,183,63,0,0,192,0,0,0,0,0,0,0,36,38,0,0,157,63,0,0,56,10,0,0,0,0,0,0,36,38,0,0,112,62,0,0,16,5,0,0,0,0,0,0,36,38,0,0,139,62,0,0,32,5,0,0,0,0,0,0,36,38,0,0,24,63,0,0,32,5,0,0,0,0,0,0,36,38,0,0,248,63,0,0,56,10,0,0,0,0,0,0,36,38,0,0,223,63,0,0,24,1,0,0,0,0,0,0,36,\n38,0,0,56,64,0,0,56,10,0,0,0,0,0,0,36,38,0,0,23,64,0,0,24,1,0,0,0,0,0,0,36,38,0,0,149,64,0,0,152,7,0,0,0,0,0,0,36,38,0,0,188,64,0,0,176,7,0,0,0,0,0,0,36,38,0,0,208,64,0,0,176,6,0,0,0,0,0,0,36,38,0,0,229,64,0,0,176,6,0,0,0,0,0,0,36,38,0,0,251,64,0,0,176,7,0,0,0,0,0,0,36,38,0,0,185,65,0,0,56,7,0,0,0,0,0,0,36,38,0,0,11,65,0,0,16,7,0,0,0,0,0,0,252,37,0,0,121,65,0,0,36,38,0,0,210,65,0,0,16,7,0,0,0,0,0,0,36,38,0,0,58,66,0,0,16,7,0,0,0,0,0,0,36,38,0,0,54,67,0,0,48,8,0,0,0,0,0,0,36,38,0,0,171,66,0,0,208,\n7,0,0,0,0,0,0,36,38,0,0,195,66,0,0,216,7,0,0,0,0,0,0,36,38,0,0,111,67,0,0,48,8,0,0,0,0,0,0,36,38,0,0,132,67,0,0,176,7,0,0,0,0,0,0,36,38,0,0,158,67,0,0,120,7,0,0,0,0,0,0,252,37,0,0,216,67,0,0,36,38,0,0,235,67,0,0,152,7,0,0,0,0,0,0,36,38,0,0,251,67,0,0,160,7,0,0,0,0,0,0,36,38,0,0,48,68,0,0,136,7,0,0,0,0,0,0,252,37,0,0,68,68,0,0,252,37,0,0,89,68,0,0,36,38,0,0,155,68,0,0,176,7,0,0,0,0,0,0,36,38,0,0,181,68,0,0,224,7,0,0,0,0,0,0,36,38,0,0,208,68,0,0,224,7,0,0,0,0,0,0,36,38,0,0,13,69,0,0,136,7,0,0,0,0,0,\n0,36,38,0,0,226,68,0,0,216,7,0,0,0,0,0,0,36,38,0,0,41,69,0,0,152,7,0,0,0,0,0,0,36,38,0,0,62,69,0,0,120,7,0,0,0,0,0,0,36,38,0,0,75,69,0,0,144,9,0,0,0,0,0,0,36,38,0,0,92,69,0,0,216,7,0,0,0,0,0,0,36,38,0,0,183,69,0,0,216,7,0,0,0,0,0,0,36,38,0,0,39,70,0,0,48,8,0,0,0,0,0,0,36,38,0,0,97,70,0,0,176,7,0,0,0,0,0,0,36,38,0,0,125,70,0,0,144,8,0,0,0,0,0,0,36,38,0,0,154,70,0,0,144,8,0,0,0,0,0,0,36,38,0,0,173,70,0,0,152,10,0,0,0,0,0,0,36,38,0,0,240,70,0,0,224,8,0,0,0,0,0,0,36,38,0,0,190,70,0,0,240,8,0,0,0,0,0,\n0,252,37,0,0,216,70,0,0,36,38,0,0,255,70,0,0,8,9,0,0,0,0,0,0,36,38,0,0,17,71,0,0,72,0,0,0,0,0,0,0,36,38,0,0,25,72,0,0,8,9,0,0,0,0,0,0,36,38,0,0,42,71,0,0,248,3,0,0,0,0,0,0,36,38,0,0,152,71,0,0,248,3,0,0,0,0,0,0,36,38,0,0,122,72,0,0,240,8,0,0,0,0,0,0,36,38,0,0,56,72,0,0,24,1,0,0,0,0,0,0,36,38,0,0,77,72,0,0,24,1,0,0,0,0,0,0,36,38,0,0,100,72,0,0,24,1,0,0,0,0,0,0,252,37,0,0,141,72,0,0,252,37,0,0,247,72,0,0,36,38,0,0,8,73,0,0,208,7,0,0,0,0,0,0,36,38,0,0,36,73,0,0,208,7,0,0,0,0,0,0,36,38,0,0,238,73,0,0,\n216,9,0,0,0,0,0,0,36,38,0,0,67,73,0,0,32,5,0,0,0,0,0,0,252,37,0,0,18,74,0,0,36,38,0,0,51,74,0,0,216,9,0,0,0,0,0,0,36,38,0,0,103,74,0,0,168,3,0,0,0,0,0,0,36,38,0,0,84,74,0,0,32,5,0,0,0,0,0,0,36,38,0,0,121,74,0,0,168,3,0,0,0,0,0,0,36,38,0,0,151,74,0,0,48,10,0,0,0,0,0,0,252,37,0,0,171,74,0,0,36,38,0,0,210,74,0,0,184,1,0,0,0,0,0,0,36,38,0,0,243,74,0,0,184,1,0,0,0,0,0,0,36,38,0,0,6,75,0,0,56,10,0,0,0,0,0,0,36,38,0,0,41,75,0,0,48,10,0,0,0,0,0,0,36,38,0,0,60,75,0,0,48,10,0,0,0,0,0,0,252,37,0,0,85,75,0,0,\n252,37,0,0,111,75,0,0,36,38,0,0,132,75,0,0,168,10,0,0,0,0,0,0,252,37,0,0,52,76,0,0,252,37,0,0,94,86,0,0,36,38,0,0,190,86,0,0,200,10,0,0,0,0,0,0,36,38,0,0,107,86,0,0,216,10,0,0,0,0,0,0,252,37,0,0,140,86,0,0,36,38,0,0,153,86,0,0,184,10,0,0,0,0,0,0,36,38,0,0,196,87,0,0,200,10,0,0,0,0,0,0,36,38,0,0,160,87,0,0,240,10,0,0,0,0,0,0,36,38,0,0,230,87,0,0,184,10,0,0,0,0,0,0,0,0,0,0,8,0,0,0,1,0,0,0,2,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,24,0,0,0,3,0,0,0,4,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,32,0,0,0,5,0,0,0,6,0,0,0,2,0,0,\n0,1,0,0,0,0,0,0,0,48,0,0,0,7,0,0,0,8,0,0,0,2,0,0,0,1,0,0,0,0,0,0,0,56,0,0,0,9,0,0,0,10,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,72,0,0,0,11,0,0,0,12,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,80,0,0,0,13,0,0,0,14,0,0,0,1,0,0,0,2,0,0,0,0,0,0,0,96,0,0,0,15,0,0,0,16,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,104,0,0,0,17,0,0,0,18,0,0,0,1,0,0,0,0,0,0,0,112,0,0,0,19,0,0,0,20,0,0,0,3,0,0,0,2,0,0,0,0,0,0,0,128,0,0,0,21,0,0,0,22,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,136,0,0,0,23,0,0,0,24,0,0,0,1,0,0,0,2,0,0,0,2,0,0,0,3,0,0,0,1,0,0,0,\n2,0,0,0,25,0,0,0,3,0,0,0,4,0,0,0,4,0,0,0,3,0,0,0,5,0,0,0,4,0,0,0,5,0,0,0,0,0,0,0,160,0,0,0,26,0,0,0,27,0,0,0,5,0,0,0,6,0,0,0,2,0,0,0,7,0,0,0,0,0,0,0,232,0,0,0,28,0,0,0,29,0,0,0,2,0,0,0,0,0,0,0,216,0,0,0,28,0,0,0,30,0,0,0,3,0,0,0,0,0,0,0,200,0,0,0,28,0,0,0,31,0,0,0,4,0,0,0,0,0,0,0,176,0,0,0,28,0,0,0,32,0,0,0,5,0,0,0,0,0,0,0,248,0,0,0,4,0,0,0,33,0,0,0,34,0,0,0,6,0,0,0,8,0,0,0,3,0,0,0,7,0,0,0,6,0,0,0,0,0,0,0,8,1,0,0,35,0,0,0,36,0,0,0,7,0,0,0,8,0,0,0,1,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,40,1,0,0,37,0,0,0,\n38,0,0,0,1,0,0,0,1,0,0,0,3,0,0,0,9,0,0,0,0,0,0,0,56,1,0,0,39,0,0,0,40,0,0,0,1,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,9,0,0,0,10,0,0,0,2,0,0,0,11,0,0,0,10,0,0,0,4,0,0,0,2,0,0,0,12,0,0,0,4,0,0,0,11,0,0,0,2,0,0,0,0,0,0,0,120,1,0,0,35,0,0,0,41,0,0,0,7,0,0,0,12,0,0,0,1,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,72,1,0,0,35,0,0,0,42,0,0,0,7,0,0,0,13,0,0,0,1,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,88,1,0,0,43,0,0,0,44,0,0,0,3,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,14,0,0,0,13,0,0,0,3,0,0,0,14,0,0,0,10,0,0,0,5,0,0,0,3,0,0,0,15,0,0,0,5,0,0,0,11,\n0,0,0,9,0,0,0,10,0,0,0,1,0,0,0,4,0,0,0,5,0,0,0,16,0,0,0,11,0,0,0,17,0,0,0,0,0,0,0,152,1,0,0,35,0,0,0,45,0,0,0,12,0,0,0,15,0,0,0,1,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,136,1,0,0,35,0,0,0,46,0,0,0,13,0,0,0,15,0,0,0,1,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,168,1,0,0,47,0,0,0,48,0,0,0,2,0,0,0,1,0,0,0,16,0,0,0,0,0,0,0,192,1,0,0,49,0,0,0,50,0,0,0,3,0,0,0,2,0,0,0,17,0,0,0,0,0,0,0,208,1,0,0,51,0,0,0,52,0,0,0,6,0,0,0,0,0,0,0,240,1,0,0,6,0,0,0,18,0,0,0,14,0,0,0,53,0,0,0,54,0,0,0,0,0,0,0,224,1,0,0,55,0,0,0,56,0,0,0,7,0,0,0,\n8,0,0,0,1,0,0,0,1,0,0,0,14,0,0,0,13,0,0,0,4,0,0,0,18,0,0,0,10,0,0,0,7,0,0,0,4,0,0,0,15,0,0,0,5,0,0,0,11,0,0,0,15,0,0,0,16,0,0,0,1,0,0,0,8,0,0,0,5,0,0,0,19,0,0,0,17,0,0,0,7,0,0,0,20,0,0,0,21,0,0,0,9,0,0,0,18,0,0,0,22,0,0,0,10,0,0,0,1,0,0,0,11,0,0,0,0,0,0,0,248,1,0,0,57,0,0,0,58,0,0,0,12,0,0,0,0,0,0,0,8,2,0,0,59,0,0,0,60,0,0,0,61,0,0,0,62,0,0,0,19,0,0,0,23,0,0,0,63,0,0,0,13,0,0,0,14,0,0,0,15,0,0,0,20,0,0,0,64,0,0,0,21,0,0,0,1,0,0,0,19,0,0,0,22,0,0,0,23,0,0,0,24,0,0,0,25,0,0,0,26,0,0,0,65,0,0,0,27,0,\n0,0,16,0,0,0,28,0,0,0,29,0,0,0,24,0,0,0,25,0,0,0,8,0,0,0,9,0,0,0,26,0,0,0,66,0,0,0,30,0,0,0,31,0,0,0,32,0,0,0,33,0,0,0,8,0,0,0,9,0,0,0,67,0,0,0,34,0,0,0,10,0,0,0,11,0,0,0,12,0,0,0,68,0,0,0,35,0,0,0,13,0,0,0,0,0,0,0,24,2,0,0,69,0,0,0,70,0,0,0,10,0,0,0,0,0,0,0,64,2,0,0,71,0,0,0,72,0,0,0,4,0,0,0,3,0,0,0,36,0,0,0,0,0,0,0,80,2,0,0,11,0,0,0,73,0,0,0,74,0,0,0,37,0,0,0,27,0,0,0,6,0,0,0,38,0,0,0,0,0,0,0,96,2,0,0,75,0,0,0,76,0,0,0,61,0,0,0,62,0,0,0,19,0,0,0,23,0,0,0,77,0,0,0,13,0,0,0,17,0,0,0,15,0,0,0,39,0,\n0,0,64,0,0,0,40,0,0,0,1,0,0,0,19,0,0,0,22,0,0,0,23,0,0,0,24,0,0,0,25,0,0,0,26,0,0,0,65,0,0,0,27,0,0,0,16,0,0,0,28,0,0,0,29,0,0,0,24,0,0,0,25,0,0,0,8,0,0,0,9,0,0,0,28,0,0,0,66,0,0,0,30,0,0,0,31,0,0,0,32,0,0,0,33,0,0,0,14,0,0,0,9,0,0,0,67,0,0,0,34,0,0,0,10,0,0,0,15,0,0,0,12,0,0,0,68,0,0,0,35,0,0,0,13,0,0,0,0,0,0,0,112,2,0,0,21,0,0,0,78,0,0,0,12,0,0,0,3,0,0,0,0,0,0,0,144,2,0,0,79,0,0,0,80,0,0,0,1,0,0,0,0,0,0,0,168,2,0,0,81,0,0,0,82,0,0,0,83,0,0,0,1,0,0,0,41,0,0,0,42,0,0,0,1,0,0,0,1,0,0,0,4,0,0,0,29,\n0,0,0,7,0,0,0,84,0,0,0,0,0,0,0,184,2,0,0,81,0,0,0,85,0,0,0,86,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,30,0,0,0,8,0,0,0,0,0,0,0,216,2,0,0,81,0,0,0,87,0,0,0,83,0,0,0,1,0,0,0,41,0,0,0,43,0,0,0,1,0,0,0,1,0,0,0,4,0,0,0,31,0,0,0,9,0,0,0,84,0,0,0,20,0,0,0,0,0,0,0,232,2,0,0,81,0,0,0,88,0,0,0,89,0,0,0,1,0,0,0,44,0,0,0,45,0,0,0,1,0,0,0,2,0,0,0,5,0,0,0,32,0,0,0,10,0,0,0,0,0,0,0,248,2,0,0,81,0,0,0,90,0,0,0,86,0,0,0,1,0,0,0,46,0,0,0,47,0,0,0,1,0,0,0,3,0,0,0,6,0,0,0,33,0,0,0,11,0,0,0,0,0,0,0,8,3,\n0,0,81,0,0,0,91,0,0,0,92,0,0,0,1,0,0,0,48,0,0,0,49,0,0,0,2,0,0,0,4,0,0,0,7,0,0,0,34,0,0,0,12,0,0,0,21,0,0,0,0,0,0,0,24,3,0,0,81,0,0,0,93,0,0,0,94,0,0,0,1,0,0,0,50,0,0,0,51,0,0,0,1,0,0,0,5,0,0,0,8,0,0,0,35,0,0,0,13,0,0,0,0,0,0,0,40,3,0,0,95,0,0,0,96,0,0,0,22,0,0,0,1,0,0,0,23,0,0,0,97,0,0,0,36,0,0,0,18,0,0,0,1,0,0,0,1,0,0,0,2,0,0,0,1,0,0,0,2,0,0,0,0,0,0,0,64,3,0,0,98,0,0,0,99,0,0,0,2,0,0,0,52,0,0,0,16,0,0,0,17,0,0,0,19,0,0,0,0,0,0,0,88,3,0,0,17,0,0,0,100,0,0,0,6,0,0,0,0,0,0,0,104,3,0,0,101,0,0,0,102,\n0,0,0,3,0,0,0,53,0,0,0,54,0,0,0,4,0,0,0,55,0,0,0,56,0,0,0,57,0,0,0,5,0,0,0,37,0,0,0,103,0,0,0,38,0,0,0,58,0,0,0,0,0,0,0,120,3,0,0,21,0,0,0,104,0,0,0,3,0,0,0,9,0,0,0,0,0,0,0,152,3,0,0,105,0,0,0,106,0,0,0,1,0,0,0,1,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,176,3,0,0,4,0,0,0,107,0,0,0,108,0,0,0,37,0,0,0,39,0,0,0,14,0,0,0,7,0,0,0,0,0,0,0,184,3,0,0,4,0,0,0,109,0,0,0,110,0,0,0,37,0,0,0,39,0,0,0,14,0,0,0,7,0,0,0,24,0,0,0,20,0,0,0,0,0,0,0,200,3,0,0,4,0,0,0,111,0,0,0,112,0,0,0,37,0,0,0,39,0,0,\n0,14,0,0,0,7,0,0,0,25,0,0,0,21,0,0,0,0,0,0,0,216,3,0,0,113,0,0,0,114,0,0,0,7,0,0,0,15,0,0,0,59,0,0,0,60,0,0,0,16,0,0,0,17,0,0,0,22,0,0,0,40,0,0,0,13,0,0,0,41,0,0,0,42,0,0,0,43,0,0,0,14,0,0,0,61,0,0,0,0,0,0,0,232,3,0,0,115,0,0,0,116,0,0,0,15,0,0,0,0,0,0,0,0,4,0,0,117,0,0,0,118,0,0,0,5,0,0,0,6,0,0,0,18,0,0,0,7,0,0,0,0,0,0,0,168,4,0,0,28,0,0,0,119,0,0,0,8,0,0,0,0,0,0,0,152,4,0,0,28,0,0,0,120,0,0,0,9,0,0,0,0,0,0,0,136,4,0,0,28,0,0,0,121,0,0,0,10,0,0,0,0,0,0,0,120,4,0,0,28,0,0,0,122,0,0,0,11,0,0,0,0,0,\n0,0,104,4,0,0,28,0,0,0,123,0,0,0,12,0,0,0,0,0,0,0,88,4,0,0,28,0,0,0,124,0,0,0,13,0,0,0,0,0,0,0,72,4,0,0,28,0,0,0,125,0,0,0,14,0,0,0,0,0,0,0,56,4,0,0,28,0,0,0,126,0,0,0,15,0,0,0,0,0,0,0,40,4,0,0,28,0,0,0,127,0,0,0,16,0,0,0,0,0,0,0,24,4,0,0,28,0,0,0,128,0,0,0,17,0,0,0,0,0,0,0,184,4,0,0,129,0,0,0,130,0,0,0,26,0,0,0,62,0,0,0,0,0,0,0,192,4,0,0,131,0,0,0,132,0,0,0,5,0,0,0,4,0,0,0,63,0,0,0,0,0,0,0,208,4,0,0,133,0,0,0,134,0,0,0,6,0,0,0,5,0,0,0,64,0,0,0,0,0,0,0,224,4,0,0,51,0,0,0,135,0,0,0,23,0,0,0,0,0,0,\n0,240,4,0,0,136,0,0,0,137,0,0,0,24,0,0,0,0,0,0,0,0,5,0,0,138,0,0,0,139,0,0,0,7,0,0,0,6,0,0,0,65,0,0,0,0,0,0,0,16,5,0,0,140,0,0,0,141,0,0,0,27,0,0,0,28,0,0,0,3,0,0,0,0,0,0,0,40,5,0,0,142,0,0,0,143,0,0,0,61,0,0,0,62,0,0,0,19,0,0,0,23,0,0,0,144,0,0,0,13,0,0,0,17,0,0,0,25,0,0,0,66,0,0,0,64,0,0,0,67,0,0,0,0,0,0,0,48,5,0,0,69,0,0,0,145,0,0,0,16,0,0,0,0,0,0,0,112,5,0,0,51,0,0,0,146,0,0,0,26,0,0,0,1,0,0,0,0,0,0,0,96,5,0,0,51,0,0,0,147,0,0,0,26,0,0,0,2,0,0,0,0,0,0,0,80,5,0,0,35,0,0,0,148,0,0,0,7,0,0,0,68,\n0,0,0,1,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,64,5,0,0,7,0,0,0,149,0,0,0,17,0,0,0,10,0,0,0,0,0,0,0,128,5,0,0,150,0,0,0,151,0,0,0,27,0,0,0,28,0,0,0,252,255,255,255,128,5,0,0,152,0,0,0,153,0,0,0,29,0,0,0,0,0,0,0,192,5,0,0,51,0,0,0,154,0,0,0,30,0,0,0,1,0,0,0,0,0,0,0,176,5,0,0,51,0,0,0,155,0,0,0,30,0,0,0,2,0,0,0,0,0,0,0,160,5,0,0,21,0,0,0,156,0,0,0,18,0,0,0,11,0,0,0,0,0,0,0,208,5,0,0,69,0,0,0,157,0,0,0,19,0,0,0,0,0,0,0,224,5,0,0,69,0,0,0,158,0,0,0,20,0,0,0,0,0,0,0,240,5,0,0,140,0,0,0,159,0,0,0,27,0,0,0,28,0,\n0,0,4,0,0,0,0,0,0,0,0,6,0,0,160,0,0,0,161,0,0,0,8,0,0,0,7,0,0,0,69,0,0,0,0,0,0,0,16,6,0,0,162,0,0,0,163,0,0,0,18,0,0,0,0,0,0,0,32,6,0,0,164,0,0,0,165,0,0,0,9,0,0,0,8,0,0,0,70,0,0,0,0,0,0,0,80,6,0,0,140,0,0,0,166,0,0,0,29,0,0,0,30,0,0,0,5,0,0,0,0,0,0,0,64,6,0,0,140,0,0,0,167,0,0,0,31,0,0,0,32,0,0,0,6,0,0,0,0,0,0,0,48,6,0,0,140,0,0,0,168,0,0,0,27,0,0,0,28,0,0,0,7,0,0,0,0,0,0,0,96,6,0,0,169,0,0,0,170,0,0,0,10,0,0,0,9,0,0,0,71,0,0,0,0,0,0,0,112,6,0,0,35,0,0,0,171,0,0,0,7,0,0,0,72,0,0,0,1,0,0,0,5,0,0,\n0,6,0,0,0,0,0,0,0,128,6,0,0,172,0,0,0,173,0,0,0,11,0,0,0,10,0,0,0,73,0,0,0,0,0,0,0,144,6,0,0,35,0,0,0,174,0,0,0,33,0,0,0,15,0,0,0,1,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,160,6,0,0,175,0,0,0,176,0,0,0,31,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,74,0,0,0,44,0,0,0,5,0,0,0,45,0,0,0,10,0,0,0,18,0,0,0,5,0,0,0,46,0,0,0,19,0,0,0,11,0,0,0,75,0,0,0,177,0,0,0,0,0,0,0,176,6,0,0,43,0,0,0,178,0,0,0,32,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,76,0,0,0,13,0,0,0,6,0,0,0,47,0,0,0,77,0,0,0,7,0,0,0,4,0,0,0,48,0,0,0,20,0,0,0,11,0,0,0,34,0,0,0,35,\n0,0,0,1,0,0,0,33,0,0,0,5,0,0,0,16,0,0,0,11,0,0,0,0,0,0,0,192,6,0,0,43,0,0,0,179,0,0,0,32,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,76,0,0,0,13,0,0,0,6,0,0,0,49,0,0,0,78,0,0,0,7,0,0,0,4,0,0,0,48,0,0,0,20,0,0,0,11,0,0,0,34,0,0,0,35,0,0,0,1,0,0,0,33,0,0,0,5,0,0,0,16,0,0,0,11,0,0,0,0,0,0,0,208,6,0,0,43,0,0,0,180,0,0,0,32,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,76,0,0,0,13,0,0,0,6,0,0,0,50,0,0,0,79,0,0,0,7,0,0,0,4,0,0,0,48,0,0,0,20,0,0,0,11,0,0,0,34,0,0,0,35,0,0,0,1,0,0,0,33,0,0,0,5,0,0,0,16,0,0,0,11,0,0,0,0,0,0,0,224,6,0,\n0,43,0,0,0,181,0,0,0,34,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,14,0,0,0,13,0,0,0,7,0,0,0,51,0,0,0,10,0,0,0,19,0,0,0,6,0,0,0,15,0,0,0,5,0,0,0,11,0,0,0,36,0,0,0,37,0,0,0,1,0,0,0,35,0,0,0,5,0,0,0,16,0,0,0,11,0,0,0,0,0,0,0,240,6,0,0,182,0,0,0,183,0,0,0,36,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,80,0,0,0,52,0,0,0,8,0,0,0,53,0,0,0,10,0,0,0,4,0,0,0,2,0,0,0,54,0,0,0,21,0,0,0,11,0,0,0,37,0,0,0,38,0,0,0,39,0,0,0,81,0,0,0,82,0,0,0,0,0,0,0,0,7,0,0,184,0,0,0,185,0,0,0,40,0,0,0,0,0,0,0,24,7,0,0,184,0,0,0,186,0,0,0,41,0,0,0,0,0,0,\n0,40,7,0,0,184,0,0,0,187,0,0,0,42,0,0,0,0,0,0,0,56,7,0,0,188,0,0,0,189,0,0,0,36,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,83,0,0,0,52,0,0,0,8,0,0,0,55,0,0,0,10,0,0,0,4,0,0,0,2,0,0,0,12,0,0,0,4,0,0,0,11,0,0,0,38,0,0,0,38,0,0,0,39,0,0,0,0,0,0,0,72,7,0,0,51,0,0,0,190,0,0,0,39,0,0,0,0,0,0,0,88,7,0,0,191,0,0,0,192,0,0,0,40,0,0,0,0,0,0,0,104,7,0,0,193,0,0,0,194,0,0,0,41,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,84,0,0,0,56,0,0,0,9,0,0,0,57,0,0,0,10,0,0,0,4,0,0,0,2,0,0,0,58,0,0,0,22,0,0,0,11,0,0,0,42,0,0,0,0,0,0,0,120,7,0,0,55,\n0,0,0,195,0,0,0,32,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,14,0,0,0,13,0,0,0,10,0,0,0,1,0,0,0,10,0,0,0,7,0,0,0,4,0,0,0,15,0,0,0,5,0,0,0,11,0,0,0,15,0,0,0,43,0,0,0,1,0,0,0,43,0,0,0,5,0,0,0,16,0,0,0,11,0,0,0,7,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,192,7,0,0,196,0,0,0,197,0,0,0,44,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,85,0,0,0,13,0,0,0,10,0,0,0,59,0,0,0,10,0,0,0,7,0,0,0,4,0,0,0,60,0,0,0,23,0,0,0,11,0,0,0,44,0,0,0,45,0,0,0,1,0,0,0,45,0,0,0,5,0,0,0,16,0,0,0,11,0,0,0,7,0,0,0,61,0,0,0,62,0,\n0,0,46,0,0,0,46,0,0,0,63,0,0,0,47,0,0,0,2,0,0,0,1,0,0,0,0,0,0,0,224,7,0,0,43,0,0,0,198,0,0,0,48,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,86,0,0,0,13,0,0,0,11,0,0,0,64,0,0,0,87,0,0,0,20,0,0,0,4,0,0,0,65,0,0,0,24,0,0,0,11,0,0,0,15,0,0,0,47,0,0,0,1,0,0,0,49,0,0,0,5,0,0,0,16,0,0,0,11,0,0,0,0,0,0,0,240,7,0,0,43,0,0,0,199,0,0,0,48,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,86,0,0,0,13,0,0,0,11,0,0,0,66,0,0,0,87,0,0,0,20,0,0,0,4,0,0,0,65,0,0,0,24,0,0,0,11,0,0,0,15,0,0,0,47,0,0,0,1,0,0,0,49,0,0,0,5,0,0,0,16,0,0,0,11,0,0,0,0,0,0,\n0,0,8,0,0,43,0,0,0,200,0,0,0,48,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,86,0,0,0,13,0,0,0,11,0,0,0,67,0,0,0,87,0,0,0,20,0,0,0,4,0,0,0,65,0,0,0,24,0,0,0,11,0,0,0,15,0,0,0,47,0,0,0,1,0,0,0,49,0,0,0,5,0,0,0,16,0,0,0,11,0,0,0,0,0,0,0,16,8,0,0,55,0,0,0,201,0,0,0,44,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,88,0,0,0,68,0,0,0,10,0,0,0,69,0,0,0,10,0,0,0,7,0,0,0,4,0,0,0,15,0,0,0,5,0,0,0,11,0,0,0,48,0,0,0,49,0,0,0,1,0,0,0,50,0,0,0,5,0,0,0,16,0,0,0,11,0,0,0,7,0,0,0,70,0,0,0,71,0,0,0,51,0,0,0,50,0,0,0,72,0,0,0,52,0,0,0,3,0,0,0,0,\n0,0,0,32,8,0,0,191,0,0,0,202,0,0,0,53,0,0,0,0,0,0,0,64,8,0,0,55,0,0,0,203,0,0,0,54,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,89,0,0,0,13,0,0,0,12,0,0,0,73,0,0,0,10,0,0,0,21,0,0,0,4,0,0,0,15,0,0,0,5,0,0,0,11,0,0,0,51,0,0,0,52,0,0,0,1,0,0,0,55,0,0,0,5,0,0,0,74,0,0,0,53,0,0,0,7,0,0,0,75,0,0,0,76,0,0,0,56,0,0,0,54,0,0,0,77,0,0,0,57,0,0,0,4,0,0,0,55,0,0,0,0,0,0,0,80,8,0,0,204,0,0,0,205,0,0,0,19,0,0,0,78,0,0,0,25,0,0,0,90,0,0,0,91,0,0,0,20,0,0,0,0,0,0,0,112,8,0,0,191,0,0,0,206,0,0,0,58,0,0,0,0,0,0,0,96,8,0,0,191,0,\n0,0,207,0,0,0,59,0,0,0,0,0,0,0,128,8,0,0,208,0,0,0,209,0,0,0,60,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,92,0,0,0,79,0,0,0,13,0,0,0,80,0,0,0,10,0,0,0,4,0,0,0,2,0,0,0,12,0,0,0,4,0,0,0,11,0,0,0,61,0,0,0,12,0,0,0,0,0,0,0,144,8,0,0,43,0,0,0,210,0,0,0,62,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,93,0,0,0,13,0,0,0,14,0,0,0,81,0,0,0,94,0,0,0,22,0,0,0,4,0,0,0,82,0,0,0,26,0,0,0,11,0,0,0,56,0,0,0,57,0,0,0,1,0,0,0,63,0,0,0,5,0,0,0,16,0,0,0,11,0,0,0,7,0,0,0,0,0,0,0,160,8,0,0,43,0,0,0,211,0,0,0,62,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,93,0,\n0,0,13,0,0,0,14,0,0,0,83,0,0,0,94,0,0,0,22,0,0,0,4,0,0,0,82,0,0,0,26,0,0,0,11,0,0,0,56,0,0,0,58,0,0,0,1,0,0,0,64,0,0,0,5,0,0,0,16,0,0,0,11,0,0,0,8,0,0,0,0,0,0,0,176,8,0,0,43,0,0,0,212,0,0,0,62,0,0,0,8,0,0,0,1,0,0,0,1,0,0,0,93,0,0,0,13,0,0,0,14,0,0,0,84,0,0,0,94,0,0,0,22,0,0,0,4,0,0,0,82,0,0,0,26,0,0,0,11,0,0,0,56,0,0,0,59,0,0,0,1,0,0,0,65,0,0,0,5,0,0,0,16,0,0,0,11,0,0,0,9,0,0,0,0,0,0,0,192,8,0,0,213,0,0,0,214,0,0,0,66,0,0,0,1,0,0,0,2,0,0,0,95,0,0,0,96,0,0,0,85,0,0,0,97,0,0,0,98,0,0,0,86,0,0,0,60,\n0,0,0,61,0,0,0,87,0,0,0,27,0,0,0,0,0,0,0,208,8,0,0,215,0,0,0,216,0,0,0,1,0,0,0,62,0,0,0,12,0,0,0,67,0,0,0,2,0,0,0,68,0,0,0,99,0,0,0,88,0,0,0,89,0,0,0,63,0,0,0,100,0,0,0,217,0,0,0,0,0,0,0,224,8,0,0,215,0,0,0,218,0,0,0,1,0,0,0,62,0,0,0,12,0,0,0,67,0,0,0,2,0,0,0,68,0,0,0,99,0,0,0,88,0,0,0,89,0,0,0,63,0,0,0,100,0,0,0,217,0,0,0,0,0,0,0,248,8,0,0,219,0,0,0,220,0,0,0,28,0,0,0,21,0,0,0,64,0,0,0,90,0,0,0,91,0,0,0,92,0,0,0,65,0,0,0,93,0,0,0,66,0,0,0,101,0,0,0,67,0,0,0,29,0,0,0,94,0,0,0,102,0,0,0,103,0,0,0,\n0,0,0,0,24,9,0,0,221,0,0,0,222,0,0,0,30,0,0,0,22,0,0,0,68,0,0,0,95,0,0,0,96,0,0,0,97,0,0,0,69,0,0,0,98,0,0,0,70,0,0,0,104,0,0,0,71,0,0,0,31,0,0,0,99,0,0,0,105,0,0,0,106,0,0,0,0,0,0,0,40,9,0,0,115,0,0,0,223,0,0,0,21,0,0,0,0,0,0,0,56,9,0,0,115,0,0,0,224,0,0,0,22,0,0,0,0,0,0,0,72,9,0,0,225,0,0,0,226,0,0,0,2,0,0,0,72,0,0,0,13,0,0,0,69,0,0,0,3,0,0,0,70,0,0,0,107,0,0,0,100,0,0,0,101,0,0,0,73,0,0,0,108,0,0,0,227,0,0,0,0,0,0,0,88,9,0,0,35,0,0,0,228,0,0,0,74,0,0,0,109,0,0,0,1,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,\n104,9,0,0,35,0,0,0,229,0,0,0,7,0,0,0,110,0,0,0,1,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,120,9,0,0,35,0,0,0,230,0,0,0,7,0,0,0,111,0,0,0,1,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,144,9,0,0,231,0,0,0,232,0,0,0,19,0,0,0,78,0,0,0,25,0,0,0,90,0,0,0,91,0,0,0,0,0,0,0,184,1,0,0,233,0,0,0,234,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,168,9,0,0,51,0,0,0,235,0,0,0,30,0,0,0,1,0,0,0,0,0,0,0,184,9,0,0,236,0,0,0,237,0,0,0,1,0,0,0,0,0,0,0,200,9,0,0,140,0,0,0,238,0,0,0,75,0,0,0,76,0,0,0,8,0,0,0,0,0,0,0,224,9,0,0,236,0,0,0,239,0,0,0,2,0,\n0,0,0,0,0,0,240,9,0,0,105,0,0,0,240,0,0,0,2,0,0,0,0,0,0,0,0,10,0,0,140,0,0,0,241,0,0,0,77,0,0,0,78,0,0,0,9,0,0,0,0,0,0,0,16,10,0,0,105,0,0,0,242,0,0,0,3,0,0,0,0,0,0,0,32,10,0,0,243,0,0,0,244,0,0,0,14,0,0,0,0,0,0,0,72,10,0,0,233,0,0,0,245,0,0,0,15,0,0,0,11,0,0,0,112,0,0,0,0,0,0,0,88,10,0,0,246,0,0,0,247,0,0,0,16,0,0,0,12,0,0,0,113,0,0,0,0,0,0,0,104,10,0,0,243,0,0,0,248,0,0,0,17,0,0,0,0,0,0,0,120,10,0,0,243,0,0,0,249,0,0,0,18,0,0,0,0,0,0,0,136,10,0,0,250,0,0,0,251,0,0,0,32,0,0,0,33,0,0,0,102,0,0,0,\n0,0,0,0,144,10,0,0,252,0,0,0,253,0,0,0,0,0,0,0,152,10,0,0,254,0,0,0,255,0,0,0,66,0,0,0,1,0,0,0,2,0,0,0,95,0,0,0,96,0,0,0,85,0,0,0,114,0,0,0,115,0,0,0,86,0,0,0,60,0,0,0,61,0,0,0,87,0,0,0,27,0,0,0,84,100,0,0,255,255,255,255,5,0,0,0,0,0,0,0,0,0,0,0,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,0,0,0,35,0,0,0,209,102,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,\n0,184,10,0,0,0,1,0,0,1,1,0,0,2,1,0,0,3,1,0,0,36,0,0,0,4,0,0,0,19,0,0,0,71,0,0,0,0,0,0,0,224,10,0,0,0,1,0,0,4,1,0,0,2,1,0,0,3,1,0,0,36,0,0,0,5,0,0,0,20,0,0,0,72,0,0,0,0,0,0,0,16,11,0,0,0,1,0,0,5,1,0,0,2,1,0,0,3,1,0,0,36,0,0,0,6,0,0,0,21,0,0,0,73,0,0,0,123,32,118,97,114,32,115,101,108,102,32,61,32,77,111,100,117,108,101,91,39,103,101,116,67,97,99,104,101,39,93,40,77,111,100,117,108,101,91,39,67,111,110,99,114,101,116,101,67,111,110,116,97,99,116,82,101,115,117,108,116,67,97,108,108,98,97,99,107,39,\n93,41,91,36,48,93,59,32,105,102,32,40,33,115,101,108,102,46,104,97,115,79,119,110,80,114,111,112,101,114,116,121,40,39,97,100,100,83,105,110,103,108,101,82,101,115,117,108,116,39,41,41,32,116,104,114,111,119,32,39,97,32,74,83,73,109,112,108,101,109,101,110,116,97,116,105,111,110,32,109,117,115,116,32,105,109,112,108,101,109,101,110,116,32,97,108,108,32,102,117,110,99,116,105,111,110,115,44,32,121,111,117,32,102,111,114,103,111,116,32,67,111,110,99,114,101,116,101,67,111,110,116,97,99,116,82,101,115,\n117,108,116,67,97,108,108,98,97,99,107,58,58,97,100,100,83,105,110,103,108,101,82,101,115,117,108,116,46,39,59,32,114,101,116,117,114,110,32,115,101,108,102,91,39,97,100,100,83,105,110,103,108,101,82,101,115,117,108,116,39,93,40,36,49,44,36,50,44,36,51,44,36,52,44,36,53,44,36,54,44,36,55,41,59,32,125,0,50,57,67,111,110,99,114,101,116,101,67,111,110,116,97,99,116,82,101,115,117,108,116,67,97,108,108,98,97,99,107,0,78,49,54,98,116,67,111,108,108,105,115,105,111,110,87,111,114,108,100,50,49,67,111,110,\n116,97,99,116,82,101,115,117,108,116,67,97,108,108,98,97,99,107,69,0,78,49,54,98,116,67,111,108,108,105,115,105,111,110,87,111,114,108,100,50,52,67,108,111,115,101,115,116,82,97,121,82,101,115,117,108,116,67,97,108],\"i8\",4,d.g);\nwa([108,98,97,99,107,69,0,78,49,54,98,116,67,111,108,108,105,115,105,111,110,87,111,114,108,100,49,55,82,97,121,82,101,115,117,108,116,67,97,108,108,98,97,99,107,69,0,49,57,98,116,71,104,111,115,116,80,97,105,114,67,97,108,108,98,97,99,107,0,50,53,98,116,79,118,101,114,108,97,112,112,105,110,103,80,97,105,114,67,97,108,108,98,97,99,107,0,50,48,98,116,68,101,102,97,117,108,116,77,111,116,105,111,110,83,116,97,116,101,0,49,51,98,116,77,111,116,105,111,110,83,116,97,116,101,0,49,56,98,116,86,101,104,\n105,99,108,101,82,97,121,99,97,115,116,101,114,0,78,49,54,98,116,67,111,108,108,105,115,105,111,110,87,111,114,108,100,50,55,67,108,111,115,101,115,116,67,111,110,118,101,120,82,101,115,117,108,116,67,97,108,108,98,97,99,107,69,0,78,49,54,98,116,67,111,108,108,105,115,105,111,110,87,111,114,108,100,50,48,67,111,110,118,101,120,82,101,115,117,108,116,67,97,108,108,98,97,99,107,69,0,50,51,98,116,68,101,102,97,117,108,116,83,111,102,116,66,111,100,121,83,111,108,118,101,114,0,49,54,98,116,83,111,102,\n116,66,111,100,121,83,111,108,118,101,114,0,52,49,98,116,83,111,102,116,66,111,100,121,82,105,103,105,100,66,111,100,121,67,111,108,108,105,115,105,111,110,67,111,110,102,105,103,117,114,97,116,105,111,110,0,78,51,53,98,116,83,111,102,116,66,111,100,121,67,111,110,99,97,118,101,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,49,55,83,119,97,112,112,101,100,67,114,101,97,116,101,70,117,110,99,69,0,51,48,98,116,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,\n109,67,114,101,97,116,101,70,117,110,99,0,78,51,53,98,116,83,111,102,116,66,111,100,121,67,111,110,99,97,118,101,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,49,48,67,114,101,97,116,101,70,117,110,99,69,0,78,50,57,98,116,83,111,102,116,82,105,103,105,100,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,49,48,67,114,101,97,116,101,70,117,110,99,69,0,78,50,56,98,116,83,111,102,116,83,111,102,116,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,\n116,104,109,49,48,67,114,101,97,116,101,70,117,110,99,69,0,83,111,102,116,66,111,100,121,77,97,116,101,114,105,97,108,68,97,116,97,0,83,111,102,116,66,111,100,121,78,111,100,101,68,97,116,97,0,83,111,102,116,66,111,100,121,76,105,110,107,68,97,116,97,0,83,111,102,116,66,111,100,121,70,97,99,101,68,97,116,97,0,83,111,102,116,66,111,100,121,84,101,116,114,97,68,97,116,97,0,83,111,102,116,82,105,103,105,100,65,110,99,104,111,114,68,97,116,97,0,102,108,111,97,116,0,83,111,102,116,66,111,100,121,80,111,\n115,101,68,97,116,97,0,83,111,102,116,66,111,100,121,67,108,117,115,116,101,114,68,97,116,97,0,105,110,116,0,98,116,83,111,102,116,66,111,100,121,74,111,105,110,116,68,97,116,97,0,98,116,83,111,102,116,66,111,100,121,70,108,111,97,116,68,97,116,97,0,49,48,98,116,83,111,102,116,66,111,100,121,0,78,49,48,98,116,83,111,102,116,66,111,100,121,49,53,82,97,121,70,114,111,109,84,111,67,97,115,116,101,114,69,0,78,54,98,116,68,98,118,116,56,73,67,111,108,108,105,100,101,69,0,78,49,48,98,116,83,111,102,116,\n66,111,100,121,53,74,111,105,110,116,69,0,78,49,48,98,116,83,111,102,116,66,111,100,121,54,67,74,111,105,110,116,69,0,83,111,102,116,66,111,100,121,0,50,52,98,116,83,111,102,116,66,111,100,121,67,111,108,108,105,115,105,111,110,83,104,97,112,101,0,85,112,100,97,116,101,67,108,117,115,116,101,114,115,0,83,111,102,116,66,111,100,121,32,97,112,112,108,121,70,111,114,99,101,115,0,65,112,112,108,121,67,108,117,115,116,101,114,115,0,98,116,67,111,110,118,101,120,73,110,116,101,114,110,97,108,83,104,97,\n112,101,68,97,116,97,0,83,79,70,84,67,76,85,83,84,69,82,0,50,55,98,116,83,111,102,116,67,108,117,115,116,101,114,67,111,108,108,105,115,105,111,110,83,104,97,112,101,0,78,49,53,98,116,83,111,102,116,67,111,108,108,105,100,101,114,115,49,50,67,111,108,108,105,100,101,67,76,95,82,83,69,0,78,49,53,98,116,83,111,102,116,67,111,108,108,105,100,101,114,115,49,49,67,108,117,115,116,101,114,66,97,115,101,69,0,78,49,53,98,116,83,111,102,116,67,111,108,108,105,100,101,114,115,49,51,67,111,108,108,105,100,101,\n83,68,70,95,82,83,69,0,78,49,53,98,116,83,111,102,116,67,111,108,108,105,100,101,114,115,49,50,67,111,108,108,105,100,101,86,70,95,83,83,69,0,78,49,53,98,116,83,111,102,116,67,111,108,108,105,100,101,114,115,49,50,67,111,108,108,105,100,101,67,76,95,83,83,69,0,50,57,98,116,83,111,102,116,82,105,103,105,100,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,0,50,48,98,116,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,0,84,114,105,97,110,103,108,101,0,49,53,\n98,116,84,114,105,97,110,103,108,101,83,104,97,112,101,0,78,49,50,98,116,67,111,110,118,101,120,67,97,115,116,49,48,67,97,115,116,82,101,115,117,108,116,69,0,90,78,51,53,98,116,83,111,102,116,66,111,100,121,67,111,110,99,97,118,101,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,50,49,99,97,108,99,117,108,97,116,101,84,105,109,101,79,102,73,109,112,97,99,116,69,80,49,55,98,116,67,111,108,108,105,115,105,111,110,79,98,106,101,99,116,83,49,95,82,75,49,54,98,116,68,105,115,112,\n97,116,99,104,101,114,73,110,102,111,80,49,54,98,116,77,97,110,105,102,111,108,100,82,101,115,117,108,116,69,51,49,76,111,99,97,108,84,114,105,97,110,103,108,101,83,112,104,101,114,101,67,97,115,116,67,97,108,108,98,97,99,107,0,50,54,98,116,83,111,102,116,66,111,100,121,84,114,105,97,110,103,108,101,67,97,108,108,98,97,99,107,0,51,53,98,116,83,111,102,116,66,111,100,121,67,111,110,99,97,118,101,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,0,115,111,108,118,101,83,111,102,\n116,67,111,110,115,116,114,97,105,110,116,115,0,112,114,101,100,105,99,116,85,110,99,111,110,115,116,114,97,105,110,116,77,111,116,105,111,110,83,111,102,116,66,111,100,121,0,114,97,121,84,101,115,116,0,50,51,98,116,83,111,102,116,83,105,110,103,108,101,82,97,121,67,97,108,108,98,97,99,107,0,50,51,98,116,66,114,111,97,100,112,104,97,115,101,82,97,121,67,97,108,108,98,97,99,107,0,50,52,98,116,66,114,111,97,100,112,104,97,115,101,65,97,98,98,67,97,108,108,98,97,99,107,0,50,52,98,116,83,111,102,116,\n82,105,103,105,100,68,121,110,97,109,105,99,115,87,111,114,108,100,0,50,56,98,116,83,111,102,116,83,111,102,116,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,0,98,116,82,105,103,105,100,66,111,100,121,70,108,111,97,116,68,97,116,97,0,49,49,98,116,82,105,103,105,100,66,111,100,121,0,105,110,116,101,114,110,97,108,83,105,110,103,108,101,83,116,101,112,83,105,109,117,108,97,116,105,111,110,0,117,112,100,97,116,101,65,99,116,105,111,110,115,0,99,114,101,97,116,101,80,114,101,100,\n105,99,116,105,118,101,67,111,110,116,97,99,116,115,0,114,101,108,101,97,115,101,32,112,114,101,100,105,99,116,105,118,101,32,99,111,110,116,97,99,116,32,109,97,110,105,102,111,108,100,115,0,112,114,101,100,105,99,116,105,118,101,32,99,111,110,118,101,120,83,119,101,101,112,84,101,115,116,0,51,52,98,116,67,108,111,115,101,115,116,78,111,116,77,101,67,111,110,118,101,120,82,101,115,117,108,116,67,97,108,108,98,97,99,107,0,117,112,100,97,116,101,65,99,116,105,118,97,116,105,111,110,83,116,97,116,101,\n0,115,111,108,118,101,67,111,110,115,116,114,97,105,110,116,115,0,99,97,108,99,117,108,97,116,101,83,105,109,117,108,97,116,105,111,110,73,115,108,97,110,100,115,0,105,110,116,101,103,114,97,116,101,84,114,97,110,115,102,111,114,109,115,0,67,67,68,32,109,111,116,105,111,110,32,99,108,97,109,112,105,110,103,0,97,112,112,108,121,32,115,112,101,99,117,108,97,116,105,118,101,32,99,111,110,116,97,99,116,32,114,101,115,116,105,116,117,116,105,111,110,0,112,114,101,100,105,99,116,85,110,99,111,110,115,116,\n114,97,105,110,116,77,111,116,105,111,110,0,115,121,110,99,104,114,111,110,105,122,101,77,111,116,105,111,110,83,116,97,116,101,115,0,115,116,101,112,83,105,109,117,108,97,116,105,111,110,0,98,116,68,121,110,97,109,105,99,115,87,111,114,108,100,70,108,111,97,116,68,97,116,97,0,100,101,98,117,103,68,114,97,119,87,111,114,108,100,0,50,51,98,116,68,105,115,99,114,101,116,101,68,121,110,97,109,105,99,115,87,111,114,108,100,0,49,53,98,116,68,121,110,97,109,105,99,115,87,111,114,108,100,0,50,55,73,110,\n112,108,97,99,101,83,111,108,118,101,114,73,115,108,97,110,100,67,97,108,108,98,97,99,107,0,78,50,53,98,116,83,105,109,117,108,97,116,105,111,110,73,115,108,97,110,100,77,97,110,97,103,101,114,49,52,73,115,108,97,110,100,67,97,108,108,98,97,99,107,69,0,98,116,71,101,110,101,114,105,99,54,68,111,102,67,111,110,115,116,114,97,105,110,116,68,97,116,97,0,49,55,98,116,84,121,112,101,100,67,111,110,115,116,114,97,105,110,116,0,49,51,98,116,84,121,112,101,100,79,98,106,101,99,116,0,50,51,98,116,71,101,110,\n101,114,105,99,54,68,111,102,67,111,110,115,116,114,97,105,110,116,0,98,116,71,101,110,101,114,105,99,54,68,111,102,83,112,114,105,110,103,67,111,110,115,116,114,97,105,110,116,68,97,116,97,0,50,57,98,116,71,101,110,101,114,105,99,54,68,111,102,83,112,114,105,110,103,67,111,110,115,116,114,97,105,110,116,0,98,116,80,111,105,110,116,50,80,111,105,110,116,67,111,110,115,116,114,97,105,110,116,70,108,111,97,116,68,97,116,97,0,50,51,98,116,80,111,105,110,116,50,80,111,105,110,116,67,111,110,115,116,114,\n97,105,110,116,0,98,116,84,121,112,101,100,67,111,110,115,116,114,97,105,110,116,70,108,111,97,116,68,97,116,97,0,98,116,83,108,105,100,101,114,67,111,110,115,116,114,97,105,110,116,68,97,116,97,0,49,56,98,116,83,108,105,100,101,114,67,111,110,115,116,114,97,105,110,116,0,98,116,67,111,110,101,84,119,105,115,116,67,111,110,115,116,114,97,105,110,116,68,97,116,97,0,50,49,98,116,67,111,110,101,84,119,105,115,116,67,111,110,115,116,114,97,105,110,116,0,98,116,72,105,110,103,101,67,111,110,115,116,114,\n97,105,110,116,70,108,111,97,116,68,97,116,97,0,49,55,98,116,72,105,110,103,101,67,111,110,115,116,114,97,105,110,116,0,115,111,108,118,101,71,114,111,117,112,67,97,99,104,101,70,114,105,101,110,100,108,121,73,116,101,114,97,116,105,111,110,115,0,115,111,108,118,101,71,114,111,117,112,67,97,99,104,101,70,114,105,101,110,100,108,121,83,101,116,117,112,0,115,111,108,118,101,71,114,111,117,112,0,51,53,98,116,83,101,113,117,101,110,116,105,97,108,73,109,112,117,108,115,101,67,111,110,115,116,114,97,105,\n110,116,83,111,108,118,101,114,0,49,56,98,116,67,111,110,115,116,114,97,105,110,116,83,111,108,118,101,114,0,49,54,98,116,82,97,121,99,97,115,116,86,101,104,105,99,108,101,0,49,55,98,116,65,99,116,105,111,110,73,110,116,101,114,102,97,99,101,0,50,53,98,116,68,101,102,97,117,108,116,86,101,104,105,99,108,101,82,97,121,99,97,115,116,101,114,0,52,51,98,116,75,105,110,101,109,97,116,105,99,67,108,111,115,101,115,116,78,111,116,77,101,67,111,110,118,101,120,82,101,115,117,108,116,67,97,108,108,98,97,99,\n107,0,51,48,98,116,75,105,110,101,109,97,116,105,99,67,104,97,114,97,99,116,101,114,67,111,110,116,114,111,108,108,101,114,0,51,48,98,116,67,104,97,114,97,99,116,101,114,67,111,110,116,114,111,108,108,101,114,73,110,116,101,114,102,97,99,101,0,50,50,98,116,83,117,98,115,105,109,112,108,101,120,67,111,110,118,101,120,67,97,115,116,0,49,50,98,116,67,111,110,118,101,120,67,97,115,116,0,98,116,67,111,108,108,105,115,105,111,110,79,98,106,101,99,116,70,108,111,97,116,68,97,116,97,0,49,55,98,116,67,111,\n108,108,105,115,105,111,110,79,98,106,101,99,116,0,49,51,98,116,71,104,111,115,116,79,98,106,101,99,116,0,50,52,98,116,80,97,105,114,67,97,99,104,105,110,103,71,104,111,115,116,79,98,106,101,99,116,0,50,51,98,116,67,111,108,108,105,115,105,111,110,80,97,105,114,67,97,108,108,98,97,99,107,0,49,55,98,116,79,118,101,114,108,97,112,67,97,108,108,98,97,99,107,0,50,49,98,116,67,111,108,108,105,115,105,111,110,68,105,115,112,97,116,99,104,101,114,0,51,49,98,116,68,101,102,97,117,108,116,67,111,108,108,105,\n115,105,111,110,67,111,110,102,105,103,117,114,97,116,105,111,110,0,50,52,98,116,67,111,108,108,105,115,105,111,110,67,111,110,102,105,103,117,114,97,116,105,111,110,0,78,51,49,98,116,67,111,110,118,101,120,80,108,97,110,101,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,49,48,67,114,101,97,116,101,70,117,110,99,69,0,78,50,54,98,116,66,111,120,66,111,120,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,49,48,67,114,101,97,116,101,70,117,110,99,69,0,78,51,\n52,98,116,83,112,104,101,114,101,84,114,105,97,110,103,108,101,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,49,48,67,114,101,97,116,101,70,117,110,99,69,0,78,51,50,98,116,83,112,104,101,114,101,83,112,104,101,114,101,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,49,48,67,114,101,97,116,101,70,117,110,99,69,0,78,49,54,98,116,69,109,112,116,121,65,108,103,111,114,105,116,104,109,49,48,67,114,101,97,116,101,70,117,110,99,69,0,78,50,56,98,116,67,111,109,\n112,111,117,110,100,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,49,55,83,119,97,112,112,101,100,67,114,101,97,116,101,70,117,110,99,69,0,78,51,54,98,116,67,111,109,112,111,117,110,100,67,111,109,112,111,117,110,100,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,49,48,67,114,101,97,116,101,70,117,110,99,69,0,78,50,56,98,116,67,111,109,112,111,117,110,100,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,49,48,67,114,101,97,116,101,\n70,117,110,99,69,0,78,51,51,98,116,67,111,110,118,101,120,67,111,110,99,97,118,101,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,49,55,83,119,97,112,112,101,100,67,114,101,97,116,101,70,117,110,99,69,0,78,51,51,98,116,67,111,110,118,101,120,67,111,110,99,97,118,101,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,49,48,67,114,101,97,116,101,70,117,110,99,69,0,50,53,98,116,83,105,109,117,108,97,116,105,111,110,73,115,108,97,110,100,77,97,110,97,103,101,\n114,0,105,115,108,97,110,100,85,110,105,111,110,70,105,110,100,65,110,100,81,117,105,99,107,83,111,114,116,0,112,114,111,99,101,115,115,73,115,108,97,110,100,115,0,51,49,98,116,67,111,110,118,101,120,80,108,97,110,101,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,0,90,78,51,51,98,116,67,111,110,118,101,120,67,111,110,99,97,118,101,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,50,49,99,97,108,99,117,108,97,116,101,84,105,109,101,79,102,73,109,112,97,\n99,116,69,80,49,55,98,116,67,111,108,108,105,115,105,111,110,79,98,106,101,99,116,83,49,95,82,75,49,54,98,116,68,105,115,112,97,116,99,104,101,114,73,110,102,111,80,49,54,98,116,77,97,110,105,102,111,108,100,82,101,115,117,108,116,69,51,49,76,111,99,97,108,84,114,105,97,110,103,108,101,83,112,104,101,114,101,67,97,115,116,67,97,108,108,98,97,99,107,0,50,52,98,116,67,111,110,118,101,120,84,114,105,97,110,103,108,101,67,97,108,108,98,97,99,107,0,51,51,98,116,67,111,110,118,101,120,67,111,110,99,97,\n118,101,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,0,50,54,98,116,66,111,120,66,111,120,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,0,49,54,98,116,77,97,110,105,102,111,108,100,82,101,115,117,108,116,0,78,51,54,98,116,68,105,115,99,114,101,116,101,67,111,108,108,105,115,105,111,110,68,101,116,101,99,116,111,114,73,110,116,101,114,102,97,99,101,54,82,101,115,117,108,116,69,0,112,101,114,102,111,114,109,68,105,115,99,114,101,116,101,67,111,108,108,\n105,115,105,111,110,68,101,116,101,99,116,105,111,110,0,100,105,115,112,97,116,99,104,65,108,108,67,111,108,108,105,115,105,111,110,80,97,105,114,115,0,90,78,49,54,98,116,67,111,108,108,105,115,105,111,110,87,111,114,108,100,50,49,114,97,121,84,101,115,116,83,105,110,103,108,101,73,110,116,101,114,110,97,108,69,82,75,49,49,98,116,84,114,97,110,115,102,111,114,109,83,50,95,80,75,50,52,98,116,67,111,108,108,105,115,105,111,110,79,98,106,101,99,116,87,114,97,112,112,101,114,82,78,83,95,49,55,82,97,121,\n82,101,115,117,108,116,67,97,108,108,98,97,99,107,69,69,49,53,76,111,99,97,108,73,110,102,111,65,100,100,101,114,50,0,90,78,49,54,98,116,67,111,108,108,105,115,105,111,110,87,111,114,108,100,50,49,114,97,121,84,101,115,116,83,105,110,103,108,101,73,110,116,101,114,110,97,108,69,82,75,49,49,98,116,84,114,97,110,115,102,111,114,109,83,50,95,80,75,50,52,98,116,67,111,108,108,105,115,105,111,110,79,98,106,101,99,116,87,114,97,112,112,101,114,82,78,83,95,49,55,82,97,121,82,101,115,117,108,116,67,97,108,\n108,98,97,99,107,69,69,57,82,97,121,84,101,115,116,101,114,0,90,78,49,54,98,116,67,111,108,108,105,115,105,111,110,87,111,114,108,100,50,49,114,97,121,84,101,115,116,83,105,110,103,108,101,73,110,116,101,114,110,97,108,69,82,75,49,49,98,116,84,114,97,110,115,102,111,114,109,83,50,95,80,75,50,52,98,116,67,111,108,108,105,115,105,111,110,79,98,106,101,99,116,87,114,97,112,112,101,114,82,78,83,95,49,55,82,97,121,82,101,115,117,108,116,67,97,108,108,98,97,99,107,69,69,50,57,66,114,105,100,103,101,84,\n114,105,97,110,103,108,101,82,97,121,99,97,115,116,67,97,108,108,98,97,99,107,95,48,0,90,78,49,54,98,116,67,111,108,108,105,115,105,111,110,87,111,114,108,100,50,49,114,97,121,84,101,115,116,83,105,110,103,108,101,73,110,116,101,114,110,97,108,69,82,75,49,49,98,116,84,114,97,110,115,102,111,114,109,83,50,95,80,75,50,52,98,116,67,111,108,108,105,115,105,111,110,79,98,106,101,99,116,87,114,97,112,112,101,114,82,78,83,95,49,55,82,97,121,82,101,115,117,108,116,67,97,108,108,98,97,99,107,69,69,50,57,66,\n114,105,100,103,101,84,114,105,97,110,103,108,101,82,97,121,99,97,115,116,67,97,108,108,98,97,99,107,0,49,57,98,116,83,105,110,103,108,101,82,97,121,67,97,108,108,98,97,99,107,0,49,55,68,101,98,117,103,68,114,97,119,99,97,108,108,98,97,99,107,0,99,97,108,99,117,108,97,116,101,79,118,101,114,108,97,112,112,105,110,103,80,97,105,114,115,0,117,112,100,97,116,101,65,97,98,98,115,0,1,79,118,101,114,102,108,111,119,32,105,110,32,65,65,66,66,44,32,111,98,106,101,99,116,32,114,101,109,111,118,101,100,32,\n102,114,111,109,32,115,105,109,117,108,97,116,105,111,110,0,73,102,32,121,111,117,32,99,97,110,32,114,101,112,114,111,100,117,99,101,32,116,104,105,115,44,32,112,108,101,97,115,101,32,101,109,97,105,108,32,98,117,103,115,64,99,111,110,116,105,110,117,111,117,115,112,104,121,115,105,99,115,46,99,111,109,10,0,80,108,101,97,115,101,32,105,110,99,108,117,100,101,32,97,98,111,118,101,32,105,110,102,111,114,109,97,116,105,111,110,44,32,121,111,117,114,32,80,108,97,116,102,111,114,109,44,32,118,101,114,\n115,105,111,110,32,111,102,32,79,83,46,10,0,84,104,97,110,107,115,46,10,0,49,54,98,116,67,111,108,108,105,115,105,111,110,87,111,114,108,100,0,99,111,110,118,101,120,83,119,101,101,112,67,111,109,112,111,117,110,100,0,90,78,49,54,98,116,67,111,108,108,105,115,105,111,110,87,111,114,108,100,50,53,111,98,106,101,99,116,81,117,101,114,121,83,105,110,103,108,101,73,110,116,101,114,110,97,108,69,80,75,49,51,98,116,67,111,110,118,101,120,83,104,97,112,101,82,75,49,49,98,116,84,114,97,110,115,102,111,114,\n109,83,53,95,80,75,50,52,98,116,67,111,108,108,105,115,105,111,110,79,98,106,101,99,116,87,114,97,112,112,101,114,82,78,83,95,50,48,67,111,110,118,101,120,82,101,115,117,108,116,67,97,108,108,98,97,99,107,69,102,69,49,52,76,111,99,97,108,73,110,102,111,65,100,100,101,114,0,90,78,49,54,98,116,67,111,108,108,105,115,105,111,110,87,111,114,108,100,50,53,111,98,106,101,99,116,81,117,101,114,121,83,105,110,103,108,101,73,110,116,101,114,110,97,108,69,80,75,49,51,98,116,67,111,110,118,101,120,83,104,97,\n112,101,82,75,49,49,98,116,84,114,97,110,115,102,111,114,109,83,53,95,80,75,50,52,98,116,67,111,108,108,105,115,105,111,110,79,98,106,101,99,116,87,114,97,112,112,101,114,82,78,83,95,50,48,67,111,110,118,101,120,82,101,115,117,108,116,67,97,108,108,98,97,99,107,69,102,69,51,50,66,114,105,100,103,101,84,114,105,97,110,103,108,101,67,111,110,118,101,120,99,97,115,116,67,97,108,108,98,97,99,107,95,48,0,90,78,49,54,98,116,67,111,108,108,105,115,105,111,110,87,111,114,108,100,50,53,111,98,106,101,99,116,\n81,117,101,114,121,83,105,110,103,108,101,73,110,116,101,114,110,97,108,69,80,75,49,51,98,116,67,111,110,118,101,120,83,104,97,112,101,82,75,49,49,98,116,84,114,97,110,115,102,111,114,109,83,53,95,80,75,50,52,98,116,67,111,108,108,105,115,105,111,110,79,98,106,101,99,116,87,114,97,112,112,101,114,82,78,83,95,50,48,67,111,110,118,101,120,82,101,115,117,108,116,67,97,108,108,98,97,99,107,69,102,69,51,50,66,114,105,100,103,101,84,114,105,97,110,103,108,101,67,111,110,118,101,120,99,97,115,116,67,97,\n108,108,98,97,99,107,0,99,111,110,118,101,120,83,119,101,101,112,84,101,115,116,0,50,49,98,116,83,105,110,103,108,101,83,119,101,101,112,67,97,108,108,98,97,99,107,0,50,51,98,116,66,114,105,100,103,101,100,77,97,110,105,102,111,108,100,82,101,115,117,108,116,0,50,51,98,116,83,105,110,103,108,101,67,111,110,116,97,99,116,67,97,108,108,98,97,99,107,0,51,52,98,116,83,112,104,101,114,101,84,114,105,97,110,103,108,101,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,0,50,52,98,116,\n80,101,114,116,117,114,98,101,100,67,111,110,116,97,99,116,82,101,115,117,108,116,0,90,78,50,51,98,116,67,111,110,118,101,120,67,111,110,118,101,120,65,108,103,111,114,105,116,104,109,49,54,112,114,111,99,101,115,115,67,111,108,108,105,115,105,111,110,69,80,75,50,52,98,116,67,111,108,108,105,115,105,111,110,79,98,106,101,99,116,87,114,97,112,112,101,114,83,50,95,82,75,49,54,98,116,68,105,115,112,97,116,99,104,101,114,73,110,102,111,80,49,54,98,116,77,97,110,105,102,111,108,100,82,101,115,117,108,\n116,69,50,49,98,116,87,105,116,104,111,117,116,77,97,114,103,105,110,82,101,115,117,108,116,0,90,78,50,51,98,116,67,111,110,118,101,120,67,111,110,118,101,120,65,108,103,111,114,105,116,104,109,49,54,112,114,111,99,101,115,115,67,111,108,108,105,115,105,111,110,69,80,75,50,52,98,116,67,111,108,108,105,115,105,111,110,79,98,106,101,99,116,87,114,97,112,112,101,114,83,50,95,82,75,49,54,98,116,68,105,115,112,97,116,99,104,101,114,73,110,102,111,80,49,54,98,116,77,97,110,105,102,111,108,100,82,101,115,\n117,108,116,69,49,51,98,116,68,117,109,109,121,82,101,115,117,108,116,0,50,51,98,116,67,111,110,118,101,120,67,111,110,118,101,120,65,108,103,111,114,105,116,104,109,0,78,50,51,98,116,67,111,110,118,101,120,67,111,110,118,101,120,65,108,103,111,114,105,116,104,109,49,48,67,114,101,97,116,101,70,117,110,99,69,0,50,50,98,116,67,111,109,112,111,117,110,100,76,101,97,102,67,97,108,108,98,97,99,107,0,50,56,98,116,67,111,109,112,111,117,110,100,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,\n116,104,109,0,51,48,98,116,67,111,109,112,111,117,110,100,67,111,109,112,111,117,110,100,76,101,97,102,67,97,108,108,98,97,99,107,0,51,54,98,116,67,111,109,112,111,117,110,100,67,111,109,112,111,117,110,100,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,0,98,116,67,111,109,112,111,117,110,100,83,104,97,112,101,67,104,105,108,100,68,97,116,97,0,98,116,67,111,109,112,111,117,110,100,83,104,97,112,101,68,97,116,97,0,67,111,109,112,111,117,110,100,0,49,53,98,116,67,111,109,112,\n111,117,110,100,83,104,97,112,101,0,98,116,67,111,110,101,83,104,97,112,101,68,97,116,97,0,67,111,110,101,0,49,49,98,116,67,111,110,101,83,104,97,112,101,0,67,111,110,101,90,0,49,50,98,116,67,111,110,101,83,104,97,112,101,90,0,67,111,110,101,88,0,49,50,98,116,67,111,110,101,83,104,97,112,101,88,0,83,80,72,69,82,69,0,49,51,98,116,83,112,104,101,114,101,83,104,97,112,101,0,90,78,75,50,50,98,116,66,118,104,84,114,105,97,110,103,108,101,77,101,115,104,83,104,97,112,101,49,57,112,114,111,99,101,115,115,\n65,108,108,84,114,105,97,110,103,108,101,115,69,80,49,56,98,116,84,114,105,97,110,103,108,101,67,97,108,108,98,97,99,107,82,75,57,98,116,86,101,99,116,111,114,51,83,52,95,69,50,49,77,121,78,111,100,101,79,118,101,114,108,97,112,67,97,108,108,98,97,99,107,0,50,49,98,116,78,111,100,101,79,118,101,114,108,97,112,67,97,108,108,98,97,99,107,0,98,116,84,114,105,97,110,103,108,101,77,101,115,104,83,104,97,112,101,68,97,116,97,0,66,86,72,84,82,73,65,78,71,76,69,77,69,83,72,0,50,50,98,116,66,118,104,84,114,\n105,97,110,103,108,101,77,101,115,104,83,104,97,112,101,0,90,78,50,50,98,116,66,118,104,84,114,105,97,110,103,108,101,77,101,115,104,83,104,97,112,101,49,52,112,101,114,102,111,114,109,82,97,121,99,97,115,116,69,80,49,56,98,116,84,114,105,97,110,103,108,101,67,97,108,108,98,97,99,107,82,75,57,98,116,86,101,99,116,111,114,51,83,52,95,69,50,49,77,121,78,111,100,101,79,118,101,114,108,97,112,67,97,108,108,98,97,99,107,0,90,78,50,50,98,116,66,118,104,84,114,105,97,110,103,108,101,77,101,115,104,83,104,\n97,112,101,49,55,112,101,114,102,111,114,109,67,111,110,118,101,120,99,97,115,116,69,80,49,56,98,116,84,114,105,97,110,103,108,101,67,97,108,108,98,97,99,107,82,75,57,98,116,86,101,99,116,111,114,51,83,52,95,83,52,95,83,52,95,69,50,49,77,121,78,111,100,101,79,118,101,114,108,97,112,67,97,108,108,98,97,99,107,0,50,49,83,117,112,112,111,114,116,86,101,114,116,101,120,67,97,108,108,98,97,99,107,0,90,78,75,49,57,98,116,84,114,105,97,110,103,108,101,77,101,115,104,83,104,97,112,101,49,57,112,114,111,99,\n101,115,115,65,108,108,84,114,105,97,110,103,108,101,115,69,80,49,56,98,116,84,114,105,97,110,103,108,101,67,97,108,108,98,97,99,107,82,75,57,98,116,86,101,99,116,111,114,51,83,52,95,69,49,54,70,105,108,116,101,114,101,100,67,97,108,108,98,97,99,107,0,84,82,73,65,78,71,76,69,77,69,83,72,0,49,57,98,116,84,114,105,97,110,103,108,101,77,101,115,104,83,104,97,112,101,0,98,116,83,116,97,116,105,99,80,108,97,110,101,83,104,97,112,101,68,97,116,97,0,83,84,65,84,73,67,80,76,65,78,69,0,49,56,98,116,83,116,\n97,116,105,99,80,108,97,110,101,83,104,97,112,101,0,50,51,98,116,80,111,108,121,104,101,100,114,97,108,67,111,110,118,101,120,83,104,97,112,101,0,51,52,98,116,80,111,108,121,104,101,100,114,97,108,67,111,110,118,101,120,65,97,98,98,67,97,99,104,105,110,103,83,104,97,112,101,0,98,116,67,111,108,108,105,115,105,111,110,83,104,97,112,101,68,97,116,97,0,49,54,98,116,67,111,108,108,105,115,105,111,110,83,104,97,112,101,0,49,51,98,116,67,111,110,118,101,120,83,104,97,112,101,0,50,49,98,116,67,111,110,118,\n101,120,73,110,116,101,114,110,97,108,83,104,97,112,101,0,98,116,67,111,110,118,101,120,72,117,108,108,83,104,97,112,101,68,97,116,97,0,67,111,110,118,101,120,0,49,55,98,116,67,111,110,118,101,120,72,117,108,108,83,104,97,112,101,0,49,56,98,116,84,114,105,97,110,103,108,101,67,97,108,108,98,97,99,107,0,51,49,98,116,73,110,116,101,114,110,97,108,84,114,105,97,110,103,108,101,73,110,100,101,120,67,97,108,108,98,97,99,107,0,98,116,67,97,112,115,117,108,101,83,104,97,112,101,68,97,116,97,0,67,97,112,\n115,117,108,101,83,104,97,112,101,0,49,52,98,116,67,97,112,115,117,108,101,83,104,97,112,101,0,67,97,112,115,117,108,101,88,0,49,53,98,116,67,97,112,115,117,108,101,83,104,97,112,101,88,0,67,97,112,115,117,108,101,90,0,49,53,98,116,67,97,112,115,117,108,101,83,104,97,112,101,90,0,50,54,76,111,99,97,108,83,117,112,112,111,114,116,86,101,114,116,101,120,67,97,108,108,98,97,99,107,0,67,111,110,118,101,120,84,114,105,109,101,115,104,0,50,53,98,116,67,111,110,118,101,120,84,114,105,97,110,103,108,101,\n77,101,115,104,83,104,97,112,101,0,49,52,98,116,67,111,110,99,97,118,101,83,104,97,112,101,0,66,111,120,0,49,48,98,116,66,111,120,83,104,97,112,101,0,49,52,98,116,79,112,116,105,109,105,122,101,100,66,118,104,0,90,78,49,52,98,116,79,112,116,105,109,105,122,101,100,66,118,104,53,98,117,105,108,100,69,80,50,51,98,116,83,116,114,105,100,105,110,103,77,101,115,104,73,110,116,101,114,102,97,99,101,98,82,75,57,98,116,86,101,99,116,111,114,51,83,52,95,69,50,48,78,111,100,101,84,114,105,97,110,103,108,101,\n67,97,108,108,98,97,99,107,0,90,78,49,52,98,116,79,112,116,105,109,105,122,101,100,66,118,104,53,98,117,105,108,100,69,80,50,51,98,116,83,116,114,105,100,105,110,103,77,101,115,104,73,110,116,101,114,102,97,99,101,98,82,75,57,98,116,86,101,99,116,111,114,51,83,52,95,69,50,57,81,117,97,110,116,105,122,101,100,78,111,100,101,84,114,105,97,110,103,108,101,67,97,108,108,98,97,99,107,0,72,69,73,71,72,84,70,73,69,76,68,0,50,53,98,116,72,101,105,103,104,116,102,105,101,108,100,84,101,114,114,97,105,110,\n83,104,97,112,101,0,98,116,67,121,108,105,110,100,101,114,83,104,97,112,101,68,97,116,97,0,67,121,108,105,110,100,101,114,89,0,49,53,98,116,67,121,108,105,110,100,101,114,83,104,97,112,101,0,67,121,108,105,110,100,101,114,88,0,49,54,98,116,67,121,108,105,110,100,101,114,83,104,97,112,101,88,0,67,121,108,105,110,100,101,114,90,0,49,54,98,116,67,121,108,105,110,100,101,114,83,104,97,112,101,90,0,49,52,98,116,84,114,105,97,110,103,108,101,77,101,115,104,0,50,48,98,116,65,120,105,115,83,119,101,101,112,\n51,73,110,116,101,114,110,97,108,73,116,69,0,50,49,98,116,66,114,111,97,100,112,104,97,115,101,73,110,116,101,114,102,97,99,101,0,49,50,98,116,65,120,105,115,83,119,101,101,112,51,0,49,53,98,116,78,117,108,108,80,97,105,114,67,97,99,104,101,0,50,50,98,116,79,118,101,114,108,97,112,112,105,110,103,80,97,105,114,67,97,99,104,101,0,90,78,50,56,98,116,72,97,115,104,101,100,79,118,101,114,108,97,112,112,105,110,103,80,97,105,114,67,97,99,104,101,49,57,99,108,101,97,110,80,114,111,120,121,70,114,111,109,\n80,97,105,114,115,69,80,49,55,98,116,66,114,111,97,100,112,104,97,115,101,80,114,111,120,121,80,49,50,98,116,68,105,115,112,97,116,99,104,101,114,69,49,55,67,108,101,97,110,80,97,105,114,67,97,108,108,98,97,99,107,0,90,78,50,56,98,116,72,97,115,104,101,100,79,118,101,114,108,97,112,112,105,110,103,80,97,105,114,67,97,99,104,101,51,55,114,101,109,111,118,101,79,118,101,114,108,97,112,112,105,110,103,80,97,105,114,115,67,111,110,116,97,105,110,105,110,103,80,114,111,120,121,69,80,49,55,98,116,66,114,\n111,97,100,112,104,97,115,101,80,114,111,120,121,80,49,50,98,116,68,105,115,112,97,116,99,104,101,114,69,49,56,82,101,109,111,118,101,80,97,105,114,67,97,108,108,98,97,99,107,0,50,56,98,116,72,97,115,104,101,100,79,118,101,114,108,97,112,112,105,110,103,80,97,105,114,67,97,99,104,101,0,49,56,98,116,68,98,118,116,84,114,101,101,67,111,108,108,105,100,101,114,0,50,48,66,114,111,97,100,112,104,97,115,101,65,97,98,98,84,101,115,116,101,114,0,49,57,66,114,111,97,100,112,104,97,115,101,82,97,121,84,101,\n115,116,101,114,0,49,54,98,116,68,98,118,116,66,114,111,97,100,112,104,97,115,101,0,49,50,98,116,68,105,115,112,97,116,99,104,101,114,0,98,116,79,112,116,105,109,105,122,101,100,66,118,104,78,111,100,101,68,97,116,97,0,98,116,81,117,97,110,116,105,122,101,100,66,118,104,78,111,100,101,68,97,116,97,0,98,116,66,118,104,83,117,98,116,114,101,101,73,110,102,111,68,97,116,97,0,98,116,81,117,97,110,116,105,122,101,100,66,118,104,70,108,111,97,116,68,97,116,97,0,49,52,98,116,81,117,97,110,116,105,122,101,\n100,66,118,104,0,50,53,98,116,84,114,105,97,110,103,108,101,82,97,121,99,97,115,116,67,97,108,108,98,97,99,107,0,50,56,98,116,84,114,105,97,110,103,108,101,67,111,110,118,101,120,99,97,115,116,67,97,108,108,98,97,99,107,0,90,78,51,51,98,116,77,105,110,107,111,119,115,107,105,80,101,110,101,116,114,97,116,105,111,110,68,101,112,116,104,83,111,108,118,101,114,49,50,99,97,108,99,80,101,110,68,101,112,116,104,69,82,50,50,98,116,86,111,114,111,110,111,105,83,105,109,112,108,101,120,83,111,108,118,101,\n114,80,75,49,51,98,116,67,111,110,118,101,120,83,104,97,112,101,83,52,95,82,75,49,49,98,116,84,114,97,110,115,102,111,114,109,83,55,95,82,57,98,116,86,101,99,116,111,114,51,83,57,95,83,57,95,80,49,50,98,116,73,68,101,98,117,103,68,114,97,119,69,50,48,98,116,73,110,116,101,114,109,101,100,105,97,116,101,82,101,115,117,108,116,0,51,51,98,116,77,105,110,107,111,119,115,107,105,80,101,110,101,116,114,97,116,105,111,110,68,101,112,116,104,83,111,108,118,101,114,0,51,48,98,116,67,111,110,118,101,120,80,\n101,110,101,116,114,97,116,105,111,110,68,101,112,116,104,83,111,108,118,101,114,0,51,48,98,116,71,106,107,69,112,97,80,101,110,101,116,114,97,116,105,111,110,68,101,112,116,104,83,111,108,118,101,114,0,49,54,98,116,80,111,105,110,116,67,111,108,108,101,99,116,111,114,0,49,53,98,116,71,106,107,67,111,110,118,101,120,67,97,115,116,0,50,55,98,116,67,111,110,116,105,110,117,111,117,115,67,111,110,118,101,120,67,111,108,108,105,115,105,111,110,0,49,55,98,116,71,106,107,80,97,105,114,68,101,116,101,99,\n116,111,114,0,51,54,98,116,68,105,115,99,114,101,116,101,67,111,108,108,105,115,105,111,110,68,101,116,101,99,116,111,114,73,110,116,101,114,102,97,99,101,0,51,48,98,116,65,99,116,105,118,97,116,105,110,103,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,0,49,54,98,116,69,109,112,116,121,65,108,103,111,114,105,116,104,109,0,51,50,98,116,83,112,104,101,114,101,83,112,104,101,114,101,67,111,108,108,105,115,105,111,110,65,108,103,111,114,105,116,104,109,0,49,54,98,116,66,111,120,\n66,111,120,68,101,116,101,99,116,111,114,0,50,50,83,112,104,101,114,101,84,114,105,97,110,103,108,101,68,101,116,101,99,116,111,114,0,50,51,98,116,72,97,115,104,101,100,83,105,109,112,108,101,80,97,105,114,67,97,99,104,101,0,49,56,98,116,67,111,110,118,101,120,80,111,108,121,104,101,100,114,111,110,0,50,54,98,116,84,114,105,97,110,103,108,101,73,110,100,101,120,86,101,114,116,101,120,65,114,114,97,121,0,98,116,73,110,116,73,110,100,101,120,68,97,116,97,0,98,116,83,104,111,114,116,73,110,116,73,110,\n100,101,120,84,114,105,112,108,101,116,68,97,116,97,0,98,116,67,104,97,114,73,110,100,101,120,84,114,105,112,108,101,116,68,97,116,97,0,98,116,86,101,99,116,111,114,51,70,108,111,97,116,68,97,116,97,0,98,116,86,101,99,116,111,114,51,68,111,117,98,108,101,68,97,116,97,0,98,116,77,101,115,104,80,97,114,116,68,97,116,97,0,98,116,83,116,114,105,100,105,110,103,77,101,115,104,73,110,116,101,114,102,97,99,101,68,97,116,97,0,50,51,98,116,83,116,114,105,100,105,110,103,77,101,115,104,73,110,116,101,114,102,\n97,99,101,0,82,111,111,116,0,17,0,10,0,17,17,17,0,0,0,0,5,0,0,0,0,0,0,9,0,0,0,0,11,0,0,0,0,0,0,0,0,17,0,15,10,17,17,17,3,10,7,0,1,19,9,11,11,0,0,9,6,11,0,0,11,0,6,17,0,0,0,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,17,0,10,10,17,17,17,0,10,0,0,2,0,9,11,0,0,0,9,0,11,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,0,0,0,0,9,12,0,0,0,0,0,12,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,13,0,0,0,4,13,\n0,0,0,0,9,14,0,0,0,0,0,14,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,15,0,0,0,0,9,16,0,0,0,0,0,16,0,0,16,0,0,18,0,0,0,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0,0,18,18,18,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,10,0,0,0,0,9,11,0,0,0,0,0,11,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,0,0,0,0,9,12,\n0,0,0,0,0,12,0,0,12,0,0,45,43,32,32,32,48,88,48,120,0,40,110,117,108,108,41,0,45,48,88,43,48,88,32,48,88,45,48,120,43,48,120,32,48,120,0,105,110,102,0,73,78,70,0,110,97,110,0,78,65,78,0,48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70,46,0,84,33,34,25,13,1,2,3,17,75,28,12,16,4,11,29,18,30,39,104,110,111,112,113,98,32,5,6,15,19,20,21,26,8,22,7,40,36,23,24,9,10,14,27,31,37,35,131,130,125,38,42,43,60,61,62,63,67,71,74,77,88,89,90,91,92,93,94,95,96,97,99,100,101,102,103,105,106,107,108,114,115,116,121,\n122,123,124,0,73,108,108,101,103,97,108,32,98,121,116,101,32,115,101,113,117,101,110,99,101,0,68,111,109,97,105,110,32,101,114,114,111,114,0,82,101,115,117,108,116,32,110,111,116,32,114,101,112,114,101,115,101,110,116,97,98,108,101,0,78,111,116,32,97,32,116,116,121,0,80,101,114,109,105,115,115,105,111,110,32,100,101,110,105,101,100,0,79,112,101,114,97,116,105,111,110,32,110,111,116,32,112,101,114,109,105,116,116,101,100,0,78,111,32,115,117,99,104,32,102,105,108,101,32,111,114,32,100,105,114,101,99,\n116,111,114,121,0,78,111,32,115,117,99,104,32,112,114,111,99,101,115,115,0,70,105,108,101,32,101,120,105,115,116,115,0,86,97,108,117,101,32,116,111,111,32,108,97,114,103,101,32,102,111,114,32,100,97,116,97,32,116,121,112,101,0,78,111,32,115,112,97,99,101,32,108,101,102,116,32,111,110,32,100,101,118,105,99,101,0,79,117,116,32,111,102,32,109,101,109,111,114,121,0,82,101,115,111,117,114,99,101,32,98,117,115,121,0,73,110,116,101,114,114,117,112,116,101,100,32,115,121,115,116,101,109,32,99,97,108,108,\n0,82,101,115,111,117,114,99,101,32,116,101,109,112,111,114,97,114,105,108,121,32,117,110,97,118,97,105,108,97,98,108,101,0,73,110,118,97,108,105,100,32,115,101,101,107,0,67,114,111,115,115,45,100,101,118],\"i8\",4,d.g+10240);\nwa([105,99,101,32,108,105,110,107,0,82,101,97,100,45,111,110,108,121,32,102,105,108,101,32,115,121,115,116,101,109,0,68,105,114,101,99,116,111,114,121,32,110,111,116,32,101,109,112,116,121,0,67,111,110,110,101,99,116,105,111,110,32,114,101,115,101,116,32,98,121,32,112,101,101,114,0,79,112,101,114,97,116,105,111,110,32,116,105,109,101,100,32,111,117,116,0,67,111,110,110,101,99,116,105,111,110,32,114,101,102,117,115,101,100,0,72,111,115,116,32,105,115,32,100,111,119,110,0,72,111,115,116,32,105,115,\n32,117,110,114,101,97,99,104,97,98,108,101,0,65,100,100,114,101,115,115,32,105,110,32,117,115,101,0,66,114,111,107,101,110,32,112,105,112,101,0,73,47,79,32,101,114,114,111,114,0,78,111,32,115,117,99,104,32,100,101,118,105,99,101,32,111,114,32,97,100,100,114,101,115,115,0,66,108,111,99,107,32,100,101,118,105,99,101,32,114,101,113,117,105,114,101,100,0,78,111,32,115,117,99,104,32,100,101,118,105,99,101,0,78,111,116,32,97,32,100,105,114,101,99,116,111,114,121,0,73,115,32,97,32,100,105,114,101,99,116,\n111,114,121,0,84,101,120,116,32,102,105,108,101,32,98,117,115,121,0,69,120,101,99,32,102,111,114,109,97,116,32,101,114,114,111,114,0,73,110,118,97,108,105,100,32,97,114,103,117,109,101,110,116,0,65,114,103,117,109,101,110,116,32,108,105,115,116,32,116,111,111,32,108,111,110,103,0,83,121,109,98,111,108,105,99,32,108,105,110,107,32,108,111,111,112,0,70,105,108,101,110,97,109,101,32,116,111,111,32,108,111,110,103,0,84,111,111,32,109,97,110,121,32,111,112,101,110,32,102,105,108,101,115,32,105,110,32,\n115,121,115,116,101,109,0,78,111,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,115,32,97,118,97,105,108,97,98,108,101,0,66,97,100,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,0,78,111,32,99,104,105,108,100,32,112,114,111,99,101,115,115,0,66,97,100,32,97,100,100,114,101,115,115,0,70,105,108,101,32,116,111,111,32,108,97,114,103,101,0,84,111,111,32,109,97,110,121,32,108,105,110,107,115,0,78,111,32,108,111,99,107,115,32,97,118,97,105,108,97,98,108,101,0,82,101,115,111,117,\n114,99,101,32,100,101,97,100,108,111,99,107,32,119,111,117,108,100,32,111,99,99,117,114,0,83,116,97,116,101,32,110,111,116,32,114,101,99,111,118,101,114,97,98,108,101,0,80,114,101,118,105,111,117,115,32,111,119,110,101,114,32,100,105,101,100,0,79,112,101,114,97,116,105,111,110,32,99,97,110,99,101,108,101,100,0,70,117,110,99,116,105,111,110,32,110,111,116,32,105,109,112,108,101,109,101,110,116,101,100,0,78,111,32,109,101,115,115,97,103,101,32,111,102,32,100,101,115,105,114,101,100,32,116,121,112,101,\n0,73,100,101,110,116,105,102,105,101,114,32,114,101,109,111,118,101,100,0,68,101,118,105,99,101,32,110,111,116,32,97,32,115,116,114,101,97,109,0,78,111,32,100,97,116,97,32,97,118,97,105,108,97,98,108,101,0,68,101,118,105,99,101,32,116,105,109,101,111,117,116,0,79,117,116,32,111,102,32,115,116,114,101,97,109,115,32,114,101,115,111,117,114,99,101,115,0,76,105,110,107,32,104,97,115,32,98,101,101,110,32,115,101,118,101,114,101,100,0,80,114,111,116,111,99,111,108,32,101,114,114,111,114,0,66,97,100,32,\n109,101,115,115,97,103,101,0,70,105,108,101,32,100,101,115,99,114,105,112,116,111,114,32,105,110,32,98,97,100,32,115,116,97,116,101,0,78,111,116,32,97,32,115,111,99,107,101,116,0,68,101,115,116,105,110,97,116,105,111,110,32,97,100,100,114,101,115,115,32,114,101,113,117,105,114,101,100,0,77,101,115,115,97,103,101,32,116,111,111,32,108,97,114,103,101,0,80,114,111,116,111,99,111,108,32,119,114,111,110,103,32,116,121,112,101,32,102,111,114,32,115,111,99,107,101,116,0,80,114,111,116,111,99,111,108,32,\n110,111,116,32,97,118,97,105,108,97,98,108,101,0,80,114,111,116,111,99,111,108,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,83,111,99,107,101,116,32,116,121,112,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,78,111,116,32,115,117,112,112,111,114,116,101,100,0,80,114,111,116,111,99,111,108,32,102,97,109,105,108,121,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,65,100,100,114,101,115,115,32,102,97,109,105,108,121,32,110,111,116,32,115,117,112,112,111,114,116,101,100,\n32,98,121,32,112,114,111,116,111,99,111,108,0,65,100,100,114,101,115,115,32,110,111,116,32,97,118,97,105,108,97,98,108,101,0,78,101,116,119,111,114,107,32,105,115,32,100,111,119,110,0,78,101,116,119,111,114,107,32,117,110,114,101,97,99,104,97,98,108,101,0,67,111,110,110,101,99,116,105,111,110,32,114,101,115,101,116,32,98,121,32,110,101,116,119,111,114,107,0,67,111,110,110,101,99,116,105,111,110,32,97,98,111,114,116,101,100,0,78,111,32,98,117,102,102,101,114,32,115,112,97,99,101,32,97,118,97,105,108,\n97,98,108,101,0,83,111,99,107,101,116,32,105,115,32,99,111,110,110,101,99,116,101,100,0,83,111,99,107,101,116,32,110,111,116,32,99,111,110,110,101,99,116,101,100,0,67,97,110,110,111,116,32,115,101,110,100,32,97,102,116,101,114,32,115,111,99,107,101,116,32,115,104,117,116,100,111,119,110,0,79,112,101,114,97,116,105,111,110,32,97,108,114,101,97,100,121,32,105,110,32,112,114,111,103,114,101,115,115,0,79,112,101,114,97,116,105,111,110,32,105,110,32,112,114,111,103,114,101,115,115,0,83,116,97,108,101,\n32,102,105,108,101,32,104,97,110,100,108,101,0,82,101,109,111,116,101,32,73,47,79,32,101,114,114,111,114,0,81,117,111,116,97,32,101,120,99,101,101,100,101,100,0,78,111,32,109,101,100,105,117,109,32,102,111,117,110,100,0,87,114,111,110,103,32,109,101,100,105,117,109,32,116,121,112,101,0,78,111,32,101,114,114,111,114,32,105,110,102,111,114,109,97,116,105,111,110,0,0,116,101,114,109,105,110,97,116,105,110,103,32,119,105,116,104,32,37,115,32,101,120,99,101,112,116,105,111,110,32,111,102,32,116,121,112,\n101,32,37,115,58,32,37,115,0,116,101,114,109,105,110,97,116,105,110,103,32,119,105,116,104,32,37,115,32,101,120,99,101,112,116,105,111,110,32,111,102,32,116,121,112,101,32,37,115,0,116,101,114,109,105,110,97,116,105,110,103,32,119,105,116,104,32,37,115,32,102,111,114,101,105,103,110,32,101,120,99,101,112,116,105,111,110,0,116,101,114,109,105,110,97,116,105,110,103,0,117,110,99,97,117,103,104,116,0,83,116,57,101,120,99,101,112,116,105,111,110,0,78,49,48,95,95,99,120,120,97,98,105,118,49,49,54,95,95,\n115,104,105,109,95,116,121,112,101,95,105,110,102,111,69,0,83,116,57,116,121,112,101,95,105,110,102,111,0,78,49,48,95,95,99,120,120,97,98,105,118,49,50,48,95,95,115,105,95,99,108,97,115,115,95,116,121,112,101,95,105,110,102,111,69,0,78,49,48,95,95,99,120,120,97,98,105,118,49,49,55,95,95,99,108,97,115,115,95,116,121,112,101,95,105,110,102,111,69,0,112,116,104,114,101,97,100,95,111,110,99,101,32,102,97,105,108,117,114,101,32,105,110,32,95,95,99,120,97,95,103,101,116,95,103,108,111,98,97,108,115,95,\n102,97,115,116,40,41,0,99,97,110,110,111,116,32,99,114,101,97,116,101,32,112,116,104,114,101,97,100,32,107,101,121,32,102,111,114,32,95,95,99,120,97,95,103,101,116,95,103,108,111,98,97,108,115,40,41,0,99,97,110,110,111,116,32,122,101,114,111,32,111,117,116,32,116,104,114,101,97,100,32,118,97,108,117,101,32,102,111,114,32,95,95,99,120,97,95,103,101,116,95,103,108,111,98,97,108,115,40,41,0,116,101,114,109,105,110,97,116,101,95,104,97,110,100,108,101,114,32,117,110,101,120,112,101,99,116,101,100,108,\n121,32,114,101,116,117,114,110,101,100,0,78,49,48,95,95,99,120,120,97,98,105,118,49,49,57,95,95,112,111,105,110,116,101,114,95,116,121,112,101,95,105,110,102,111,69,0,78,49,48,95,95,99,120,120,97,98,105,118,49,49,55,95,95,112,98,97,115,101,95,116,121,112,101,95,105,110,102,111,69,0,78,49,48,95,95,99,120,120,97,98,105,118,49,50,49,95,95,118,109,105,95,99,108,97,115,115,95,116,121,112,101,95,105,110,102,111,69,0],\"i8\",4,d.g+20480);var cb=la;la+=16;c._i64Subtract=db;c._i64Add=eb;c._memset=fb;\nc._bitshift64Lshr=gb;c._bitshift64Shl=hb;function ib(){return!!ib.d}var jb=0,kb=[],lb={};function mb(a,b){mb.d||(mb.d={});a in mb.d||(c.dynCall_v(b),mb.d[a]=1)}c._llvm_bswap_i16=nb;c._memcpy=ob;var pb=0;function qb(){pb+=4;return l[pb-4>>2]}\nvar rb={},sb=wa([8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,\n1,0,2,0,1,0,3,0,1,0,2,0,1,0],\"i8\",2);c._llvm_cttz_i32=tb;c.___udivmoddi4=ub;c.___udivdi3=vb;var wb={};c.___muldsi3=xb;c.___muldi3=yb;c._sbrk=zb;c._memmove=Ab;var Bb=1;\nfunction Cb(){var a=jb;if(!a)return(d.e(0),0)|0;var b=lb[a],e=b.type;if(!e)return(d.e(0),a)|0;var f=Array.prototype.slice.call(arguments);c.___cxa_is_pointer_type(e);Cb.buffer||(Cb.buffer=xa(4));l[Cb.buffer>>2]=a;for(var a=Cb.buffer,g=0;g<f.length;g++)if(f[g]&&c.___cxa_can_catch(f[g],e,a))return a=l[a>>2],b.A=a,(d.e(f[g]),a)|0;a=l[a>>2];return(d.e(e),a)|0}c.___uremdi3=Db;c._llvm_bswap_i32=Eb;\nfunction Fb(a,b){pb=b;try{var e=qb(),f=qb(),g=qb(),h=0;Fb.buffer||(Fb.d=[null,[],[]],Fb.q=function(a,b){var e=Fb.d[a];assert(e);if(0===b||10===b){var f=1===a?c.print:c.printErr,g;a:{for(var h=g=0;e[h];)++h;if(16<h-g&&e.subarray&&Ea)g=Ea.decode(e.subarray(g,h));else for(var k,m,v,z,B,yc,h=\"\";;){k=e[g++];if(!k){g=h;break a}k&128?(m=e[g++]&63,192==(k&224)?h+=String.fromCharCode((k&31)<<6|m):(v=e[g++]&63,224==(k&240)?k=(k&15)<<12|m<<6|v:(z=e[g++]&63,240==(k&248)?k=(k&7)<<18|m<<12|v<<6|z:(B=e[g++]&63,\n248==(k&252)?k=(k&3)<<24|m<<18|v<<12|z<<6|B:(yc=e[g++]&63,k=(k&1)<<30|m<<24|v<<18|z<<12|B<<6|yc))),65536>k?h+=String.fromCharCode(k):(k-=65536,h+=String.fromCharCode(55296|k>>10,56320|k&1023)))):h+=String.fromCharCode(k)}}f(g);e.length=0}else e.push(b)});for(var k=0;k<g;k++){for(var m=l[f+8*k>>2],v=l[f+(8*k+4)>>2],B=0;B<v;B++)Fb.q(e,ya[m+B]);h+=v}return h}catch(z){return\"undefined\"!==typeof FS&&z instanceof FS.o||qa(z),-z.r}}\nVa.push(function(){var a=c._fflush;a&&a(0);if(a=Fb.q){var b=Fb.d;b[1].length&&a(1,10);b[2].length&&a(2,10)}});ma=wa(1,\"i32\",2);Na=ka=d.p(la);Oa=Na+Qa;Pa=d.p(Oa);l[ma>>2]=Pa;c.B={Math:Math,Int8Array:Int8Array,Int16Array:Int16Array,Int32Array:Int32Array,Uint8Array:Uint8Array,Uint16Array:Uint16Array,Uint32Array:Uint32Array,Float32Array:Float32Array,Float64Array:Float64Array,NaN:NaN,Infinity:Infinity};\nc.C={abort:qa,assert:assert,enlargeMemory:function(){oa()},getTotalMemory:function(){return na},abortOnCannotGrowMemory:oa,invoke_viiiii:function(a,b,e,f,g,h){try{c.dynCall_viiiii(a,b,e,f,g,h)}catch(k){if(\"number\"!==typeof k&&\"longjmp\"!==k)throw k;c.setThrew(1,0)}},invoke_vid:function(a,b,e){try{c.dynCall_vid(a,b,e)}catch(f){if(\"number\"!==typeof f&&\"longjmp\"!==f)throw f;c.setThrew(1,0)}},invoke_vi:function(a,b){try{c.dynCall_vi(a,b)}catch(e){if(\"number\"!==typeof e&&\"longjmp\"!==e)throw e;c.setThrew(1,\n0)}},invoke_viiidii:function(a,b,e,f,g,h,k){try{c.dynCall_viiidii(a,b,e,f,g,h,k)}catch(m){if(\"number\"!==typeof m&&\"longjmp\"!==m)throw m;c.setThrew(1,0)}},invoke_vii:function(a,b,e){try{c.dynCall_vii(a,b,e)}catch(f){if(\"number\"!==typeof f&&\"longjmp\"!==f)throw f;c.setThrew(1,0)}},invoke_iiiiiiiiiii:function(a,b,e,f,g,h,k,m,v,B,z){try{return c.dynCall_iiiiiiiiiii(a,b,e,f,g,h,k,m,v,B,z)}catch(T){if(\"number\"!==typeof T&&\"longjmp\"!==T)throw T;c.setThrew(1,0)}},invoke_ii:function(a,b){try{return c.dynCall_ii(a,\nb)}catch(e){if(\"number\"!==typeof e&&\"longjmp\"!==e)throw e;c.setThrew(1,0)}},invoke_viidi:function(a,b,e,f,g){try{c.dynCall_viidi(a,b,e,f,g)}catch(h){if(\"number\"!==typeof h&&\"longjmp\"!==h)throw h;c.setThrew(1,0)}},invoke_viddiii:function(a,b,e,f,g,h,k){try{c.dynCall_viddiii(a,b,e,f,g,h,k)}catch(m){if(\"number\"!==typeof m&&\"longjmp\"!==m)throw m;c.setThrew(1,0)}},invoke_vidii:function(a,b,e,f,g){try{c.dynCall_vidii(a,b,e,f,g)}catch(h){if(\"number\"!==typeof h&&\"longjmp\"!==h)throw h;c.setThrew(1,0)}},invoke_iiiii:function(a,\nb,e,f,g){try{return c.dynCall_iiiii(a,b,e,f,g)}catch(h){if(\"number\"!==typeof h&&\"longjmp\"!==h)throw h;c.setThrew(1,0)}},invoke_vidi:function(a,b,e,f){try{c.dynCall_vidi(a,b,e,f)}catch(g){if(\"number\"!==typeof g&&\"longjmp\"!==g)throw g;c.setThrew(1,0)}},invoke_diiiiiiii:function(a,b,e,f,g,h,k,m,v){try{return c.dynCall_diiiiiiii(a,b,e,f,g,h,k,m,v)}catch(B){if(\"number\"!==typeof B&&\"longjmp\"!==B)throw B;c.setThrew(1,0)}},invoke_viiiiddddiid:function(a,b,e,f,g,h,k,m,v,B,z,T){try{c.dynCall_viiiiddddiid(a,\nb,e,f,g,h,k,m,v,B,z,T)}catch(Pb){if(\"number\"!==typeof Pb&&\"longjmp\"!==Pb)throw Pb;c.setThrew(1,0)}},invoke_diiiii:function(a,b,e,f,g,h){try{return c.dynCall_diiiii(a,b,e,f,g,h)}catch(k){if(\"number\"!==typeof k&&\"longjmp\"!==k)throw k;c.setThrew(1,0)}},invoke_vidd:function(a,b,e,f){try{c.dynCall_vidd(a,b,e,f)}catch(g){if(\"number\"!==typeof g&&\"longjmp\"!==g)throw g;c.setThrew(1,0)}},invoke_iiii:function(a,b,e,f){try{return c.dynCall_iiii(a,b,e,f)}catch(g){if(\"number\"!==typeof g&&\"longjmp\"!==g)throw g;\nc.setThrew(1,0)}},invoke_viiiiid:function(a,b,e,f,g,h,k){try{c.dynCall_viiiiid(a,b,e,f,g,h,k)}catch(m){if(\"number\"!==typeof m&&\"longjmp\"!==m)throw m;c.setThrew(1,0)}},invoke_viiiiii:function(a,b,e,f,g,h,k){try{c.dynCall_viiiiii(a,b,e,f,g,h,k)}catch(m){if(\"number\"!==typeof m&&\"longjmp\"!==m)throw m;c.setThrew(1,0)}},invoke_iiid:function(a,b,e,f){try{return c.dynCall_iiid(a,b,e,f)}catch(g){if(\"number\"!==typeof g&&\"longjmp\"!==g)throw g;c.setThrew(1,0)}},invoke_di:function(a,b){try{return c.dynCall_di(a,\nb)}catch(e){if(\"number\"!==typeof e&&\"longjmp\"!==e)throw e;c.setThrew(1,0)}},invoke_iiiiiii:function(a,b,e,f,g,h,k){try{return c.dynCall_iiiiiii(a,b,e,f,g,h,k)}catch(m){if(\"number\"!==typeof m&&\"longjmp\"!==m)throw m;c.setThrew(1,0)}},invoke_diiidii:function(a,b,e,f,g,h,k){try{return c.dynCall_diiidii(a,b,e,f,g,h,k)}catch(m){if(\"number\"!==typeof m&&\"longjmp\"!==m)throw m;c.setThrew(1,0)}},invoke_viidii:function(a,b,e,f,g,h){try{c.dynCall_viidii(a,b,e,f,g,h)}catch(k){if(\"number\"!==typeof k&&\"longjmp\"!==\nk)throw k;c.setThrew(1,0)}},invoke_viiiiiii:function(a,b,e,f,g,h,k,m){try{c.dynCall_viiiiiii(a,b,e,f,g,h,k,m)}catch(v){if(\"number\"!==typeof v&&\"longjmp\"!==v)throw v;c.setThrew(1,0)}},invoke_viiiiiiiii:function(a,b,e,f,g,h,k,m,v,B){try{c.dynCall_viiiiiiiii(a,b,e,f,g,h,k,m,v,B)}catch(z){if(\"number\"!==typeof z&&\"longjmp\"!==z)throw z;c.setThrew(1,0)}},invoke_viiiiiiiiii:function(a,b,e,f,g,h,k,m,v,B,z){try{c.dynCall_viiiiiiiiii(a,b,e,f,g,h,k,m,v,B,z)}catch(T){if(\"number\"!==typeof T&&\"longjmp\"!==T)throw T;\nc.setThrew(1,0)}},invoke_iii:function(a,b,e){try{return c.dynCall_iii(a,b,e)}catch(f){if(\"number\"!==typeof f&&\"longjmp\"!==f)throw f;c.setThrew(1,0)}},invoke_diii:function(a,b,e,f){try{return c.dynCall_diii(a,b,e,f)}catch(g){if(\"number\"!==typeof g&&\"longjmp\"!==g)throw g;c.setThrew(1,0)}},invoke_diiiiiiiiii:function(a,b,e,f,g,h,k,m,v,B,z){try{return c.dynCall_diiiiiiiiii(a,b,e,f,g,h,k,m,v,B,z)}catch(T){if(\"number\"!==typeof T&&\"longjmp\"!==T)throw T;c.setThrew(1,0)}},invoke_viiiid:function(a,b,e,f,g,\nh){try{c.dynCall_viiiid(a,b,e,f,g,h)}catch(k){if(\"number\"!==typeof k&&\"longjmp\"!==k)throw k;c.setThrew(1,0)}},invoke_diiiiiiiii:function(a,b,e,f,g,h,k,m,v,B){try{return c.dynCall_diiiiiiiii(a,b,e,f,g,h,k,m,v,B)}catch(z){if(\"number\"!==typeof z&&\"longjmp\"!==z)throw z;c.setThrew(1,0)}},invoke_did:function(a,b,e){try{return c.dynCall_did(a,b,e)}catch(f){if(\"number\"!==typeof f&&\"longjmp\"!==f)throw f;c.setThrew(1,0)}},invoke_viiiidddddidi:function(a,b,e,f,g,h,k,m,v,B,z,T,Pb){try{c.dynCall_viiiidddddidi(a,\nb,e,f,g,h,k,m,v,B,z,T,Pb)}catch(lc){if(\"number\"!==typeof lc&&\"longjmp\"!==lc)throw lc;c.setThrew(1,0)}},invoke_diidii:function(a,b,e,f,g,h){try{return c.dynCall_diidii(a,b,e,f,g,h)}catch(k){if(\"number\"!==typeof k&&\"longjmp\"!==k)throw k;c.setThrew(1,0)}},invoke_diiii:function(a,b,e,f,g){try{return c.dynCall_diiii(a,b,e,f,g)}catch(h){if(\"number\"!==typeof h&&\"longjmp\"!==h)throw h;c.setThrew(1,0)}},invoke_iiiiiiiiii:function(a,b,e,f,g,h,k,m,v,B){try{return c.dynCall_iiiiiiiiii(a,b,e,f,g,h,k,m,v,B)}catch(z){if(\"number\"!==\ntypeof z&&\"longjmp\"!==z)throw z;c.setThrew(1,0)}},invoke_viiid:function(a,b,e,f,g){try{c.dynCall_viiid(a,b,e,f,g)}catch(h){if(\"number\"!==typeof h&&\"longjmp\"!==h)throw h;c.setThrew(1,0)}},invoke_viii:function(a,b,e,f){try{c.dynCall_viii(a,b,e,f)}catch(g){if(\"number\"!==typeof g&&\"longjmp\"!==g)throw g;c.setThrew(1,0)}},invoke_v:function(a){try{c.dynCall_v(a)}catch(b){if(\"number\"!==typeof b&&\"longjmp\"!==b)throw b;c.setThrew(1,0)}},invoke_viid:function(a,b,e,f){try{c.dynCall_viid(a,b,e,f)}catch(g){if(\"number\"!==\ntypeof g&&\"longjmp\"!==g)throw g;c.setThrew(1,0)}},invoke_iidid:function(a,b,e,f,g){try{return c.dynCall_iidid(a,b,e,f,g)}catch(h){if(\"number\"!==typeof h&&\"longjmp\"!==h)throw h;c.setThrew(1,0)}},invoke_viiii:function(a,b,e,f,g){try{c.dynCall_viiii(a,b,e,f,g)}catch(h){if(\"number\"!==typeof h&&\"longjmp\"!==h)throw h;c.setThrew(1,0)}},_pthread_getspecific:function(a){return wb[a]||0},___cxa_begin_catch:function(a){var b=lb[a];b&&!b.D&&(b.D=!0,ib.d--);b&&(b.ba=!1);kb.push(a);a:{if(a&&!lb[a])for(var e in lb)if(lb[e].A===\na){b=e;break a}b=a}b&&lb[b].aa++;return a},_pthread_setspecific:function(a,b){if(!(a in wb))return 22;wb[a]=b;return 0},_pthread_key_create:function(a){if(0==a)return 22;l[a>>2]=Bb;wb[Bb]=0;Bb++;return 0},_abort:function(){c.abort()},___setErrNo:function(a){c.___errno_location&&(l[c.___errno_location()>>2]=a);return a},___syscall6:function(a,b){pb=b;try{var e=rb.I();FS.close(e);return 0}catch(f){return\"undefined\"!==typeof FS&&f instanceof FS.o||qa(f),-f.r}},_llvm_trap:function(){qa(\"trap!\")},_llvm_pow_f32:$a,\n_gettimeofday:function(a){var b=Date.now();l[a>>2]=b/1E3|0;l[a+4>>2]=b%1E3*1E3|0;return 0},_pthread_once:mb,_emscripten_memcpy_big:function(a,b,e){ya.set(ya.subarray(b,b+e),a);return a},___gxx_personality_v0:function(){},___syscall140:function(a,b){pb=b;try{var e=rb.I();qb();var f=qb(),g=qb(),h=qb();FS.Y(e,f,h);l[g>>2]=e.position;e.K&&0===f&&0===h&&(e.K=null);return 0}catch(k){return\"undefined\"!==typeof FS&&k instanceof FS.o||qa(k),-k.r}},___resumeException:function(a){jb||(jb=a);throw a+\" - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.\";\n},_emscripten_asm_const_diiiiiiii:function(a,b,e,f,g,h,k,m,v){return ab[a](b,e,f,g,h,k,m,v)},___cxa_find_matching_catch:Cb,___cxa_pure_virtual:function(){pa=!0;throw\"Pure virtual function called!\";},___syscall146:Fb,__ZSt18uncaught_exceptionv:ib,DYNAMICTOP_PTR:ma,tempDoublePtr:cb,ABORT:pa,STACKTOP:ka,STACK_MAX:Oa,cttz_i8:sb};// EMSCRIPTEN_START_ASM\n\nvar n=(function(global,env,buffer) {\n\"use asm\";var a=new global.Int8Array(buffer);var b=new global.Int16Array(buffer);var c=new global.Int32Array(buffer);var d=new global.Uint8Array(buffer);var e=new global.Uint16Array(buffer);var f=new global.Uint32Array(buffer);var g=new global.Float32Array(buffer);var h=new global.Float64Array(buffer);var i=env.DYNAMICTOP_PTR|0;var j=env.tempDoublePtr|0;var k=env.ABORT|0;var l=env.STACKTOP|0;var m=env.STACK_MAX|0;var n=env.cttz_i8|0;var o=0;var p=0;var q=0;var r=0;var s=global.NaN,t=global.Infinity;var u=0,v=0,w=0,x=0,y=0.0;var z=0;var A=global.Math.floor;var B=global.Math.abs;var C=global.Math.sqrt;var D=global.Math.pow;var E=global.Math.cos;var F=global.Math.sin;var G=global.Math.tan;var H=global.Math.acos;var I=global.Math.asin;var J=global.Math.atan;var K=global.Math.atan2;var L=global.Math.exp;var M=global.Math.log;var N=global.Math.ceil;var O=global.Math.imul;var P=global.Math.min;var Q=global.Math.max;var R=global.Math.clz32;var S=env.abort;var T=env.assert;var U=env.enlargeMemory;var V=env.getTotalMemory;var W=env.abortOnCannotGrowMemory;var X=env.invoke_viiiii;var Y=env.invoke_vid;var Z=env.invoke_vi;var _=env.invoke_viiidii;var $=env.invoke_vii;var aa=env.invoke_iiiiiiiiiii;var ba=env.invoke_ii;var ca=env.invoke_viidi;var da=env.invoke_viddiii;var ea=env.invoke_vidii;var fa=env.invoke_iiiii;var ga=env.invoke_vidi;var ha=env.invoke_diiiiiiii;var ia=env.invoke_viiiiddddiid;var ja=env.invoke_diiiii;var ka=env.invoke_vidd;var la=env.invoke_iiii;var ma=env.invoke_viiiiid;var na=env.invoke_viiiiii;var oa=env.invoke_iiid;var pa=env.invoke_di;var qa=env.invoke_iiiiiii;var ra=env.invoke_diiidii;var sa=env.invoke_viidii;var ta=env.invoke_viiiiiii;var ua=env.invoke_viiiiiiiii;var va=env.invoke_viiiiiiiiii;var wa=env.invoke_iii;var xa=env.invoke_diii;var ya=env.invoke_diiiiiiiiii;var za=env.invoke_viiiid;var Aa=env.invoke_diiiiiiiii;var Ba=env.invoke_did;var Ca=env.invoke_viiiidddddidi;var Da=env.invoke_diidii;var Ea=env.invoke_diiii;var Fa=env.invoke_iiiiiiiiii;var Ga=env.invoke_viiid;var Ha=env.invoke_viii;var Ia=env.invoke_v;var Ja=env.invoke_viid;var Ka=env.invoke_iidid;var La=env.invoke_viiii;var Ma=env._pthread_getspecific;var Na=env.___cxa_begin_catch;var Oa=env._pthread_setspecific;var Pa=env._pthread_key_create;var Qa=env._abort;var Ra=env.___setErrNo;var Sa=env.___syscall6;var Ta=env._llvm_trap;var Ua=env._llvm_pow_f32;var Va=env._gettimeofday;var Wa=env._pthread_once;var Xa=env._emscripten_memcpy_big;var Ya=env.___gxx_personality_v0;var Za=env.___syscall140;var _a=env.___resumeException;var $a=env._emscripten_asm_const_diiiiiiii;var ab=env.___cxa_find_matching_catch;var bb=env.___cxa_pure_virtual;var cb=env.___syscall146;var db=env.__ZSt18uncaught_exceptionv;var eb=0.0;\n// EMSCRIPTEN_START_FUNCS\nfunction sf(b){b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;k=c[b+12>>2]|0;l=c[b+36>>2]|0;if((l|0)>=(k|0))return;if((c[b+40>>2]|0)<(k|0)){if(!k){g=l;d=0}else{c[6432]=(c[6432]|0)+1;d=ec((k<<2|3)+16|0)|0;if(!d)d=0;else{c[(d+4+15&-16)+-4>>2]=d;d=d+4+15&-16}g=c[b+36>>2]|0}f=c[b+44>>2]|0;if((g|0)<=0)if(!f)e=b+48|0;else j=12;else{e=0;do{c[d+(e<<2)>>2]=c[f+(e<<2)>>2];e=e+1|0}while((e|0)!=(g|0));j=12}if((j|0)==12)if(!(a[b+48>>0]|0))e=b+48|0;else{c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0);e=b+48|0}a[e>>0]=1;c[b+44>>2]=d;c[b+40>>2]=k;i=b+44|0}else{d=c[b+44>>2]|0;i=b+44|0}Hk(d+(l<<2)|0,0,(k<<2)-(l<<2)|0)|0;c[b+36>>2]=k;h=c[b+56>>2]|0;if((h|0)<(k|0)){if((c[b+60>>2]|0)<(k|0)){if(!k){g=h;d=0}else{c[6432]=(c[6432]|0)+1;d=ec((k<<2|3)+16|0)|0;if(!d)d=0;else{c[(d+4+15&-16)+-4>>2]=d;d=d+4+15&-16}g=c[b+56>>2]|0}f=c[b+64>>2]|0;if((g|0)<=0)if(!f)e=b+68|0;else j=26;else{e=0;do{c[d+(e<<2)>>2]=c[f+(e<<2)>>2];e=e+1|0}while((e|0)!=(g|0));j=26}if((j|0)==26)if(!(a[b+68>>0]|0))e=b+68|0;else{c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0);e=b+68|0}a[e>>0]=1;c[b+64>>2]=d;c[b+60>>2]=k}else d=c[b+64>>2]|0;Hk(d+(h<<2)|0,0,(k<<2)-(h<<2)|0)|0}c[b+56>>2]=k;if((k|0)>0){Hk(c[i>>2]|0,-1,k<<2|0)|0;Hk(c[b+64>>2]|0,-1,k<<2|0)|0}if((l|0)<=0)return;g=c[b+16>>2]|0;d=c[i>>2]|0;e=c[b+64>>2]|0;f=0;do{k=c[(c[g+(f<<4)+4>>2]|0)+12>>2]<<16|c[(c[g+(f<<4)>>2]|0)+12>>2];k=(k+~(k<<15)>>10^k+~(k<<15))*9|0;k=d+((((k>>6^k)+~((k>>6^k)<<11)>>16^(k>>6^k)+~((k>>6^k)<<11))&(c[b+12>>2]|0)+-1)<<2)|0;c[e+(f<<2)>>2]=c[k>>2];c[k>>2]=f;f=f+1|0}while((f|0)!=(l|0));return}function tf(a,b,d){a=a|0;b=+b;d=+d;var e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0,m=0,n=0.0,o=0,p=0,q=0,r=0,s=0.0,t=0.0,u=0.0,v=0,w=0,x=0,y=0,z=0.0;v=c[a+832>>2]|0;if((v|0)<=0)return;a=c[a+840>>2]|0;o=0;do{l=c[a+(o*56|0)>>2]|0;m=c[a+(o*56|0)+4>>2]|0;y=c[m+8>>2]|0;x=c[m+12>>2]|0;w=c[m+16>>2]|0;p=a+(o*56|0)+8|0;j=+g[p>>2];q=a+(o*56|0)+12|0;i=+g[q>>2];r=a+(o*56|0)+16|0;t=+g[r>>2];b=+g[y+8>>2]*j+ +g[x+8>>2]*i+ +g[w+8>>2]*t;e=+g[y+12>>2]*j+ +g[x+12>>2]*i+ +g[w+12>>2]*t;d=+g[y+16>>2]*j+ +g[x+16>>2]*i+ +g[w+16>>2]*t;n=+g[l+8>>2];f=+g[l+12>>2];h=+g[l+16>>2];s=n-+g[l+24>>2]-(b-(j*+g[y+24>>2]+i*+g[x+24>>2]+t*+g[w+24>>2]));u=f-+g[l+28>>2]-(e-(j*+g[y+28>>2]+i*+g[x+28>>2]+t*+g[w+28>>2]));t=h-+g[l+32>>2]-(d-(j*+g[y+32>>2]+i*+g[x+32>>2]+t*+g[w+32>>2]));i=+g[a+(o*56|0)+24>>2];j=+g[a+(o*56|0)+28>>2];k=+g[a+(o*56|0)+32>>2];if(s*i+u*j+t*k<0.0){e=+g[a+(o*56|0)+40>>2]-(n*i+f*j+h*k-(b*i+e*j+d*k));b=i*e+0.0;d=j*e+0.0;e=k*e+0.0}else{b=0.0;d=0.0;e=0.0}z=+g[a+(o*56|0)+44>>2];b=b-z*(s-i*(s*i+u*j+t*k));d=d-z*(u-j*(s*i+u*j+t*k));t=e-z*(t-k*(s*i+u*j+t*k));u=+g[a+(o*56|0)+48>>2];g[l+8>>2]=n+u*b;g[l+12>>2]=f+u*d;g[l+16>>2]=u*t+h;y=a+(o*56|0)+52|0;u=+g[y>>2]*+g[p>>2];x=c[m+8>>2]|0;g[x+8>>2]=+g[x+8>>2]-b*u;g[x+12>>2]=+g[x+12>>2]-d*u;g[x+16>>2]=+g[x+16>>2]-t*u;u=+g[y>>2]*+g[q>>2];x=c[m+12>>2]|0;g[x+8>>2]=+g[x+8>>2]-b*u;g[x+12>>2]=+g[x+12>>2]-d*u;g[x+16>>2]=+g[x+16>>2]-t*u;u=+g[y>>2]*+g[r>>2];y=c[m+16>>2]|0;g[y+8>>2]=+g[y+8>>2]-b*u;g[y+12>>2]=+g[y+12>>2]-d*u;g[y+16>>2]=+g[y+16>>2]-t*u;o=o+1|0}while((o|0)!=(v|0));return}function uf(b){b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;k=c[b+12>>2]|0;l=c[b+32>>2]|0;if((l|0)>=(k|0))return;if((c[b+36>>2]|0)<(k|0)){if(!k){g=l;d=0}else{c[6432]=(c[6432]|0)+1;d=ec((k<<2|3)+16|0)|0;if(!d)d=0;else{c[(d+4+15&-16)+-4>>2]=d;d=d+4+15&-16}g=c[b+32>>2]|0}f=c[b+40>>2]|0;if((g|0)<=0)if(!f)e=b+44|0;else j=12;else{e=0;do{c[d+(e<<2)>>2]=c[f+(e<<2)>>2];e=e+1|0}while((e|0)!=(g|0));j=12}if((j|0)==12)if(!(a[b+44>>0]|0))e=b+44|0;else{c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0);e=b+44|0}a[e>>0]=1;c[b+40>>2]=d;c[b+36>>2]=k;i=b+40|0}else{d=c[b+40>>2]|0;i=b+40|0}Hk(d+(l<<2)|0,0,(k<<2)-(l<<2)|0)|0;c[b+32>>2]=k;h=c[b+52>>2]|0;if((h|0)<(k|0)){if((c[b+56>>2]|0)<(k|0)){if(!k){g=h;d=0}else{c[6432]=(c[6432]|0)+1;d=ec((k<<2|3)+16|0)|0;if(!d)d=0;else{c[(d+4+15&-16)+-4>>2]=d;d=d+4+15&-16}g=c[b+52>>2]|0}f=c[b+60>>2]|0;if((g|0)<=0)if(!f)e=b+64|0;else j=26;else{e=0;do{c[d+(e<<2)>>2]=c[f+(e<<2)>>2];e=e+1|0}while((e|0)!=(g|0));j=26}if((j|0)==26)if(!(a[b+64>>0]|0))e=b+64|0;else{c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0);e=b+64|0}a[e>>0]=1;c[b+60>>2]=d;c[b+56>>2]=k}else d=c[b+60>>2]|0;Hk(d+(h<<2)|0,0,(k<<2)-(h<<2)|0)|0}c[b+52>>2]=k;if((k|0)>0){Hk(c[i>>2]|0,-1,k<<2|0)|0;Hk(c[b+60>>2]|0,-1,k<<2|0)|0}if((l|0)<=0)return;g=c[b+16>>2]|0;d=c[i>>2]|0;e=c[b+60>>2]|0;f=0;do{k=c[g+(f*12|0)+4>>2]<<16|c[g+(f*12|0)>>2];k=(k+~(k<<15)>>10^k+~(k<<15))*9|0;k=d+((((k>>6^k)+~((k>>6^k)<<11)>>16^(k>>6^k)+~((k>>6^k)<<11))&(c[b+12>>2]|0)+-1)<<2)|0;c[e+(f<<2)>>2]=c[k>>2];c[k>>2]=f;f=f+1|0}while((f|0)!=(l|0));return}function vf(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;if((c[b+8>>2]|0)>=(d|0))return;if((d|0)!=0?(c[6432]=(c[6432]|0)+1,e=ec((d*36|3)+16|0)|0,(e|0)!=0):0){c[(e+4+15&-16)+-4>>2]=e;r=e+4+15&-16}else r=0;m=c[b+4>>2]|0;if((m|0)>0){p=0;do{n=c[b+12>>2]|0;k=r+(p*36|0)+16|0;a[k>>0]=1;j=r+(p*36|0)+12|0;c[j>>2]=0;l=r+(p*36|0)+4|0;c[l>>2]=0;i=r+(p*36|0)+8|0;c[i>>2]=0;o=c[n+(p*36|0)+4>>2]|0;if((o|0)>0){c[6432]=(c[6432]|0)+1;e=ec((o<<2|3)+16|0)|0;if(!e)h=0;else{c[(e+4+15&-16)+-4>>2]=e;h=e+4+15&-16}f=c[l>>2]|0;g=c[j>>2]|0;if((f|0)<=0){if(g|0)q=13}else{e=0;do{c[h+(e<<2)>>2]=c[g+(e<<2)>>2];e=e+1|0}while((e|0)!=(f|0));q=13}if((q|0)==13?(q=0,a[k>>0]|0):0){c[6433]=(c[6433]|0)+1;Pc(c[g+-4>>2]|0)}a[k>>0]=1;c[j>>2]=h;c[i>>2]=o;Hk(h|0,0,o<<2|0)|0;g=c[j>>2]|0;c[l>>2]=o;e=c[n+(p*36|0)+12>>2]|0;f=0;do{c[g+(f<<2)>>2]=c[e+(f<<2)>>2];f=f+1|0}while((f|0)!=(o|0))}else c[l>>2]=o;o=r+(p*36|0)+20|0;n=n+(p*36|0)+20|0;c[o>>2]=c[n>>2];c[o+4>>2]=c[n+4>>2];c[o+8>>2]=c[n+8>>2];c[o+12>>2]=c[n+12>>2];p=p+1|0}while((p|0)!=(m|0));e=c[b+4>>2]|0;if((e|0)>0){i=0;do{g=c[b+12>>2]|0;k=g+(i*36|0)+4|0;j=g+(i*36|0)+12|0;h=c[j>>2]|0;f=g+(i*36|0)+16|0;if(h|0){if(a[f>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[j>>2]=0}a[f>>0]=1;c[j>>2]=0;c[k>>2]=0;c[g+(i*36|0)+8>>2]=0;i=i+1|0}while((i|0)!=(e|0))}}e=c[b+12>>2]|0;if(e|0){if(a[b+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}c[b+12>>2]=0}a[b+16>>0]=1;c[b+12>>2]=r;c[b+8>>2]=d;return}function wf(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=Gb[c[(c[d>>2]|0)+40>>2]&31](d,a)|0;g=Gb[c[(c[d>>2]|0)+28>>2]&31](d,e)|0;c[b>>2]=g;if(g|0)jb[c[(c[d>>2]|0)+48>>2]&127](d,e);c[b+4>>2]=c[a+4>>2];c[b+20>>2]=c[a+72>>2];e=c[a+16>>2]|0;c[b+16>>2]=e;c[b+12>>2]=0;if(!e)return 16504;g=vb[c[(c[d>>2]|0)+16>>2]&63](d,76,e)|0;e=c[g+8>>2]|0;c[b+12>>2]=Gb[c[(c[d>>2]|0)+28>>2]&31](d,e)|0;if((c[b+16>>2]|0)>0){f=0;while(1){h=c[a+24>>2]|0;c[e+72>>2]=c[h+(f*80|0)+72>>2];c[e+64>>2]=Gb[c[(c[d>>2]|0)+28>>2]&31](d,c[h+(f*80|0)+64>>2]|0)|0;if(!(Gb[c[(c[d>>2]|0)+24>>2]&31](d,c[(c[a+24>>2]|0)+(f*80|0)+64>>2]|0)|0)){h=c[(c[d>>2]|0)+16>>2]|0;i=c[(c[a+24>>2]|0)+(f*80|0)+64>>2]|0;i=lb[c[(c[i>>2]|0)+52>>2]&127](i)|0;i=vb[h&63](d,i,1)|0;h=c[(c[a+24>>2]|0)+(f*80|0)+64>>2]|0;h=vb[c[(c[h>>2]|0)+56>>2]&63](h,c[i+8>>2]|0,d)|0;fb[c[(c[d>>2]|0)+20>>2]&31](d,i,h,1346455635,c[(c[a+24>>2]|0)+(f*80|0)+64>>2]|0)}i=c[a+24>>2]|0;c[e+68>>2]=c[i+(f*80|0)+68>>2];c[e>>2]=c[i+(f*80|0)>>2];c[e+4>>2]=c[i+(f*80|0)+4>>2];c[e+8>>2]=c[i+(f*80|0)+8>>2];c[e+12>>2]=c[i+(f*80|0)+12>>2];c[e+16>>2]=c[i+(f*80|0)+16>>2];c[e+20>>2]=c[i+(f*80|0)+20>>2];c[e+24>>2]=c[i+(f*80|0)+24>>2];c[e+28>>2]=c[i+(f*80|0)+28>>2];c[e+32>>2]=c[i+(f*80|0)+32>>2];c[e+36>>2]=c[i+(f*80|0)+36>>2];c[e+40>>2]=c[i+(f*80|0)+40>>2];c[e+44>>2]=c[i+(f*80|0)+44>>2];c[e+48>>2]=c[i+(f*80|0)+48>>2];c[e+52>>2]=c[i+(f*80|0)+52>>2];c[e+56>>2]=c[i+(f*80|0)+56>>2];c[e+60>>2]=c[i+(f*80|0)+60>>2];f=f+1|0;if((f|0)>=(c[b+16>>2]|0)){e=d;break}else e=e+76|0}}else e=d;fb[c[(c[e>>2]|0)+20>>2]&31](d,g,16479,1497453121,c[g+8>>2]|0);return 16504}function xf(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0.0,i=0.0,j=0.0,k=0,m=0,n=0.0,o=0.0,p=0.0,q=0.0;f=l;l=l+256|0;c[f+32>>2]=5816;k=f+32+36|0;c[k>>2]=c[b>>2];c[k+4>>2]=c[b+4>>2];c[k+8>>2]=c[b+8>>2];c[k+12>>2]=c[b+12>>2];m=f+32+52|0;c[m>>2]=c[d>>2];c[m+4>>2]=c[d+4>>2];c[m+8>>2]=c[d+8>>2];c[m+12>>2]=c[d+12>>2];c[f+32+212>>2]=a;c[f+32+216>>2]=e;c[f+32+68>>2]=1065353216;c[f+32+72>>2]=0;c[f+32+72+4>>2]=0;c[f+32+72+8>>2]=0;c[f+32+72+12>>2]=0;c[f+32+88>>2]=1065353216;c[f+32+92>>2]=0;c[f+32+92+4>>2]=0;c[f+32+92+8>>2]=0;c[f+32+92+12>>2]=0;c[f+32+108>>2]=1065353216;c[f+32+112>>2]=0;c[f+32+116>>2]=c[k>>2];c[f+32+116+4>>2]=c[k+4>>2];c[f+32+116+8>>2]=c[k+8>>2];c[f+32+116+12>>2]=c[k+12>>2];c[f+32+132>>2]=1065353216;c[f+32+136>>2]=0;c[f+32+136+4>>2]=0;c[f+32+136+8>>2]=0;c[f+32+136+12>>2]=0;c[f+32+152>>2]=1065353216;c[f+32+156>>2]=0;c[f+32+156+4>>2]=0;c[f+32+156+8>>2]=0;c[f+32+156+12>>2]=0;c[f+32+172>>2]=1065353216;c[f+32+176>>2]=0;c[f+32+180>>2]=c[d>>2];c[f+32+180+4>>2]=c[d+4>>2];c[f+32+180+8>>2]=c[d+8>>2];c[f+32+180+12>>2]=c[d+12>>2];n=+g[d>>2]-+g[b>>2];j=+g[d+4>>2]-+g[b+4>>2];i=+g[d+8>>2]-+g[b+8>>2];h=1.0/+C(+(n*n+j*j+i*i));q=n*h==0.0?999999984306749440.0:1.0/(n*h);g[f+32+4>>2]=q;p=j*h==0.0?999999984306749440.0:1.0/(j*h);g[f+32+8>>2]=p;o=i*h==0.0?999999984306749440.0:1.0/(i*h);g[f+32+12>>2]=o;c[f+32+20>>2]=q<0.0&1;c[f+32+24>>2]=p<0.0&1;c[f+32+28>>2]=o<0.0&1;g[f+32+32>>2]=n*h*(+g[m>>2]-+g[k>>2])+j*h*(+g[f+32+56>>2]-+g[f+32+40>>2])+i*h*(+g[f+32+60>>2]-+g[f+32+44>>2]);a=c[a+68>>2]|0;e=c[(c[a>>2]|0)+24>>2]|0;c[f+16>>2]=0;c[f+16+4>>2]=0;c[f+16+8>>2]=0;c[f+16+12>>2]=0;c[f>>2]=0;c[f+4>>2]=0;c[f+8>>2]=0;c[f+12>>2]=0;xb[e&7](a,b,d,f+32|0,f+16|0,f);l=f;return}function yf(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var h=0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0;h=l;l=l+128|0;if(!b){l=h;return}if(c[b+40>>2]|0){yf(a,c[b+36>>2]|0,d+1|0,e,f);yf(a,c[b+40>>2]|0,d+1|0,e,f)}if((d|0)<0){l=h;return}m=+g[b>>2];r=+g[b+16>>2];j=+g[b+4>>2];q=+g[b+20>>2];i=+g[b+8>>2];p=+g[b+24>>2];k=(m+r)*.5-(r-m)*.5;n=(j+q)*.5-(q-j)*.5;o=(i+p)*.5-(p-i)*.5;m=(m+r)*.5+(r-m)*.5;j=(j+q)*.5+(q-j)*.5;i=(i+p)*.5+(p-i)*.5;b=(c[b+40>>2]|0)==0?f:e;g[h>>2]=k;g[h+4>>2]=n;g[h+8>>2]=o;g[h+12>>2]=0.0;g[h+16>>2]=m;g[h+20>>2]=n;g[h+24>>2]=o;g[h+28>>2]=0.0;g[h+32>>2]=m;g[h+36>>2]=j;g[h+40>>2]=o;g[h+44>>2]=0.0;g[h+48>>2]=k;g[h+52>>2]=j;g[h+56>>2]=o;g[h+60>>2]=0.0;g[h+64>>2]=k;g[h+68>>2]=n;g[h+72>>2]=i;g[h+76>>2]=0.0;g[h+80>>2]=m;g[h+84>>2]=n;g[h+88>>2]=i;g[h+92>>2]=0.0;g[h+96>>2]=m;g[h+100>>2]=j;g[h+104>>2]=i;g[h+108>>2]=0.0;g[h+112>>2]=k;g[h+116>>2]=j;g[h+120>>2]=i;g[h+124>>2]=0.0;Vb[c[(c[a>>2]|0)+8>>2]&127](a,h,h+16|0,b);Vb[c[(c[a>>2]|0)+8>>2]&127](a,h+16|0,h+32|0,b);Vb[c[(c[a>>2]|0)+8>>2]&127](a,h+32|0,h+48|0,b);Vb[c[(c[a>>2]|0)+8>>2]&127](a,h+48|0,h,b);Vb[c[(c[a>>2]|0)+8>>2]&127](a,h+64|0,h+80|0,b);Vb[c[(c[a>>2]|0)+8>>2]&127](a,h+80|0,h+96|0,b);Vb[c[(c[a>>2]|0)+8>>2]&127](a,h+96|0,h+112|0,b);Vb[c[(c[a>>2]|0)+8>>2]&127](a,h+112|0,h+64|0,b);Vb[c[(c[a>>2]|0)+8>>2]&127](a,h,h+64|0,b);Vb[c[(c[a>>2]|0)+8>>2]&127](a,h+16|0,h+80|0,b);Vb[c[(c[a>>2]|0)+8>>2]&127](a,h+32|0,h+96|0,b);Vb[c[(c[a>>2]|0)+8>>2]&127](a,h+48|0,h+112|0,b);l=h;return}function zf(b,d,e,f,h,i){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;var j=0,k=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0;r=l;l=l+96|0;n=r;o=n+96|0;do{c[n>>2]=0;n=n+4|0}while((n|0)<(o|0));if(!i)q=c[c[b+880>>2]>>2]|0;else q=i;i=c[b+772>>2]|0;if((i|0)==(c[b+776>>2]|0)?(p=i|0?i<<1:1,(i|0)<(p|0)):0){if(!p)j=0;else{c[6432]=(c[6432]|0)+1;i=ec((p*104|3)+16|0)|0;if(!i)j=0;else{c[(i+4+15&-16)+-4>>2]=i;j=i+4+15&-16}i=c[b+772>>2]|0}if((i|0)>0){k=0;do{n=j+(k*104|0)|0;m=(c[b+780>>2]|0)+(k*104|0)|0;o=n+104|0;do{c[n>>2]=c[m>>2];n=n+4|0;m=m+4|0}while((n|0)<(o|0));k=k+1|0}while((k|0)!=(i|0))}i=c[b+780>>2]|0;if(i|0){if(a[b+784>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[b+780>>2]=0}a[b+784>>0]=1;c[b+780>>2]=j;c[b+776>>2]=p;i=c[b+772>>2]|0}n=c[b+780>>2]|0;c[n+(i*104|0)>>2]=0;c[n+(i*104|0)+4>>2]=q;n=n+(i*104|0)+8|0;m=r;o=n+96|0;do{c[n>>2]=c[m>>2];n=n+4|0;m=m+4|0}while((n|0)<(o|0));q=c[b+772>>2]|0;c[b+772>>2]=q+1;p=c[b+780>>2]|0;k=c[b+720>>2]|0;c[p+(q*104|0)+8>>2]=k+(d*104|0);o=c[b+720>>2]|0;c[p+(q*104|0)+12>>2]=o+(e*104|0);m=c[b+720>>2]|0;c[p+(q*104|0)+16>>2]=m+(f*104|0);n=c[b+720>>2]|0;c[p+(q*104|0)+20>>2]=n+(h*104|0);z=+g[k+(d*104|0)+8>>2];w=+g[k+(d*104|0)+12>>2];A=+g[k+(d*104|0)+16>>2];t=+g[m+(f*104|0)+8>>2]-z;y=+g[m+(f*104|0)+12>>2]-w;v=+g[m+(f*104|0)+16>>2]-A;u=+g[n+(h*104|0)+8>>2]-z;x=+g[n+(h*104|0)+12>>2]-w;s=+g[n+(h*104|0)+16>>2]-A;g[p+(q*104|0)+24>>2]=(+g[o+(e*104|0)+16>>2]-A)*(t*x-y*u)+((+g[o+(e*104|0)+8>>2]-z)*(y*s-v*x)+(+g[o+(e*104|0)+12>>2]-w)*(v*u-t*s));a[b+924>>0]=1;l=r;return}function Af(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0.0;f=l;l=l+784|0;c[f+712>>2]=1065353216;c[f+712+4>>2]=0;c[f+712+4+4>>2]=0;c[f+712+4+8>>2]=0;c[f+712+4+12>>2]=0;c[f+712+20>>2]=1065353216;c[f+712+24>>2]=0;c[f+712+24+4>>2]=0;c[f+712+24+8>>2]=0;c[f+712+24+12>>2]=0;c[f+712+40>>2]=1065353216;e=f+712+44|0;c[e>>2]=0;c[e+4>>2]=0;c[e+8>>2]=0;c[e+12>>2]=0;c[e+16>>2]=0;c[f+536>>2]=3816;c[f+536+168>>2]=0;g[f+536+172>>2]=0.0;c[f+536+164>>2]=c[b+200>>2];e=c[b+196>>2]|0;c[f+480+8>>2]=0;c[f+480+12>>2]=1065353216;c[f+480+16>>2]=1065353216;c[f+480+20>>2]=1065353216;g[f+480+24>>2]=0.0;c[f+480>>2]=6796;c[f+480+4>>2]=8;c[f+480+28>>2]=e;c[f+480+44>>2]=e;c[f+376+8>>2]=0;c[f+376+12>>2]=1065353216;c[f+376+16>>2]=1065353216;c[f+376+20>>2]=1065353216;g[f+376+24>>2]=0.0;g[f+376+44>>2]=.03999999910593033;c[f+376+52>>2]=0;c[f+376>>2]=3844;c[f+376+4>>2]=1;c[f+376+56>>2]=c[d>>2];c[f+376+56+4>>2]=c[d+4>>2];c[f+376+56+8>>2]=c[d+8>>2];c[f+376+56+12>>2]=c[d+12>>2];c[f+376+72>>2]=c[d+16>>2];c[f+376+72+4>>2]=c[d+16+4>>2];c[f+376+72+8>>2]=c[d+16+8>>2];c[f+376+72+12>>2]=c[d+16+12>>2];c[f+376+88>>2]=c[d+32>>2];c[f+376+88+4>>2]=c[d+32+4>>2];c[f+376+88+8>>2]=c[d+32+8>>2];c[f+376+88+12>>2]=c[d+32+12>>2];g[f+16+308>>2]=9.999999747378752e-05;a[f+16+332>>0]=0;c[f>>2]=5088;c[f+4>>2]=f+16;c[f+8>>2]=f+480;c[f+12>>2]=f+376;if(Yc(f,b+4|0,b+68|0,f+712|0,f+712|0,f+536|0)|0?(h=+g[f+536+164>>2],+g[b+200>>2]>h):0)g[b+200>>2]=h;c[f+376>>2]=7248;e=c[f+376+52>>2]|0;if(!e){l=f;return}hb[c[c[e>>2]>>2]&511](e);e=c[f+376+52>>2]|0;if(!e){l=f;return}c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0);l=f;return}function Bf(d,e,f,g,h,i,j,k,m){d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;m=m|0;var n=0,o=0;o=l;l=l+48|0;c[6432]=(c[6432]|0)+1;g=ec(83)|0;if(!g)n=0;else{c[(g+4+15&-16)+-4>>2]=g;n=g+4+15&-16}c[n>>2]=h;b[n+4>>1]=i;b[n+6>>1]=j;i=n+16|0;c[i>>2]=c[e>>2];c[i+4>>2]=c[e+4>>2];c[i+8>>2]=c[e+8>>2];c[i+12>>2]=c[e+12>>2];i=n+32|0;c[i>>2]=c[f>>2];c[i+4>>2]=c[f+4>>2];c[i+8>>2]=c[f+8>>2];c[i+12>>2]=c[f+12>>2];c[n+8>>2]=0;i=n+56|0;c[i>>2]=0;j=n+52|0;c[j>>2]=0;c[o+16>>2]=c[e>>2];c[o+16+4>>2]=c[e+4>>2];c[o+16+8>>2]=c[e+8>>2];c[o+16+12>>2]=c[e+12>>2];c[o+16+16>>2]=c[f>>2];c[o+16+16+4>>2]=c[f+4>>2];c[o+16+16+8>>2]=c[f+8>>2];c[o+16+16+12>>2]=c[f+12>>2];c[n+60>>2]=c[d+144>>2];g=(c[d+188>>2]|0)+1|0;c[d+188>>2]=g;c[n+12>>2]=g;g=c[d+8>>2]|0;if(!g){c[6432]=(c[6432]|0)+1;g=ec(63)|0;if(!g)g=0;else{c[(g+4+15&-16)+-4>>2]=g;g=g+4+15&-16}k=g;m=k+44|0;do{c[k>>2]=0;k=k+4|0}while((k|0)<(m|0))}else c[d+8>>2]=0;c[g+32>>2]=0;c[g+36>>2]=n;c[g+40>>2]=0;c[g>>2]=c[o+16>>2];c[g+4>>2]=c[o+16+4>>2];c[g+8>>2]=c[o+16+8>>2];c[g+12>>2]=c[o+16+12>>2];c[g+16>>2]=c[o+16+16>>2];c[g+20>>2]=c[o+16+20>>2];c[g+24>>2]=c[o+16+24>>2];c[g+28>>2]=c[o+16+28>>2];We(d+4|0,c[d+4>>2]|0,g);c[d+16>>2]=(c[d+16>>2]|0)+1;c[n+48>>2]=g;k=d+124+(c[d+144>>2]<<2)|0;c[j>>2]=0;c[i>>2]=c[k>>2];g=c[k>>2]|0;if(g|0)c[g+52>>2]=n;c[k>>2]=n;if(a[d+193>>0]|0){l=o;return n|0}c[o>>2]=9028;c[o+4>>2]=d;c[o+8>>2]=n;Qe(c[d+4>>2]|0,o+16|0,o);Qe(c[d+64>>2]|0,o+16|0,o);l=o;return n|0}function Cf(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0;f=l;l=l+608|0;p=+g[d+116>>2]-+g[d+52>>2];o=+g[d+120>>2]-+g[d+56>>2];n=+g[d+124>>2]-+g[d+60>>2];i=+g[e+116>>2]-+g[e+52>>2];k=+g[e+120>>2]-+g[e+56>>2];j=+g[e+124>>2]-+g[e+60>>2];m=+g[d+252>>2];if(p*p+o*o+n*n<m*m?(p=+g[e+252>>2],i*i+k*k+j*j<p*p):0){p=1.0;l=f;return +p}b=c[d+192>>2]|0;h=c[e+248>>2]|0;c[f+552+8>>2]=0;c[f+552+12>>2]=1065353216;c[f+552+16>>2]=1065353216;c[f+552+20>>2]=1065353216;g[f+552+24>>2]=0.0;c[f+552>>2]=6796;c[f+552+4>>2]=8;c[f+552+28>>2]=h;c[f+552+44>>2]=h;c[f+376>>2]=3816;g[f+376+164>>2]=999999984306749440.0;c[f+376+168>>2]=0;g[f+376+172>>2]=0.0;g[f+16+308>>2]=9.999999747378752e-05;a[f+16+332>>0]=0;c[f>>2]=9292;c[f+4>>2]=f+16;c[f+8>>2]=b;c[f+12>>2]=f+552;if(jd(f,d+4|0,d+68|0,e+4|0,e+68|0,f+376|0)|0){i=+g[f+376+164>>2];if(+g[d+244>>2]>i)g[d+244>>2]=i;if(+g[e+244>>2]>i)g[e+244>>2]=i;if(i<1.0)j=i;else j=1.0}else j=1.0;b=c[e+192>>2]|0;h=c[d+248>>2]|0;c[f+552+8>>2]=0;c[f+552+12>>2]=1065353216;c[f+552+16>>2]=1065353216;c[f+552+20>>2]=1065353216;g[f+552+24>>2]=0.0;c[f+552>>2]=6796;c[f+552+4>>2]=8;c[f+552+28>>2]=h;c[f+552+44>>2]=h;c[f+376>>2]=3816;g[f+376+164>>2]=999999984306749440.0;c[f+376+168>>2]=0;g[f+376+172>>2]=0.0;g[f+16+308>>2]=9.999999747378752e-05;a[f+16+332>>0]=0;c[f>>2]=9292;c[f+4>>2]=f+16;c[f+8>>2]=f+552;c[f+12>>2]=b;if(jd(f,d+4|0,d+68|0,e+4|0,e+68|0,f+376|0)|0){i=+g[f+376+164>>2];if(+g[d+244>>2]>i)g[d+244>>2]=i;if(+g[e+244>>2]>i)g[e+244>>2]=i;if(!(j>i))i=j}else i=j;p=i;l=f;return +p}function Df(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0,j=0,k=0,m=0,n=0,o=0,p=0,q=0,r=0.0,s=0.0,t=0.0;q=l;l=l+48|0;p=c[b+720>>2]|0;a:do if(h?(k=c[b+732>>2]|0,(k|0)>0):0){h=c[b+740>>2]|0;j=0;while(1){i=c[h+(j*52|0)+8>>2]|0;if((i|0)==(p+(d*104|0)|0)?(c[h+(j*52|0)+12>>2]|0)==(p+(e*104|0)|0):0){h=25;break}if((i|0)==(p+(e*104|0)|0)?(c[h+(j*52|0)+12>>2]|0)==(p+(d*104|0)|0):0){h=25;break}j=j+1|0;if((j|0)>=(k|0))break a}if((h|0)==25){l=q;return}}while(0);m=q;n=m+44|0;do{c[m>>2]=0;m=m+4|0}while((m|0)<(n|0));if(!f)f=c[c[b+880>>2]>>2]|0;h=c[b+732>>2]|0;if((h|0)==(c[b+736>>2]|0)?(o=h|0?h<<1:1,(h|0)<(o|0)):0){if(!o)i=0;else{c[6432]=(c[6432]|0)+1;h=ec((o*52|3)+16|0)|0;if(!h)i=0;else{c[(h+4+15&-16)+-4>>2]=h;i=h+4+15&-16}h=c[b+732>>2]|0}if((h|0)>0){j=0;do{m=i+(j*52|0)|0;k=(c[b+740>>2]|0)+(j*52|0)|0;n=m+52|0;do{c[m>>2]=c[k>>2];m=m+4|0;k=k+4|0}while((m|0)<(n|0));j=j+1|0}while((j|0)!=(h|0))}h=c[b+740>>2]|0;if(h|0){if(a[b+744>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[b+740>>2]=0}a[b+744>>0]=1;c[b+740>>2]=i;c[b+736>>2]=o;h=c[b+732>>2]|0}m=c[b+740>>2]|0;c[m+(h*52|0)>>2]=0;c[m+(h*52|0)+4>>2]=f;m=m+(h*52|0)+8|0;k=q;n=m+44|0;do{c[m>>2]=c[k>>2];m=m+4|0;k=k+4|0}while((m|0)<(n|0));o=c[b+732>>2]|0;c[b+732>>2]=o+1;f=c[b+740>>2]|0;c[f+(o*52|0)+8>>2]=p+(d*104|0);c[f+(o*52|0)+12>>2]=p+(e*104|0);t=+g[p+(d*104|0)+8>>2]-+g[p+(e*104|0)+8>>2];s=+g[p+(d*104|0)+12>>2]-+g[p+(e*104|0)+12>>2];r=+g[p+(d*104|0)+16>>2]-+g[p+(e*104|0)+16>>2];g[f+(o*52|0)+16>>2]=+C(+(t*t+s*s+r*r));a[b+924>>0]=1;l=q;return}function Ef(a,d){a=a|0;d=d|0;var e=0,f=0,h=0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0;e=l;l=l+128|0;G=c[(c[a+8>>2]|0)+24>>2]|0;h=c[G+(d*80|0)+64>>2]|0;f=c[a+12>>2]|0;x=+g[G+(d*80|0)>>2];D=+g[f>>2];w=+g[G+(d*80|0)+16>>2];C=+g[f+4>>2];v=+g[G+(d*80|0)+32>>2];B=+g[f+8>>2];u=+g[G+(d*80|0)+4>>2];t=+g[G+(d*80|0)+20>>2];s=+g[G+(d*80|0)+36>>2];r=+g[G+(d*80|0)+8>>2];p=+g[G+(d*80|0)+24>>2];n=+g[G+(d*80|0)+40>>2];A=+g[f+16>>2];z=+g[f+20>>2];y=+g[f+24>>2];q=+g[f+32>>2];o=+g[f+36>>2];m=+g[f+40>>2];F=+g[G+(d*80|0)+48>>2];E=+g[G+(d*80|0)+52>>2];i=+g[G+(d*80|0)+56>>2];k=+g[f+48>>2]+(D*F+C*E+B*i);j=A*F+z*E+y*i+ +g[f+52>>2];i=q*F+o*E+m*i+ +g[f+56>>2];g[e+56>>2]=x*D+w*C+v*B;g[e+56+4>>2]=D*u+C*t+B*s;g[e+56+8>>2]=D*r+C*p+B*n;g[e+56+12>>2]=0.0;g[e+56+16>>2]=x*A+w*z+v*y;g[e+56+20>>2]=u*A+t*z+s*y;g[e+56+24>>2]=r*A+p*z+n*y;g[e+56+28>>2]=0.0;g[e+56+32>>2]=x*q+w*o+v*m;g[e+56+36>>2]=u*q+t*o+s*m;g[e+56+40>>2]=r*q+p*o+n*m;g[e+56+44>>2]=0.0;g[e+56+48>>2]=k;g[e+56+52>>2]=j;g[e+56+56>>2]=i;g[e+56+60>>2]=0.0;f=c[a+4>>2]|0;c[e+32>>2]=0;c[e+32+4>>2]=h;c[e+32+8>>2]=f;c[e+32+12>>2]=e+56;c[e+32+16>>2]=-1;c[e+32+20>>2]=d;f=c[a+24>>2]|0;g[e+4>>2]=1.0;c[e+8>>2]=0;b[e+12>>1]=1;b[e+14>>1]=-1;c[e+16>>2]=0;c[e>>2]=5920;c[e+20>>2]=f;c[e+24>>2]=d;c[e+4>>2]=c[f+4>>2];c[e+16>>2]=c[f+16>>2];Jc(c[a+16>>2]|0,c[a+20>>2]|0,e+32|0,e);l=e;return}function Ff(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0.0,h=0,i=0,j=0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0;i=l;l=l+96|0;f=+zb[c[(c[a>>2]|0)+48>>2]&15](a);h=0;do{q=i+80+(h<<2)|0;c[i+80>>2]=0;c[i+80+4>>2]=0;c[i+80+8>>2]=0;c[i+80+12>>2]=0;g[q>>2]=1.0;j=c[(c[a>>2]|0)+64>>2]|0;k=+g[i+80>>2];m=+g[i+80+4>>2];n=+g[i+80+8>>2];o=k*+g[b+4>>2]+m*+g[b+20>>2]+n*+g[b+36>>2];p=k*+g[b+8>>2]+m*+g[b+24>>2]+n*+g[b+40>>2];g[i+48>>2]=+g[b>>2]*k+ +g[b+16>>2]*m+ +g[b+32>>2]*n;g[i+48+4>>2]=o;g[i+48+8>>2]=p;g[i+48+12>>2]=0.0;Rb[j&127](i+64|0,a,i+48|0);p=+g[i+64>>2];o=+g[i+64+4>>2];n=+g[i+64+8>>2];m=p*+g[b+16>>2]+o*+g[b+20>>2]+n*+g[b+24>>2]+ +g[b+52>>2];k=p*+g[b+32>>2]+o*+g[b+36>>2]+n*+g[b+40>>2]+ +g[b+56>>2];g[i+32>>2]=p*+g[b>>2]+o*+g[b+4>>2]+n*+g[b+8>>2]+ +g[b+48>>2];g[i+32+4>>2]=m;g[i+32+8>>2]=k;g[i+32+12>>2]=0.0;j=i+32+(h<<2)|0;g[e+(h<<2)>>2]=f+ +g[j>>2];g[q>>2]=-1.0;q=c[(c[a>>2]|0)+64>>2]|0;k=+g[i+80>>2];m=+g[i+80+4>>2];n=+g[i+80+8>>2];o=k*+g[b+4>>2]+m*+g[b+20>>2]+n*+g[b+36>>2];p=k*+g[b+8>>2]+m*+g[b+24>>2]+n*+g[b+40>>2];g[i>>2]=+g[b>>2]*k+ +g[b+16>>2]*m+ +g[b+32>>2]*n;g[i+4>>2]=o;g[i+8>>2]=p;g[i+12>>2]=0.0;Rb[q&127](i+16|0,a,i);p=+g[i+16>>2];o=+g[i+16+4>>2];n=+g[i+16+8>>2];m=p*+g[b+16>>2]+o*+g[b+20>>2]+n*+g[b+24>>2]+ +g[b+52>>2];k=p*+g[b+32>>2]+o*+g[b+36>>2]+n*+g[b+40>>2]+ +g[b+56>>2];g[i+32>>2]=p*+g[b>>2]+o*+g[b+4>>2]+n*+g[b+8>>2]+ +g[b+48>>2];g[i+32+4>>2]=m;g[i+32+8>>2]=k;g[i+32+12>>2]=0.0;g[d+(h<<2)>>2]=+g[j>>2]-f;h=h+1|0}while((h|0)!=3);l=i;return}function Gf(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0,j=0,k=0,m=0,n=0,o=0,p=0;k=l;l=l+160|0;i=c[b+12>>2]|0;if(!i){l=k;return}m=(a[b+16>>0]|0)!=0;n=m?e:d;e=m?d:e;p=c[n+4>>2]|0;o=c[e+4>>2]|0;c[h+4>>2]=i;d=c[i+752>>2]|0;c[k+136>>2]=9456;c[k+136+4>>2]=p;c[k+136+8>>2]=o;c[k+136+12>>2]=d;g[k+128>>2]=999999984306749440.0;d=c[n+12>>2]|0;c[k>>2]=c[d>>2];c[k+4>>2]=c[d+4>>2];c[k+8>>2]=c[d+8>>2];c[k+12>>2]=c[d+12>>2];c[k+16>>2]=c[d+16>>2];c[k+16+4>>2]=c[d+16+4>>2];c[k+16+8>>2]=c[d+16+8>>2];c[k+16+12>>2]=c[d+16+12>>2];c[k+32>>2]=c[d+32>>2];c[k+32+4>>2]=c[d+32+4>>2];c[k+32+8>>2]=c[d+32+8>>2];c[k+32+12>>2]=c[d+32+12>>2];c[k+48>>2]=c[d+48>>2];c[k+48+4>>2]=c[d+48+4>>2];c[k+48+8>>2]=c[d+48+8>>2];c[k+48+12>>2]=c[d+48+12>>2];e=c[e+12>>2]|0;c[k+64>>2]=c[e>>2];c[k+64+4>>2]=c[e+4>>2];c[k+64+8>>2]=c[e+8>>2];c[k+64+12>>2]=c[e+12>>2];c[k+80>>2]=c[e+16>>2];c[k+80+4>>2]=c[e+16+4>>2];c[k+80+8>>2]=c[e+16+8>>2];c[k+80+12>>2]=c[e+16+12>>2];c[k+96>>2]=c[e+32>>2];c[k+96+4>>2]=c[e+32+4>>2];c[k+96+8>>2]=c[e+32+8>>2];c[k+96+12>>2]=c[e+32+12>>2];c[k+112>>2]=c[e+48>>2];c[k+112+4>>2]=c[e+48+4>>2];c[k+112+8>>2]=c[e+48+8>>2];c[k+112+12>>2]=c[e+48+12>>2];Fd(k+136|0,k,h,c[f+20>>2]|0,m);do if(a[b+8>>0]|0?(j=c[h+4>>2]|0,c[j+748>>2]|0):0){e=c[j+740>>2]|0;d=c[(c[h+8>>2]|0)+8>>2]|0;i=c[(c[h+12>>2]|0)+8>>2]|0;if((e|0)==(d|0)){Le(j,e+4|0,i+4|0);break}else{Le(j,i+4|0,d+4|0);break}}while(0);l=k;return}function Hf(a){a=a|0;var b=0,d=0,e=0,f=0,h=0,i=0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0,q=0;b=c[a+752>>2]|0;if((b|0)>0){d=c[a+760>>2]|0;e=0;do{f=c[d+(e*44|0)+8>>2]|0;h=c[d+(e*44|0)+12>>2]|0;i=c[d+(e*44|0)+16>>2]|0;l=+g[f+8>>2];n=+g[f+12>>2];j=+g[f+16>>2];k=+g[h+8>>2]-l;o=+g[h+12>>2]-n;m=+g[h+16>>2]-j;l=+g[i+8>>2]-l;n=+g[i+12>>2]-n;j=+g[i+16>>2]-j;g[d+(e*44|0)+36>>2]=+C(+((k*n-o*l)*(k*n-o*l)+((o*j-m*n)*(o*j-m*n)+(m*l-k*j)*(m*l-k*j))));e=e+1|0}while((e|0)!=(b|0))}d=c[a+712>>2]|0;if((d|0)>0){c[6432]=(c[6432]|0)+1;b=ec((d<<2|3)+16|0)|0;if(!b)f=0;else{c[(b+4+15&-16)+-4>>2]=b;f=b+4+15&-16}Hk(f|0,0,d<<2|0)|0;d=c[a+712>>2]|0;if((d|0)>0){b=c[a+720>>2]|0;e=0;do{g[b+(e*104|0)+92>>2]=0.0;e=e+1|0}while((e|0)!=(d|0));i=f;h=f}else{i=f;h=f}}else{i=0;h=0}f=c[a+752>>2]|0;if((f|0)>0){b=c[a+760>>2]|0;d=c[a+720>>2]|0;e=0;do{o=+B(+(+g[b+(e*44|0)+36>>2]));p=c[b+(e*44|0)+8>>2]|0;q=h+(((p-d|0)/104|0)<<2)|0;c[q>>2]=(c[q>>2]|0)+1;g[p+92>>2]=o+ +g[p+92>>2];p=c[b+(e*44|0)+12>>2]|0;q=h+(((p-d|0)/104|0)<<2)|0;c[q>>2]=(c[q>>2]|0)+1;g[p+92>>2]=o+ +g[p+92>>2];p=c[b+(e*44|0)+16>>2]|0;q=h+(((p-d|0)/104|0)<<2)|0;c[q>>2]=(c[q>>2]|0)+1;g[p+92>>2]=o+ +g[p+92>>2];e=e+1|0}while((e|0)!=(f|0));d=c[a+712>>2]|0}if((d|0)>0){e=0;do{b=c[h+(e<<2)>>2]|0;if((b|0)>0){q=(c[a+720>>2]|0)+(e*104|0)+92|0;g[q>>2]=+g[q>>2]/+(b|0)}else g[(c[a+720>>2]|0)+(e*104|0)+92>>2]=0.0;e=e+1|0}while((e|0)!=(d|0));if(!i)return}else if((h|0)==0|(i|0)==0)return;c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0);return}function If(b,d){b=b|0;d=+d;var e=0,f=0,h=0,i=0,j=0,k=0,m=0,n=0.0,o=0.0,p=0.0,q=0.0;m=l;l=l+16|0;Yi(12192);e=c[b+232>>2]|0;if((e|0)>0){k=(a[26312]|0)==0;j=0;do{i=c[(c[b+240>>2]|0)+(j<<2)>>2]|0;a:do if(i){f=c[i+216>>2]|0;b:do switch(f|0){case 4:case 2:{if((f|0)==4)break a;break}default:{q=+g[i+312>>2];p=+g[i+316>>2];o=+g[i+320>>2];n=+g[i+472>>2];if(q*q+p*p+o*o<n*n?(n=+g[i+328>>2],o=+g[i+332>>2],p=+g[i+336>>2],q=+g[i+476>>2],n*n+o*o+p*p<q*q):0){g[i+220>>2]=+g[i+220>>2]+d;break b}g[i+220>>2]=0.0;if((f&-2|0)!=4){c[i+216>>2]=0;f=0}}}while(0);h=f&-2;do if(k){if((h|0)!=2?!(+g[i+220>>2]>2.0):0)break;if(c[i+204>>2]&3|0){if((h|0)==4)break a;c[i+216>>2]=2;break a}if((f|0)==1){if((h|0)==4)break a;c[i+216>>2]=3;break a}else{if((f|0)!=2)break a;e=(c[i+260>>2]|0)+2|0;c[i+328>>2]=0;c[i+328+4>>2]=0;c[i+328+8>>2]=0;c[i+328+12>>2]=0;c[i+260>>2]=e;c[i+312>>2]=0;c[i+312+4>>2]=0;c[i+312+8>>2]=0;c[i+312+12>>2]=0;e=c[b+232>>2]|0;break a}}while(0);if((h|0)!=4)c[i+216>>2]=1}while(0);j=j+1|0}while((j|0)<(e|0))}e=c[2395]|0;k=(c[e+16>>2]|0)+-1|0;c[e+16>>2]=k;if(k|0){l=m;return}do if(c[e+4>>2]|0){Va(m|0,0)|0;k=c[6431]|0;g[e+8>>2]=+g[e+8>>2]+ +(((c[m+4>>2]|0)-(c[k+4>>2]|0)+(((c[m>>2]|0)-(c[k>>2]|0)|0)*1e6|0)-(c[e+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[e+16>>2]|0)){e=c[2395]|0;break}else{l=m;return}}while(0);c[2395]=c[e+20>>2];l=m;return}function Jf(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0;I=l;l=l+32|0;j=+g[b+16>>2];f=+g[b>>2];k=+g[b+20>>2];h=+g[b+4>>2];o=+g[b+24>>2];i=+g[b+8>>2];t=+g[b+32>>2];x=+g[b+36>>2];y=+g[b+40>>2];F=(k-h)*(y-i)-(o-i)*(x-h);G=(o-i)*(t-f)-(j-f)*(y-i);H=(j-f)*(x-h)-(k-h)*(t-f);g[I+16>>2]=F;g[I+16+4>>2]=G;g[I+16+8>>2]=H;g[I+16+12>>2]=0.0;p=+g[a+4>>2];r=+g[a+8>>2];v=+g[a+12>>2];E=F*p+G*r+H*v-(f*F+h*G+i*H);n=+g[a+20>>2];s=+g[a+24>>2];w=+g[a+28>>2];if(E*(F*n+G*s+H*w-(f*F+h*G+i*H))>=0.0){l=I;return}B=c[a+36>>2]|0;if(E<=0.0&(B&1|0)!=0){l=I;return}D=E/(E-(F*n+G*s+H*w-(f*F+h*G+i*H)));if(!(D<+g[a+40>>2])){l=I;return}A=(F*F+G*G+H*H)*-9.999999747378752e-05;z=f-(n*D+p*(1.0-D));u=h-(s*D+r*(1.0-D));q=i-(w*D+v*(1.0-D));m=j-(n*D+p*(1.0-D));k=k-(s*D+r*(1.0-D));j=o-(w*D+v*(1.0-D));if(!(H*(z*k-u*m)+(F*(u*j-q*k)+G*(q*m-z*j))>=A)){l=I;return}i=t-(n*D+p*(1.0-D));h=x-(s*D+r*(1.0-D));f=y-(w*D+v*(1.0-D));if(!(H*(m*h-k*i)+(F*(k*f-j*h)+G*(j*i-m*f))>=A)){l=I;return}if(!(H*(u*i-z*h)+(F*(q*h-u*f)+G*(z*f-q*i))>=A)){l=I;return}f=1.0/+C(+(F*F+G*G+H*H));g[I+16>>2]=F*f;g[I+16+4>>2]=G*f;g[I+16+8>>2]=H*f;b=c[(c[a>>2]|0)+12>>2]|0;if(E<=0.0&(B&2|0)==0){g[I>>2]=-(F*f);g[I+4>>2]=-(G*f);g[I+8>>2]=-(H*f);g[I+12>>2]=0.0;g[a+40>>2]=+Nb[b&3](a,I,D,d,e);l=I;return}else{g[a+40>>2]=+Nb[b&3](a,I+16|0,D,d,e);l=I;return}}function Kf(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0,j=0,k=0,m=0,n=0;k=l;l=l+144|0;i=c[b+12>>2]|0;if(!i){l=k;return}n=c[d+4>>2]|0;m=c[e+4>>2]|0;c[h+4>>2]=i;g[k+12+128>>2]=999999984306749440.0;d=c[d+12>>2]|0;c[k+12>>2]=c[d>>2];c[k+12+4>>2]=c[d+4>>2];c[k+12+8>>2]=c[d+8>>2];c[k+12+12>>2]=c[d+12>>2];c[k+12+16>>2]=c[d+16>>2];c[k+12+16+4>>2]=c[d+16+4>>2];c[k+12+16+8>>2]=c[d+16+8>>2];c[k+12+16+12>>2]=c[d+16+12>>2];c[k+12+32>>2]=c[d+32>>2];c[k+12+32+4>>2]=c[d+32+4>>2];c[k+12+32+8>>2]=c[d+32+8>>2];c[k+12+32+12>>2]=c[d+32+12>>2];c[k+12+48>>2]=c[d+48>>2];c[k+12+48+4>>2]=c[d+48+4>>2];c[k+12+48+8>>2]=c[d+48+8>>2];c[k+12+48+12>>2]=c[d+48+12>>2];e=c[e+12>>2]|0;c[k+12+64>>2]=c[e>>2];c[k+12+64+4>>2]=c[e+4>>2];c[k+12+64+8>>2]=c[e+8>>2];c[k+12+64+12>>2]=c[e+12>>2];c[k+12+80>>2]=c[e+16>>2];c[k+12+80+4>>2]=c[e+16+4>>2];c[k+12+80+8>>2]=c[e+16+8>>2];c[k+12+80+12>>2]=c[e+16+12>>2];c[k+12+96>>2]=c[e+32>>2];c[k+12+96+4>>2]=c[e+32+4>>2];c[k+12+96+8>>2]=c[e+32+8>>2];c[k+12+96+12>>2]=c[e+32+12>>2];c[k+12+112>>2]=c[e+48>>2];c[k+12+112+4>>2]=c[e+48+4>>2];c[k+12+112+8>>2]=c[e+48+8>>2];c[k+12+112+12>>2]=c[e+48+12>>2];c[k>>2]=9436;c[k+4>>2]=n;c[k+8>>2]=m;gc(k,k+12|0,h,c[f+20>>2]|0,0);do if(a[b+8>>0]|0?(j=c[h+4>>2]|0,c[j+748>>2]|0):0){d=c[j+740>>2]|0;e=c[(c[h+8>>2]|0)+8>>2]|0;i=c[(c[h+12>>2]|0)+8>>2]|0;if((d|0)==(e|0)){Le(j,d+4|0,i+4|0);break}else{Le(j,i+4|0,e+4|0);break}}while(0);l=k;return}function Lf(b,d,e,f,h,i,j,k,m){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;j=j|0;k=k|0;m=m|0;var n=0,o=0,p=0,q=0,r=0;r=l;l=l+80|0;g[r+16+60>>2]=0.0;g[r+16+8>>2]=0.0;g[r+16+12>>2]=.10000000149011612;g[r+16+16>>2]=300.0;g[r+16>>2]=1.0;g[r+16+4>>2]=-1.0;g[r+16+28>>2]=0.0;g[r+16+32>>2]=.20000000298023224;g[r+16+36>>2]=0.0;g[r+16+40>>2]=0.0;g[r+16+20>>2]=1.0;g[r+16+24>>2]=.5;c[r+16+56>>2]=0;g[r+16+48>>2]=0.0;a[r+16+44>>0]=0;p=0;do{o=c[b+856+(p<<2)>>2]|0;n=a[b+788+p>>0]|0;if(!o){if(n<<24>>24){n=1;q=5}}else q=5;if((q|0)==5){q=0;g[r+16+40>>2]=0.0;c[r+16+56>>2]=o;c[r+16+52>>2]=c[b+840+(p<<2)>>2];c[r+16+48>>2]=c[b+824+(p<<2)>>2];c[r+16+20>>2]=c[b+732>>2];a[r+16+44>>0]=n;c[r+16+4>>2]=c[b+696+(p<<2)>>2];c[r+16+24>>2]=c[b+728>>2];c[r+16>>2]=c[b+680+(p<<2)>>2];g[r+16+16>>2]=0.0;c[r+16+12>>2]=c[b+808+(p<<2)>>2];c[r+16+8>>2]=c[b+792+(p<<2)>>2];c[r>>2]=c[b+1064+(p<<2)>>2];c[r+4>>2]=c[b+1080+(p<<2)>>2];c[r+8>>2]=c[b+1096+(p<<2)>>2];g[r+12>>2]=0.0;o=c[b+1304>>2]>>p*3;if(!(o&1))n=c[d+32>>2]|0;else n=b+740+(p<<2)|0;c[r+16+28>>2]=c[n>>2];if(!(o&2))n=c[d+32>>2]|0;else n=b+772+(p<<2)|0;c[r+16+36>>2]=c[n>>2];c[r+16+32>>2]=c[((o&4|0)==0?d+4|0:b+756+(p<<2)|0)>>2];if(a[b+1301>>0]|0){o=p+1|0;if(!(c[b+868+(((o|0)==3?0:o)<<6)+56>>2]|0))n=1;else n=(c[b+868+(((p+2|0)%3|0)<<6)+56>>2]|0)==0&1}else n=0;e=(pd(b,r+16|0,f,h,i,j,k,m,d,e,r,0,n)|0)+e|0}p=p+1|0}while((p|0)!=3);l=r;return e|0}function Mf(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0,j=0,k=0,m=0,n=0,o=0,p=0,q=0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0;q=l;l=l+48|0;if((f|0)==(d|0)|((d|0)==(e|0)|(e|0)==(f|0))){l=q;return}m=q;n=m+36|0;do{c[m>>2]=0;m=m+4|0}while((m|0)<(n|0));if(!h)p=c[c[b+880>>2]>>2]|0;else p=h;h=c[b+752>>2]|0;if((h|0)==(c[b+756>>2]|0)?(o=h|0?h<<1:1,(h|0)<(o|0)):0){if(!o)i=0;else{c[6432]=(c[6432]|0)+1;h=ec((o*44|3)+16|0)|0;if(!h)i=0;else{c[(h+4+15&-16)+-4>>2]=h;i=h+4+15&-16}h=c[b+752>>2]|0}if((h|0)>0){j=0;do{m=i+(j*44|0)|0;k=(c[b+760>>2]|0)+(j*44|0)|0;n=m+44|0;do{c[m>>2]=c[k>>2];m=m+4|0;k=k+4|0}while((m|0)<(n|0));j=j+1|0}while((j|0)!=(h|0))}h=c[b+760>>2]|0;if(h|0){if(a[b+764>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[b+760>>2]=0}a[b+764>>0]=1;c[b+760>>2]=i;c[b+756>>2]=o;h=c[b+752>>2]|0}m=c[b+760>>2]|0;c[m+(h*44|0)>>2]=0;c[m+(h*44|0)+4>>2]=p;m=m+(h*44|0)+8|0;k=q;n=m+36|0;do{c[m>>2]=c[k>>2];m=m+4|0;k=k+4|0}while((m|0)<(n|0));p=c[b+752>>2]|0;c[b+752>>2]=p+1;o=c[b+760>>2]|0;k=c[b+720>>2]|0;c[o+(p*44|0)+8>>2]=k+(d*104|0);m=c[b+720>>2]|0;c[o+(p*44|0)+12>>2]=m+(e*104|0);n=c[b+720>>2]|0;c[o+(p*44|0)+16>>2]=n+(f*104|0);t=+g[k+(d*104|0)+8>>2];v=+g[k+(d*104|0)+12>>2];r=+g[k+(d*104|0)+16>>2];s=+g[m+(e*104|0)+8>>2]-t;w=+g[m+(e*104|0)+12>>2]-v;u=+g[m+(e*104|0)+16>>2]-r;t=+g[n+(f*104|0)+8>>2]-t;v=+g[n+(f*104|0)+12>>2]-v;r=+g[n+(f*104|0)+16>>2]-r;g[o+(p*44|0)+36>>2]=+C(+((s*v-w*t)*(s*v-w*t)+((w*r-u*v)*(w*r-u*v)+(u*t-s*r)*(u*t-s*r))));a[b+924>>0]=1;l=q;return}function Nf(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0;k=l;l=l+16|0;i=c[b+28>>2]|0;j=c[b+32>>2]|0;if(!(a[b+1301>>0]|0)){h=0;e=Lf(b,d,0,i+4|0,j+4|0,i+312|0,j+312|0,i+328|0,j+328|0)|0;do{f=b+868+(h<<6)|0;if(!((c[b+868+(h<<6)+56>>2]|0)==0?(a[b+868+(h<<6)+44>>0]|0)==0:0)){g=b+1208+(h<<4)|0;c[k>>2]=c[g>>2];c[k+4>>2]=c[g+4>>2];c[k+8>>2]=c[g+8>>2];c[k+12>>2]=c[g+12>>2];g=c[b+1304>>2]>>(h*3|0)+9;if(!(g&1))c[b+868+(h<<6)+28>>2]=c[c[d+32>>2]>>2];if(!(g&2))c[b+868+(h<<6)+36>>2]=c[c[d+32>>2]>>2];if(!(g&4))c[b+868+(h<<6)+32>>2]=c[d+4>>2];e=(pd(b,f,i+4|0,j+4|0,i+312|0,j+312|0,i+328|0,j+328|0,d,e,k,1,0)|0)+e|0}h=h+1|0}while((h|0)!=3);l=k;return}h=0;e=0;do{f=b+868+(h<<6)|0;if(!((c[b+868+(h<<6)+56>>2]|0)==0?(a[b+868+(h<<6)+44>>0]|0)==0:0)){g=b+1208+(h<<4)|0;c[k>>2]=c[g>>2];c[k+4>>2]=c[g+4>>2];c[k+8>>2]=c[g+8>>2];c[k+12>>2]=c[g+12>>2];g=c[b+1304>>2]>>(h*3|0)+9;if(!(g&1))c[b+868+(h<<6)+28>>2]=c[c[d+32>>2]>>2];if(!(g&2))c[b+868+(h<<6)+36>>2]=c[c[d+32>>2]>>2];if(!(g&4))c[b+868+(h<<6)+32>>2]=c[d+4>>2];e=(pd(b,f,i+4|0,j+4|0,i+312|0,j+312|0,i+328|0,j+328|0,d,e,k,1,0)|0)+e|0}h=h+1|0}while((h|0)!=3);Lf(b,d,e,i+4|0,j+4|0,i+312|0,j+312|0,i+328|0,j+328|0)|0;l=k;return}function Of(a,b,d){a=a|0;b=+b;d=+d;var e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,m=0,n=0.0,o=0.0,p=0.0,q=0,r=0,s=0.0,t=0,u=0,v=0,w=0.0,x=0.0,y=0.0,z=0.0;v=l;l=l+16|0;k=+g[a+452>>2];q=c[a+192>>2]|0;s=+zb[c[(c[q>>2]|0)+48>>2]&15](q);q=c[a+812>>2]|0;if((q|0)<=0){l=v;return}t=0;do{r=c[a+820>>2]|0;u=c[r+(t*104|0)>>2]|0;u=(c[u+236>>2]&2|0)==0?0:u;if(u|0){p=+g[u+332>>2];e=+g[r+(t*104|0)+84>>2];j=+g[u+336>>2];n=+g[r+(t*104|0)+80>>2];f=+g[r+(t*104|0)+76>>2];o=+g[u+328>>2];d=k*(p*e-j*n+ +g[u+312>>2]);e=k*(+g[u+316>>2]+(j*f-e*o));f=k*(n*o-p*f+ +g[u+320>>2])}else{d=0.0;e=0.0;f=0.0}m=c[r+(t*104|0)+24>>2]|0;n=+g[m+8>>2];o=+g[m+12>>2];p=+g[m+16>>2];j=n-+g[m+24>>2]-d;i=o-+g[m+28>>2]-e;h=p-+g[m+32>>2]-f;d=+g[r+(t*104|0)+4>>2];e=+g[r+(t*104|0)+8>>2];f=+g[r+(t*104|0)+12>>2];if(j*d+i*e+h*f<=1.1920928955078125e-07?(y=n*d+o*e+p*f+ +g[r+(t*104|0)+20>>2],z=+g[r+(t*104|0)+96>>2],y=(y<s?y:s)*+g[r+(t*104|0)+100>>2],x=(j-(j-d*(j*d+i*e+h*f))*z+d*y)*b,w=(i-(i-e*(j*d+i*e+h*f))*z+y*e)*b,j=(h-(h-f*(j*d+i*e+h*f))*z+y*f)*b,f=+g[r+(t*104|0)+28>>2]*x+ +g[r+(t*104|0)+32>>2]*w+ +g[r+(t*104|0)+36>>2]*j,h=x*+g[r+(t*104|0)+44>>2]+w*+g[r+(t*104|0)+48>>2]+j*+g[r+(t*104|0)+52>>2],j=x*+g[r+(t*104|0)+60>>2]+w*+g[r+(t*104|0)+64>>2]+j*+g[r+(t*104|0)+68>>2],g[v>>2]=f,g[v+4>>2]=h,g[v+8>>2]=j,g[v+12>>2]=0.0,i=+g[r+(t*104|0)+92>>2],g[m+8>>2]=n-f*i,g[m+12>>2]=o-i*h,g[m+16>>2]=p-i*j,u|0):0)Vk(u,v,r+(t*104|0)+76|0);t=t+1|0}while((t|0)!=(q|0));l=v;return}function Pf(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;e=c[a+56>>2]|0;if(!e){e=c[a+52>>2]|0;if(!e){c[6432]=(c[6432]|0)+1;e=ec(31)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}f=c[a+60>>2]|0;c[e+4>>2]=f;g=e+8|0;c[g>>2]=0;c[6432]=(c[6432]|0)+1;f=ec((f*24|3)+16|0)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}c[e>>2]=f;c[g>>2]=c[a+48>>2];c[a+48>>2]=e}else c[a+52>>2]=c[e+8>>2];h=c[e>>2]|0;e=c[e+4>>2]|0;if((e|0)>0){f=0;g=h;do{f=f+1|0;i=g;g=g+24|0;c[i>>2]=(f|0)<(e|0)?g:0}while((f|0)!=(e|0))}}else h=e;c[a+56>>2]=c[h>>2];c[h>>2]=0;c[h+4>>2]=0;c[h+8>>2]=0;c[h+12>>2]=0;c[h+16>>2]=0;c[h+20>>2]=0;e=c[a+56>>2]|0;if(!e){e=c[a+52>>2]|0;if(!e){c[6432]=(c[6432]|0)+1;e=ec(31)|0;if(!e)f=0;else{c[(e+4+15&-16)+-4>>2]=e;f=e+4+15&-16}e=c[a+60>>2]|0;c[f+4>>2]=e;g=f+8|0;c[g>>2]=0;c[6432]=(c[6432]|0)+1;e=ec((e*24|3)+16|0)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}c[f>>2]=e;c[g>>2]=c[a+48>>2];c[a+48>>2]=f}else{c[a+52>>2]=c[e+8>>2];f=e}e=c[f>>2]|0;f=c[f+4>>2]|0;if((f|0)>0){g=0;i=e;do{g=g+1|0;j=i;i=i+24|0;c[j>>2]=(g|0)<(f|0)?i:0}while((g|0)!=(f|0))}}c[a+56>>2]=c[e>>2];j=e;c[j>>2]=0;c[j+4>>2]=0;c[h+8>>2]=e;c[e+8>>2]=h;j=c[a+100>>2]|0;c[h+20>>2]=j;c[e+20>>2]=j;c[h+12>>2]=d;c[e+12>>2]=b;c[h+16>>2]=0;c[e+16>>2]=0;e=c[a+116>>2]|0;c[a+116>>2]=e+1;if((e|0)<(c[a+120>>2]|0))return h|0;c[a+120>>2]=e+1;return h|0}function Qf(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,h=0,i=0;c[b+4>>2]=1065353216;c[b+8>>2]=1065353216;c[b+12>>2]=1065353216;g[b+16>>2]=0.0;a[b+36>>0]=1;c[b+32>>2]=0;c[b+24>>2]=0;c[b+28>>2]=0;c[b+48>>2]=0;c[b>>2]=8576;a[b+100>>0]=1;c[b+96>>2]=0;c[b+88>>2]=0;c[b+92>>2]=0;a[b+120>>0]=1;c[b+116>>2]=0;c[b+108>>2]=0;c[b+112>>2]=0;a[b+140>>0]=1;c[b+136>>2]=0;c[b+128>>2]=0;c[b+132>>2]=0;a[b+160>>0]=1;c[b+156>>2]=0;c[b+148>>2]=0;c[b+152>>2]=0;a[b+164>>0]=d&1;a[b+165>>0]=e&1;g[b+168>>2]=0.0;c[6432]=(c[6432]|0)+1;d=ec(51)|0;if(!d)f=0;else{c[(d+4+15&-16)+-4>>2]=d;f=d+4+15&-16}d=c[b+24>>2]|0;if((d|0)>0){e=0;do{h=f+(e<<5)|0;i=(c[b+32>>2]|0)+(e<<5)|0;c[h>>2]=c[i>>2];c[h+4>>2]=c[i+4>>2];c[h+8>>2]=c[i+8>>2];c[h+12>>2]=c[i+12>>2];c[h+16>>2]=c[i+16>>2];c[h+20>>2]=c[i+20>>2];c[h+24>>2]=c[i+24>>2];c[h+28>>2]=c[i+28>>2];e=e+1|0}while((e|0)!=(d|0))}d=c[b+32>>2]|0;if(d|0){if(a[b+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+32>>2]=0}a[b+36>>0]=1;c[b+32>>2]=f;c[b+28>>2]=1;i=c[b+24>>2]|0;c[f+(i<<5)>>2]=0;c[f+(i<<5)+4>>2]=0;c[f+(i<<5)+8>>2]=12;c[f+(i<<5)+12>>2]=0;c[f+(i<<5)+16>>2]=0;c[f+(i<<5)+20>>2]=16;c[f+(i<<5)+24>>2]=2;c[f+(i<<5)+28>>2]=0;c[b+24>>2]=(c[b+24>>2]|0)+1;i=(a[b+164>>0]|0)==0;d=c[b+32>>2]|0;c[d>>2]=(c[(i?b+148|0:b+128|0)>>2]|0)/3|0;c[d+4>>2]=0;c[d+24>>2]=i?3:2;c[d+8>>2]=i?6:12;if(!(a[b+165>>0]|0)){h=12;b=(c[b+108>>2]|0)/3|0;i=d+12|0;c[i>>2]=b;i=d+16|0;c[i>>2]=0;i=d+20|0;c[i>>2]=h;return}else{h=16;b=c[b+88>>2]|0;i=d+12|0;c[i>>2]=b;i=d+16|0;c[i>>2]=0;i=d+20|0;c[i>>2]=h;return}}function Rf(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0;f=ks()|0;pj(f,4,b);c[f>>2]=4832;c[f+552>>2]=c[d>>2];c[f+552+4>>2]=c[d+4>>2];c[f+552+8>>2]=c[d+8>>2];c[f+552+12>>2]=c[d+12>>2];c[f+568>>2]=c[d+16>>2];c[f+568+4>>2]=c[d+16+4>>2];c[f+568+8>>2]=c[d+16+8>>2];c[f+568+12>>2]=c[d+16+12>>2];c[f+584>>2]=c[d+32>>2];c[f+584+4>>2]=c[d+32+4>>2];c[f+584+8>>2]=c[d+32+8>>2];c[f+584+12>>2]=c[d+32+12>>2];c[f+600>>2]=c[d+48>>2];c[f+600+4>>2]=c[d+48+4>>2];c[f+600+8>>2]=c[d+48+8>>2];c[f+600+12>>2]=c[d+48+12>>2];c[f+616>>2]=c[d>>2];c[f+616+4>>2]=c[d+4>>2];c[f+616+8>>2]=c[d+8>>2];c[f+616+12>>2]=c[d+12>>2];c[f+632>>2]=c[d+16>>2];c[f+632+4>>2]=c[d+16+4>>2];c[f+632+8>>2]=c[d+16+8>>2];c[f+632+12>>2]=c[d+16+12>>2];c[f+648>>2]=c[d+32>>2];c[f+648+4>>2]=c[d+32+4>>2];c[f+648+8>>2]=c[d+32+8>>2];c[f+648+12>>2]=c[d+32+12>>2];c[f+664>>2]=c[d+48>>2];c[f+664+4>>2]=c[d+48+4>>2];c[f+664+8>>2]=c[d+48+8>>2];c[f+664+12>>2]=c[d+48+12>>2];g[f+688>>2]=0.0;g[f+692>>2]=-1.0;g[f+696>>2]=.8999999761581421;g[f+700>>2]=.30000001192092896;g[f+704>>2]=1.0;g[f+708>>2]=0.0;g[f+712>>2]=0.0;a[f+716>>0]=0;a[f+736>>0]=0;a[f+737>>0]=0;a[f+738>>0]=0;a[f+739>>0]=1;a[f+740>>0]=e&1;c[f+748>>2]=0;d=c[f+28>>2]|0;l=+g[f+600>>2];k=+g[f+604>>2];j=+g[f+608>>2];i=l*+g[d+20>>2]+k*+g[d+24>>2]+j*+g[d+28>>2]+ +g[d+56>>2];h=l*+g[d+36>>2]+k*+g[d+40>>2]+j*+g[d+44>>2]+ +g[d+60>>2];g[f+664>>2]=l*+g[d+4>>2]+k*+g[d+8>>2]+j*+g[d+12>>2]+ +g[d+52>>2];g[f+668>>2]=i;g[f+672>>2]=h;g[f+676>>2]=0.0;g[f+732>>2]=e?-1.0:1.0;return f|0}function Sf(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,m=0,n=0,o=0;o=l;l=l+32|0;if((b|0)<0)b=c[a+12>>2]|0;d=c[a>>2]|0;if(!((b|0)>0&(d|0)!=0)){l=o;return}while(1){e=d+40|0;if(c[e>>2]|0){n=0;while(1){m=(c[a+16>>2]|0)>>>n&1;g=d+32|0;h=c[g>>2]|0;if(h>>>0>d>>>0){i=(c[h+40>>2]|0)==(d|0)&1;j=c[h+36+((i^1)<<2)>>2]|0;k=c[h+32>>2]|0;if(!k)f=a;else f=k+36+(((c[k+40>>2]|0)==(h|0)&1)<<2)|0;c[f>>2]=d;c[j+32>>2]=d;c[h+32>>2]=d;c[g>>2]=k;k=d+36|0;c[h+36>>2]=c[k>>2];c[h+40>>2]=c[e>>2];c[(c[k>>2]|0)+32>>2]=h;c[(c[e>>2]|0)+32>>2]=h;c[d+36+(i<<2)>>2]=h;c[d+36+((i^1)<<2)>>2]=j;c[o>>2]=c[h>>2];c[o+4>>2]=c[h+4>>2];c[o+8>>2]=c[h+8>>2];c[o+12>>2]=c[h+12>>2];c[o+16>>2]=c[h+16>>2];c[o+20>>2]=c[h+20>>2];c[o+24>>2]=c[h+24>>2];c[o+28>>2]=c[h+28>>2];c[h>>2]=c[d>>2];c[h+4>>2]=c[d+4>>2];c[h+8>>2]=c[d+8>>2];c[h+12>>2]=c[d+12>>2];c[h+16>>2]=c[d+16>>2];c[h+20>>2]=c[d+20>>2];c[h+24>>2]=c[d+24>>2];c[h+28>>2]=c[d+28>>2];c[d>>2]=c[o>>2];c[d+4>>2]=c[o+4>>2];c[d+8>>2]=c[o+8>>2];c[d+12>>2]=c[o+12>>2];c[d+16>>2]=c[o+16>>2];c[d+20>>2]=c[o+20>>2];c[d+24>>2]=c[o+24>>2];c[d+28>>2]=c[o+28>>2];d=h}d=c[d+36+(m<<2)>>2]|0;e=d+40|0;if(!(c[e>>2]|0))break;else n=n+1&31}}if(!(Kg(a,d)|0))e=0;else e=c[a>>2]|0;We(a,e,d);c[a+16>>2]=(c[a+16>>2]|0)+1;b=b+-1|0;if(!b)break;d=c[a>>2]|0}l=o;return}function Tf(b,d){b=b|0;d=d|0;var e=0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0;e=ks()|0;pj(e,4,b);c[e>>2]=4832;c[e+552>>2]=c[d>>2];c[e+552+4>>2]=c[d+4>>2];c[e+552+8>>2]=c[d+8>>2];c[e+552+12>>2]=c[d+12>>2];c[e+568>>2]=c[d+16>>2];c[e+568+4>>2]=c[d+16+4>>2];c[e+568+8>>2]=c[d+16+8>>2];c[e+568+12>>2]=c[d+16+12>>2];c[e+584>>2]=c[d+32>>2];c[e+584+4>>2]=c[d+32+4>>2];c[e+584+8>>2]=c[d+32+8>>2];c[e+584+12>>2]=c[d+32+12>>2];c[e+600>>2]=c[d+48>>2];c[e+600+4>>2]=c[d+48+4>>2];c[e+600+8>>2]=c[d+48+8>>2];c[e+600+12>>2]=c[d+48+12>>2];c[e+616>>2]=c[d>>2];c[e+616+4>>2]=c[d+4>>2];c[e+616+8>>2]=c[d+8>>2];c[e+616+12>>2]=c[d+12>>2];c[e+632>>2]=c[d+16>>2];c[e+632+4>>2]=c[d+16+4>>2];c[e+632+8>>2]=c[d+16+8>>2];c[e+632+12>>2]=c[d+16+12>>2];c[e+648>>2]=c[d+32>>2];c[e+648+4>>2]=c[d+32+4>>2];c[e+648+8>>2]=c[d+32+8>>2];c[e+648+12>>2]=c[d+32+12>>2];c[e+664>>2]=c[d+48>>2];c[e+664+4>>2]=c[d+48+4>>2];c[e+664+8>>2]=c[d+48+8>>2];c[e+664+12>>2]=c[d+48+12>>2];g[e+688>>2]=0.0;g[e+692>>2]=-1.0;g[e+696>>2]=.8999999761581421;g[e+700>>2]=.30000001192092896;g[e+704>>2]=1.0;g[e+708>>2]=0.0;g[e+712>>2]=0.0;a[e+716>>0]=0;a[e+736>>0]=0;a[e+737>>0]=0;a[e+738>>0]=0;a[e+739>>0]=1;a[e+740>>0]=0;c[e+748>>2]=0;d=c[e+28>>2]|0;k=+g[e+600>>2];j=+g[e+604>>2];i=+g[e+608>>2];h=k*+g[d+20>>2]+j*+g[d+24>>2]+i*+g[d+28>>2]+ +g[d+56>>2];f=k*+g[d+36>>2]+j*+g[d+40>>2]+i*+g[d+44>>2]+ +g[d+60>>2];g[e+664>>2]=k*+g[d+4>>2]+j*+g[d+8>>2]+i*+g[d+12>>2]+ +g[d+52>>2];g[e+668>>2]=h;g[e+672>>2]=f;g[e+676>>2]=0.0;g[e+732>>2]=1.0;return e|0}function Uf(b){b=b|0;var d=0,e=0.0,f=0,h=0,i=0.0,j=0.0,k=0;k=l;l=l+64|0;Yi(12362);a:do if(!(a[b+274>>0]|0)){d=c[b+232>>2]|0;if((d|0)>0){h=0;while(1){f=c[(c[b+240>>2]|0)+(h<<2)>>2]|0;switch(c[f+216>>2]|0){case 2:case 5:break;default:if((c[f+480>>2]|0)!=0?(c[f+204>>2]&3|0)==0:0){e=+g[b+264>>2];if((a[b+300>>0]|0)!=0?(j=+g[b+268>>2],j!=0.0):0)e=e-j;else e=e*+g[f+244>>2];Cg(f+68|0,+g[f+132>>2],+g[f+136>>2],+g[f+140>>2],f+148|0,e,k);d=c[f+480>>2]|0;jb[c[(c[d>>2]|0)+12>>2]&127](d,k);d=c[b+232>>2]|0}}h=h+1|0;if((h|0)>=(d|0))break a}}}else{d=c[b+8>>2]|0;if((d|0)>0){h=0;do{f=c[(c[b+16>>2]|0)+(h<<2)>>2]|0;if((!((f|0)==0?1:(c[f+236>>2]&2|0)==0)?(c[f+480>>2]|0)!=0:0)?(c[f+204>>2]&3|0)==0:0){e=+g[b+264>>2];if((a[b+300>>0]|0)!=0?(i=+g[b+268>>2],i!=0.0):0)e=e-i;else e=e*+g[f+244>>2];Cg(f+68|0,+g[f+132>>2],+g[f+136>>2],+g[f+140>>2],f+148|0,e,k);d=c[f+480>>2]|0;jb[c[(c[d>>2]|0)+12>>2]&127](d,k);d=c[b+8>>2]|0}h=h+1|0}while((h|0)<(d|0))}}while(0);d=c[2395]|0;b=(c[d+16>>2]|0)+-1|0;c[d+16>>2]=b;if(b|0){l=k;return}do if(c[d+4>>2]|0){Va(k|0,0)|0;b=c[6431]|0;g[d+8>>2]=+g[d+8>>2]+ +(((c[k+4>>2]|0)-(c[b+4>>2]|0)+(((c[k>>2]|0)-(c[b>>2]|0)|0)*1e6|0)-(c[d+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[d+16>>2]|0)){d=c[2395]|0;break}else{l=k;return}}while(0);c[2395]=c[d+20>>2];l=k;return}function Vf(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,C=0.0,D=0.0,E=0.0;i=l;l=l+32|0;d=a[b+8>>0]|0?d:e;if(((c[(c[d+4>>2]|0)+4>>2]|0)+-21|0)>>>0>=9){l=i;return}e=c[(c[d+8>>2]|0)+192>>2]|0;y=+zb[c[(c[e>>2]|0)+48>>2]&15](e);c[b+64>>2]=f;g[b+68>>2]=y+.05999999865889549;c[b+56>>2]=h;h=c[b+16>>2]|0;Rb[c[(c[h>>2]|0)+28>>2]&127](h,i+16|0,i);y=+g[i>>2];x=+g[i+16>>2];w=+g[i+4>>2];v=+g[i+16+4>>2];u=+g[i+8>>2];t=+g[i+16+8>>2];h=c[d+12>>2]|0;C=+g[h>>2];o=+g[h+16>>2];D=+g[h+32>>2];z=+g[h+4>>2];m=+g[h+20>>2];A=+g[h+36>>2];q=+g[h+8>>2];j=+g[h+24>>2];r=+g[h+40>>2];E=-+g[h+48>>2];s=-+g[h+52>>2];k=-+g[h+56>>2];p=(y+x)*.5*C+(w+v)*.5*o+(u+t)*.5*D+(C*E+o*s+D*k);n=(y+x)*.5*z+(w+v)*.5*m+(u+t)*.5*A+(z*E+m*s+A*k);k=(y+x)*.5*q+(w+v)*.5*j+(u+t)*.5*r+(q*E+j*s+r*k);s=+g[b+68>>2];o=((y-x)*.5+s)*+B(+(C+o*0.0+D*0.0))+((w-v)*.5+s)*+B(+(C*0.0+o+D*0.0))+((u-t)*.5+s)*+B(+(D+(C*0.0+o*0.0)));m=((y-x)*.5+s)*+B(+(z+m*0.0+A*0.0))+((w-v)*.5+s)*+B(+(z*0.0+m+A*0.0))+((u-t)*.5+s)*+B(+(A+(z*0.0+m*0.0)));j=((y-x)*.5+s)*+B(+(q+j*0.0+r*0.0))+((w-v)*.5+s)*+B(+(q*0.0+j+r*0.0))+((u-t)*.5+s)*+B(+(r+(q*0.0+j*0.0)));g[b+24>>2]=p-o;g[b+28>>2]=n-m;g[b+32>>2]=k-j;g[b+36>>2]=0.0;g[b+40>>2]=p+o;g[b+44>>2]=n+m;g[b+48>>2]=k+j;g[b+52>>2]=0.0;Vb[c[(c[e>>2]|0)+64>>2]&127](e,b+12|0,b+24|0,b+40|0);l=i;return}function Wf(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0,i=0,j=0,k=0,m=0,n=0;k=l;l=l+16|0;c[b+8>>2]=0;c[b+12>>2]=1065353216;c[b+16>>2]=1065353216;c[b+20>>2]=1065353216;g[b+24>>2]=0.0;g[b+44>>2]=.03999999910593033;c[b+52>>2]=0;c[b+56>>2]=1065353216;c[b+60>>2]=1065353216;c[b+64>>2]=1065353216;g[b+68>>2]=0.0;c[b+72>>2]=-1082130432;c[b+76>>2]=-1082130432;c[b+80>>2]=-1082130432;g[b+84>>2]=0.0;a[b+88>>0]=0;c[b>>2]=7380;a[b+108>>0]=1;c[b+104>>2]=0;c[b+96>>2]=0;c[b+100>>2]=0;c[b+4>>2]=4;if((e|0)<=0){c[b+96>>2]=e;ej(b);l=k;return}c[6432]=(c[6432]|0)+1;h=ec((e<<4|3)+16|0)|0;if(!h)j=0;else{c[(h+4+15&-16)+-4>>2]=h;j=h+4+15&-16}h=c[b+96>>2]|0;if((h|0)>0){i=0;do{m=j+(i<<4)|0;n=(c[b+104>>2]|0)+(i<<4)|0;c[m>>2]=c[n>>2];c[m+4>>2]=c[n+4>>2];c[m+8>>2]=c[n+8>>2];c[m+12>>2]=c[n+12>>2];i=i+1|0}while((i|0)!=(h|0))}h=c[b+104>>2]|0;if(h|0){if(a[b+108>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[b+104>>2]=0}a[b+108>>0]=1;c[b+104>>2]=j;c[b+100>>2]=e;c[j>>2]=c[k>>2];c[j+4>>2]=c[k+4>>2];c[j+8>>2]=c[k+8>>2];c[j+12>>2]=c[k+12>>2];if((e|0)!=1){h=1;do{n=(c[b+104>>2]|0)+(h<<4)|0;c[n>>2]=c[k>>2];c[n+4>>2]=c[k+4>>2];c[n+8>>2]=c[k+8>>2];c[n+12>>2]=c[k+12>>2];h=h+1|0}while((h|0)!=(e|0))}c[b+96>>2]=e;i=0;h=d;while(1){d=c[h+4>>2]|0;m=c[h+8>>2]|0;n=c[b+104>>2]|0;c[n+(i<<4)>>2]=c[h>>2];c[n+(i<<4)+4>>2]=d;c[n+(i<<4)+8>>2]=m;g[n+(i<<4)+12>>2]=0.0;i=i+1|0;if((i|0)==(e|0))break;else h=h+f|0}ej(b);l=k;return}function Xf(b){b=b|0;var d=0;c[b>>2]=4884;d=c[b+176>>2]|0;if(d|0){if(a[b+180>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+176>>2]=0}a[b+180>>0]=1;c[b+176>>2]=0;c[b+168>>2]=0;c[b+172>>2]=0;d=c[b+156>>2]|0;if(d|0){if(a[b+160>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+156>>2]=0}a[b+160>>0]=1;c[b+156>>2]=0;c[b+148>>2]=0;c[b+152>>2]=0;d=c[b+136>>2]|0;if(d|0){if(a[b+140>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+136>>2]=0}a[b+140>>0]=1;c[b+136>>2]=0;c[b+128>>2]=0;c[b+132>>2]=0;d=c[b+116>>2]|0;if(d|0){if(a[b+120>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+116>>2]=0}a[b+120>>0]=1;c[b+116>>2]=0;c[b+108>>2]=0;c[b+112>>2]=0;d=c[b+96>>2]|0;if(d|0){if(a[b+100>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+96>>2]=0}a[b+100>>0]=1;c[b+96>>2]=0;c[b+88>>2]=0;c[b+92>>2]=0;d=c[b+76>>2]|0;if(d|0){if(a[b+80>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+76>>2]=0}a[b+80>>0]=1;c[b+76>>2]=0;c[b+68>>2]=0;c[b+72>>2]=0;d=c[b+56>>2]|0;if(d|0){if(a[b+60>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+56>>2]=0}a[b+60>>0]=1;c[b+56>>2]=0;c[b+48>>2]=0;c[b+52>>2]=0;d=c[b+36>>2]|0;if(d|0){if(a[b+40>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+36>>2]=0}a[b+40>>0]=1;c[b+36>>2]=0;c[b+28>>2]=0;c[b+32>>2]=0;d=c[b+16>>2]|0;if(!d){a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;b=b+12|0;c[b>>2]=0;return}if(a[b+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+16>>2]=0;a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;b=b+12|0;c[b>>2]=0;return}function Yf(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0,y=0.0;x=l;l=l+48|0;t=+g[e>>2];u=+g[d>>2];v=+g[e+4>>2];w=+g[d+4>>2];s=+g[e+8>>2];h=+g[d+8>>2];i=+C(+((t-u)*.5*(t-u)*.5+(v-w)*.5*(v-w)*.5+(s-h)*.5*(s-h)*.5));j=+g[a+56>>2];d=+B(+j)>.7071067690849304;k=+g[a+52>>2];if(d){r=1.0/+C(+(j*j+k*k));y=+g[a+48>>2];f=y*-(j*r);m=y;n=0.0;o=-(j*r);p=k*r;q=(j*j+k*k)*r;r=-(y*k*r)}else{q=+g[a+48>>2];r=1.0/+C(+(q*q+k*k));f=(q*q+k*k)*r;m=q;n=-(k*r);o=q*r;p=0.0;q=-(j*q*r);r=j*-(k*r)}y=(t+u)*.5*m+(v+w)*.5*k+(s+h)*.5*j-+g[a+64>>2];m=(t+u)*.5-m*y;n=i*n;o=i*o;u=i*p;q=i*q;r=i*r;t=i*f;g[x>>2]=q+(n+m);g[x+4>>2]=r+(o+((v+w)*.5-k*y));g[x+8>>2]=t+(u+((s+h)*.5-j*y));g[x+12>>2]=0.0;g[x+16>>2]=n+m-q;g[x+20>>2]=o+((v+w)*.5-k*y)-r;g[x+24>>2]=u+((s+h)*.5-j*y)-t;g[x+28>>2]=0.0;g[x+32>>2]=m-n-q;g[x+36>>2]=(v+w)*.5-k*y-o-r;g[x+40>>2]=(s+h)*.5-j*y-u-t;g[x+44>>2]=0.0;Vb[c[(c[b>>2]|0)+8>>2]&127](b,x,0,0);g[x>>2]=m-n-q;g[x+4>>2]=(v+w)*.5-k*y-o-r;g[x+8>>2]=(s+h)*.5-j*y-u-t;g[x+12>>2]=0.0;g[x+16>>2]=q+(m-n);g[x+20>>2]=r+((v+w)*.5-k*y-o);g[x+24>>2]=t+((s+h)*.5-j*y-u);g[x+28>>2]=0.0;g[x+32>>2]=q+(n+m);g[x+36>>2]=r+(o+((v+w)*.5-k*y));g[x+40>>2]=t+(u+((s+h)*.5-j*y));g[x+44>>2]=0.0;Vb[c[(c[b>>2]|0)+8>>2]&127](b,x,0,1);l=x;return}function Zf(a,b,e){a=a|0;b=b|0;e=e|0;Ze(a,b,e)|0;c[b+256>>2]=c[a+264>>2];c[b+260>>2]=c[a+268>>2];c[b+264>>2]=c[a+272>>2];c[b+268>>2]=c[a+276>>2];c[b+272>>2]=c[a+280>>2];c[b+276>>2]=c[a+284>>2];c[b+280>>2]=c[a+288>>2];c[b+284>>2]=c[a+292>>2];c[b+288>>2]=c[a+296>>2];c[b+292>>2]=c[a+300>>2];c[b+296>>2]=c[a+304>>2];c[b+300>>2]=c[a+308>>2];c[b+304>>2]=c[a+312>>2];c[b+308>>2]=c[a+316>>2];c[b+312>>2]=c[a+320>>2];c[b+316>>2]=c[a+324>>2];c[b+320>>2]=c[a+328>>2];c[b+324>>2]=c[a+332>>2];c[b+328>>2]=c[a+336>>2];c[b+332>>2]=c[a+340>>2];c[b+448>>2]=c[a+344>>2];c[b+336>>2]=c[a+544>>2];c[b+340>>2]=c[a+548>>2];c[b+344>>2]=c[a+552>>2];c[b+348>>2]=c[a+556>>2];c[b+352>>2]=c[a+348>>2];c[b+356>>2]=c[a+352>>2];c[b+360>>2]=c[a+356>>2];c[b+364>>2]=c[a+360>>2];c[b+368>>2]=c[a+364>>2];c[b+372>>2]=c[a+368>>2];c[b+376>>2]=c[a+372>>2];c[b+380>>2]=c[a+376>>2];c[b+384>>2]=c[a+380>>2];c[b+388>>2]=c[a+384>>2];c[b+392>>2]=c[a+388>>2];c[b+396>>2]=c[a+392>>2];c[b+400>>2]=c[a+396>>2];c[b+404>>2]=c[a+400>>2];c[b+408>>2]=c[a+404>>2];c[b+412>>2]=c[a+408>>2];c[b+416>>2]=c[a+412>>2];c[b+420>>2]=c[a+416>>2];c[b+424>>2]=c[a+420>>2];c[b+428>>2]=c[a+424>>2];c[b+432>>2]=c[a+428>>2];c[b+436>>2]=c[a+432>>2];c[b+440>>2]=c[a+436>>2];c[b+444>>2]=c[a+440>>2];c[b+452>>2]=c[a+444>>2];c[b+456>>2]=c[a+448>>2];c[b+484>>2]=d[a+452>>0];c[b+460>>2]=c[a+456>>2];c[b+464>>2]=c[a+460>>2];c[b+468>>2]=c[a+464>>2];c[b+472>>2]=c[a+468>>2];c[b+476>>2]=c[a+472>>2];c[b+480>>2]=c[a+476>>2];return 11988}function _f(b,d,e,f,h){b=b|0;d=+d;e=e|0;f=f|0;h=h|0;var i=0;i=l;l=l+144|0;c[b+164>>2]=1065353216;c[b+168>>2]=1065353216;c[b+172>>2]=1065353216;g[b+176>>2]=0.0;c[b+180>>2]=0;g[b+184>>2]=999999984306749440.0;c[b+188>>2]=0;c[b+188+4>>2]=0;c[b+188+8>>2]=0;c[b+188+12>>2]=0;c[b+204>>2]=1;c[b+208>>2]=-1;c[b+212>>2]=-1;c[b+216>>2]=1;g[b+220>>2]=0.0;g[b+224>>2]=.5;g[b+228>>2]=0.0;g[b+232>>2]=0.0;c[b+236>>2]=1;c[b+240>>2]=0;g[b+244>>2]=1.0;c[b+248>>2]=0;c[b+248+4>>2]=0;c[b+248+8>>2]=0;c[b+248+12>>2]=0;c[b+4>>2]=1065353216;c[b+8>>2]=0;c[b+8+4>>2]=0;c[b+8+8>>2]=0;c[b+8+12>>2]=0;c[b+24>>2]=1065353216;c[b+28>>2]=0;c[b+28+4>>2]=0;c[b+28+8>>2]=0;c[b+28+12>>2]=0;c[b+44>>2]=1065353216;c[b+48>>2]=0;c[b+48+4>>2]=0;c[b+48+8>>2]=0;c[b+48+12>>2]=0;c[b+48+16>>2]=0;c[b>>2]=4236;a[b+500>>0]=1;c[b+496>>2]=0;c[b+488>>2]=0;c[b+492>>2]=0;g[i>>2]=d;c[i+4>>2]=e;c[i+72>>2]=f;c[i+76>>2]=c[h>>2];c[i+76+4>>2]=c[h+4>>2];c[i+76+8>>2]=c[h+8>>2];c[i+76+12>>2]=c[h+12>>2];g[i+92>>2]=0.0;g[i+96>>2]=0.0;g[i+100>>2]=.5;g[i+104>>2]=0.0;g[i+108>>2]=0.0;g[i+112>>2]=.800000011920929;g[i+116>>2]=1.0;a[i+120>>0]=0;g[i+124>>2]=.004999999888241291;g[i+128>>2]=.009999999776482582;g[i+132>>2]=.009999999776482582;g[i+136>>2]=.009999999776482582;c[i+8>>2]=1065353216;c[i+12>>2]=0;c[i+12+4>>2]=0;c[i+12+8>>2]=0;c[i+12+12>>2]=0;c[i+28>>2]=1065353216;c[i+32>>2]=0;c[i+32+4>>2]=0;c[i+32+8>>2]=0;c[i+32+12>>2]=0;c[i+48>>2]=1065353216;c[i+52>>2]=0;c[i+52+4>>2]=0;c[i+52+8>>2]=0;c[i+52+12>>2]=0;c[i+52+16>>2]=0;sd(b,i);l=i;return}function $f(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;l=c[d>>2]|0;l=Gb[c[(c[l>>2]|0)+56>>2]&31](l,48)|0;c[l>>2]=9172;c[l+4>>2]=c[d>>2];c[l>>2]=6352;a[l+28>>0]=1;c[l+24>>2]=0;c[l+16>>2]=0;c[l+20>>2]=0;c[l+32>>2]=c[d+4>>2];a[l+36>>0]=0;c[6432]=(c[6432]|0)+1;b=ec(87)|0;if(!b)k=0;else{c[(b+4+15&-16)+-4>>2]=b;k=b+4+15&-16}c[k>>2]=9476;h=k+20|0;a[h>>0]=1;j=k+16|0;c[j>>2]=0;d=k+8|0;c[d>>2]=0;i=k+12|0;c[i>>2]=0;a[k+24>>0]=0;a[k+44>>0]=1;c[k+40>>2]=0;c[k+32>>2]=0;c[k+36>>2]=0;a[k+64>>0]=1;c[k+60>>2]=0;c[k+52>>2]=0;c[k+56>>2]=0;c[6432]=(c[6432]|0)+1;b=ec(43)|0;if(!b)g=0;else{c[(b+4+15&-16)+-4>>2]=b;g=b+4+15&-16}b=c[d>>2]|0;if((b|0)>0){d=0;do{m=g+(d*12|0)|0;n=(c[j>>2]|0)+(d*12|0)|0;c[m>>2]=c[n>>2];c[m+4>>2]=c[n+4>>2];c[m+8>>2]=c[n+8>>2];d=d+1|0}while((d|0)!=(b|0))}b=c[j>>2]|0;if(!b){a[h>>0]=1;c[j>>2]=g;c[i>>2]=2;uf(k);n=l+8|0;c[n>>2]=k;n=e+4|0;n=c[n>>2]|0;n=n+68|0;n=c[n>>2]|0;m=l+40|0;c[m>>2]=n;m=f+4|0;m=c[m>>2]|0;m=m+68|0;m=c[m>>2]|0;n=l+44|0;c[n>>2]=m;return l|0}if(a[h>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[b+-4>>2]|0)}c[j>>2]=0;a[h>>0]=1;c[j>>2]=g;c[i>>2]=2;uf(k);n=l+8|0;c[n>>2]=k;n=e+4|0;n=c[n>>2]|0;n=n+68|0;n=c[n>>2]|0;m=l+40|0;c[m>>2]=n;m=f+4|0;m=c[m>>2]|0;m=m+68|0;m=c[m>>2]|0;n=l+44|0;c[n>>2]=m;return l|0}function ag(d,e){d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0;if(!(a[d+164>>0]|0)){f=c[d+148>>2]|0;if((f|0)==(c[d+152>>2]|0)?(k=f|0?f<<1:1,(f|0)<(k|0)):0){if(!k)g=0;else{c[6432]=(c[6432]|0)+1;f=ec((k<<1)+19|0)|0;if(!f)g=0;else{c[(f+4+15&-16)+-4>>2]=f;g=f+4+15&-16}f=c[d+148>>2]|0}i=c[d+156>>2]|0;if((f|0)<=0)if(!i)f=d+160|0;else h=27;else{h=0;do{b[g+(h<<1)>>1]=b[i+(h<<1)>>1]|0;h=h+1|0}while((h|0)!=(f|0));h=27}if((h|0)==27){if(a[d+160>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[d+156>>2]=0;f=d+160|0}a[f>>0]=1;c[d+156>>2]=g;c[d+152>>2]=k;f=c[d+148>>2]|0}b[(c[d+156>>2]|0)+(f<<1)>>1]=e;c[d+148>>2]=f+1;e=d+156|0;e=c[e>>2]|0;d=d+32|0;d=c[d>>2]|0;d=d+4|0;c[d>>2]=e;return}else{f=c[d+128>>2]|0;if((f|0)==(c[d+132>>2]|0)?(j=f|0?f<<1:1,(f|0)<(j|0)):0){if(!j)g=0;else{c[6432]=(c[6432]|0)+1;f=ec((j<<2|3)+16|0)|0;if(!f)g=0;else{c[(f+4+15&-16)+-4>>2]=f;g=f+4+15&-16}f=c[d+128>>2]|0}i=c[d+136>>2]|0;if((f|0)<=0)if(!i)f=d+140|0;else h=12;else{h=0;do{c[g+(h<<2)>>2]=c[i+(h<<2)>>2];h=h+1|0}while((h|0)!=(f|0));h=12}if((h|0)==12){if(a[d+140>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[d+136>>2]=0;f=d+140|0}a[f>>0]=1;c[d+136>>2]=g;c[d+132>>2]=j;f=c[d+128>>2]|0}c[(c[d+136>>2]|0)+(f<<2)>>2]=e;c[d+128>>2]=(c[d+128>>2]|0)+1;e=d+136|0;e=c[e>>2]|0;d=d+32|0;d=c[d>>2]|0;d=d+4|0;c[d>>2]=e;return}}function bg(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;Ed(b,d);c[b>>2]=3196;c[6432]=(c[6432]|0)+1;e=ec(27)|0;i=e+4+15&-16;c[i+-4>>2]=e;a[i+4>>0]=0;c[(e+4+15&-16)>>2]=3228;c[b+92>>2]=i;c[6432]=(c[6432]|0)+1;i=ec(27)|0;e=i+4+15&-16;c[e+-4>>2]=i;a[e+4>>0]=0;c[(i+4+15&-16)>>2]=3248;c[b+96>>2]=e;c[6432]=(c[6432]|0)+1;e=ec(27)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}c[e>>2]=3248;c[b+100>>2]=e;a[e+4>>0]=1;c[6432]=(c[6432]|0)+1;i=ec(27)|0;e=i+4+15&-16;c[e+-4>>2]=i;a[e+4>>0]=0;c[(i+4+15&-16)>>2]=3268;c[b+104>>2]=e;c[6432]=(c[6432]|0)+1;e=ec(27)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}c[e>>2]=3288;c[b+108>>2]=e;a[e+4>>0]=1;if(!(a[b+20>>0]|0))return;e=c[b+16>>2]|0;if(!e)return;if((c[e>>2]|0)>=156)return;f=c[e+16>>2]|0;if(f){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0);e=c[b+16>>2]|0;if(!e)i=b+16|0;else{f=b+16|0;g=11}}else{f=b+16|0;g=11}if((g|0)==11){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0);i=f}c[6432]=(c[6432]|0)+1;e=ec(39)|0;if(!e)h=0;else{c[(e+4+15&-16)+-4>>2]=e;h=e+4+15&-16}e=c[d+12>>2]|0;c[h>>2]=156;f=h+4|0;c[f>>2]=e;c[6432]=(c[6432]|0)+1;e=ec((e*156|3)+16|0)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}c[h+16>>2]=e;c[h+12>>2]=e;f=c[f>>2]|0;c[h+8>>2]=f;if(f+-1|0){b=c[h>>2]|0;g=f+-1|0;d=e;do{j=d;d=d+b|0;c[j>>2]=d;g=g+-1|0}while((g|0)!=0);e=e+(O(b,f+-1|0)|0)|0}c[e>>2]=0;c[i>>2]=h;return}function cg(b,d,e,f,h,i,k,l,m){b=b|0;d=d|0;e=e|0;f=+f;h=+h;i=+i;k=k|0;l=l|0;m=m|0;var n=0,o=0.0,p=0.0,q=0.0,r=0.0;n=Vr()|0;c[n+8>>2]=0;g[n+12>>2]=0.0;c[n>>2]=8184;c[n+4>>2]=24;c[n+64>>2]=b;c[n+68>>2]=d;g[n+72>>2]=h;g[n+76>>2]=i;g[n+80>>2]=+(b+-1|0);g[n+84>>2]=+(d+-1|0);g[n+88>>2]=f;c[n+92>>2]=e;c[n+96>>2]=l;a[n+100>>0]=m&1;a[n+101>>0]=0;a[n+102>>0]=0;c[n+104>>2]=k;c[n+108>>2]=1065353216;c[n+112>>2]=1065353216;c[n+116>>2]=1065353216;g[n+120>>2]=0.0;switch(k|0){case 0:{g[n+16>>2]=h;c[n+20>>2]=0;f=0.0;i=h;h=0.0;b=n+80|0;d=n+84|0;e=n+76|0;break}case 1:{c[n+16>>2]=0;g[n+20>>2]=h;f=h;i=0.0;h=0.0;b=n+76|0;d=n+84|0;e=n+80|0;break}case 2:{c[n+16>>2]=0;c[n+20>>2]=0;f=0.0;i=0.0;b=n+84|0;d=n+76|0;e=n+80|0;break}default:{h=+g[n+16>>2];q=+g[n+32>>2];f=+g[n+20>>2];p=+g[n+36>>2];i=+g[n+24>>2];o=+g[n+40>>2];h=q+h;f=p+f;i=o+i;h=h*.5;f=f*.5;i=i*.5;m=n+48|0;g[m>>2]=h;m=n+52|0;g[m>>2]=f;m=n+56|0;g[m>>2]=i;m=n+60|0;g[m>>2]=0.0;return n|0}}g[n+24>>2]=h;g[n+28>>2]=0.0;k=c[e>>2]|0;c[n+32>>2]=k;l=c[b>>2]|0;c[n+36>>2]=l;m=c[d>>2]|0;c[n+40>>2]=m;g[n+44>>2]=0.0;r=(c[j>>2]=k,+g[j>>2]);q=(c[j>>2]=l,+g[j>>2]);o=i;p=f;f=q;q=h;i=(c[j>>2]=m,+g[j>>2]);o=r+o;p=f+p;q=i+q;o=o*.5;p=p*.5;q=q*.5;m=n+48|0;g[m>>2]=o;m=n+52|0;g[m>>2]=p;m=n+56|0;g[m>>2]=q;m=n+60|0;g[m>>2]=0.0;return n|0}function dg(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;hb[c[(c[b>>2]|0)+32>>2]&511](b);e=vb[c[(c[b>>2]|0)+16>>2]&63](b,104,1)|0;d=c[e+8>>2]|0;f=d;g=f+104|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(g|0));c[d+88>>2]=c[a+248>>2];c[d+92>>2]=c[a+252>>2];c[d+96>>2]=c[a+256>>2];c[d+100>>2]=c[a+260>>2];c[d>>2]=c[a+92>>2];c[d+4>>2]=c[a+96>>2];c[d+8>>2]=c[a+100>>2];c[d+12>>2]=c[a+104>>2];c[d+16>>2]=c[a+108>>2];c[d+20>>2]=c[a+116>>2];c[d+24>>2]=c[a+120>>2];c[d+28>>2]=c[a+124>>2];c[d+32>>2]=c[a+128>>2];c[d+36>>2]=c[a+132>>2];c[d+40>>2]=c[a+140>>2];c[d+44>>2]=c[a+144>>2];c[d+48>>2]=c[a+148>>2];c[d+52>>2]=c[a+152>>2];c[d+56>>2]=c[a+168>>2];c[d+60>>2]=c[a+172>>2];c[d+64>>2]=c[a+112>>2];c[d+68>>2]=c[a+156>>2];c[d+72>>2]=c[a+160>>2];c[d+76>>2]=c[a+164>>2];c[d+80>>2]=c[a+136>>2];fb[c[(c[b>>2]|0)+20>>2]&31](b,e,12401,1145853764,d);d=c[a+8>>2]|0;if((d|0)<=0){Ni(a,b);ad(a,b);a=c[b>>2]|0;a=a+36|0;a=c[a>>2]|0;hb[a&511](b);return}f=0;do{e=c[(c[a+16>>2]|0)+(f<<2)>>2]|0;if(c[e+236>>2]&8){g=lb[c[(c[e>>2]|0)+16>>2]&127](e)|0;g=vb[c[(c[b>>2]|0)+16>>2]&63](b,g,1)|0;d=vb[c[(c[e>>2]|0)+20>>2]&63](e,c[g+8>>2]|0,b)|0;fb[c[(c[b>>2]|0)+20>>2]&31](b,g,d,1497645651,e);d=c[a+8>>2]|0}f=f+1|0}while((f|0)<(d|0));Ni(a,b);ad(a,b);a=c[b>>2]|0;a=a+36|0;a=c[a>>2]|0;hb[a&511](b);return}function eg(a,b){a=a|0;b=+b;var d=0,e=0,f=0,h=0,i=0.0,j=0.0,k=0.0;h=l;l=l+32|0;d=c[a+8>>2]|0;if((d|0)<=0){l=h;return}f=0;do{e=c[(c[a+16>>2]|0)+(f<<2)>>2]|0;if((!((e|0)==0?1:(c[e+236>>2]&2|0)==0)?(c[e+216>>2]|0)!=2:0)?!(b==0.0?1:(c[e+204>>2]&2|0)==0):0){d=c[e+480>>2]|0;if(!d)d=e+4|0;else{jb[c[(c[d>>2]|0)+8>>2]&127](d,e+4|0);d=e+4|0}j=1.0/b*(+g[e+56>>2]-+g[e+120>>2]);k=1.0/b*(+g[e+60>>2]-+g[e+124>>2]);g[e+312>>2]=1.0/b*(+g[e+52>>2]-+g[e+116>>2]);g[e+316>>2]=j;g[e+320>>2]=k;g[e+324>>2]=0.0;rf(e+68|0,d,h+8|0,h);k=+g[h>>2];j=1.0/b*k*+g[h+8+4>>2];i=1.0/b*k*+g[h+8+8>>2];g[e+328>>2]=1.0/b*+g[h+8>>2]*k;g[e+332>>2]=j;g[e+336>>2]=i;g[e+340>>2]=0.0;c[e+132>>2]=c[e+312>>2];c[e+132+4>>2]=c[e+312+4>>2];c[e+132+8>>2]=c[e+312+8>>2];c[e+132+12>>2]=c[e+312+12>>2];c[e+148>>2]=c[e+328>>2];c[e+148+4>>2]=c[e+328+4>>2];c[e+148+8>>2]=c[e+328+8>>2];c[e+148+12>>2]=c[e+328+12>>2];c[e+68>>2]=c[d>>2];c[e+68+4>>2]=c[d+4>>2];c[e+68+8>>2]=c[d+8>>2];c[e+68+12>>2]=c[d+12>>2];c[e+84>>2]=c[e+20>>2];c[e+84+4>>2]=c[e+20+4>>2];c[e+84+8>>2]=c[e+20+8>>2];c[e+84+12>>2]=c[e+20+12>>2];c[e+100>>2]=c[e+36>>2];c[e+100+4>>2]=c[e+36+4>>2];c[e+100+8>>2]=c[e+36+8>>2];c[e+100+12>>2]=c[e+36+12>>2];c[e+116>>2]=c[e+52>>2];c[e+116+4>>2]=c[e+52+4>>2];c[e+116+8>>2]=c[e+52+8>>2];c[e+116+12>>2]=c[e+52+12>>2];d=c[a+8>>2]|0}f=f+1|0}while((f|0)<(d|0));l=h;return}function fg(a,b,d){a=a|0;b=+b;d=+d;var e=0,f=0,h=0,i=0,j=0,k=0.0,m=0.0,n=0.0,o=0,p=0.0,q=0.0,r=0.0,s=0.0,t=0,u=0.0,v=0.0,w=0,x=0.0,y=0.0,z=0.0,A=0.0;h=l;l=l+16|0;b=+g[a+336>>2]*b;d=+g[a+452>>2];e=c[a+792>>2]|0;if((e|0)<=0){l=h;return}f=0;do{t=c[a+800>>2]|0;j=t+(f*96|0)+20|0;w=c[j>>2]|0;o=c[t+(f*96|0)>>2]|0;z=+g[t+(f*96|0)+4>>2];y=+g[t+(f*96|0)+8>>2];x=+g[t+(f*96|0)+12>>2];i=t+(f*96|0)+76|0;v=+g[w+332>>2];q=+g[t+(f*96|0)+84>>2];A=+g[w+336>>2];m=+g[t+(f*96|0)+80>>2];k=+g[i>>2];n=+g[w+328>>2];s=+g[o+8>>2];r=+g[o+12>>2];p=+g[o+16>>2];u=b*(z*+g[w+4>>2]+y*+g[w+8>>2]+x*+g[w+12>>2]+ +g[w+52>>2]-s)+(d*(v*q-A*m+ +g[w+312>>2])-(s-+g[o+24>>2]));q=b*(z*+g[w+20>>2]+y*+g[w+24>>2]+x*+g[w+28>>2]+ +g[w+56>>2]-r)+(d*(+g[w+316>>2]+(A*k-q*n))-(r-+g[o+28>>2]));k=b*(z*+g[w+36>>2]+y*+g[w+40>>2]+x*+g[w+44>>2]+ +g[w+60>>2]-p)+(d*(m*n-v*k+ +g[w+320>>2])-(p-+g[o+32>>2]));v=+g[t+(f*96|0)+24>>2];n=(u*+g[t+(f*96|0)+28>>2]+q*+g[t+(f*96|0)+32>>2]+ +g[t+(f*96|0)+36>>2]*k)*v;m=(u*+g[t+(f*96|0)+44>>2]+q*+g[t+(f*96|0)+48>>2]+k*+g[t+(f*96|0)+52>>2])*v;k=v*(u*+g[t+(f*96|0)+60>>2]+q*+g[t+(f*96|0)+64>>2]+k*+g[t+(f*96|0)+68>>2]);q=+g[t+(f*96|0)+92>>2];g[o+8>>2]=s+n*q;g[o+12>>2]=q*m+r;g[o+16>>2]=q*k+p;j=c[j>>2]|0;g[h>>2]=-n;g[h+4>>2]=-m;g[h+8>>2]=-k;g[h+12>>2]=0.0;Vk(j,h,i);f=f+1|0}while((f|0)!=(e|0));l=h;return}function gg(a){a=a|0;var b=0,d=0,e=0.0,f=0.0,h=0.0,i=0,j=0.0,k=0,l=0,m=0.0,n=0.0,o=0,p=0.0;b=c[a+712>>2]|0;if((b|0)>0){d=0;do{l=(c[a+720>>2]|0)+(d*104|0)+72|0;d=d+1|0;c[l>>2]=0;c[l+4>>2]=0;c[l+8>>2]=0;c[l+12>>2]=0}while((d|0)!=(b|0))}b=c[a+752>>2]|0;if((b|0)>0){d=0;do{o=c[a+760>>2]|0;k=c[o+(d*44|0)+12>>2]|0;i=c[o+(d*44|0)+8>>2]|0;j=+g[i+8>>2];e=+g[k+8>>2]-j;f=+g[i+12>>2];h=+g[k+12>>2]-f;m=+g[i+16>>2];n=+g[k+16>>2]-m;l=c[o+(d*44|0)+16>>2]|0;j=+g[l+8>>2]-j;f=+g[l+12>>2]-f;m=+g[l+16>>2]-m;p=1.0/+C(+((e*f-h*j)*(e*f-h*j)+((h*m-n*f)*(h*m-n*f)+(n*j-e*m)*(n*j-e*m))));g[o+(d*44|0)+20>>2]=p*(h*m-n*f);g[o+(d*44|0)+24>>2]=p*(n*j-e*m);g[o+(d*44|0)+28>>2]=(e*f-h*j)*p;c[o+(d*44|0)+32>>2]=0;g[i+72>>2]=h*m-n*f+ +g[i+72>>2];g[i+76>>2]=n*j-e*m+ +g[i+76>>2];g[i+80>>2]=e*f-h*j+ +g[i+80>>2];g[k+72>>2]=h*m-n*f+ +g[k+72>>2];g[k+76>>2]=n*j-e*m+ +g[k+76>>2];g[k+80>>2]=e*f-h*j+ +g[k+80>>2];g[l+72>>2]=h*m-n*f+ +g[l+72>>2];g[l+76>>2]=n*j-e*m+ +g[l+76>>2];g[l+80>>2]=e*f-h*j+ +g[l+80>>2];d=d+1|0}while((d|0)!=(b|0))}l=c[a+712>>2]|0;if((l|0)<=0)return;b=c[a+720>>2]|0;k=0;do{d=b+(k*104|0)+72|0;e=+g[d>>2];i=b+(k*104|0)+76|0;f=+g[i>>2];a=b+(k*104|0)+80|0;h=+g[a>>2];j=+C(+(e*e+f*f+h*h));if(j>1.1920928955078125e-07){g[d>>2]=e*(1.0/j);g[i>>2]=1.0/j*f;g[a>>2]=1.0/j*h}k=k+1|0}while((k|0)!=(l|0));return}function hg(b,d,e,f){b=b|0;d=+d;e=e|0;f=+f;var h=0,i=0.0,j=0,k=0;k=l;l=l+16|0;Va(c[6431]|0,0)|0;Xq(25684);c[6422]=(c[6422]|0)+1;j=c[6425]|0;c[6425]=j+1;if(!j){Va(k|0,0)|0;j=c[6431]|0;c[6424]=(c[k+4>>2]|0)-(c[j+4>>2]|0)+(((c[k>>2]|0)-(c[j>>2]|0)|0)*1e6|0)}c[6430]=0;Va(k|0,0)|0;Yi(12386);if(e){g[b+268>>2]=f;i=+g[b+264>>2]+d;g[b+264>>2]=i;if(!(i>=f)){d=f;j=0}else{g[b+264>>2]=i-+(~~(i/f)|0)*f;d=f;j=~~(i/f)}}else{g[b+264>>2]=a[b+300>>0]|0?0.0:d;g[b+268>>2]=0.0;j=!(+B(+d)<1.1920928955078125e-07)&1;e=j}if(lb[c[(c[b>>2]|0)+20>>2]&127](b)|0){h=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;a[26312]=(lb[c[(c[h>>2]|0)+48>>2]&127](h)|0)>>>4&1}if(j){e=(j|0)>(e|0)?e:j;gb[c[(c[b>>2]|0)+164>>2]&31](b,d*+(e|0));hb[c[(c[b>>2]|0)+168>>2]&511](b);if((e|0)>0){h=0;do{gb[c[(c[b>>2]|0)+160>>2]&31](b,d);hb[c[(c[b>>2]|0)+80>>2]&511](b);h=h+1|0}while((h|0)<(e|0));e=b}else e=b}else{hb[c[(c[b>>2]|0)+80>>2]&511](b);e=b}hb[c[(c[e>>2]|0)+120>>2]&511](b);c[6430]=(c[6430]|0)+1;e=c[2395]|0;b=(c[e+16>>2]|0)+-1|0;c[e+16>>2]=b;if(b|0){l=k;return j|0}do if(c[e+4>>2]|0){Va(k|0,0)|0;b=c[6431]|0;g[e+8>>2]=+g[e+8>>2]+ +(((c[k+4>>2]|0)-(c[b+4>>2]|0)+(((c[k>>2]|0)-(c[b>>2]|0)|0)*1e6|0)-(c[e+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[e+16>>2]|0)){e=c[2395]|0;break}else{l=k;return j|0}}while(0);c[2395]=c[e+20>>2];l=k;return j|0}function ig(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0;h=cs()|0;c[h+4>>2]=5;c[h+8>>2]=-1;c[h+12>>2]=-1;g[h+16>>2]=3402823466385288598117041.0e14;a[h+20>>0]=1;a[h+21>>0]=0;c[h+24>>2]=-1;c[h+28>>2]=b;c[h+32>>2]=d;g[h+36>>2]=0.0;g[h+40>>2]=.30000001192092896;c[h+44>>2]=0;c[h>>2]=4776;c[h+300>>2]=c[e>>2];c[h+300+4>>2]=c[e+4>>2];c[h+300+8>>2]=c[e+8>>2];c[h+300+12>>2]=c[e+12>>2];c[h+316>>2]=c[e+16>>2];c[h+316+4>>2]=c[e+16+4>>2];c[h+316+8>>2]=c[e+16+8>>2];c[h+316+12>>2]=c[e+16+12>>2];c[h+332>>2]=c[e+32>>2];c[h+332+4>>2]=c[e+32+4>>2];c[h+332+8>>2]=c[e+32+8>>2];c[h+332+12>>2]=c[e+32+12>>2];c[h+348>>2]=c[e+48>>2];c[h+348+4>>2]=c[e+48+4>>2];c[h+348+8>>2]=c[e+48+8>>2];c[h+348+12>>2]=c[e+48+12>>2];c[h+364>>2]=c[f>>2];c[h+364+4>>2]=c[f+4>>2];c[h+364+8>>2]=c[f+8>>2];c[h+364+12>>2]=c[f+12>>2];c[h+380>>2]=c[f+16>>2];c[h+380+4>>2]=c[f+16+4>>2];c[h+380+8>>2]=c[f+16+8>>2];c[h+380+12>>2]=c[f+16+12>>2];c[h+396>>2]=c[f+32>>2];c[h+396+4>>2]=c[f+32+4>>2];c[h+396+8>>2]=c[f+32+8>>2];c[h+396+12>>2]=c[f+32+12>>2];c[h+412>>2]=c[f+48>>2];c[h+412+4>>2]=c[f+48+4>>2];c[h+412+8>>2]=c[f+48+8>>2];c[h+412+12>>2]=c[f+48+12>>2];a[h+552>>0]=0;c[h+524>>2]=0;g[h+572>>2]=-1.0;g[h+444>>2]=999999984306749440.0;g[h+448>>2]=999999984306749440.0;g[h+452>>2]=999999984306749440.0;g[h+428>>2]=1.0;g[h+432>>2]=.30000001192092896;g[h+436>>2]=1.0;g[h+440>>2]=.009999999776482582;g[h+456>>2]=.05000000074505806;c[h+592>>2]=0;g[h+596>>2]=0.0;g[h+600>>2]=.699999988079071;g[h+604>>2]=0.0;return h|0}function jg(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0.0,i=0.0,j=0.0,k=0.0,m=0,n=0.0;m=l;l=l+672|0;c[m+568+8>>2]=0;c[m+568+12>>2]=1065353216;c[m+568+16>>2]=1065353216;c[m+568+20>>2]=1065353216;g[m+568+24>>2]=0.0;c[m+568+52>>2]=0;c[m+568>>2]=3844;c[m+568+4>>2]=1;c[m+568+56>>2]=c[d>>2];c[m+568+56+4>>2]=c[d+4>>2];c[m+568+56+8>>2]=c[d+8>>2];c[m+568+56+12>>2]=c[d+12>>2];c[m+568+72>>2]=c[d+16>>2];c[m+568+72+4>>2]=c[d+16+4>>2];c[m+568+72+8>>2]=c[d+16+8>>2];c[m+568+72+12>>2]=c[d+16+12>>2];c[m+568+88>>2]=c[d+32>>2];c[m+568+88+4>>2]=c[d+32+4>>2];c[m+568+88+8>>2]=c[d+32+8>>2];c[m+568+88+12>>2]=c[d+32+12>>2];c[m+568+44>>2]=c[b+204>>2];g[m+208+308>>2]=9.999999747378752e-05;a[m+208+332>>0]=0;c[m+200>>2]=9272;d=c[b+4>>2]|0;c[m+176>>2]=9340;c[m+176+4>>2]=m+208;c[m+176+8>>2]=m+200;c[m+176+12>>2]=d;c[m+176+16>>2]=m+568;c[m+176+20>>2]=0;c[m>>2]=3816;c[m+168>>2]=0;g[m+164>>2]=1.0;c[m+172>>2]=c[b+208>>2];if((Bd(m+176|0,b+8|0,b+72|0,b+136|0,b+136|0,m)|0?(h=+g[m+132>>2],i=+g[m+136>>2],j=+g[m+140>>2],h*h+i*i+j*j>9.999999747378752e-05):0)?(k=+g[m+164>>2],k<+g[b+200>>2]):0){n=1.0/+C(+(h*h+i*i+j*j));g[m+132>>2]=h*n;g[m+136>>2]=i*n;g[m+140>>2]=j*n;+Bb[c[(c[b>>2]|0)+12>>2]&3](b,m+132|0,m+148|0,k,e,f)}c[m+568>>2]=7248;e=c[m+568+52>>2]|0;if(!e){l=m;return}hb[c[c[e>>2]>>2]&511](e);e=c[m+568+52>>2]|0;if(!e){l=m;return}c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0);l=m;return}function kg(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0;h=+g[d+100>>2];j=+g[d+16>>2];k=+g[d+20>>2];l=+g[d+24>>2];e=+g[d+108>>2];e=+g[d+112>>2]-h*+g[d+116>>2]-(j*+g[a+64>>2]+k*+g[a+68>>2]+l*+g[a+72>>2]+(+g[d>>2]*+g[a+80>>2]+ +g[d+4>>2]*+g[a+84>>2]+ +g[d+8>>2]*+g[a+88>>2]))*e-e*(+g[d+48>>2]*+g[b+64>>2]+ +g[d+52>>2]*+g[b+68>>2]+ +g[d+56>>2]*+g[b+72>>2]+(+g[d+32>>2]*+g[b+80>>2]+ +g[d+36>>2]*+g[b+84>>2]+ +g[d+40>>2]*+g[b+88>>2]));f=+g[d+120>>2];if(!(h+e<f)){f=+g[d+124>>2];if(h+e>f){i=f;e=f-h}else i=h+e}else{i=f;e=f-h}g[d+100>>2]=i;if(c[a+240>>2]|0){i=e*k*+g[a+132>>2]*+g[a+116>>2];k=e*l*+g[a+136>>2]*+g[a+120>>2];g[a+64>>2]=+g[a+112>>2]*e*j*+g[a+128>>2]+ +g[a+64>>2];g[a+68>>2]=i+ +g[a+68>>2];g[a+72>>2]=k+ +g[a+72>>2];k=e*+g[a+100>>2]*+g[d+68>>2];l=e*+g[a+104>>2]*+g[d+72>>2];g[a+80>>2]=e*+g[a+96>>2]*+g[d+64>>2]+ +g[a+80>>2];g[a+84>>2]=k+ +g[a+84>>2];g[a+88>>2]=l+ +g[a+88>>2]}if(!(c[b+240>>2]|0))return;l=e*+g[d+52>>2]*+g[b+132>>2]*+g[b+116>>2];k=e*+g[d+56>>2]*+g[b+136>>2]*+g[b+120>>2];g[b+64>>2]=+g[b+112>>2]*e*+g[d+48>>2]*+g[b+128>>2]+ +g[b+64>>2];g[b+68>>2]=l+ +g[b+68>>2];g[b+72>>2]=k+ +g[b+72>>2];k=e*+g[b+100>>2]*+g[d+84>>2];l=e*+g[b+104>>2]*+g[d+88>>2];g[b+80>>2]=e*+g[b+96>>2]*+g[d+80>>2]+ +g[b+80>>2];g[b+84>>2]=k+ +g[b+84>>2];g[b+88>>2]=l+ +g[b+88>>2];return}function lg(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0;e=+g[d+128>>2];if(!(e!=0.0))return;c[5968]=(c[5968]|0)+1;k=+g[d+96>>2];f=+g[d+16>>2];h=+g[d+20>>2];i=+g[d+24>>2];j=+g[d+108>>2];j=e-k*+g[d+116>>2]-(f*+g[a+144>>2]+h*+g[a+148>>2]+i*+g[a+152>>2]+(+g[d>>2]*+g[a+160>>2]+ +g[d+4>>2]*+g[a+164>>2]+ +g[d+8>>2]*+g[a+168>>2]))*j-j*(+g[d+48>>2]*+g[b+144>>2]+ +g[d+52>>2]*+g[b+148>>2]+ +g[d+56>>2]*+g[b+152>>2]+(+g[d+32>>2]*+g[b+160>>2]+ +g[d+36>>2]*+g[b+164>>2]+ +g[d+40>>2]*+g[b+168>>2]));l=+g[d+120>>2];e=k+j<l?l-k:j;g[d+96>>2]=k+j<l?l:k+j;if(c[a+240>>2]|0){l=e*h*+g[a+132>>2]*+g[a+116>>2];k=e*i*+g[a+136>>2]*+g[a+120>>2];g[a+144>>2]=+g[a+112>>2]*e*f*+g[a+128>>2]+ +g[a+144>>2];g[a+148>>2]=l+ +g[a+148>>2];g[a+152>>2]=k+ +g[a+152>>2];k=e*+g[a+100>>2]*+g[d+68>>2];l=e*+g[a+104>>2]*+g[d+72>>2];g[a+160>>2]=e*+g[a+96>>2]*+g[d+64>>2]+ +g[a+160>>2];g[a+164>>2]=k+ +g[a+164>>2];g[a+168>>2]=l+ +g[a+168>>2]}if(!(c[b+240>>2]|0))return;l=e*+g[d+52>>2]*+g[b+132>>2]*+g[b+116>>2];k=e*+g[d+56>>2]*+g[b+136>>2]*+g[b+120>>2];g[b+144>>2]=+g[b+112>>2]*e*+g[d+48>>2]*+g[b+128>>2]+ +g[b+144>>2];g[b+148>>2]=l+ +g[b+148>>2];g[b+152>>2]=k+ +g[b+152>>2];k=e*+g[b+100>>2]*+g[d+84>>2];l=e*+g[b+104>>2]*+g[d+88>>2];g[b+160>>2]=e*+g[b+96>>2]*+g[d+80>>2]+ +g[b+160>>2];g[b+164>>2]=k+ +g[b+164>>2];g[b+168>>2]=l+ +g[b+168>>2];return}function mg(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var h=0.0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0,t=0;t=l;l=l+32|0;s=c[a+12>>2]|0;if(!s){l=t;return}c[f+4>>2]=s;a=c[b+4>>2]|0;e=c[d+4>>2]|0;b=c[b+12>>2]|0;d=c[d+12>>2]|0;m=+g[d+48>>2];h=+g[b+48>>2]-m;n=+g[d+52>>2];i=+g[b+52>>2]-n;o=+g[d+56>>2];k=+g[b+56>>2]-o;q=+C(+(h*h+i*i+k*k));r=+g[e+28>>2]*+g[e+12>>2];p=+g[a+28>>2]*+g[a+12>>2]+r;if(q>p){if(!(c[s+748>>2]|0)){l=t;return}a=c[s+740>>2]|0;b=c[(c[f+8>>2]|0)+8>>2]|0;e=c[(c[f+12>>2]|0)+8>>2]|0;if((a|0)==(b|0)){Le(s,a+4|0,e+4|0);l=t;return}else{Le(s,e+4|0,b+4|0);l=t;return}}c[t+16>>2]=1065353216;c[t+16+4>>2]=0;c[t+16+8>>2]=0;g[t+16+12>>2]=0.0;if(q>1.1920928955078125e-07){g[t+16>>2]=h*(1.0/q);g[t+16+4>>2]=i*(1.0/q);g[t+16+8>>2]=k*(1.0/q);g[t+16+12>>2]=0.0;j=h*(1.0/q);i=i*(1.0/q);h=k*(1.0/q)}else{j=1.0;i=0.0;h=0.0}g[t>>2]=r*j+m;g[t+4>>2]=r*i+n;g[t+8>>2]=r*h+o;g[t+12>>2]=0.0;Qb[c[(c[f>>2]|0)+16>>2]&15](f,t+16|0,t,q-p);a=c[f+4>>2]|0;do if(c[a+748>>2]|0){b=c[a+740>>2]|0;d=c[(c[f+8>>2]|0)+8>>2]|0;e=c[(c[f+12>>2]|0)+8>>2]|0;if((b|0)==(d|0)){Le(a,b+4|0,e+4|0);break}else{Le(a,e+4|0,d+4|0);break}}while(0);l=t;return}function ng(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;c[6419]=(c[6419]|0)+1;l=((e<<16|d)+~((e<<16|d)<<15)>>10^(e<<16|d)+~((e<<16|d)<<15))*9|0;l=(l>>6^l)+~((l>>6^l)<<11)>>16^(l>>6^l)+~((l>>6^l)<<11);k=c[b+12>>2]|0;f=c[(c[b+40>>2]|0)+((k+-1&l)<<2)>>2]|0;a:do if((f|0)!=-1){h=c[b+16>>2]|0;while(1){g=h+(f*12|0)|0;if((c[g>>2]|0)==(d|0)?(c[h+(f*12|0)+4>>2]|0)==(e|0):0)break;f=c[(c[b+60>>2]|0)+(f<<2)>>2]|0;if((f|0)==-1)break a}if(g|0){b=g;return b|0}}while(0);j=c[b+8>>2]|0;if((j|0)==(k|0)){h=k|0?k<<1:1;if((k|0)<(h|0)){if(!h){g=k;i=0}else{c[6432]=(c[6432]|0)+1;f=ec((h*12|3)+16|0)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}g=c[b+8>>2]|0;i=f}if((g|0)>0){f=0;do{m=i+(f*12|0)|0;n=(c[b+16>>2]|0)+(f*12|0)|0;c[m>>2]=c[n>>2];c[m+4>>2]=c[n+4>>2];c[m+8>>2]=c[n+8>>2];f=f+1|0}while((f|0)!=(g|0))}f=c[b+16>>2]|0;if(f|0){if(a[b+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[b+16>>2]=0}a[b+20>>0]=1;c[b+16>>2]=i;c[b+12>>2]=h;f=c[b+8>>2]|0}else{f=k;h=k}}else{f=j;h=k}c[b+8>>2]=f+1;g=c[b+16>>2]|0;if((k|0)<(h|0)){uf(b);f=(c[b+12>>2]|0)+-1&l}else f=k+-1&l;c[g+(j*12|0)>>2]=d;c[g+(j*12|0)+4>>2]=e;c[g+(j*12|0)+8>>2]=0;n=(c[b+40>>2]|0)+(f<<2)|0;c[(c[b+60>>2]|0)+(j<<2)>>2]=c[n>>2];c[n>>2]=j;n=g+(j*12|0)|0;return n|0}function og(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0;i=ks()|0;c[i+4>>2]=4;c[i+8>>2]=-1;c[i+12>>2]=-1;g[i+16>>2]=3402823466385288598117041.0e14;a[i+20>>0]=1;a[i+21>>0]=0;c[i+24>>2]=-1;c[i+28>>2]=b;c[i+32>>2]=d;g[i+36>>2]=0.0;g[i+40>>2]=.30000001192092896;c[i+44>>2]=0;c[i>>2]=4832;c[i+552>>2]=c[e>>2];c[i+552+4>>2]=c[e+4>>2];c[i+552+8>>2]=c[e+8>>2];c[i+552+12>>2]=c[e+12>>2];c[i+568>>2]=c[e+16>>2];c[i+568+4>>2]=c[e+16+4>>2];c[i+568+8>>2]=c[e+16+8>>2];c[i+568+12>>2]=c[e+16+12>>2];c[i+584>>2]=c[e+32>>2];c[i+584+4>>2]=c[e+32+4>>2];c[i+584+8>>2]=c[e+32+8>>2];c[i+584+12>>2]=c[e+32+12>>2];c[i+600>>2]=c[e+48>>2];c[i+600+4>>2]=c[e+48+4>>2];c[i+600+8>>2]=c[e+48+8>>2];c[i+600+12>>2]=c[e+48+12>>2];c[i+616>>2]=c[f>>2];c[i+616+4>>2]=c[f+4>>2];c[i+616+8>>2]=c[f+8>>2];c[i+616+12>>2]=c[f+12>>2];c[i+632>>2]=c[f+16>>2];c[i+632+4>>2]=c[f+16+4>>2];c[i+632+8>>2]=c[f+16+8>>2];c[i+632+12>>2]=c[f+16+12>>2];c[i+648>>2]=c[f+32>>2];c[i+648+4>>2]=c[f+32+4>>2];c[i+648+8>>2]=c[f+32+8>>2];c[i+648+12>>2]=c[f+32+12>>2];c[i+664>>2]=c[f+48>>2];c[i+664+4>>2]=c[f+48+4>>2];c[i+664+8>>2]=c[f+48+8>>2];c[i+664+12>>2]=c[f+48+12>>2];g[i+688>>2]=0.0;g[i+692>>2]=-1.0;g[i+696>>2]=.8999999761581421;g[i+700>>2]=.30000001192092896;g[i+704>>2]=1.0;g[i+708>>2]=0.0;g[i+712>>2]=0.0;a[i+716>>0]=0;a[i+736>>0]=0;a[i+737>>0]=0;a[i+738>>0]=0;a[i+739>>0]=1;a[i+740>>0]=h&1;c[i+748>>2]=0;g[i+732>>2]=h?-1.0:1.0;return i|0}function pg(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;e=Gb[c[(c[d>>2]|0)+40>>2]&31](d,a)|0;g=Gb[c[(c[d>>2]|0)+28>>2]&31](d,e)|0;c[b>>2]=g;if(g|0)jb[c[(c[d>>2]|0)+48>>2]&127](d,e);c[b+4>>2]=c[a+4>>2];g=c[a+48>>2]|0;vb[c[(c[g>>2]|0)+56>>2]&63](g,b+12|0,d)|0;c[b+52>>2]=c[a+12>>2];do if((c[a+52>>2]|0)!=0?((lb[c[(c[d>>2]|0)+52>>2]&127](d)|0)&1|0)==0:0){e=Gb[c[(c[d>>2]|0)+24>>2]&31](d,c[a+52>>2]|0)|0;if(!e){c[b+40>>2]=Gb[c[(c[d>>2]|0)+28>>2]&31](d,c[a+52>>2]|0)|0;c[b+44>>2]=0;e=c[a+52>>2]|0;e=lb[c[(c[e>>2]|0)+12>>2]&127](e)|0;e=vb[c[(c[d>>2]|0)+16>>2]&63](d,e,1)|0;g=c[a+52>>2]|0;g=vb[c[(c[g>>2]|0)+16>>2]&63](g,c[e+8>>2]|0,d)|0;fb[c[(c[d>>2]|0)+20>>2]&31](d,e,g,1213612625,c[a+52>>2]|0);break}else{c[b+40>>2]=e;c[b+44>>2]=0;break}}else f=8;while(0);if((f|0)==8){c[b+40>>2]=0;c[b+44>>2]=0}if(c[a+56>>2]|0?((lb[c[(c[d>>2]|0)+52>>2]&127](d)|0)&2|0)==0:0){e=Gb[c[(c[d>>2]|0)+24>>2]&31](d,c[a+56>>2]|0)|0;if(!e){c[b+48>>2]=Gb[c[(c[d>>2]|0)+28>>2]&31](d,c[a+56>>2]|0)|0;b=c[a+56>>2]|0;b=lb[c[(c[b>>2]|0)+8>>2]&127](b)|0;b=vb[c[(c[d>>2]|0)+16>>2]&63](d,b,1)|0;g=c[a+56>>2]|0;g=vb[c[(c[g>>2]|0)+12>>2]&63](g,c[b+8>>2]|0,d)|0;fb[c[(c[d>>2]|0)+20>>2]&31](d,b,g,1346456916,c[a+56>>2]|0);return 16785}else{c[b+48>>2]=e;return 16785}}c[b+48>>2]=0;return 16785}function qg(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0;h=ks()|0;c[h+4>>2]=4;c[h+8>>2]=-1;c[h+12>>2]=-1;g[h+16>>2]=3402823466385288598117041.0e14;a[h+20>>0]=1;a[h+21>>0]=0;c[h+24>>2]=-1;c[h+28>>2]=b;c[h+32>>2]=d;g[h+36>>2]=0.0;g[h+40>>2]=.30000001192092896;c[h+44>>2]=0;c[h>>2]=4832;c[h+552>>2]=c[e>>2];c[h+552+4>>2]=c[e+4>>2];c[h+552+8>>2]=c[e+8>>2];c[h+552+12>>2]=c[e+12>>2];c[h+568>>2]=c[e+16>>2];c[h+568+4>>2]=c[e+16+4>>2];c[h+568+8>>2]=c[e+16+8>>2];c[h+568+12>>2]=c[e+16+12>>2];c[h+584>>2]=c[e+32>>2];c[h+584+4>>2]=c[e+32+4>>2];c[h+584+8>>2]=c[e+32+8>>2];c[h+584+12>>2]=c[e+32+12>>2];c[h+600>>2]=c[e+48>>2];c[h+600+4>>2]=c[e+48+4>>2];c[h+600+8>>2]=c[e+48+8>>2];c[h+600+12>>2]=c[e+48+12>>2];c[h+616>>2]=c[f>>2];c[h+616+4>>2]=c[f+4>>2];c[h+616+8>>2]=c[f+8>>2];c[h+616+12>>2]=c[f+12>>2];c[h+632>>2]=c[f+16>>2];c[h+632+4>>2]=c[f+16+4>>2];c[h+632+8>>2]=c[f+16+8>>2];c[h+632+12>>2]=c[f+16+12>>2];c[h+648>>2]=c[f+32>>2];c[h+648+4>>2]=c[f+32+4>>2];c[h+648+8>>2]=c[f+32+8>>2];c[h+648+12>>2]=c[f+32+12>>2];c[h+664>>2]=c[f+48>>2];c[h+664+4>>2]=c[f+48+4>>2];c[h+664+8>>2]=c[f+48+8>>2];c[h+664+12>>2]=c[f+48+12>>2];g[h+688>>2]=0.0;g[h+692>>2]=-1.0;g[h+696>>2]=.8999999761581421;g[h+700>>2]=.30000001192092896;g[h+704>>2]=1.0;g[h+708>>2]=0.0;g[h+712>>2]=0.0;a[h+716>>0]=0;a[h+736>>0]=0;a[h+737>>0]=0;a[h+738>>0]=0;a[h+739>>0]=1;a[h+740>>0]=0;c[h+748>>2]=0;g[h+732>>2]=1.0;return h|0}function rg(b,d){b=b|0;d=d|0;var e=0,f=0,h=0,i=0.0,j=0,k=0.0,l=0.0,m=0.0,n=0;if(a[b+1308>>0]|0){c[d>>2]=0;c[d+4>>2]=0;return}_c(b,(c[b+28>>2]|0)+4|0,(c[b+32>>2]|0)+4|0);c[d>>2]=0;c[d+4>>2]=6;if((c[b+856>>2]|0)==0?(a[b+788>>0]|0)==0:0){e=0;f=6}else{c[d>>2]=1;c[d+4>>2]=5;e=1;f=5}if(!((c[b+860>>2]|0)==0?(a[b+789>>0]|0)==0:0)){e=e+1|0;c[d>>2]=e;f=f+-1|0;c[d+4>>2]=f}if((c[b+864>>2]|0)==0?(a[b+790>>0]|0)==0:0)n=0;else{e=e+1|0;c[d>>2]=e;f=f+-1|0;c[d+4>>2]=f;n=0}do{k=+g[b+868+(n<<6)>>2];l=+g[b+868+(n<<6)+4>>2];m=+Hj(+g[b+1192+(n<<2)>>2],k,l);g[b+868+(n<<6)+52>>2]=m;do if(!(k>l)){if(k>m){c[b+868+(n<<6)+56>>2]=1;h=b+868+(n<<6)+48|0;g[h>>2]=m-k;if(!(m-k>3.1415927410125732))if(m-k<-3.1415927410125732)i=6.2831854820251465;else{j=18;break}else i=-6.2831854820251465;g[h>>2]=m-k+i;j=18;break}h=b+868+(n<<6)+56|0;if(l<m){c[h>>2]=2;h=b+868+(n<<6)+48|0;g[h>>2]=m-l;if(!(m-l>3.1415927410125732))if(m-l<-3.1415927410125732)i=6.2831854820251465;else{j=18;break}else i=-6.2831854820251465;g[h>>2]=m-l+i;j=18}else j=17}else{h=b+868+(n<<6)+56|0;j=17}while(0);if((j|0)==17){j=0;c[h>>2]=0;if(a[b+868+(n<<6)+44>>0]|0)j=18}if((j|0)==18){e=e+1|0;c[d>>2]=e;f=f+-1|0;c[d+4>>2]=f}n=n+1|0}while((n|0)!=3);return}function sg(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0;k=+g[d+100>>2];e=+g[d+16>>2];f=+g[d+20>>2];h=+g[d+24>>2];j=+g[d+108>>2];j=+g[d+112>>2]-k*+g[d+116>>2]-(e*+g[a+64>>2]+f*+g[a+68>>2]+h*+g[a+72>>2]+(+g[d>>2]*+g[a+80>>2]+ +g[d+4>>2]*+g[a+84>>2]+ +g[d+8>>2]*+g[a+88>>2]))*j-j*(+g[d+48>>2]*+g[b+64>>2]+ +g[d+52>>2]*+g[b+68>>2]+ +g[d+56>>2]*+g[b+72>>2]+(+g[d+32>>2]*+g[b+80>>2]+ +g[d+36>>2]*+g[b+84>>2]+ +g[d+40>>2]*+g[b+88>>2]));l=+g[d+120>>2];i=k+j<l?l-k:j;g[d+100>>2]=k+j<l?l:k+j;if(c[a+240>>2]|0){l=i*f*+g[a+132>>2]*+g[a+116>>2];k=i*h*+g[a+136>>2]*+g[a+120>>2];g[a+64>>2]=+g[a+112>>2]*i*e*+g[a+128>>2]+ +g[a+64>>2];g[a+68>>2]=l+ +g[a+68>>2];g[a+72>>2]=k+ +g[a+72>>2];k=i*+g[a+100>>2]*+g[d+68>>2];l=i*+g[a+104>>2]*+g[d+72>>2];g[a+80>>2]=i*+g[a+96>>2]*+g[d+64>>2]+ +g[a+80>>2];g[a+84>>2]=k+ +g[a+84>>2];g[a+88>>2]=l+ +g[a+88>>2]}if(!(c[b+240>>2]|0))return;l=i*+g[d+52>>2]*+g[b+132>>2]*+g[b+116>>2];k=i*+g[d+56>>2]*+g[b+136>>2]*+g[b+120>>2];g[b+64>>2]=+g[b+112>>2]*i*+g[d+48>>2]*+g[b+128>>2]+ +g[b+64>>2];g[b+68>>2]=l+ +g[b+68>>2];g[b+72>>2]=k+ +g[b+72>>2];k=i*+g[b+100>>2]*+g[d+84>>2];l=i*+g[b+104>>2]*+g[d+88>>2];g[b+80>>2]=i*+g[b+96>>2]*+g[d+80>>2]+ +g[b+80>>2];g[b+84>>2]=k+ +g[b+84>>2];g[b+88>>2]=l+ +g[b+88>>2];return}function tg(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0,v=0,w=0.0,x=0,y=0;x=l;l=l+16|0;f=c[a+52>>2]|0;w=+g[a+28+(((f+2|0)%3|0)<<2)>>2];if((e|0)<=0){l=x;return}h=0;while(1){c[x>>2]=0;c[x+4>>2]=0;c[x+8>>2]=0;c[x+12>>2]=0;c[x+(f<<2)>>2]=c[a+28+(f<<2)>>2];f=b+(h<<4)|0;u=b+(h<<4)+4|0;v=b+(h<<4)+8|0;m=w*+g[f>>2]+ +g[x>>2];o=w*+g[u>>2]+ +g[x+4>>2];n=w*+g[v>>2]+ +g[x+8>>2];p=+zb[c[(c[a>>2]|0)+48>>2]&15](a);i=+g[f>>2];j=+g[u>>2];k=+g[v>>2];if(i*(m-p*i)+j*(o-p*j)+k*(n-p*k)>-999999984306749440.0){g[d+(h<<4)>>2]=m-p*i;g[d+(h<<4)+4>>2]=o-p*j;g[d+(h<<4)+8>>2]=n-p*k;g[d+(h<<4)+12>>2]=0.0;q=+g[f>>2];s=+g[u>>2];t=+g[v>>2];r=i*(m-p*i)+j*(o-p*j)+k*(n-p*k)}else{q=i;s=j;t=k;r=-999999984306749440.0}c[x>>2]=0;c[x+4>>2]=0;c[x+8>>2]=0;c[x+12>>2]=0;y=c[a+52>>2]|0;g[x+(y<<2)>>2]=-+g[a+28+(y<<2)>>2];p=w*q+ +g[x>>2];o=w*s+ +g[x+4>>2];m=w*t+ +g[x+8>>2];n=+zb[c[(c[a>>2]|0)+48>>2]&15](a);k=+g[f>>2];j=+g[u>>2];i=+g[v>>2];if(k*(p-n*k)+j*(o-n*j)+i*(m-n*i)>r){g[d+(h<<4)>>2]=p-n*k;g[d+(h<<4)+4>>2]=o-n*j;g[d+(h<<4)+8>>2]=m-n*i;g[d+(h<<4)+12>>2]=0.0}h=h+1|0;if((h|0)==(e|0))break;f=c[a+52>>2]|0}l=x;return}function ug(a,b,d,e,f,h,i,j,k,l){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;j=+j;k=k|0;l=+l;var m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0;c[a>>2]=c[h>>2];c[a+4>>2]=c[h+4>>2];c[a+8>>2]=c[h+8>>2];c[a+12>>2]=c[h+12>>2];s=+g[e+4>>2];v=+g[a+8>>2];w=+g[e+8>>2];p=+g[a+4>>2];m=+g[a>>2];r=+g[e>>2];u=(s*v-w*p)*+g[b>>2]+ +g[b+4>>2]*(w*m-v*r)+(p*r-s*m)*+g[b+8>>2];t=(s*v-w*p)*+g[b+16>>2]+(w*m-v*r)*+g[b+20>>2]+(p*r-s*m)*+g[b+24>>2];s=(s*v-w*p)*+g[b+32>>2]+(w*m-v*r)*+g[b+36>>2]+(p*r-s*m)*+g[b+40>>2];g[a+16>>2]=u;g[a+20>>2]=t;g[a+24>>2]=s;g[a+28>>2]=0.0;r=+g[f+4>>2];w=+g[f+8>>2];n=+g[f>>2];q=+g[d>>2]*(r*-v-w*-p)+ +g[d+4>>2]*(w*-m-n*-v)+(n*-p-r*-m)*+g[d+8>>2];o=(r*-v-w*-p)*+g[d+16>>2]+(w*-m-n*-v)*+g[d+20>>2]+(n*-p-r*-m)*+g[d+24>>2];m=(r*-v-w*-p)*+g[d+32>>2]+(w*-m-n*-v)*+g[d+36>>2]+(n*-p-r*-m)*+g[d+40>>2];g[a+32>>2]=q;g[a+36>>2]=o;g[a+40>>2]=m;g[a+44>>2]=0.0;u=+g[i>>2]*u;t=+g[i+4>>2]*t;s=+g[i+8>>2]*s;g[a+48>>2]=u;g[a+52>>2]=t;g[a+56>>2]=s;g[a+60>>2]=0.0;r=+g[k>>2]*q;p=+g[k+4>>2]*o;n=+g[k+8>>2]*m;g[a+64>>2]=r;g[a+68>>2]=p;g[a+72>>2]=n;g[a+76>>2]=0.0;g[a+80>>2]=u*+g[a+16>>2]+t*+g[a+20>>2]+s*+g[a+24>>2]+j+l+(r*q+p*o+n*m);return}function vg(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0;k=l;l=l+96|0;g=c[b+8>>2]|0;if((g|0)==(c[b+12>>2]|0)?(j=g|0?g<<1:1,(g|0)<(j|0)):0){if(!j)h=0;else{c[6432]=(c[6432]|0)+1;g=ec((j<<2|3)+16|0)|0;if(!g)h=0;else{c[(g+4+15&-16)+-4>>2]=g;h=g+4+15&-16}g=c[b+8>>2]|0}if((g|0)>0){i=0;do{c[h+(i<<2)>>2]=c[(c[b+16>>2]|0)+(i<<2)>>2];i=i+1|0}while((i|0)!=(g|0))}i=c[b+16>>2]|0;if(i){if(a[b+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0);g=c[b+8>>2]|0}c[b+16>>2]=0}a[b+20>>0]=1;c[b+16>>2]=h;c[b+12>>2]=j}c[(c[b+16>>2]|0)+(g<<2)>>2]=d;c[b+8>>2]=g+1;c[k+32>>2]=c[d+4>>2];c[k+32+4>>2]=c[d+4+4>>2];c[k+32+8>>2]=c[d+4+8>>2];c[k+32+12>>2]=c[d+4+12>>2];c[k+32+16>>2]=c[d+20>>2];c[k+32+16+4>>2]=c[d+20+4>>2];c[k+32+16+8>>2]=c[d+20+8>>2];c[k+32+16+12>>2]=c[d+20+12>>2];c[k+32+32>>2]=c[d+36>>2];c[k+32+32+4>>2]=c[d+36+4>>2];c[k+32+32+8>>2]=c[d+36+8>>2];c[k+32+32+12>>2]=c[d+36+12>>2];c[k+32+48>>2]=c[d+52>>2];c[k+32+48+4>>2]=c[d+52+4>>2];c[k+32+48+8>>2]=c[d+52+8>>2];c[k+32+48+12>>2]=c[d+52+12>>2];j=c[d+192>>2]|0;Vb[c[(c[j>>2]|0)+8>>2]&127](j,k+32|0,k+16|0,k);j=c[b+68>>2]|0;c[d+188>>2]=Pb[c[(c[j>>2]|0)+8>>2]&3](j,k+16|0,k,c[(c[d+192>>2]|0)+4>>2]|0,d,e,f,c[b+24>>2]|0,0)|0;l=k;return}function wg(b){b=b|0;var d=0,e=0,f=0;c[b>>2]=4272;if(a[b+272>>0]|0?(d=c[b+204>>2]|0,hb[c[c[d>>2]>>2]&511](d),d=c[b+204>>2]|0,d|0):0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+196>>2]|0;if(d|0?(hb[c[c[d>>2]>>2]&511](d),f=c[b+196>>2]|0,f|0):0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}if(a[b+273>>0]|0?(e=c[b+200>>2]|0,hb[c[c[e>>2]>>2]&511](e),e=c[b+200>>2]|0,e|0):0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}d=c[b+316>>2]|0;if(d|0){if(a[b+320>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+316>>2]=0}a[b+320>>0]=1;c[b+316>>2]=0;c[b+308>>2]=0;c[b+312>>2]=0;d=c[b+288>>2]|0;if(d|0){if(a[b+292>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+288>>2]=0}a[b+292>>0]=1;c[b+288>>2]=0;c[b+280>>2]=0;c[b+284>>2]=0;d=c[b+240>>2]|0;if(d|0){if(a[b+244>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+240>>2]=0}a[b+244>>0]=1;c[b+240>>2]=0;c[b+232>>2]=0;c[b+236>>2]=0;d=c[b+220>>2]|0;if(d|0){if(a[b+224>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+220>>2]=0}a[b+224>>0]=1;c[b+220>>2]=0;c[b+212>>2]=0;c[b+216>>2]=0;d=c[b+188>>2]|0;if(!d){a[b+192>>0]=1;c[b+188>>2]=0;c[b+180>>2]=0;f=b+184|0;c[f>>2]=0;vj(b);return}if(a[b+192>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+188>>2]=0;a[b+192>>0]=1;c[b+188>>2]=0;c[b+180>>2]=0;f=b+184|0;c[f>>2]=0;vj(b);return}function xg(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,h=0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0;h=l;l=l+64|0;a[d+84>>0]=0;c[h>>2]=c[b+4>>2];c[h+4>>2]=c[b+4+4>>2];c[h+8>>2]=c[b+4+8>>2];c[h+12>>2]=c[b+4+12>>2];c[h+16>>2]=c[b+20>>2];c[h+16+4>>2]=c[b+20+4>>2];c[h+16+8>>2]=c[b+20+8>>2];c[h+16+12>>2]=c[b+20+12>>2];c[h+32>>2]=c[b+36>>2];c[h+32+4>>2]=c[b+36+4>>2];c[h+32+8>>2]=c[b+36+8>>2];c[h+32+12>>2]=c[b+36+12>>2];c[h+48>>2]=c[b+52>>2];c[h+48+4>>2]=c[b+52+4>>2];c[h+48+8>>2]=c[b+52+8>>2];c[h+48+12>>2]=c[b+52+12>>2];if(e?(f=c[b+480>>2]|0,f|0):0)jb[c[(c[f>>2]|0)+8>>2]&127](f,h);w=+g[d+156>>2];u=+g[h>>2];v=+g[d+160>>2];t=+g[h+4>>2];o=+g[d+164>>2];s=+g[h+8>>2];r=+g[h+16>>2];q=+g[h+20>>2];p=+g[h+24>>2];n=+g[h+32>>2];k=+g[h+36>>2];i=+g[h+40>>2];m=w*r+v*q+o*p+ +g[h+52>>2];j=w*n+v*k+o*i+ +g[h+56>>2];g[d+36>>2]=w*u+v*t+o*s+ +g[h+48>>2];g[d+40>>2]=m;g[d+44>>2]=j;g[d+48>>2]=0.0;j=+g[d+172>>2];m=+g[d+176>>2];o=+g[d+180>>2];g[d+52>>2]=u*j+t*m+s*o;g[d+56>>2]=j*r+m*q+o*p;g[d+60>>2]=j*n+m*k+o*i;g[d+64>>2]=0.0;o=+g[d+188>>2];m=+g[d+192>>2];j=+g[d+196>>2];g[d+68>>2]=u*o+t*m+s*j;g[d+72>>2]=o*r+m*q+j*p;g[d+76>>2]=o*n+m*k+j*i;g[d+80>>2]=0.0;l=h;return}function yg(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0.0;a:do if(b>>>0<=20)do switch(b|0){case 9:{e=(c[d>>2]|0)+(4-1)&~(4-1);b=c[e>>2]|0;c[d>>2]=e+4;c[a>>2]=b;break a}case 10:{b=(c[d>>2]|0)+(4-1)&~(4-1);e=c[b>>2]|0;c[d>>2]=b+4;c[a>>2]=e;c[a+4>>2]=((e|0)<0)<<31>>31;break a}case 11:{b=(c[d>>2]|0)+(4-1)&~(4-1);e=c[b>>2]|0;c[d>>2]=b+4;c[a>>2]=e;c[a+4>>2]=0;break a}case 12:{f=(c[d>>2]|0)+(8-1)&~(8-1);b=c[f>>2]|0;e=c[f+4>>2]|0;c[d>>2]=f+8;c[a>>2]=b;c[a+4>>2]=e;break a}case 13:{e=(c[d>>2]|0)+(4-1)&~(4-1);f=c[e>>2]|0;c[d>>2]=e+4;c[a>>2]=(f&65535)<<16>>16;c[a+4>>2]=(((f&65535)<<16>>16|0)<0)<<31>>31;break a}case 14:{e=(c[d>>2]|0)+(4-1)&~(4-1);f=c[e>>2]|0;c[d>>2]=e+4;c[a>>2]=f&65535;c[a+4>>2]=0;break a}case 15:{e=(c[d>>2]|0)+(4-1)&~(4-1);f=c[e>>2]|0;c[d>>2]=e+4;c[a>>2]=(f&255)<<24>>24;c[a+4>>2]=(((f&255)<<24>>24|0)<0)<<31>>31;break a}case 16:{e=(c[d>>2]|0)+(4-1)&~(4-1);f=c[e>>2]|0;c[d>>2]=e+4;c[a>>2]=f&255;c[a+4>>2]=0;break a}case 17:{f=(c[d>>2]|0)+(8-1)&~(8-1);g=+h[f>>3];c[d>>2]=f+8;h[a>>3]=g;break a}case 18:{f=(c[d>>2]|0)+(8-1)&~(8-1);g=+h[f>>3];c[d>>2]=f+8;h[a>>3]=g;break a}default:break a}while(0);while(0);return}function zg(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0,i=0.0,j=0.0,k=0.0,m=0.0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0.0,y=0;w=l;l=l+2048|0;if((e|0)>0)f=0;else{l=w;return}do{g[d+(f<<4)+12>>2]=-999999984306749440.0;f=f+1|0}while((f|0)!=(e|0));t=0;do{if((lb[c[(c[a>>2]|0)+96>>2]&127](a)|0)>0){p=b+(t<<4)|0;s=b+(t<<4)+4|0;o=b+(t<<4)+8|0;r=d+(t<<4)+12|0;q=d+(t<<4)|0;u=0;do{if(((lb[c[(c[a>>2]|0)+96>>2]&127](a)|0)-u|0)<128){f=(lb[c[(c[a>>2]|0)+96>>2]&127](a)|0)-u|0;if((f|0)>0)v=10;else{i=-3402823466385288598117041.0e14;f=-1}}else{f=128;v=10}if((v|0)==10){v=0;h=0;do{Rb[c[(c[a>>2]|0)+108>>2]&127](a,h,w+(h<<4)|0);h=h+1|0}while((h|0)!=(f|0));j=+g[p>>2];k=+g[s>>2];m=+g[o>>2];n=0;i=-3402823466385288598117041.0e14;h=-1;do{x=j*+g[w+(n<<4)>>2]+k*+g[w+(n<<4)+4>>2]+m*+g[w+(n<<4)+8>>2];y=x>i;h=y?n:h;i=y?x:i;n=n+1|0}while((n|0)!=(f|0));f=h}if(i>+g[r>>2]){y=w+(f<<4)|0;c[q>>2]=c[y>>2];c[q+4>>2]=c[y+4>>2];c[q+8>>2]=c[y+8>>2];c[q+12>>2]=c[y+12>>2];g[r>>2]=i}u=u+128|0}while((u|0)<(lb[c[(c[a>>2]|0)+96>>2]&127](a)|0))}t=t+1|0}while((t|0)!=(e|0));l=w;return}function Ag(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;c[6418]=(c[6418]|0)+1;h=((d<<16|b)+~((d<<16|b)<<15)>>10^(d<<16|b)+~((d<<16|b)<<15))*9|0;m=c[a+40>>2]|0;h=m+(((c[a+12>>2]|0)+-1&((h>>6^h)+~((h>>6^h)<<11)>>16^(h>>6^h)+~((h>>6^h)<<11)))<<2)|0;g=c[h>>2]|0;if((g|0)==-1){a=0;return a|0}n=c[a+16>>2]|0;e=g;while(1){l=n+(e*12|0)|0;if((c[l>>2]|0)==(b|0)?(c[n+(e*12|0)+4>>2]|0)==(d|0):0)break;e=c[(c[a+60>>2]|0)+(e<<2)>>2]|0;if((e|0)==-1){e=0;f=13;break}}if((f|0)==13)return e|0;if(!l){a=0;return a|0}k=c[n+(e*12|0)+8>>2]|0;j=(e*12|0)/12|0;i=c[a+60>>2]|0;if((g|0)==(j|0))e=-1;else{e=g;while(1){b=c[i+(e<<2)>>2]|0;if((b|0)==(j|0))break;else e=b}}c[((e|0)==-1?h:i+(e<<2)|0)>>2]=c[i+(j<<2)>>2];h=(c[a+8>>2]|0)+-1|0;if((h|0)==(j|0)){c[a+8>>2]=j;a=k;return a|0}b=c[n+(h*12|0)+4>>2]<<16|c[n+(h*12|0)>>2];b=(b+~(b<<15)>>10^b+~(b<<15))*9|0;b=((b>>6^b)+~((b>>6^b)<<11)>>16^(b>>6^b)+~((b>>6^b)<<11))&(c[a+12>>2]|0)+-1;e=m;f=b;g=-1;while(1){d=c[e+(f<<2)>>2]|0;if((d|0)==(h|0))break;else{e=i;f=d;g=d}}c[((g|0)==-1?m+(b<<2)|0:i+(g<<2)|0)>>2]=c[i+(h<<2)>>2];c[l>>2]=c[n+(h*12|0)>>2];c[l+4>>2]=c[n+(h*12|0)+4>>2];c[l+8>>2]=c[n+(h*12|0)+8>>2];n=(c[a+40>>2]|0)+(b<<2)|0;c[(c[a+60>>2]|0)+(j<<2)>>2]=c[n>>2];c[n>>2]=j;c[a+8>>2]=(c[a+8>>2]|0)+-1;a=k;return a|0}function Bg(b,d){b=b|0;d=d|0;var e=0;e=cs()|0;pj(e,5,b);c[e>>2]=4776;c[e+300>>2]=c[d>>2];c[e+300+4>>2]=c[d+4>>2];c[e+300+8>>2]=c[d+8>>2];c[e+300+12>>2]=c[d+12>>2];c[e+316>>2]=c[d+16>>2];c[e+316+4>>2]=c[d+16+4>>2];c[e+316+8>>2]=c[d+16+8>>2];c[e+316+12>>2]=c[d+16+12>>2];c[e+332>>2]=c[d+32>>2];c[e+332+4>>2]=c[d+32+4>>2];c[e+332+8>>2]=c[d+32+8>>2];c[e+332+12>>2]=c[d+32+12>>2];c[e+348>>2]=c[d+48>>2];c[e+348+4>>2]=c[d+48+4>>2];c[e+348+8>>2]=c[d+48+8>>2];c[e+348+12>>2]=c[d+48+12>>2];a[e+527>>0]=0;c[e+364>>2]=c[e+300>>2];c[e+364+4>>2]=c[e+300+4>>2];c[e+364+8>>2]=c[e+300+8>>2];c[e+364+12>>2]=c[e+300+12>>2];c[e+380>>2]=c[e+316>>2];c[e+380+4>>2]=c[e+316+4>>2];c[e+380+8>>2]=c[e+316+8>>2];c[e+380+12>>2]=c[e+316+12>>2];c[e+396>>2]=c[e+332>>2];c[e+396+4>>2]=c[e+332+4>>2];c[e+396+8>>2]=c[e+332+8>>2];c[e+396+12>>2]=c[e+332+12>>2];a[e+524>>0]=0;a[e+525>>0]=0;a[e+526>>0]=0;a[e+552>>0]=0;c[e+412>>2]=0;c[e+412+4>>2]=0;c[e+412+8>>2]=0;c[e+412+12>>2]=0;g[e+572>>2]=-1.0;g[e+444>>2]=999999984306749440.0;g[e+448>>2]=999999984306749440.0;g[e+452>>2]=999999984306749440.0;g[e+428>>2]=1.0;g[e+432>>2]=.30000001192092896;g[e+436>>2]=1.0;g[e+440>>2]=.009999999776482582;g[e+456>>2]=.05000000074505806;c[e+592>>2]=0;g[e+596>>2]=0.0;g[e+600>>2]=.699999988079071;g[e+604>>2]=0.0;return e|0}function Cg(a,b,c,d,e,f,h){a=a|0;b=+b;c=+c;d=+d;e=e|0;f=+f;h=h|0;var i=0.0,j=0.0,k=0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0;k=l;l=l+16|0;j=c*f+ +g[a+52>>2];i=d*f+ +g[a+56>>2];g[h+48>>2]=b*f+ +g[a+48>>2];g[h+52>>2]=j;g[h+56>>2]=i;g[h+60>>2]=0.0;i=+g[e>>2];j=+g[e+4>>2];b=+g[e+8>>2];d=+C(+(i*i+j*j+b*b));d=d*f>.7853981852531433?.7853981852531433/f:d;if(d<1.0000000474974513e-03)c=f*.5-d*f*f*f*.02083333395421505*d;else c=+F(+(d*.5*f))/d;o=i*c;n=j*c;i=b*c;q=+E(+(d*f*.5));eh(a,k);b=+g[k>>2];p=+g[k+12>>2];c=+g[k+8>>2];f=+g[k+4>>2];r=1.0/+C(+((q*p-o*b-n*f-i*c)*(q*p-o*b-n*f-i*c)+((i*p+q*c+o*f-n*b)*(i*p+q*c+o*f-n*b)+((q*b+o*p+n*c-i*f)*(q*b+o*p+n*c-i*f)+(i*b+(n*p+q*f)-o*c)*(i*b+(n*p+q*f)-o*c)))));d=(q*b+o*p+n*c-i*f)*r;j=r*(i*b+(n*p+q*f)-o*c);m=r*(i*p+q*c+o*f-n*b);c=r*(q*p-o*b-n*f-i*c);i=d*(2.0/(c*c+(m*m+(d*d+j*j))));f=j*(2.0/(c*c+(m*m+(d*d+j*j))));b=m*(2.0/(c*c+(m*m+(d*d+j*j))));g[h>>2]=1.0-(j*f+m*b);g[h+4>>2]=d*f-c*b;g[h+8>>2]=d*b+c*f;g[h+12>>2]=0.0;g[h+16>>2]=d*f+c*b;g[h+20>>2]=1.0-(d*i+m*b);g[h+24>>2]=j*b-c*i;g[h+28>>2]=0.0;g[h+32>>2]=d*b-c*f;g[h+36>>2]=j*b+c*i;g[h+40>>2]=1.0-(d*i+j*f);g[h+44>>2]=0.0;l=k;return}function Dg(a,b,d,e,f,h,i){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;var k=0.0,m=0,n=0.0,o=0.0,p=0.0,q=0,r=0,s=0.0,t=0;r=l;l=l+16|0;g[e>>2]=3402823466385288598117041.0e14;g[f>>2]=-3402823466385288598117041.0e14;m=c[a+96>>2]|0;if((m|0)>0){q=0;do{t=c[a+104>>2]|0;s=+g[t+(q<<4)>>2]*+g[a+12>>2];n=+g[t+(q<<4)+4>>2]*+g[a+16>>2];o=+g[t+(q<<4)+8>>2]*+g[a+20>>2];k=s*+g[b>>2]+n*+g[b+4>>2]+o*+g[b+8>>2]+ +g[b+48>>2];p=s*+g[b+16>>2]+n*+g[b+20>>2]+o*+g[b+24>>2]+ +g[b+52>>2];o=s*+g[b+32>>2]+n*+g[b+36>>2]+o*+g[b+40>>2]+ +g[b+56>>2];n=k*+g[d>>2]+p*+g[d+4>>2]+o*+g[d+8>>2];if(n<+g[e>>2]){g[e>>2]=n;g[h>>2]=k;g[h+4>>2]=p;g[h+8>>2]=o;g[h+12>>2]=0.0}if(n>+g[f>>2]){g[f>>2]=n;g[i>>2]=k;g[i+4>>2]=p;g[i+8>>2]=o;g[i+12>>2]=0.0}q=q+1|0}while((q|0)!=(m|0));n=+g[f>>2];m=(g[j>>2]=n,c[j>>2]|0)}else{m=-8388609;n=-3402823466385288598117041.0e14}k=+g[e>>2];if(!(k>n)){l=r;return}c[e>>2]=m;g[f>>2]=k;c[r>>2]=c[h>>2];c[r+4>>2]=c[h+4>>2];c[r+8>>2]=c[h+8>>2];c[r+12>>2]=c[h+12>>2];c[h>>2]=c[i>>2];c[h+4>>2]=c[i+4>>2];c[h+8>>2]=c[i+8>>2];c[h+12>>2]=c[i+12>>2];c[i>>2]=c[r>>2];c[i+4>>2]=c[r+4>>2];c[i+8>>2]=c[r+8>>2];c[i+12>>2]=c[r+12>>2];l=r;return}function Eg(a,b){a=a|0;b=b|0;var d=0,e=0;d=l;l=l+48|0;e=(c[a+48>>2]|0)+4|0;c[e>>2]=c[b>>2];c[e+4>>2]=c[b+4>>2];c[e+8>>2]=c[b+8>>2];c[e+12>>2]=c[b+12>>2];b=d+32+4|0;c[b>>2]=0;c[b+4>>2]=0;c[b+8>>2]=0;g[d+32>>2]=1.0;Rb[c[(c[a>>2]|0)+68>>2]&127](d+16|0,a,d+32|0);g[a+32>>2]=+g[d+16>>2]+ +g[a+12>>2];g[d+32>>2]=-1.0;Rb[c[(c[a>>2]|0)+68>>2]&127](d,a,d+32|0);c[d+16>>2]=c[d>>2];c[d+16+4>>2]=c[d+4>>2];c[d+16+8>>2]=c[d+8>>2];c[d+16+12>>2]=c[d+12>>2];g[a+16>>2]=+g[d+16>>2]-+g[a+12>>2];c[d+32>>2]=0;c[d+32+4>>2]=0;c[d+32+8>>2]=0;c[d+32+12>>2]=0;g[b>>2]=1.0;Rb[c[(c[a>>2]|0)+68>>2]&127](d+16|0,a,d+32|0);g[a+36>>2]=+g[d+16+4>>2]+ +g[a+12>>2];g[b>>2]=-1.0;Rb[c[(c[a>>2]|0)+68>>2]&127](d,a,d+32|0);c[d+16>>2]=c[d>>2];c[d+16+4>>2]=c[d+4>>2];c[d+16+8>>2]=c[d+8>>2];c[d+16+12>>2]=c[d+12>>2];g[a+20>>2]=+g[d+16+4>>2]-+g[a+12>>2];c[d+32>>2]=0;c[d+32+4>>2]=0;c[d+32+8>>2]=0;c[d+32+12>>2]=0;g[d+32+8>>2]=1.0;Rb[c[(c[a>>2]|0)+68>>2]&127](d+16|0,a,d+32|0);g[a+40>>2]=+g[d+16+8>>2]+ +g[a+12>>2];g[d+32+8>>2]=-1.0;Rb[c[(c[a>>2]|0)+68>>2]&127](d,a,d+32|0);c[d+16>>2]=c[d>>2];c[d+16+4>>2]=c[d+4>>2];c[d+16+8>>2]=c[d+8>>2];c[d+16+12>>2]=c[d+12>>2];g[a+24>>2]=+g[d+16+8>>2]-+g[a+12>>2];l=d;return}function Fg(b,d,e){b=b|0;d=+d;e=e|0;var f=0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0;f=c[b+8>>2]|0;if(f|0?(c[f+204>>2]&3|0)==0:0){if((c[f+216>>2]&-2|0)!=4)c[f+216>>2]=1;g[f+220>>2]=0.0}f=c[b+12>>2]|0;if(f|0?(c[f+204>>2]&3|0)==0:0){if((c[f+216>>2]&-2|0)!=4)c[f+216>>2]=1;g[f+220>>2]=0.0}f=c[b+20>>2]|0;if(f|0?(c[f+204>>2]&3|0)==0:0){if((c[f+216>>2]&-2|0)!=4)c[f+216>>2]=1;g[f+220>>2]=0.0}f=c[b+24>>2]|0;if(f|0?(c[f+204>>2]&3|0)==0:0){if((c[f+216>>2]&-2|0)!=4)c[f+216>>2]=1;g[f+220>>2]=0.0}f=c[b+156>>2]|0;c[b+156>>2]=f+1;a[b+152>>0]=(f|0)>=(c[b+160>>2]|0)&1;if(f|0){c[b+72>>2]=0;c[b+72+4>>2]=0;c[b+72+8>>2]=0;c[b+72+12>>2]=0;c[b+72+16>>2]=0;c[b+72+20>>2]=0;c[b+72+24>>2]=0;c[b+72+28>>2]=0;return}j=+g[b+64>>2];i=1.0/d*+g[b+72>>2]*j;h=1.0/d*j*+g[b+76>>2];d=1.0/d*j*+g[b+80>>2];g[b+72>>2]=i;g[b+76>>2]=h;g[b+80>>2]=d;g[b+84>>2]=0.0;j=+g[b+68>>2];if(j>0.0){l=j*i*+g[b+120>>2]+j*h*+g[b+124>>2]+j*d*+g[b+128>>2];k=j*i*+g[b+136>>2]+j*h*+g[b+140>>2]+j*d*+g[b+144>>2];g[b+88>>2]=j*i*+g[b+104>>2]+j*h*+g[b+108>>2]+j*d*+g[b+112>>2];g[b+92>>2]=l;g[b+96>>2]=k;g[b+100>>2]=0.0;g[b+72>>2]=(1.0-j)*i;g[b+76>>2]=(1.0-j)*h;g[b+80>>2]=(1.0-j)*d;i=(1.0-j)*i;h=(1.0-j)*h;d=(1.0-j)*d}g[b+72>>2]=1.0/+(e|0)*i;g[b+76>>2]=1.0/+(e|0)*h;g[b+80>>2]=1.0/+(e|0)*d;return}function Gg(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var h=0.0,i=0.0,j=0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0;j=l;l=l+48|0;n=+g[d>>2];o=+g[d+4>>2];m=+g[d+8>>2];p=n*+g[b+4>>2]+o*+g[b+20>>2]+m*+g[b+36>>2];q=n*+g[b+8>>2]+o*+g[b+24>>2]+m*+g[b+40>>2];g[j+32>>2]=+g[b>>2]*n+ +g[b+16>>2]*o+ +g[b+32>>2]*m;g[j+32+4>>2]=p;g[j+32+8>>2]=q;g[j+32+12>>2]=0.0;Rb[c[(c[a>>2]|0)+64>>2]&127](j+16|0,a,j+32|0);q=+g[j+16>>2];p=+g[j+16+4>>2];m=+g[j+16+8>>2];o=q*+g[b>>2]+p*+g[b+4>>2]+m*+g[b+8>>2]+ +g[b+48>>2];n=q*+g[b+16>>2]+p*+g[b+20>>2]+m*+g[b+24>>2]+ +g[b+52>>2];m=q*+g[b+32>>2]+p*+g[b+36>>2]+m*+g[b+40>>2]+ +g[b+56>>2];r=c[(c[a>>2]|0)+64>>2]|0;p=-+g[j+32+4>>2];q=-+g[j+32+8>>2];g[j>>2]=-+g[j+32>>2];g[j+4>>2]=p;g[j+8>>2]=q;g[j+12>>2]=0.0;Rb[r&127](j+16|0,a,j);q=+g[j+16>>2];p=+g[j+16+4>>2];i=+g[j+16+8>>2];k=q*+g[b>>2]+p*+g[b+4>>2]+i*+g[b+8>>2]+ +g[b+48>>2];h=q*+g[b+16>>2]+p*+g[b+20>>2]+i*+g[b+24>>2]+ +g[b+52>>2];i=q*+g[b+32>>2]+p*+g[b+36>>2]+i*+g[b+40>>2]+ +g[b+56>>2];g[e>>2]=o*+g[d>>2]+n*+g[d+4>>2]+m*+g[d+8>>2];i=k*+g[d>>2]+h*+g[d+4>>2]+i*+g[d+8>>2];g[f>>2]=i;h=+g[e>>2];if(!(h>i)){l=j;return}g[e>>2]=i;g[f>>2]=h;l=j;return}function Hg(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var h=0.0,i=0,j=0,k=0.0,m=0,n=0,o=0.0,p=0.0,q=0,r=0;n=l;l=l+16|0;if((f|0)>-3&(f+3|0)>-1){c[6432]=(c[6432]|0)+1;a=ec((f+3<<4|3)+16|0)|0;if(!a)m=0;else{c[(a+4+15&-16)+-4>>2]=a;m=a+4+15&-16}a=0;do{j=m+(a<<4)|0;c[j>>2]=c[n>>2];c[j+4>>2]=c[n+4>>2];c[j+8>>2]=c[n+8>>2];c[j+12>>2]=c[n+12>>2];a=a+1|0}while((a|0)!=(f+3|0));i=0;j=m;while(1){if(!i)h=0.0;else{a=i;k=.5;h=0.0;while(1){h=(a&1|0)==0?h:h+k;a=a>>1;if(!a)break;else k=k*.5}}k=h*2.0+-1.0;o=(+(i<<1|0)*3.1415927410125732+3.1415927410125732)/+(f+3|0);p=+C(+(1.0-k*k));h=p*+F(+o);g[j>>2]=p*+E(+o);g[j+4>>2]=h;g[j+8>>2]=k;g[j+12>>2]=0.0;i=i+1|0;if((i|0)==(f+3|0)){j=m;i=m;break}else j=j+16|0}}else{j=0;i=0}if((f|0)>-3){a=0;do{r=i+(a<<4)|0;q=i+(a<<4)+4|0;m=i+(a<<4)+8|0;o=+g[q>>2]*+g[e+4>>2]+ +g[d+4>>2];p=+g[m>>2]*+g[e+8>>2]+ +g[d+8>>2];g[r>>2]=+g[r>>2]*+g[e>>2]+ +g[d>>2];g[q>>2]=o;g[m>>2]=p;g[i+(a<<4)+12>>2]=0.0;a=a+1|0}while((a|0)<(f+3|0))}a=_b(b,i,f+3|0,1)|0;if((i|0)==0|(j|0)==0){l=n;return a|0}c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0);l=n;return a|0}function Ig(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,m=0;m=l;l=l+16|0;h=c[a+12>>2]|0;i=c[h+(((d+b|0)/2|0)<<4)>>2]|0;j=c[h+(((d+b|0)/2|0)<<4)+4>>2]|0;k=c[h+(((d+b|0)/2|0)<<4)+8>>2]|0;e=b;f=d;while(1){g=e;while(1){e=c[h+(g<<4)+4>>2]|0;if((e|0)>=(j|0)){if((e|0)!=(j|0))break;e=c[h+(g<<4)>>2]|0;if((e|0)>=(i|0)){if((e|0)!=(i|0))break;if((c[h+(g<<4)+8>>2]|0)>=(k|0))break}}g=g+1|0}while(1){e=c[h+(f<<4)+4>>2]|0;if((j|0)>=(e|0)){if((j|0)!=(e|0))break;e=c[h+(f<<4)>>2]|0;if((i|0)>=(e|0)){if((i|0)!=(e|0))break;if((k|0)>=(c[h+(f<<4)+8>>2]|0))break}}f=f+-1|0}if((g|0)>(f|0))e=g;else{e=h+(g<<4)|0;c[m>>2]=c[e>>2];c[m+4>>2]=c[e+4>>2];c[m+8>>2]=c[e+8>>2];c[m+12>>2]=c[e+12>>2];h=h+(f<<4)|0;c[e>>2]=c[h>>2];c[e+4>>2]=c[h+4>>2];c[e+8>>2]=c[h+8>>2];c[e+12>>2]=c[h+12>>2];e=(c[a+12>>2]|0)+(f<<4)|0;c[e>>2]=c[m>>2];c[e+4>>2]=c[m+4>>2];c[e+8>>2]=c[m+8>>2];c[e+12>>2]=c[m+12>>2];e=g+1|0;f=f+-1|0}if((e|0)>(f|0))break;h=c[a+12>>2]|0}if((f|0)>(b|0))Ig(a,b,f);if((e|0)>=(d|0)){l=m;return}Ig(a,e,d);l=m;return}function Jg(a){a=a|0;var b=0,d=0,e=0,f=0.0,h=0.0,i=0.0,j=0,k=0.0,l=0.0,m=0.0,n=0,o=0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0;kl(a+988|0);if((c[a+752>>2]|0)<=0)return;o=0;do{j=c[a+760>>2]|0;n=j+(o*44|0)|0;d=c[j+(o*44|0)+8>>2]|0;e=c[j+(o*44|0)+12>>2]|0;b=c[j+(o*44|0)+16>>2]|0;k=+g[d+8>>2];m=+g[d+12>>2];l=+g[d+16>>2];q=+g[d+20>>2];u=+g[e+8>>2];f=u<k?u:k;r=+g[e+12>>2];h=r<m?r:m;s=+g[e+16>>2];i=s<l?s:l;t=+g[e+20>>2];p=t<q?t:q;k=k<u?u:k;m=m<r?r:m;l=l<s?s:l;q=q<t?t:q;t=+g[b+8>>2];f=t<f?t:f;s=+g[b+12>>2];h=s<h?s:h;r=+g[b+16>>2];i=r<i?r:i;u=+g[b+20>>2];p=u<p?u:p;q=q<u?u:q;k=(k<t?t:k)+0.0;m=(m<s?s:m)+0.0;l=(l<r?r:l)+0.0;b=c[a+992>>2]|0;if(!b){c[6432]=(c[6432]|0)+1;b=ec(63)|0;if(!b)b=0;else{c[(b+4+15&-16)+-4>>2]=b;b=b+4+15&-16}d=b;e=d+44|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0))}else c[a+992>>2]=0;c[b+32>>2]=0;c[b+36>>2]=n;c[b+40>>2]=0;g[b>>2]=f;g[b+4>>2]=h;g[b+8>>2]=i;g[b+12>>2]=p;g[b+16>>2]=k;g[b+20>>2]=m;g[b+24>>2]=l;g[b+28>>2]=q;We(a+988|0,c[a+988>>2]|0,b);c[a+1e3>>2]=(c[a+1e3>>2]|0)+1;c[j+(o*44|0)+40>>2]=b;o=o+1|0}while((o|0)<(c[a+752>>2]|0));return}function Kg(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0,v=0,w=0,x=0,y=0;if((c[a>>2]|0)==(b|0)){c[a>>2]=0;a=0;return a|0}e=c[b+32>>2]|0;d=c[e+32>>2]|0;b=c[e+36+(((c[e+40>>2]|0)!=(b|0)&1)<<2)>>2]|0;if(!d){c[a>>2]=b;c[b+32>>2]=0;d=c[a+4>>2]|0;if(!d)d=b;else{c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0);d=c[a>>2]|0}c[a+4>>2]=e;a=d;return a|0}c[d+36+(((c[d+40>>2]|0)==(e|0)&1)<<2)>>2]=b;c[b+32>>2]=d;b=c[a+4>>2]|0;if(b|0){c[6433]=(c[6433]|0)+1;Pc(c[b+-4>>2]|0)}c[a+4>>2]=e;do{s=+g[d>>2];x=d+4|0;q=+g[x>>2];v=d+8|0;o=+g[v>>2];y=d+16|0;m=+g[y>>2];w=d+20|0;i=+g[w>>2];e=d+24|0;k=+g[e>>2];u=c[d+36>>2]|0;b=c[d+40>>2]|0;t=+g[u>>2];r=+g[b>>2];r=t<r?t:r;g[d>>2]=r;t=+g[u+16>>2];l=+g[b+16>>2];l=t>l?t:l;g[y>>2]=l;t=+g[u+4>>2];p=+g[b+4>>2];p=t<p?t:p;g[x>>2]=p;t=+g[u+20>>2];h=+g[b+20>>2];h=t>h?t:h;g[w>>2]=h;t=+g[u+8>>2];n=+g[b+8>>2];n=t<n?t:n;g[v>>2]=n;t=+g[u+24>>2];j=+g[b+24>>2];j=t>j?t:j;g[e>>2]=j;if(!(s!=r|q!=p|o!=n|m!=l)?!(k!=j|i!=h):0){f=14;break}d=c[d+32>>2]|0}while((d|0)!=0);if((f|0)==14)return d|0;y=c[a>>2]|0;return y|0}function Lg(a){a=a|0;var b=0,d=0,e=0.0,f=0.0,h=0.0,i=0,j=0;i=c[a+28>>2]|0;e=0.0;f=0.0;h=0.0;j=0;a:while(1){switch(j|0){case 0:{e=+g[a+80>>2]+ +g[a+64>>2];f=+g[a+84>>2]+ +g[a+68>>2];h=+g[a+88>>2]+ +g[a+72>>2];break}case 1:{e=+g[a+80>>2]+ +g[a+64>>2];f=+g[a+84>>2]+ +g[a+68>>2];h=+g[a+72>>2]-+g[a+88>>2];break}case 2:{e=+g[a+80>>2]+ +g[a+64>>2];f=+g[a+68>>2]-+g[a+84>>2];h=+g[a+88>>2]+ +g[a+72>>2];break}case 3:{e=+g[a+80>>2]+ +g[a+64>>2];f=+g[a+68>>2]-+g[a+84>>2];h=+g[a+72>>2]-+g[a+88>>2];break}case 4:{e=+g[a+64>>2]-+g[a+80>>2];f=+g[a+84>>2]+ +g[a+68>>2];h=+g[a+88>>2]+ +g[a+72>>2];break}case 5:{e=+g[a+64>>2]-+g[a+80>>2];f=+g[a+84>>2]+ +g[a+68>>2];h=+g[a+72>>2]-+g[a+88>>2];break}case 6:{e=+g[a+64>>2]-+g[a+80>>2];f=+g[a+68>>2]-+g[a+84>>2];h=+g[a+88>>2]+ +g[a+72>>2];break}case 7:{e=+g[a+64>>2]-+g[a+80>>2];f=+g[a+68>>2]-+g[a+84>>2];h=+g[a+72>>2]-+g[a+88>>2];break}default:{}}if((i|0)>0){b=c[a+36>>2]|0;d=0;do{if(+g[b+(d*36|0)+32>>2]+(e*+g[b+(d*36|0)+20>>2]+f*+g[b+(d*36|0)+24>>2]+h*+g[b+(d*36|0)+28>>2])>0.0){b=0;d=16;break a}d=d+1|0}while((d|0)<(i|0))}j=j+1|0;if((j|0)>=8){b=1;d=16;break}}if((d|0)==16)return b|0;return 0}function Mg(a,b,d,e,f,h,i){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;var k=0.0,m=0,n=0.0,o=0.0,p=0.0,q=0,r=0,s=0.0,t=0;r=l;l=l+16|0;g[e>>2]=3402823466385288598117041.0e14;g[f>>2]=-3402823466385288598117041.0e14;m=c[a+8>>2]|0;if((m|0)>0){q=0;do{t=c[a+16>>2]|0;s=+g[t+(q<<4)>>2];n=+g[t+(q<<4)+4>>2];o=+g[t+(q<<4)+8>>2];k=s*+g[b>>2]+n*+g[b+4>>2]+o*+g[b+8>>2]+ +g[b+48>>2];p=s*+g[b+16>>2]+n*+g[b+20>>2]+o*+g[b+24>>2]+ +g[b+52>>2];o=s*+g[b+32>>2]+n*+g[b+36>>2]+o*+g[b+40>>2]+ +g[b+56>>2];n=k*+g[d>>2]+p*+g[d+4>>2]+o*+g[d+8>>2];if(n<+g[e>>2]){g[e>>2]=n;g[h>>2]=k;g[h+4>>2]=p;g[h+8>>2]=o;g[h+12>>2]=0.0}if(n>+g[f>>2]){g[f>>2]=n;g[i>>2]=k;g[i+4>>2]=p;g[i+8>>2]=o;g[i+12>>2]=0.0}q=q+1|0}while((q|0)!=(m|0));n=+g[f>>2];m=(g[j>>2]=n,c[j>>2]|0)}else{m=-8388609;n=-3402823466385288598117041.0e14}k=+g[e>>2];if(!(k>n)){l=r;return}c[e>>2]=m;g[f>>2]=k;c[r>>2]=c[h>>2];c[r+4>>2]=c[h+4>>2];c[r+8>>2]=c[h+8>>2];c[r+12>>2]=c[h+12>>2];c[h>>2]=c[i>>2];c[h+4>>2]=c[i+4>>2];c[h+8>>2]=c[i+8>>2];c[h+12>>2]=c[i+12>>2];c[i>>2]=c[r>>2];c[i+4>>2]=c[r+4>>2];c[i+8>>2]=c[r+8>>2];c[i+12>>2]=c[r+12>>2];l=r;return}function Ng(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,m=0;m=l;l=l+32|0;j=(a[b+28>>0]|0)!=0;k=j?e:d;j=j?d:e;h=c[k+4>>2]|0;i=c[h+16>>2]|0;g=c[b+12>>2]|0;if((g|0)<(i|0)){if((c[b+16>>2]|0)<(i|0)){if(!i){e=g;f=0}else{c[6432]=(c[6432]|0)+1;d=ec((i<<2|3)+16|0)|0;if(!d)d=0;else{c[(d+4+15&-16)+-4>>2]=d;d=d+4+15&-16}e=c[b+12>>2]|0;f=d}if((e|0)>0){d=0;do{c[f+(d<<2)>>2]=c[(c[b+20>>2]|0)+(d<<2)>>2];d=d+1|0}while((d|0)!=(e|0))}d=c[b+20>>2]|0;if(d|0){if(a[b+24>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+20>>2]=0}a[b+24>>0]=1;c[b+20>>2]=f;c[b+16>>2]=i;e=b+20|0}else e=b+20|0;d=g;do{c[(c[e>>2]|0)+(d<<2)>>2]=0;d=d+1|0}while((d|0)!=(i|0))}c[b+12>>2]=i;if((i|0)<=0){l=m;return}d=0;do{if(!(c[h+64>>2]|0)){e=c[(c[h+24>>2]|0)+(d*80|0)+64>>2]|0;f=c[k+8>>2]|0;g=c[k+12>>2]|0;c[m>>2]=k;c[m+4>>2]=e;c[m+8>>2]=f;c[m+12>>2]=g;c[m+16>>2]=-1;c[m+20>>2]=d;g=c[b+4>>2]|0;g=pb[c[(c[g>>2]|0)+8>>2]&31](g,m,j,c[b+32>>2]|0)|0;c[(c[b+20>>2]|0)+(d<<2)>>2]=g}else c[(c[b+20>>2]|0)+(d<<2)>>2]=0;d=d+1|0}while((d|0)!=(i|0));l=m;return}function Og(a,b,e){a=a|0;b=b|0;e=e|0;Sh(a,b,e)|0;c[b+52>>2]=c[a+48>>2];c[b+56>>2]=c[a+52>>2];c[b+60>>2]=c[a+56>>2];c[b+64>>2]=c[a+60>>2];c[b+68>>2]=c[a+64>>2];c[b+72>>2]=c[a+68>>2];c[b+76>>2]=c[a+72>>2];c[b+80>>2]=c[a+76>>2];c[b+84>>2]=c[a+80>>2];c[b+88>>2]=c[a+84>>2];c[b+92>>2]=c[a+88>>2];c[b+96>>2]=c[a+92>>2];c[b+100>>2]=c[a+96>>2];c[b+104>>2]=c[a+100>>2];c[b+108>>2]=c[a+104>>2];c[b+112>>2]=c[a+108>>2];c[b+116>>2]=c[a+112>>2];c[b+120>>2]=c[a+116>>2];c[b+124>>2]=c[a+120>>2];c[b+128>>2]=c[a+124>>2];c[b+132>>2]=c[a+128>>2];c[b+136>>2]=c[a+132>>2];c[b+140>>2]=c[a+136>>2];c[b+144>>2]=c[a+140>>2];c[b+148>>2]=c[a+144>>2];c[b+152>>2]=c[a+148>>2];c[b+156>>2]=c[a+152>>2];c[b+160>>2]=c[a+156>>2];c[b+164>>2]=c[a+160>>2];c[b+168>>2]=c[a+164>>2];c[b+172>>2]=c[a+168>>2];c[b+176>>2]=c[a+172>>2];c[b+228>>2]=c[a+868>>2];c[b+212>>2]=c[a+872>>2];c[b+196>>2]=c[a+680>>2];c[b+180>>2]=c[a+696>>2];c[b+232>>2]=c[a+932>>2];c[b+216>>2]=c[a+936>>2];c[b+200>>2]=c[a+684>>2];c[b+184>>2]=c[a+700>>2];c[b+236>>2]=c[a+996>>2];c[b+220>>2]=c[a+1e3>>2];c[b+204>>2]=c[a+688>>2];c[b+188>>2]=c[a+704>>2];c[b+244>>2]=d[a+1300>>0];c[b+248>>2]=d[a+1301>>0];return 12561}function Pg(b){b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0;d=c[b+32>>2]|0;if(!d)g=0;else g=c[b+40>>2]|0;e=c[b+52>>2]|0;if(!e)h=0;else h=c[b+60>>2]|0;f=c[b+72>>2]|0;if(!f)i=0;else i=c[b+80>>2]|0;j=c[b+8>>2]|0;+Ib[c[(c[j>>2]|0)+12>>2]&3](j,g,d,h,e,i,f,c[b+4>>2]|0,c[b+20>>2]|0,c[b+24>>2]|0);d=c[b+32>>2]|0;if((d|0)<0){if((c[b+36>>2]|0)<0){e=c[b+40>>2]|0;if(e|0){if(a[b+44>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}c[b+40>>2]=0}a[b+44>>0]=1;c[b+40>>2]=0;c[b+36>>2]=0}do{c[(c[b+40>>2]|0)+(d<<2)>>2]=0;d=d+1|0}while((d|0)!=0)}c[b+32>>2]=0;d=c[b+52>>2]|0;if((d|0)<0){if((c[b+56>>2]|0)<0){e=c[b+60>>2]|0;if(e|0){if(a[b+64>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}c[b+60>>2]=0}a[b+64>>0]=1;c[b+60>>2]=0;c[b+56>>2]=0}do{c[(c[b+60>>2]|0)+(d<<2)>>2]=0;d=d+1|0}while((d|0)!=0)}c[b+52>>2]=0;d=c[b+72>>2]|0;if((d|0)>=0){c[b+72>>2]=0;return}if((c[b+76>>2]|0)<0){e=c[b+80>>2]|0;if(e|0){if(a[b+84>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}c[b+80>>2]=0}a[b+84>>0]=1;c[b+80>>2]=0;c[b+76>>2]=0}do{c[(c[b+80>>2]|0)+(d<<2)>>2]=0;d=d+1|0}while((d|0)!=0);c[b+72>>2]=0;return}function Qg(b){b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0;c[6432]=(c[6432]|0)+1;d=ec(39)|0;if(!d)i=0;else{c[(d+4+15&-16)+-4>>2]=d;i=d+4+15&-16}g=i;c[i>>2]=0;c[i+4>>2]=0;c[i+8>>2]=0;c[i+12>>2]=0;c[i+16>>2]=0;if((c[b+872>>2]|0)>0){h=c[c[b+880>>2]>>2]|0;c[i>>2]=c[h>>2];c[i+4>>2]=c[h+4>>2];c[i+8>>2]=c[h+8>>2];c[i+12>>2]=c[h+12>>2];c[i+16>>2]=c[h+16>>2]}else{c[i>>2]=0;c[i+4>>2]=0;c[i+8>>2]=0;c[i+12>>2]=0;c[i+16>>2]=0}d=c[b+872>>2]|0;if((d|0)!=(c[b+876>>2]|0)){h=d;f=b+880|0;f=c[f>>2]|0;f=f+(h<<2)|0;c[f>>2]=g;h=h+1|0;c[b+872>>2]=h;return i|0}h=d|0?d<<1:1;if((d|0)>=(h|0)){h=d;f=b+880|0;f=c[f>>2]|0;f=f+(h<<2)|0;c[f>>2]=g;h=h+1|0;c[b+872>>2]=h;return i|0}if(!h)e=0;else{c[6432]=(c[6432]|0)+1;d=ec((h<<2|3)+16|0)|0;if(!d)e=0;else{c[(d+4+15&-16)+-4>>2]=d;e=d+4+15&-16}d=c[b+872>>2]|0}if((d|0)>0){f=0;do{c[e+(f<<2)>>2]=c[(c[b+880>>2]|0)+(f<<2)>>2];f=f+1|0}while((f|0)!=(d|0))}f=c[b+880>>2]|0;if(f){if(a[b+884>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0);d=c[b+872>>2]|0}c[b+880>>2]=0}a[b+884>>0]=1;c[b+880>>2]=e;c[b+876>>2]=h;h=d;f=b+880|0;f=c[f>>2]|0;f=f+(h<<2)|0;c[f>>2]=g;h=h+1|0;c[b+872>>2]=h;return i|0}function Rg(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;e=c[b+4>>2]|0;if((e|0)==(c[b+8>>2]|0)){vf(b,e|0?e<<1:1);e=c[b+4>>2]|0}o=c[b+12>>2]|0;l=o+(e*36|0)+16|0;a[l>>0]=1;k=o+(e*36|0)+12|0;c[k>>2]=0;n=o+(e*36|0)+4|0;c[n>>2]=0;j=o+(e*36|0)+8|0;c[j>>2]=0;p=c[d+4>>2]|0;if((p|0)<=0){c[n>>2]=p;p=o+(e*36|0)+20|0;d=d+20|0;c[p>>2]=c[d>>2];c[p+4>>2]=c[d+4>>2];c[p+8>>2]=c[d+8>>2];c[p+12>>2]=c[d+12>>2];d=c[b+4>>2]|0;d=d+1|0;c[b+4>>2]=d;return}c[6432]=(c[6432]|0)+1;f=ec((p<<2|3)+16|0)|0;if(!f)i=0;else{c[(f+4+15&-16)+-4>>2]=f;i=f+4+15&-16}g=c[n>>2]|0;h=c[k>>2]|0;if((g|0)<=0){if(h|0)m=10}else{f=0;do{c[i+(f<<2)>>2]=c[h+(f<<2)>>2];f=f+1|0}while((f|0)!=(g|0));m=10}if((m|0)==10?a[l>>0]|0:0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}a[l>>0]=1;c[k>>2]=i;c[j>>2]=p;Hk(i|0,0,p<<2|0)|0;h=c[k>>2]|0;c[n>>2]=p;f=c[d+12>>2]|0;g=0;do{c[h+(g<<2)>>2]=c[f+(g<<2)>>2];g=g+1|0}while((g|0)!=(p|0));p=o+(e*36|0)+20|0;d=d+20|0;c[p>>2]=c[d>>2];c[p+4>>2]=c[d+4>>2];c[p+8>>2]=c[d+8>>2];c[p+12>>2]=c[d+12>>2];d=c[b+4>>2]|0;d=d+1|0;c[b+4>>2]=d;return}function Sg(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0,k=0,l=0,m=0.0,n=0,o=0,p=0.0,q=0.0;Vb[c[(c[a>>2]|0)+8>>2]&127](a,b,f,h);n=c[h>>2]|0;k=c[h+4>>2]|0;b=c[h+8>>2]|0;l=c[f>>2]|0;o=c[f+4>>2]|0;i=c[f+8>>2]|0;m=+g[d>>2];p=+g[d+4>>2];q=+g[d+8>>2];if(m>0.0)n=(g[j>>2]=(c[j>>2]=n,+g[j>>2])+m,c[j>>2]|0);else l=(g[j>>2]=(c[j>>2]=l,+g[j>>2])+m,c[j>>2]|0);if(p>0.0){d=o;k=(g[j>>2]=(c[j>>2]=k,+g[j>>2])+p,c[j>>2]|0)}else d=(g[j>>2]=(c[j>>2]=o,+g[j>>2])+p,c[j>>2]|0);if(q>0.0)b=(g[j>>2]=(c[j>>2]=b,+g[j>>2])+q,c[j>>2]|0);else i=(g[j>>2]=(c[j>>2]=i,+g[j>>2])+q,c[j>>2]|0);m=+g[e>>2];p=+g[e+4>>2];q=+g[e+8>>2];q=+C(+(m*m+p*p+q*q));q=q*+zb[c[(c[a>>2]|0)+16>>2]&15](a);c[f>>2]=l;c[f+4>>2]=d;c[f+8>>2]=i;g[f+12>>2]=0.0;c[h>>2]=n;c[h+4>>2]=k;c[h+8>>2]=b;g[h+12>>2]=0.0;g[f>>2]=+g[f>>2]-q;g[f+4>>2]=+g[f+4>>2]-q;g[f+8>>2]=+g[f+8>>2]-q;g[h>>2]=q+ +g[h>>2];g[h+4>>2]=q+ +g[h+4>>2];g[h+8>>2]=q+ +g[h+8>>2];return}function Tg(b,d,e){b=b|0;d=+d;e=e|0;var f=0,h=0.0,i=0,j=0,k=0,l=0,m=0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0;j=c[b+712>>2]|0;if(e){if((j|0)>0){e=c[b+720>>2]|0;f=0;do{g[e+(f*104|0)+88>>2]=0.0;f=f+1|0}while((f|0)!=(j|0))}e=c[b+752>>2]|0;if((e|0)>0){f=c[b+760>>2]|0;i=0;do{m=c[f+(i*44|0)+8>>2]|0;l=c[f+(i*44|0)+12>>2]|0;k=c[f+(i*44|0)+16>>2]|0;o=+g[m+8>>2];q=+g[m+12>>2];h=+g[m+16>>2];n=+g[l+8>>2]-o;r=+g[l+12>>2]-q;p=+g[l+16>>2]-h;o=+g[k+8>>2]-o;q=+g[k+12>>2]-q;h=+g[k+16>>2]-h;h=+C(+((n*q-r*o)*(n*q-r*o)+((r*h-p*q)*(r*h-p*q)+(p*o-n*h)*(p*o-n*h))));g[m+88>>2]=h+ +g[m+88>>2];g[l+88>>2]=h+ +g[l+88>>2];g[k+88>>2]=h+ +g[k+88>>2];i=i+1|0}while((i|0)!=(e|0))}if((j|0)<=0){m=b+924|0;a[m>>0]=1;return}e=c[b+720>>2]|0;f=0;do{m=e+(f*104|0)+88|0;g[m>>2]=1.0/+g[m>>2];f=f+1|0}while((f|0)!=(j|0))}if((j|0)<=0){m=b+924|0;a[m>>0]=1;return}f=c[b+720>>2]|0;e=0;h=0.0;do{r=+g[f+(e*104|0)+88>>2];h=h+(r>0.0?1.0/r:0.0);e=e+1|0}while((e|0)!=(j|0));h=1.0/h*d;e=0;do{m=f+(e*104|0)+88|0;g[m>>2]=+g[m>>2]/h;e=e+1|0}while((e|0)!=(j|0));m=b+924|0;a[m>>0]=1;return}function Ug(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=+f;var h=0,i=0.0,j=0,k=0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0;l=+g[d>>2];if(+g[b>>2]<=l){i=+g[d+4>>2];if((((+g[b+4>>2]<=i?+g[b+8>>2]<=+g[d+8>>2]:0)?+g[b+16>>2]>=+g[d+16>>2]:0)?+g[b+20>>2]>=+g[d+20>>2]:0)?+g[b+24>>2]>=+g[d+24>>2]:0){d=0;return d|0}else h=d+4|0}else{h=d+4|0;i=+g[d+4>>2]}g[d>>2]=l-f;n=i-f;g[h>>2]=n;i=+g[d+8>>2]-f;g[d+8>>2]=i;q=+g[d+16>>2]+f;g[d+16>>2]=q;o=+g[d+20>>2]+f;g[d+20>>2]=o;m=+g[d+24>>2]+f;g[d+24>>2]=m;p=+g[e>>2];g[(p>0.0?d+16|0:d)>>2]=p+(p>0.0?q:l-f);f=+g[e+4>>2];g[(f>0.0?d+20|0:h)>>2]=f+(f>0.0?o:n);f=+g[e+8>>2];g[(f>0.0?d+24|0:d+8|0)>>2]=f+(f>0.0?m:i);h=Kg(a,b)|0;a:do if(h){j=c[a+8>>2]|0;if((j|0)<=-1){h=c[a>>2]|0;break}if(j){k=0;while(1){e=c[h+32>>2]|0;k=k+1|0;if(!e)break a;if((k|0)>=(j|0)){h=e;break}else h=e}}}else h=0;while(0);c[b>>2]=c[d>>2];c[b+4>>2]=c[d+4>>2];c[b+8>>2]=c[d+8>>2];c[b+12>>2]=c[d+12>>2];c[b+16>>2]=c[d+16>>2];c[b+20>>2]=c[d+20>>2];c[b+24>>2]=c[d+24>>2];c[b+28>>2]=c[d+28>>2];We(a,h,b);d=1;return d|0}function Vg(a,b){a=+a;b=+b;var d=0,e=0,f=0,h=0,i=0,k=0,l=0,m=0;l=(g[j>>2]=a,c[j>>2]|0);i=(g[j>>2]=b,c[j>>2]|0);a:do if((i<<1|0)!=0?!((l>>>23&255|0)==255|((eC(b)|0)&2147483647)>>>0>2139095040):0){if(l<<1>>>0<=i<<1>>>0)return +((l<<1|0)==(i<<1|0)?a*0.0:a);if(!(l>>>23&255)){if((l<<9|0)>-1){d=0;e=l<<9;do{d=d+-1|0;e=e<<1}while((e|0)>-1);e=d}else e=0;d=e;f=l<<1-e}else{d=l>>>23&255;f=l&8388607|8388608}if(!(i>>>23&255)){if((i<<9|0)>-1){e=0;h=i<<9;do{e=e+-1|0;h=h<<1}while((h|0)>-1)}else e=0;k=e;i=i<<1-e}else{k=i>>>23&255;i=i&8388607|8388608}e=f-i|0;b:do if((d|0)>(k|0)){h=(e|0)>-1;while(1){if(h){if(!e)break}else e=f;f=e<<1;d=d+-1|0;e=f-i|0;if((d|0)>(k|0))h=(e|0)>-1;else{h=(e|0)>-1;break b}}b=a*0.0;break a}else h=(e|0)>-1;while(0);if(h){if(!e){b=a*0.0;break}}else e=f;if(e>>>0<8388608)do{e=e<<1;d=d+-1|0}while(e>>>0<8388608);if((d|0)>0)d=e+-8388608|d<<23;else d=e>>>(1-d|0);b=(c[j>>2]=d|l&-2147483648,+g[j>>2])}else m=3;while(0);if((m|0)==3)b=a*b/(a*b);return +b}function Wg(a,b,d,e,f,h,i,j,k,m){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;j=j|0;k=k|0;m=m|0;var n=0.0,o=0.0;m=l;l=l+80|0;o=+g[h+52>>2]-+g[f+52>>2];n=+g[h+56>>2]-+g[f+56>>2];g[m+56>>2]=+g[h+48>>2]-+g[f+48>>2];g[m+56+4>>2]=o;g[m+56+8>>2]=n;g[m+56+12>>2]=0.0;if(vc(d,f,e,h,m+56|0,m,1)|0){c[j>>2]=c[m+4>>2];c[j+4>>2]=c[m+4+4>>2];c[j+8>>2]=c[m+4+8>>2];c[j+12>>2]=c[m+4+12>>2];c[k>>2]=c[m+20>>2];c[k+4>>2]=c[m+20+4>>2];c[k+8>>2]=c[m+20+8>>2];c[k+12>>2]=c[m+20+12>>2];c[i>>2]=c[m+36>>2];c[i+4>>2]=c[m+36+4>>2];c[i+8>>2]=c[m+36+8>>2];c[i+12>>2]=c[m+36+12>>2];k=1;l=m;return k|0}if(!(qd(d,f,e,h,m+56|0,m)|0)){k=0;l=m;return k|0}c[j>>2]=c[m+4>>2];c[j+4>>2]=c[m+4+4>>2];c[j+8>>2]=c[m+4+8>>2];c[j+12>>2]=c[m+4+12>>2];c[k>>2]=c[m+20>>2];c[k+4>>2]=c[m+20+4>>2];c[k+8>>2]=c[m+20+8>>2];c[k+12>>2]=c[m+20+12>>2];c[i>>2]=c[m+36>>2];c[i+4>>2]=c[m+36+4>>2];c[i+8>>2]=c[m+36+8>>2];c[i+12>>2]=c[m+36+12>>2];k=0;l=m;return k|0}function Xg(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0,j=0,k=0,m=0.0,n=0.0,o=0,p=0,q=0.0,r=0;p=l;l=l+2048|0;c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;e=+g[d>>2];h=+g[d+4>>2];f=+g[d+8>>2];if(e*e+h*h+f*f<9.999999747378752e-05){n=1.0;m=0.0;h=0.0}else{q=1.0/+C(+(e*e+h*h+f*f));n=e*q;m=h*q;h=f*q}if((lb[c[(c[b>>2]|0)+96>>2]&127](b)|0)<=0){l=p;return}k=0;f=-999999984306749440.0;while(1){if(((lb[c[(c[b>>2]|0)+96>>2]&127](b)|0)-k|0)<128){d=(lb[c[(c[b>>2]|0)+96>>2]&127](b)|0)-k|0;if((d|0)>0)o=8;else{e=-3402823466385288598117041.0e14;d=-1}}else{d=128;o=8}if((o|0)==8){o=0;i=0;do{Rb[c[(c[b>>2]|0)+108>>2]&127](b,i,p+(i<<4)|0);i=i+1|0}while((i|0)!=(d|0));j=0;e=-3402823466385288598117041.0e14;i=-1;do{q=n*+g[p+(j<<4)>>2]+m*+g[p+(j<<4)+4>>2]+h*+g[p+(j<<4)+8>>2];r=q>e;i=r?j:i;e=r?q:e;j=j+1|0}while((j|0)!=(d|0));d=i}if(e>f){r=p+(d<<4)|0;c[a>>2]=c[r>>2];c[a+4>>2]=c[r+4>>2];c[a+8>>2]=c[r+8>>2];c[a+12>>2]=c[r+12>>2]}else e=f;k=k+128|0;if((k|0)>=(lb[c[(c[b>>2]|0)+96>>2]&127](b)|0))break;else f=e}l=p;return}function Yg(b,e,f,h,i,j){b=b|0;e=e|0;f=f|0;h=h|0;i=i|0;j=j|0;var k=0;if((d[h+55>>0]|0|0)==(e|0)){h=0;return h|0}k=c[5100+(i<<2)>>2]|0;if(+g[h>>2]*+g[f+16>>2]+ +g[h+4>>2]*+g[f+20>>2]+ +g[h+8>>2]*+g[f+24>>2]-+g[h+16>>2]<-9.999999747378752e-06){k=_e(b,c[h+20+(k<<2)>>2]|0,c[h+20+(i<<2)>>2]|0,f,0)|0;if(!k){h=0;return h|0}a[k+52>>0]=i;c[k+32>>2]=h;a[h+52+i>>0]=0;c[h+32+(i<<2)>>2]=k;i=c[j>>2]|0;if(!i)c[j+4>>2]=k;else{a[i+53>>0]=2;c[i+36>>2]=k;a[k+54>>0]=1;c[k+40>>2]=i}c[j>>2]=k;c[j+8>>2]=(c[j+8>>2]|0)+1;h=1;return h|0}i=c[5112+(i<<2)>>2]|0;a[h+55>>0]=e;if(!(Yg(b,e,f,c[h+32+(k<<2)>>2]|0,d[h+52+k>>0]|0,j)|0)){h=0;return h|0}if(!(Yg(b,e,f,c[h+32+(i<<2)>>2]|0,d[h+52+i>>0]|0,j)|0)){h=0;return h|0}i=c[h+48>>2]|0;if(i|0)c[i+44>>2]=c[h+44>>2];i=c[h+44>>2]|0;if(i|0)c[i+48>>2]=c[h+48>>2];if((c[b+9280>>2]|0)==(h|0))c[b+9280>>2]=c[h+48>>2];c[b+9284>>2]=(c[b+9284>>2]|0)+-1;c[h+44>>2]=0;c[h+48>>2]=c[b+9288>>2];i=c[b+9288>>2]|0;if(i|0)c[i+44>>2]=h;c[b+9288>>2]=h;c[b+9292>>2]=(c[b+9292>>2]|0)+1;h=1;return h|0}function Zg(b,d){b=b|0;d=d|0;var e=0,f=0,h=0.0,i=0,j=0,k=0.0,l=0.0;e=c[d+204>>2]|0;if((e&3|0)==0?(c[d+504>>2]&1|0)==0:0){h=+g[d+344>>2];if(h!=0.0){l=1.0/h*+g[b+252>>2];k=1.0/h*+g[b+256>>2];g[d+364>>2]=1.0/h*+g[b+248>>2];g[d+368>>2]=l;g[d+372>>2]=k;g[d+376>>2]=0.0}c[d+380>>2]=c[b+248>>2];c[d+380+4>>2]=c[b+248+4>>2];c[d+380+8>>2]=c[b+248+8>>2];c[d+380+12>>2]=c[b+248+12>>2]}if(!(c[d+192>>2]|0))return;if(e&1){if((c[d+216>>2]&-2|0)!=4)c[d+216>>2]=2}else{f=c[b+232>>2]|0;if((f|0)==(c[b+236>>2]|0)?(j=f|0?f<<1:1,(f|0)<(j|0)):0){if(!j)e=0;else{c[6432]=(c[6432]|0)+1;e=ec((j<<2|3)+16|0)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}f=c[b+232>>2]|0}if((f|0)>0){i=0;do{c[e+(i<<2)>>2]=c[(c[b+240>>2]|0)+(i<<2)>>2];i=i+1|0}while((i|0)!=(f|0))}i=c[b+240>>2]|0;if(i){if(a[b+244>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0);f=c[b+232>>2]|0}c[b+240>>2]=0}a[b+244>>0]=1;c[b+240>>2]=e;c[b+236>>2]=j;e=c[d+204>>2]|0}c[(c[b+240>>2]|0)+(f<<2)>>2]=d;c[b+232>>2]=f+1}j=(e&3|0)==0;Vb[c[(c[b>>2]|0)+36>>2]&127](b,d,j?1:2,j?-1:-3);return}function _g(a,d,f,g){a=a|0;d=d|0;f=f|0;g=g|0;var h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0;i=c[a+68+(d<<2)>>2]|0;h=b[i+((f&65535)+-1<<2)>>1]|0;if((e[i+((f&65535)<<2)>>1]|0)>=(h&65535))return;j=c[a+60>>2]|0;l=j+((e[i+((f&65535)<<2)+2>>1]|0)<<6)+54+(d<<1)|0;k=i+((f&65535)<<2)|0;f=i+((f&65535)+-1<<2)|0;while(1){i=e[f+2>>1]|0;if(!(h&1)){h=e[k+2>>1]|0;if(((((e[j+(h<<6)+54+((1<<d&3)<<1)>>1]|0)>=(e[j+(i<<6)+48+((1<<d&3)<<1)>>1]|0)?(e[j+(i<<6)+54+((1<<d&3)<<1)>>1]|0)>=(e[j+(h<<6)+48+((1<<d&3)<<1)>>1]|0):0)?(e[j+(h<<6)+54+((1<<(1<<d&3)&3)<<1)>>1]|0)>=(e[j+(i<<6)+48+((1<<(1<<d&3)&3)<<1)>>1]|0):0)?(e[j+(i<<6)+54+((1<<(1<<d&3)&3)<<1)>>1]|0)>=(e[j+(h<<6)+48+((1<<(1<<d&3)&3)<<1)>>1]|0):0)?(o=c[a+92>>2]|0,m=j+(h<<6)|0,n=j+(i<<6)|0,pb[c[(c[o>>2]|0)+12>>2]&31](o,m,n,g)|0,o=c[a+96>>2]|0,o|0):0)pb[c[(c[o>>2]|0)+12>>2]&31](o,m,n,g)|0;h=j+(i<<6)+48+(d<<1)|0}else h=j+(i<<6)+54+(d<<1)|0;b[h>>1]=(b[h>>1]|0)+1<<16>>16;b[l>>1]=(b[l>>1]|0)+-1<<16>>16;i=e[k>>1]|e[k+2>>1]<<16;h=e[f>>1]|e[f+2>>1]<<16;b[k>>1]=h;b[k+2>>1]=h>>>16;b[f>>1]=i;b[f+2>>1]=i>>>16;i=k+-4|0;f=f+-4|0;h=b[f>>1]|0;if((e[i>>1]|0)>=(h&65535))break;j=c[a+60>>2]|0;k=i}return}function $g(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0,i=0.0,j=0,k=0,l=0,m=0.0,n=0.0;h=c[d+204>>2]|0;if((h&3|0)==0?(c[d+504>>2]&1|0)==0:0){i=+g[d+344>>2];if(i!=0.0){n=1.0/i*+g[b+252>>2];m=1.0/i*+g[b+256>>2];g[d+364>>2]=1.0/i*+g[b+248>>2];g[d+368>>2]=n;g[d+372>>2]=m;g[d+376>>2]=0.0}c[d+380>>2]=c[b+248>>2];c[d+380+4>>2]=c[b+248+4>>2];c[d+380+8>>2]=c[b+248+8>>2];c[d+380+12>>2]=c[b+248+12>>2]}if(!(c[d+192>>2]|0))return;if(h&1){if((c[d+216>>2]&-2|0)!=4)c[d+216>>2]=2}else{h=c[b+232>>2]|0;if((h|0)==(c[b+236>>2]|0)?(l=h|0?h<<1:1,(h|0)<(l|0)):0){if(!l)j=0;else{c[6432]=(c[6432]|0)+1;h=ec((l<<2|3)+16|0)|0;if(!h)j=0;else{c[(h+4+15&-16)+-4>>2]=h;j=h+4+15&-16}h=c[b+232>>2]|0}if((h|0)>0){k=0;do{c[j+(k<<2)>>2]=c[(c[b+240>>2]|0)+(k<<2)>>2];k=k+1|0}while((k|0)!=(h|0))}k=c[b+240>>2]|0;if(k){if(a[b+244>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[k+-4>>2]|0);h=c[b+232>>2]|0}c[b+240>>2]=0}a[b+244>>0]=1;c[b+240>>2]=j;c[b+236>>2]=l}c[(c[b+240>>2]|0)+(h<<2)>>2]=d;c[b+232>>2]=h+1}Vb[c[(c[b>>2]|0)+36>>2]&127](b,d,e,f);return}function ah(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0;o=(+g[a+32>>2]-+g[a+16>>2])*.5;l=(+g[a+36>>2]-+g[a+20>>2])*.5;i=(+g[a+40>>2]-+g[a+24>>2])*.5;n=+zb[c[(c[a>>2]|0)+48>>2]&15](a);k=+zb[c[(c[a>>2]|0)+48>>2]&15](a);i=i+ +zb[c[(c[a>>2]|0)+48>>2]&15](a);C=(+g[a+32>>2]+ +g[a+16>>2])*.5;z=(+g[a+36>>2]+ +g[a+20>>2])*.5;x=(+g[a+40>>2]+ +g[a+24>>2])*.5;G=+g[b>>2];w=+B(+G);F=+g[b+4>>2];v=+B(+F);t=+g[b+8>>2];u=+B(+t);E=+g[b+16>>2];s=+B(+E);D=+g[b+20>>2];r=+B(+D);p=+g[b+24>>2];q=+B(+p);A=+g[b+32>>2];m=+B(+A);y=+g[b+36>>2];j=+B(+y);f=+g[b+40>>2];h=+B(+f);t=C*G+z*F+x*t+ +g[b+48>>2];p=C*E+z*D+x*p+ +g[b+52>>2];f=C*A+z*y+x*f+ +g[b+56>>2];g[d>>2]=t-((o+n)*w+(l+k)*v+i*u);g[d+4>>2]=p-((o+n)*s+(l+k)*r+i*q);g[d+8>>2]=f-((o+n)*m+(l+k)*j+i*h);g[d+12>>2]=0.0;g[e>>2]=(o+n)*w+(l+k)*v+i*u+t;g[e+4>>2]=(o+n)*s+(l+k)*r+i*q+p;g[e+8>>2]=(o+n)*m+(l+k)*j+i*h+f;g[e+12>>2]=0.0;return}function bh(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0,H=0.0,I=0.0;I=+g[a+48>>2];z=+g[a+32>>2];H=+g[a+52>>2];x=+g[a+36>>2];F=+g[a+56>>2];v=+g[a+40>>2];G=(c[a+16>>2]|0)==0;m=+zb[c[(c[a>>2]|0)+48>>2]&15](a);k=+zb[c[(c[a>>2]|0)+48>>2]&15](a);i=+zb[c[(c[a>>2]|0)+48>>2]&15](a);m=(G?0.0:(I-z)*.5)+m;k=(G?0.0:(H-x)*.5)+k;i=(G?0.0:(F-v)*.5)+i;E=+g[b>>2];u=+B(+E);D=+g[b+4>>2];t=+B(+D);r=+g[b+8>>2];s=+B(+r);C=+g[b+16>>2];q=+B(+C);A=+g[b+20>>2];p=+B(+A);n=+g[b+24>>2];o=+B(+n);y=+g[b+32>>2];l=+B(+y);w=+g[b+36>>2];j=+B(+w);f=+g[b+40>>2];h=+B(+f);z=G?0.0:(I+z)*.5;x=G?0.0:(H+x)*.5;v=G?0.0:(F+v)*.5;r=z*E+x*D+v*r+ +g[b+48>>2];n=z*C+x*A+v*n+ +g[b+52>>2];f=z*y+x*w+v*f+ +g[b+56>>2];g[d>>2]=r-(m*u+k*t+i*s);g[d+4>>2]=n-(m*q+k*p+i*o);g[d+8>>2]=f-(m*l+k*j+i*h);g[d+12>>2]=0.0;g[e>>2]=m*u+k*t+i*s+r;g[e+4>>2]=m*q+k*p+i*o+n;g[e+8>>2]=m*l+k*j+i*h+f;g[e+12>>2]=0.0;return}function ch(a,d,f){a=a|0;d=d|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;h=c[a+68+(d<<2)>>2]|0;m=c[a+60>>2]|0;n=e[h+((f&65535)<<2)+2>>1]|0;g=b[h+((f&65535)+-1<<2)>>1]|0;if((e[h+((f&65535)<<2)>>1]|0)>=(g&65535))return;i=m;j=h+((f&65535)<<2)|0;f=h+((f&65535)+-1<<2)|0;while(1){h=e[f+2>>1]|0;if(!(g&1))g=i+(h<<6)+48+(d<<1)|0;else{if(((((e[m+(n<<6)+54+((1<<d&3)<<1)>>1]|0)>=(e[i+(h<<6)+48+((1<<d&3)<<1)>>1]|0)?(e[i+(h<<6)+54+((1<<d&3)<<1)>>1]|0)>=(e[m+(n<<6)+48+((1<<d&3)<<1)>>1]|0):0)?(e[m+(n<<6)+54+((1<<(1<<d&3)&3)<<1)>>1]|0)>=(e[i+(h<<6)+48+((1<<(1<<d&3)&3)<<1)>>1]|0):0)?(e[i+(h<<6)+54+((1<<(1<<d&3)&3)<<1)>>1]|0)>=(e[m+(n<<6)+48+((1<<(1<<d&3)&3)<<1)>>1]|0):0)?(l=c[a+92>>2]|0,k=i+(h<<6)|0,vb[c[(c[l>>2]|0)+8>>2]&63](l,m+(n<<6)|0,k)|0,l=c[a+96>>2]|0,l|0):0)vb[c[(c[l>>2]|0)+8>>2]&63](l,m+(n<<6)|0,k)|0;g=i+(h<<6)+54+(d<<1)|0}b[g>>1]=(b[g>>1]|0)+1<<16>>16;b[m+(n<<6)+48+(d<<1)>>1]=(b[m+(n<<6)+48+(d<<1)>>1]|0)+-1<<16>>16;h=e[j>>1]|e[j+2>>1]<<16;g=e[f>>1]|e[f+2>>1]<<16;b[j>>1]=g;b[j+2>>1]=g>>>16;b[f>>1]=h;b[f+2>>1]=h>>>16;h=j+-4|0;f=f+-4|0;g=b[f>>1]|0;if((e[h>>1]|0)>=(g&65535))break;i=c[a+60>>2]|0;j=h}return}function dh(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;f=c[a+212>>2]|0;a:do if((f|0)>0){g=c[a+220>>2]|0;d=0;while(1){e=g+(d<<2)|0;if((c[e>>2]|0)==(b|0))break;d=d+1|0;if((d|0)>=(f|0))break a}if((d|0)<(f|0)){c[e>>2]=c[g+(f+-1<<2)>>2];c[(c[a+220>>2]|0)+(f+-1<<2)>>2]=b;c[a+212>>2]=f+-1}}while(0);a=c[b+28>>2]|0;d=c[a+488>>2]|0;b:do if((d|0)>0){g=c[a+496>>2]|0;e=0;while(1){f=g+(e<<2)|0;if((c[f>>2]|0)==(b|0))break;e=e+1|0;if((e|0)>=(d|0))break b}if((e|0)<(d|0)){c[f>>2]=c[g+(d+-1<<2)>>2];c[(c[a+496>>2]|0)+(d+-1<<2)>>2]=b;c[a+488>>2]=d+-1;d=d+-1|0}}while(0);c[a+256>>2]=(d|0)>0&1;a=c[b+32>>2]|0;d=c[a+488>>2]|0;if((d|0)<=0){b=d;b=(b|0)>0;b=b&1;h=a+256|0;c[h>>2]=b;return}g=c[a+496>>2]|0;e=0;while(1){f=g+(e<<2)|0;if((c[f>>2]|0)==(b|0))break;e=e+1|0;if((e|0)>=(d|0)){h=19;break}}if((h|0)==19){b=(d|0)>0;b=b&1;h=a+256|0;c[h>>2]=b;return}if((e|0)>=(d|0)){b=d;b=(b|0)>0;b=b&1;h=a+256|0;c[h>>2]=b;return}c[f>>2]=c[g+(d+-1<<2)>>2];c[(c[a+496>>2]|0)+(d+-1<<2)>>2]=b;c[a+488>>2]=d+-1;b=d+-1|0;b=(b|0)>0;b=b&1;h=a+256|0;c[h>>2]=b;return}function eh(a,b){a=a|0;b=b|0;var c=0.0,d=0.0,e=0.0,f=0,h=0,i=0,j=0;f=l;l=l+16|0;c=+g[(bH(a)|0)>>2];d=+g[(IG(a+16|0)|0)>>2];e=+g[(HG(a+32|0)|0)>>2];if(c+d+e>0.0){e=+PG(c+d+e+1.0);g[f+12>>2]=e*.5;d=+g[(IG(a+32|0)|0)>>2];g[f>>2]=(d-+g[(HG(a+16|0)|0)>>2])*(.5/e);d=+g[(HG(a)|0)>>2];g[f+4>>2]=(d-+g[(bH(a+32|0)|0)>>2])*(.5/e);d=+g[(bH(a+16|0)|0)>>2];g[f+8>>2]=(d-+g[(IG(a)|0)>>2])*(.5/e);j=f;i=f+4|0;h=f+8|0;a=f+12|0;ir(b,j,i,h,a);l=f;return}else{h=(c<d?d:c)<e?2:c<d&1;i=bH(a+(h<<4)|0)|0;e=+g[i+(h<<2)>>2];j=bH(a+((((h+1|0)>>>0)%3|0)<<4)|0)|0;e=e-+g[j+((((h+1|0)>>>0)%3|0)<<2)>>2];a=bH(a+((((h+2|0)>>>0)%3|0)<<4)|0)|0;e=+PG(e-+g[a+((((h+2|0)>>>0)%3|0)<<2)>>2]+1.0);g[f+(h<<2)>>2]=e*.5;g[f+12>>2]=(+g[a+((((h+1|0)>>>0)%3|0)<<2)>>2]-+g[j+((((h+2|0)>>>0)%3|0)<<2)>>2])*(.5/e);g[f+((((h+1|0)>>>0)%3|0)<<2)>>2]=(+g[j+(h<<2)>>2]+ +g[i+((((h+1|0)>>>0)%3|0)<<2)>>2])*(.5/e);g[f+((((h+2|0)>>>0)%3|0)<<2)>>2]=(+g[a+(h<<2)>>2]+ +g[i+((((h+2|0)>>>0)%3|0)<<2)>>2])*(.5/e);a=f;h=f+4|0;i=f+8|0;j=f+12|0;ir(b,a,h,i,j);l=f;return}}function fh(b,d){b=b|0;d=d|0;var e=0,f=0.0,h=0.0,i=0.0,j=0;j=lb[c[(c[b>>2]|0)+28>>2]&127](b)|0;i=+g[j>>2]-+g[d>>2];h=+g[j+4>>2]-+g[d+4>>2];f=+g[j+8>>2]-+g[d+8>>2];if(!(i*i+h*h+f*f>1.1920928955078125e-07))return;Eg(b,d);if((a[b+61>>0]|0)!=0?(e=c[b+52>>2]|0,hb[c[c[e>>2]>>2]&511](e),e=c[b+52>>2]|0,(e|0)!=0):0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0);d=b+52|0}else d=b+52|0;c[6432]=(c[6432]|0)+1;e=ec(191)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}c[e+52>>2]=282;a[e+60>>0]=0;a[e+80>>0]=1;c[e+76>>2]=0;c[e+68>>2]=0;c[e+72>>2]=0;a[e+100>>0]=1;c[e+96>>2]=0;c[e+88>>2]=0;c[e+92>>2]=0;a[e+120>>0]=1;c[e+116>>2]=0;c[e+108>>2]=0;c[e+112>>2]=0;a[e+140>>0]=1;c[e+136>>2]=0;c[e+128>>2]=0;c[e+132>>2]=0;c[e+144>>2]=0;a[e+164>>0]=1;c[e+160>>2]=0;c[e+152>>2]=0;c[e+156>>2]=0;c[e+168>>2]=0;c[e+4>>2]=-8388609;c[e+8>>2]=-8388609;c[e+12>>2]=-8388609;g[e+16>>2]=0.0;c[e+20>>2]=2139095039;c[e+24>>2]=2139095039;c[e+28>>2]=2139095039;g[e+32>>2]=0.0;c[e>>2]=8104;c[d>>2]=e;Xc(e,c[b+48>>2]|0,(a[b+60>>0]|0)!=0,b+16|0,b+32|0);a[b+61>>0]=1;return}function gh(b,d){b=b|0;d=d|0;var e=0.0,f=0.0;if(a[b+1309>>0]|0){e=(+g[b+1256>>2]-+g[b+1316>>2])*+g[b+1340>>2];g[b+792>>2]=e*(+g[d>>2]*+g[b+1364>>2]/+(c[d+48>>2]|0));e=+B(+e);g[b+808>>2]=e/+g[d>>2]}if(a[b+1310>>0]|0){e=(+g[b+1260>>2]-+g[b+1320>>2])*+g[b+1344>>2];g[b+796>>2]=e*(+g[d>>2]*+g[b+1368>>2]/+(c[d+48>>2]|0));e=+B(+e);g[b+812>>2]=e/+g[d>>2]}if(a[b+1311>>0]|0){e=(+g[b+1264>>2]-+g[b+1324>>2])*+g[b+1348>>2];g[b+800>>2]=e*(+g[d>>2]*+g[b+1372>>2]/+(c[d+48>>2]|0));e=+B(+e);g[b+816>>2]=e/+g[d>>2]}if(a[b+1312>>0]|0){f=-((+g[b+1192>>2]-+g[b+1328>>2])*+g[b+1352>>2]);e=+g[d>>2];g[b+876>>2]=e*+g[b+1376>>2]/+(c[d+48>>2]|0)*f;g[b+880>>2]=+B(+f)/e}if(a[b+1313>>0]|0){e=-((+g[b+1196>>2]-+g[b+1332>>2])*+g[b+1356>>2]);f=+g[d>>2];g[b+940>>2]=f*+g[b+1380>>2]/+(c[d+48>>2]|0)*e;g[b+944>>2]=+B(+e)/f}if(!(a[b+1314>>0]|0)){Nf(b,d);return}e=-((+g[b+1200>>2]-+g[b+1336>>2])*+g[b+1360>>2]);f=+g[d>>2];g[b+1004>>2]=f*+g[b+1384>>2]/+(c[d+48>>2]|0)*e;g[b+1008>>2]=+B(+e)/f;Nf(b,d);return}function hh(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0.0,i=0.0,j=0.0;e=l;l=l+160|0;c[e+136>>2]=0;c[e+136+4>>2]=0;c[e+136+8>>2]=0;c[e+136+12>>2]=0;c[e+136+16>>2]=0;c[e+32>>2]=7132;f=e+32+4|0;c[f>>2]=0;c[f+4>>2]=0;c[f+8>>2]=0;c[f+12>>2]=0;c[e+32+20>>2]=1065353216;c[e+32+24>>2]=0;c[e+32+24+4>>2]=0;c[e+32+24+8>>2]=0;c[e+32+24+12>>2]=0;c[e+32+40>>2]=1065353216;c[e+32+44>>2]=0;c[e+32+44+4>>2]=0;c[e+32+44+8>>2]=0;c[e+32+44+12>>2]=0;c[e+32+60>>2]=1065353216;c[e+32+64>>2]=0;c[e+32+68>>2]=c[e+136+4>>2];c[e+32+68+4>>2]=c[e+136+4+4>>2];c[e+32+68+8>>2]=c[e+136+4+8>>2];c[e+32+68+12>>2]=c[e+136+4+12>>2];g[e+32+84>>2]=-999999984306749440.0;j=+g[d>>2];i=+g[d+4>>2];h=+g[d+8>>2];g[e+32+88>>2]=j+i*0.0+h*0.0;g[e+32+92>>2]=j*0.0+i+h*0.0;g[e+32+96>>2]=j*0.0+i*0.0+h;g[e+32+100>>2]=0.0;c[e+16>>2]=1566444395;c[e+16+4>>2]=1566444395;c[e+16+8>>2]=1566444395;g[e+16+12>>2]=0.0;d=c[(c[b>>2]|0)+64>>2]|0;g[e>>2]=-999999984306749440.0;g[e+4>>2]=-999999984306749440.0;g[e+8>>2]=-999999984306749440.0;g[e+12>>2]=0.0;Vb[d&127](b,e+32|0,e,e+16|0);c[a>>2]=c[f>>2];c[a+4>>2]=c[f+4>>2];c[a+8>>2]=c[f+8>>2];c[a+12>>2]=c[f+12>>2];l=e;return}function ih(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0;q=l;l=l+16|0;c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;e=+g[d>>2];f=+g[d+4>>2];h=+g[d+8>>2];if(e*e+f*f+h*h<9.999999747378752e-05){p=1.0;o=0.0;n=0.0}else{n=1.0/+C(+(e*e+f*f+h*h));p=e*n;o=f*n;n=h*n}d=c[b+52>>2]|0;m=+g[b+28+(((d+2|0)%3|0)<<2)>>2];c[q>>2]=0;c[q+4>>2]=0;c[q+8>>2]=0;c[q+12>>2]=0;c[q+(d<<2)>>2]=c[b+28+(d<<2)>>2];j=p*m;k=o*m;m=n*m;f=j+ +g[q>>2];i=k+ +g[q+4>>2];e=m+ +g[q+8>>2];h=+zb[c[(c[b>>2]|0)+48>>2]&15](b);f=f-p*h;i=i-o*h;h=e-n*h;e=n*h+(p*f+o*i);if(e>-999999984306749440.0){g[a>>2]=f;g[a+4>>2]=i;g[a+8>>2]=h;g[a+12>>2]=0.0;i=e}else i=-999999984306749440.0;c[q>>2]=0;c[q+4>>2]=0;c[q+8>>2]=0;c[q+12>>2]=0;d=c[b+52>>2]|0;g[q+(d<<2)>>2]=-+g[b+28+(d<<2)>>2];e=j+ +g[q>>2];h=k+ +g[q+4>>2];m=m+ +g[q+8>>2];f=+zb[c[(c[b>>2]|0)+48>>2]&15](b);e=e-p*f;h=h-o*f;f=m-n*f;if(!(n*f+(p*e+o*h)>i)){l=q;return}g[a>>2]=e;g[a+4>>2]=h;g[a+8>>2]=f;g[a+12>>2]=0.0;l=q;return}function jh(a,b,d,e,f,h,i,j,k,m){a=a|0;b=b|0;d=d|0;e=e|0;f=+f;h=+h;i=+i;j=+j;k=+k;m=+m;var n=0;n=l;l=l+128|0;c[n+80>>2]=c[a+4>>2];c[n+80+4>>2]=c[a+20>>2];c[n+80+8>>2]=c[a+36>>2];g[n+80+12>>2]=0.0;c[n+80+16>>2]=c[a+8>>2];c[n+80+20>>2]=c[a+24>>2];c[n+80+24>>2]=c[a+40>>2];g[n+80+28>>2]=0.0;c[n+80+32>>2]=c[a+12>>2];c[n+80+36>>2]=c[a+28>>2];c[n+80+40>>2]=c[a+44>>2];g[n+80+44>>2]=0.0;c[n+32>>2]=c[b+4>>2];c[n+32+4>>2]=c[b+20>>2];c[n+32+8>>2]=c[b+36>>2];g[n+32+12>>2]=0.0;c[n+32+16>>2]=c[b+8>>2];c[n+32+20>>2]=c[b+24>>2];c[n+32+24>>2]=c[b+40>>2];g[n+32+28>>2]=0.0;c[n+32+32>>2]=c[b+12>>2];c[n+32+36>>2]=c[b+28>>2];c[n+32+40>>2]=c[b+44>>2];g[n+32+44>>2]=0.0;h=h-+g[a+56>>2];i=i-+g[a+60>>2];g[n+16>>2]=f-+g[a+52>>2];g[n+16+4>>2]=h;g[n+16+8>>2]=i;g[n+16+12>>2]=0.0;k=k-+g[b+56>>2];m=m-+g[b+60>>2];g[n>>2]=j-+g[b+52>>2];g[n+4>>2]=k;g[n+8>>2]=m;g[n+12>>2]=0.0;ug(d,n+80|0,n+32|0,n+16|0,n,e,a+396|0,+g[a+344>>2],b+396|0,+g[b+344>>2]);l=n;return}function kh(b,d){b=b|0;d=d|0;var e=0.0,f=0,h=0.0,i=0.0,k=0,l=0.0,m=0.0;if(a[b+48>>0]|0){c[d>>2]=0;c[d+4>>2]=0;return}c[d>>2]=4;c[d+4>>2]=2;Qc(b,(c[b+28>>2]|0)+4|0,(c[b+32>>2]|0)+4|0);g[b+1088>>2]=0.0;a[b+297>>0]=0;e=+g[b+192>>2];h=+g[b+196>>2];do if(!(e<=h))k=0;else{m=+g[b+892>>2];l=+g[b+908>>2];i=+g[b+924>>2];i=+Hj(+K(+(+g[b+832>>2]*m+ +g[b+848>>2]*l+ +g[b+864>>2]*i),+(+g[b+828>>2]*m+ +g[b+844>>2]*l+ +g[b+860>>2]*i)),e,h);g[b+1084>>2]=i;if(!(i<e))if(i>h)e=h;else{k=0;break}g[b+1088>>2]=i-e;a[b+297>>0]=1;k=1}while(0);a[b+296>>0]=0;f=c[b+1032>>2]|0;c[b+1080>>2]=f;e=+g[b+184>>2];h=+g[b+188>>2];i=(c[j>>2]=f,+g[j>>2]);do if(!(e<=h))f=10;else{if(!(i>h)){if(!(i<e)){f=10;break}}else e=h;g[b+1032>>2]=i-e;a[b+296>>0]=1;f=12}while(0);if((f|0)==10?(g[b+1032>>2]=0.0,a[b+1096>>0]|0):0)f=12;if((f|0)==12){c[d>>2]=(c[d>>2]|0)+1;c[d+4>>2]=(c[d+4>>2]|0)+-1}if(k<<24>>24==0?(a[b+1112>>0]|0)==0:0)return;c[d>>2]=(c[d>>2]|0)+1;c[d+4>>2]=(c[d+4>>2]|0)+-1;return}function lh(a,b,c,d,e,f,h,i,j,k,l,m,n,o){a=a|0;b=+b;c=+c;d=+d;e=+e;f=+f;h=+h;i=+i;j=+j;k=+k;l=+l;m=+m;n=+n;o=+o;var p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0;q=(j-f)*(n-h)-(k-h)*(m-f);r=(k-h)*(l-e)-(i-e)*(n-h);s=(i-e)*(m-f)-(j-f)*(l-e);if(+B(+(s*d+(q*b+r*c)))<1.1920928955078125e-07){s=-1.0;return +s}t=+g[a>>2];v=+g[a+4>>2];u=+g[a+8>>2];p=-(q*t+r*v+s*u-(s*h+(q*e+r*f)))/(s*d+(q*b+r*c));if(((p>1.1920928955078125e-06&p<o?s*((j-(v+p*c))*(e-(t+p*b))-(f-(v+p*c))*(i-(t+p*b)))+(q*((f-(v+p*c))*(k-(u+p*d))-(h-(u+p*d))*(j-(v+p*c)))+r*((h-(u+p*d))*(i-(t+p*b))-(k-(u+p*d))*(e-(t+p*b))))>-1.1920928955078125e-06:0)?s*((m-(v+p*c))*(i-(t+p*b))-(j-(v+p*c))*(l-(t+p*b)))+(q*((j-(v+p*c))*(n-(u+p*d))-(k-(u+p*d))*(m-(v+p*c)))+r*((k-(u+p*d))*(l-(t+p*b))-(n-(u+p*d))*(i-(t+p*b))))>-1.1920928955078125e-06:0)?s*((f-(v+p*c))*(l-(t+p*b))-(m-(v+p*c))*(e-(t+p*b)))+(q*((m-(v+p*c))*(h-(u+p*d))-(n-(u+p*d))*(f-(v+p*c)))+r*((n-(u+p*d))*(e-(t+p*b))-(h-(u+p*d))*(l-(t+p*b))))>-1.1920928955078125e-06:0){v=p;return +v}v=-1.0;return +v}function mh(a,b,d,e,f){a=a|0;b=+b;d=+d;e=+e;f=f|0;var h=0,i=0,j=0,k=0,m=0.0,n=0.0;j=l;l=l+48|0;m=1.0/+C(+(b*b+d*d+e*e));g[f>>2]=m*b;g[f+4>>2]=m*d;g[f+8>>2]=m*e;g[f+12>>2]=0.0;h=c[a+120>>2]|0;k=c[a+124>>2]|0;i=(c[a>>2]|0)+(k>>1)|0;if(k&1)h=c[(c[i>>2]|0)+h>>2]|0;Rb[h&127](j,i,f);b=-+g[f>>2];d=-+g[f+4>>2];e=-+g[f+8>>2];h=c[a+120>>2]|0;k=c[a+124>>2]|0;i=(c[a+4>>2]|0)+(k>>1)|0;if(k&1)h=c[(c[i>>2]|0)+h>>2]|0;m=+g[a+24>>2]*b+ +g[a+28>>2]*d+ +g[a+32>>2]*e;n=+g[a+40>>2]*b+ +g[a+44>>2]*d+ +g[a+48>>2]*e;g[j+16>>2]=+g[a+8>>2]*b+ +g[a+12>>2]*d+ +g[a+16>>2]*e;g[j+16+4>>2]=m;g[j+16+8>>2]=n;g[j+16+12>>2]=0.0;Rb[h&127](j+32|0,i,j+16|0);n=+g[j+32>>2];b=+g[j+32+4>>2];d=+g[j+32+8>>2];e=+g[j+4>>2]-(n*+g[a+72>>2]+b*+g[a+76>>2]+d*+g[a+80>>2]+ +g[a+108>>2]);m=+g[j+8>>2]-(n*+g[a+88>>2]+b*+g[a+92>>2]+d*+g[a+96>>2]+ +g[a+112>>2]);g[f+16>>2]=+g[j>>2]-(n*+g[a+56>>2]+b*+g[a+60>>2]+d*+g[a+64>>2]+ +g[a+104>>2]);g[f+20>>2]=e;g[f+24>>2]=m;g[f+28>>2]=0.0;l=j;return}function nh(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;if(a[b+165>>0]|0){if((c[b+92>>2]|0)>=(d|0))return;if((d|0)!=0?(c[6432]=(c[6432]|0)+1,f=ec((d<<4|3)+16|0)|0,(f|0)!=0):0){c[(f+4+15&-16)+-4>>2]=f;g=f+4+15&-16}else g=0;e=c[b+88>>2]|0;if((e|0)>0){f=0;do{i=g+(f<<4)|0;h=(c[b+96>>2]|0)+(f<<4)|0;c[i>>2]=c[h>>2];c[i+4>>2]=c[h+4>>2];c[i+8>>2]=c[h+8>>2];c[i+12>>2]=c[h+12>>2];f=f+1|0}while((f|0)!=(e|0))}e=c[b+96>>2]|0;if(e|0){if(a[b+100>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}c[b+96>>2]=0}a[b+100>>0]=1;c[b+96>>2]=g;c[b+92>>2]=d;return}if((c[b+112>>2]|0)>=(d|0))return;if((d|0)!=0?(c[6432]=(c[6432]|0)+1,e=ec((d<<2|3)+16|0)|0,(e|0)!=0):0){c[(e+4+15&-16)+-4>>2]=e;h=e+4+15&-16}else h=0;f=c[b+108>>2]|0;g=c[b+116>>2]|0;if((f|0)<=0)if(!g)e=b+120|0;else i=21;else{e=0;do{c[h+(e<<2)>>2]=c[g+(e<<2)>>2];e=e+1|0}while((e|0)!=(f|0));i=21}if((i|0)==21){if(a[b+120>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[g+-4>>2]|0)}c[b+116>>2]=0;e=b+120|0}a[e>>0]=1;c[b+116>>2]=h;c[b+112>>2]=d;return}function oh(a,b,d,e,f,g,h,i,j){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;if(!(c[i+44>>2]|0))return;b=c[i+20>>2]|0;if(!(c[i+64>>2]&256)){if((b|0)<=0)return;j=0;do{g=c[a+28>>2]|0;if((g|0)>0){b=0;do{f=c[(c[a+116>>2]|0)+(b<<2)>>2]|0;h=c[a+36>>2]|0;d=c[a+16>>2]|0;lg(d+((c[h+(f*152|0)+144>>2]|0)*244|0)|0,d+((c[h+(f*152|0)+148>>2]|0)*244|0)|0,h+(f*152|0)|0);b=b+1|0}while((b|0)!=(g|0));b=c[i+20>>2]|0}j=j+1|0}while((j|0)<(b|0));return}else{if((b|0)<=0)return;j=0;do{g=c[a+28>>2]|0;if((g|0)>0){b=0;do{f=c[(c[a+116>>2]|0)+(b<<2)>>2]|0;h=c[a+36>>2]|0;d=c[a+16>>2]|0;lg(d+((c[h+(f*152|0)+144>>2]|0)*244|0)|0,d+((c[h+(f*152|0)+148>>2]|0)*244|0)|0,h+(f*152|0)|0);b=b+1|0}while((b|0)!=(g|0));b=c[i+20>>2]|0}j=j+1|0}while((j|0)<(b|0));return}}function ph(d,e){d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0;if(!(a[d+164>>0]|0)){if((c[d+152>>2]|0)>=(e|0))return;if((e|0)!=0?(c[6432]=(c[6432]|0)+1,f=ec((e<<1)+19|0)|0,(f|0)!=0):0){c[(f+4+15&-16)+-4>>2]=f;i=f+4+15&-16}else i=0;g=c[d+148>>2]|0;h=c[d+156>>2]|0;if((g|0)<=0)if(!h)f=d+160|0;else j=22;else{f=0;do{b[i+(f<<1)>>1]=b[h+(f<<1)>>1]|0;f=f+1|0}while((f|0)!=(g|0));j=22}if((j|0)==22){if(a[d+160>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[d+156>>2]=0;f=d+160|0}a[f>>0]=1;c[d+156>>2]=i;c[d+152>>2]=e;return}else{if((c[d+132>>2]|0)>=(e|0))return;if((e|0)!=0?(c[6432]=(c[6432]|0)+1,g=ec((e<<2|3)+16|0)|0,(g|0)!=0):0){c[(g+4+15&-16)+-4>>2]=g;i=g+4+15&-16}else i=0;g=c[d+128>>2]|0;h=c[d+136>>2]|0;if((g|0)<=0)if(!h)f=d+140|0;else j=10;else{f=0;do{c[i+(f<<2)>>2]=c[h+(f<<2)>>2];f=f+1|0}while((f|0)!=(g|0));j=10}if((j|0)==10){if(a[d+140>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[d+136>>2]=0;f=d+140|0}a[f>>0]=1;c[d+136>>2]=i;c[d+132>>2]=e;return}}function qh(a,b,d){a=a|0;b=b|0;d=d|0;Sh(a,b,d)|0;c[b+52>>2]=c[a+300>>2];c[b+56>>2]=c[a+304>>2];c[b+60>>2]=c[a+308>>2];c[b+64>>2]=c[a+312>>2];c[b+68>>2]=c[a+316>>2];c[b+72>>2]=c[a+320>>2];c[b+76>>2]=c[a+324>>2];c[b+80>>2]=c[a+328>>2];c[b+84>>2]=c[a+332>>2];c[b+88>>2]=c[a+336>>2];c[b+92>>2]=c[a+340>>2];c[b+96>>2]=c[a+344>>2];c[b+100>>2]=c[a+348>>2];c[b+104>>2]=c[a+352>>2];c[b+108>>2]=c[a+356>>2];c[b+112>>2]=c[a+360>>2];c[b+116>>2]=c[a+364>>2];c[b+120>>2]=c[a+368>>2];c[b+124>>2]=c[a+372>>2];c[b+128>>2]=c[a+376>>2];c[b+132>>2]=c[a+380>>2];c[b+136>>2]=c[a+384>>2];c[b+140>>2]=c[a+388>>2];c[b+144>>2]=c[a+392>>2];c[b+148>>2]=c[a+396>>2];c[b+152>>2]=c[a+400>>2];c[b+156>>2]=c[a+404>>2];c[b+160>>2]=c[a+408>>2];c[b+164>>2]=c[a+412>>2];c[b+168>>2]=c[a+416>>2];c[b+172>>2]=c[a+420>>2];c[b+176>>2]=c[a+424>>2];c[b+180>>2]=c[a+444>>2];c[b+184>>2]=c[a+448>>2];c[b+188>>2]=c[a+452>>2];c[b+192>>2]=c[a+428>>2];c[b+196>>2]=c[a+432>>2];c[b+200>>2]=c[a+436>>2];c[b+204>>2]=c[a+440>>2];return 12847}function rh(a,b,d){a=a|0;b=b|0;d=+d;var e=0,f=0.0,h=0.0,i=0.0,j=0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0;j=l;l=l+32|0;n=+g[a+56>>2];r=+g[a+72>>2]-n;m=+g[a+60>>2];p=+g[a+76>>2]-m;k=+g[a+64>>2];s=+g[a+80>>2]-k;o=+g[a+88>>2]-n;q=+g[a+92>>2]-m;h=+g[a+96>>2]-k;i=1.0/+C(+((r*q-p*o)*(r*q-p*o)+((p*h-s*q)*(p*h-s*q)+(s*o-r*h)*(s*o-r*h))));f=i*(p*h-s*q);h=i*(s*o-r*h);i=(r*q-p*o)*i;k=i*+g[b+8>>2]+(+g[b>>2]*f+ +g[b+4>>2]*h)-(f*n+h*m+i*k);if(!(k>=-d)|!(k<=d)){a=0;l=j;return a|0}e=0;while(1){Vb[c[(c[a>>2]|0)+104>>2]&127](a,e,j+16|0,j);n=+g[j+16>>2];s=+g[j>>2]-n;p=+g[j+16+4>>2];o=+g[j+4>>2]-p;m=+g[j+16+8>>2];r=+g[j+8>>2]-m;q=1.0/+C(+((h*s-f*o)*(h*s-f*o)+((i*o-h*r)*(i*o-h*r)+(f*r-i*s)*(f*r-i*s))));e=e+1|0;if((h*s-f*o)*q*+g[b+8>>2]+(+g[b>>2]*q*(i*o-h*r)+ +g[b+4>>2]*q*(f*r-i*s))-(m*(h*s-f*o)*q+(n*q*(i*o-h*r)+p*q*(f*r-i*s)))<-d){e=0;b=5;break}if((e|0)>=3){e=1;b=5;break}}if((b|0)==5){l=j;return e|0}return 0}function sh(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0,i=0,j=0;c[6432]=(c[6432]|0)+1;h=ec(55)|0;if(!h)j=0;else{c[(h+4+15&-16)+-4>>2]=h;j=h+4+15&-16}c[j>>2]=d;c[j+4>>2]=e;c[j+8>>2]=f;c[j+12>>2]=-1;c[j+16>>2]=-1;c[j+20>>2]=-1;c[j+28>>2]=-1;g[j+32>>2]=0.0;f=j;h=c[b+4>>2]|0;c[j+24>>2]=h;if((h|0)!=(c[b+8>>2]|0)){i=h;e=b+12|0;e=c[e>>2]|0;e=e+(i<<2)|0;c[e>>2]=f;i=i+1|0;c[b+4>>2]=i;return j|0}i=h|0?h<<1:1;if((h|0)>=(i|0)){i=h;e=b+12|0;e=c[e>>2]|0;e=e+(i<<2)|0;c[e>>2]=f;i=i+1|0;c[b+4>>2]=i;return j|0}if(!i)d=0;else{c[6432]=(c[6432]|0)+1;h=ec((i<<2|3)+16|0)|0;if(!h)d=0;else{c[(h+4+15&-16)+-4>>2]=h;d=h+4+15&-16}h=c[b+4>>2]|0}if((h|0)>0){e=0;do{c[d+(e<<2)>>2]=c[(c[b+12>>2]|0)+(e<<2)>>2];e=e+1|0}while((e|0)!=(h|0))}e=c[b+12>>2]|0;if(e){if(a[b+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0);h=c[b+4>>2]|0}c[b+12>>2]=0}a[b+16>>0]=1;c[b+12>>2]=d;c[b+8>>2]=i;i=h;e=b+12|0;e=c[e>>2]|0;e=e+(i<<2)|0;c[e>>2]=f;i=i+1|0;c[b+4>>2]=i;return j|0}function th(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,C=0.0,D=0.0,E=0.0,F=0.0;o=+zb[c[(c[a>>2]|0)+48>>2]&15](a);u=+g[a+72>>2];t=+g[a+56>>2];r=+g[a+76>>2];q=+g[a+60>>2];n=+g[a+80>>2];m=+g[a+64>>2];F=+g[b>>2];y=+B(+F);E=+g[b+4>>2];x=+B(+E);k=+g[b+8>>2];l=+B(+k);D=+g[b+16>>2];w=+B(+D);C=+g[b+20>>2];v=+B(+C);i=+g[b+24>>2];j=+B(+i);A=+g[b+32>>2];s=+B(+A);z=+g[b+36>>2];p=+B(+z);f=+g[b+40>>2];h=+B(+f);k=(u+t)*.5*F+(r+q)*.5*E+(n+m)*.5*k+ +g[b+48>>2];i=(u+t)*.5*D+(r+q)*.5*C+(n+m)*.5*i+ +g[b+52>>2];f=(u+t)*.5*A+(r+q)*.5*z+(n+m)*.5*f+ +g[b+56>>2];l=(o+(u-t)*.5)*y+(o+(r-q)*.5)*x+(o+(n-m)*.5)*l;j=(o+(u-t)*.5)*w+(o+(r-q)*.5)*v+(o+(n-m)*.5)*j;h=(o+(u-t)*.5)*s+(o+(r-q)*.5)*p+(o+(n-m)*.5)*h;g[d>>2]=k-l;g[d+4>>2]=i-j;g[d+8>>2]=f-h;g[d+12>>2]=0.0;g[e>>2]=l+k;g[e+4>>2]=j+i;g[e+8>>2]=h+f;g[e+12>>2]=0.0;return}function uh(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0.0,i=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0,z=0;f=l;l=l+16|0;y=c[a+52>>2]|0;z=c[a+28+(((y+2|0)%3|0)<<2)>>2]|0;c[f>>2]=z;c[f+4>>2]=z;c[f+8>>2]=z;g[f+12>>2]=0.0;g[f+(y<<2)>>2]=(c[j>>2]=z,+g[j>>2])+ +g[a+28+(y<<2)>>2];k=+zb[c[(c[a>>2]|0)+48>>2]&15](a);h=+zb[c[(c[a>>2]|0)+48>>2]&15](a);o=+zb[c[(c[a>>2]|0)+48>>2]&15](a);k=k+ +g[f>>2];g[f>>2]=k;h=h+ +g[f+4>>2];g[f+4>>2]=h;o=o+ +g[f+8>>2];v=+B(+(+g[b>>2]));u=+B(+(+g[b+4>>2]));w=+B(+(+g[b+8>>2]));r=+B(+(+g[b+16>>2]));q=+B(+(+g[b+20>>2]));s=+B(+(+g[b+24>>2]));m=+B(+(+g[b+32>>2]));i=+B(+(+g[b+36>>2]));n=+B(+(+g[b+40>>2]));x=+g[b+48>>2];t=+g[b+52>>2];p=+g[b+56>>2];g[d>>2]=x-(o*w+(v*k+u*h));g[d+4>>2]=t-(o*s+(r*k+q*h));g[d+8>>2]=p-(o*n+(m*k+i*h));g[d+12>>2]=0.0;g[e>>2]=x+(o*w+(v*k+u*h));g[e+4>>2]=t+(o*s+(r*k+q*h));g[e+8>>2]=p+(o*n+(m*k+i*h));g[e+12>>2]=0.0;l=f;return}function vh(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0;if(a[d+32>>0]&1){f=c[b+4>>2]|0;if(f|0)Vk(f,d,e);f=c[b>>2]|0;if(f|0){n=+g[d>>2];l=+g[f+128>>2];m=+g[d+4>>2];k=+g[d+8>>2];h=+g[e+4>>2];p=+g[e+8>>2];o=+g[e>>2];j=+g[f+180>>2]*(k*h-m*p)+ +g[f+184>>2]*(n*p-k*o)+(m*o-n*h)*+g[f+188>>2];i=(k*h-m*p)*+g[f+196>>2]+(n*p-k*o)*+g[f+200>>2]+(m*o-n*h)*+g[f+204>>2];h=(k*h-m*p)*+g[f+212>>2]+(n*p-k*o)*+g[f+216>>2]+(m*o-n*h)*+g[f+220>>2];g[f+244>>2]=n*l+ +g[f+244>>2];g[f+248>>2]=l*m+ +g[f+248>>2];g[f+252>>2]=l*k+ +g[f+252>>2];g[f+316>>2]=n*l+ +g[f+316>>2];g[f+320>>2]=l*m+ +g[f+320>>2];g[f+324>>2]=l*k+ +g[f+324>>2];g[f+260>>2]=j+ +g[f+260>>2];g[f+264>>2]=i+ +g[f+264>>2];g[f+268>>2]=h+ +g[f+268>>2];g[f+332>>2]=j+ +g[f+332>>2];g[f+336>>2]=i+ +g[f+336>>2];g[f+340>>2]=h+ +g[f+340>>2];c[f+308>>2]=(c[f+308>>2]|0)+1}}if(!(a[d+32>>0]&2))return;Ki(b,d+16|0,e);return}function wh(a){a=a|0;var b=0,d=0,e=0,f=0;d=l;l=l+16|0;Yi(14420);hb[c[(c[a>>2]|0)+8>>2]&511](a);hb[c[(c[a>>2]|0)+12>>2]&511](a);b=c[a+24>>2]|0;Yi(14454);if(b|0){f=c[(c[b>>2]|0)+32>>2]|0;e=c[a+68>>2]|0;e=lb[c[(c[e>>2]|0)+36>>2]&127](e)|0;Vb[f&127](b,e,a+28|0,c[a+24>>2]|0)}a=c[2395]|0;f=(c[a+16>>2]|0)+-1|0;c[a+16>>2]=f;do if(!f){if(c[a+4>>2]|0){Va(d|0,0)|0;b=c[6431]|0;g[a+8>>2]=+g[a+8>>2]+ +(((c[d+4>>2]|0)-(c[b+4>>2]|0)+(((c[d>>2]|0)-(c[b>>2]|0)|0)*1e6|0)-(c[a+12>>2]|0)|0)>>>0)/1.0e3;b=c[2395]|0;if(c[a+16>>2]|0)break}else b=a;b=c[b+20>>2]|0;c[2395]=b}else b=a;while(0);a=b+16|0;f=(c[a>>2]|0)+-1|0;c[a>>2]=f;if(f|0){l=d;return}do if(c[b+4>>2]|0){Va(d|0,0)|0;e=c[6431]|0;f=b+8|0;g[f>>2]=+g[f>>2]+ +(((c[d+4>>2]|0)-(c[e+4>>2]|0)+(((c[d>>2]|0)-(c[e>>2]|0)|0)*1e6|0)-(c[b+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[a>>2]|0)){b=c[2395]|0;break}else{l=d;return}}while(0);c[2395]=c[b+20>>2];l=d;return}function xh(b,d){b=b|0;d=d|0;var e=0;c[b>>2]=8964;a[b+40>>0]=1;c[b+36>>2]=0;c[b+28>>2]=0;c[b+32>>2]=0;a[b+60>>0]=1;c[b+56>>2]=0;c[b+48>>2]=0;c[b+52>>2]=0;c[b+4>>2]=0;c[b+8>>2]=0;c[b+12>>2]=-1;c[b+16>>2]=0;c[b+20>>2]=0;a[b+100>>0]=1;c[b+96>>2]=0;c[b+88>>2]=0;c[b+92>>2]=0;a[b+120>>0]=1;c[b+116>>2]=0;c[b+108>>2]=0;c[b+112>>2]=0;c[b+64>>2]=0;c[b+68>>2]=0;c[b+72>>2]=-1;c[b+76>>2]=0;c[b+80>>2]=0;a[b+193>>0]=0;a[b+194>>0]=1;a[b+192>>0]=((d|0)!=0^1)&1;g[b+140>>2]=0.0;c[b+144>>2]=0;c[b+164>>2]=0;c[b+148>>2]=1;c[b+152>>2]=0;c[b+156>>2]=10;c[b+160>>2]=1;c[b+168>>2]=0;c[b+172>>2]=0;g[b+176>>2]=0.0;if(d|0){e=d;d=b+136|0;c[d>>2]=e;d=b+188|0;c[d>>2]=0;d=b+180|0;c[d>>2]=0;d=b+184|0;c[d>>2]=0;b=b+124|0;c[b>>2]=0;c[b+4>>2]=0;c[b+8>>2]=0;return}c[6432]=(c[6432]|0)+1;d=ec(95)|0;if(!d)d=0;else{c[(d+4+15&-16)+-4>>2]=d;d=d+4+15&-16}ki(d);e=b+136|0;c[e>>2]=d;e=b+188|0;c[e>>2]=0;e=b+180|0;c[e>>2]=0;e=b+184|0;c[e>>2]=0;e=b+124|0;c[e>>2]=0;c[e+4>>2]=0;c[e+8>>2]=0;return}function yh(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0,j=0.0,k=0.0;i=c[b>>2]|0;if((i|0)==(c[a+80>>2]|0)){k=1.0;return +k}if(c[i+204>>2]&4|0){k=1.0;return +k}f=+g[b+8>>2];h=+g[b+12>>2];e=+g[b+16>>2];if(d){j=f;k=h}else{j=+g[i+4>>2]*f+ +g[i+8>>2]*h+ +g[i+12>>2]*e;k=f*+g[i+20>>2]+h*+g[i+24>>2]+e*+g[i+28>>2];e=f*+g[i+36>>2]+h*+g[i+40>>2]+e*+g[i+44>>2]}if(j*+g[a+84>>2]+k*+g[a+88>>2]+e*+g[a+92>>2]<+g[a+100>>2]){k=1.0;return +k}c[a+4>>2]=c[b+40>>2];c[a+76>>2]=i;if(d){c[a+44>>2]=c[b+8>>2];c[a+44+4>>2]=c[b+8+4>>2];c[a+44+8>>2]=c[b+8+8>>2];c[a+44+12>>2]=c[b+8+12>>2]}else{e=+g[b+8>>2];f=+g[b+12>>2];h=+g[b+16>>2];j=e*+g[i+20>>2]+f*+g[i+24>>2]+h*+g[i+28>>2];k=e*+g[i+36>>2]+f*+g[i+40>>2]+h*+g[i+44>>2];g[a+44>>2]=+g[i+4>>2]*e+ +g[i+8>>2]*f+ +g[i+12>>2]*h;g[a+48>>2]=j;g[a+52>>2]=k;g[a+56>>2]=0.0}c[a+60>>2]=c[b+24>>2];c[a+60+4>>2]=c[b+24+4>>2];c[a+60+8>>2]=c[b+24+8>>2];c[a+60+12>>2]=c[b+24+12>>2];k=+g[b+40>>2];return +k}function zh(b){b=b|0;var d=0,e=0,f=0,g=0,h=0;d=c[b+16>>2]|0;if(d|0){if(a[b+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+16>>2]=0}a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;c[b+12>>2]=0;d=c[b+40>>2]|0;if(d|0){if(a[b+44>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+40>>2]=0}a[b+44>>0]=1;c[b+40>>2]=0;c[b+32>>2]=0;c[b+36>>2]=0;d=c[b+60>>2]|0;if(d|0){if(a[b+64>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+60>>2]=0}a[b+64>>0]=1;c[b+60>>2]=0;c[b+52>>2]=0;c[b+56>>2]=0;if((c[b+12>>2]|0)>=2){uf(b);return}c[6432]=(c[6432]|0)+1;d=ec(43)|0;if(!d)f=0;else{c[(d+4+15&-16)+-4>>2]=d;f=d+4+15&-16}d=c[b+8>>2]|0;if((d|0)>0){e=0;do{g=f+(e*12|0)|0;h=(c[b+16>>2]|0)+(e*12|0)|0;c[g>>2]=c[h>>2];c[g+4>>2]=c[h+4>>2];c[g+8>>2]=c[h+8>>2];e=e+1|0}while((e|0)!=(d|0))}d=c[b+16>>2]|0;if(d|0){if(a[b+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+16>>2]=0}a[b+20>>0]=1;c[b+16>>2]=f;c[b+12>>2]=2;uf(b);return}function Ah(a,b,e){a=a|0;b=b|0;e=e|0;Sh(a,b,e)|0;c[b+52>>2]=c[a+52>>2];c[b+56>>2]=c[a+56>>2];c[b+60>>2]=c[a+60>>2];c[b+64>>2]=c[a+64>>2];c[b+68>>2]=c[a+68>>2];c[b+72>>2]=c[a+72>>2];c[b+76>>2]=c[a+76>>2];c[b+80>>2]=c[a+80>>2];c[b+84>>2]=c[a+84>>2];c[b+88>>2]=c[a+88>>2];c[b+92>>2]=c[a+92>>2];c[b+96>>2]=c[a+96>>2];c[b+100>>2]=c[a+100>>2];c[b+104>>2]=c[a+104>>2];c[b+108>>2]=c[a+108>>2];c[b+112>>2]=c[a+112>>2];c[b+116>>2]=c[a+116>>2];c[b+120>>2]=c[a+120>>2];c[b+124>>2]=c[a+124>>2];c[b+128>>2]=c[a+128>>2];c[b+132>>2]=c[a+132>>2];c[b+136>>2]=c[a+136>>2];c[b+140>>2]=c[a+140>>2];c[b+144>>2]=c[a+144>>2];c[b+148>>2]=c[a+148>>2];c[b+152>>2]=c[a+152>>2];c[b+156>>2]=c[a+156>>2];c[b+160>>2]=c[a+160>>2];c[b+164>>2]=c[a+164>>2];c[b+168>>2]=c[a+168>>2];c[b+172>>2]=c[a+172>>2];c[b+176>>2]=c[a+176>>2];c[b+180>>2]=c[a+188>>2];c[b+184>>2]=c[a+184>>2];c[b+188>>2]=c[a+196>>2];c[b+192>>2]=c[a+192>>2];c[b+196>>2]=d[a+180>>0];c[b+200>>2]=d[a+49>>0];return 12803}function Bh(b,d,e,f,h,i){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;var j=0,k=0,l=0.0,m=0.0,n=0.0,o=0.0;c[6432]=(c[6432]|0)+1;b=ec((h+2|0)>>>0>268435455?18:(h+2<<4|3)+16|0)|0;if(!b)k=0;else{c[(b+4+15&-16)+-4>>2]=b;k=b+4+15&-16}j=UG((h+2|0)>>>0>1073741823?-1:h+2<<2)|0;if((h|0)>-2){b=0;do{o=+(b|0)/+(h+1|0);n=+g[e>>2];m=+g[e+4>>2];m=m+o*(+g[f+4>>2]-m);l=+g[e+8>>2];l=l+o*(+g[f+8>>2]-l);g[k+(b<<4)>>2]=n+o*(+g[f>>2]-n);g[k+(b<<4)+4>>2]=m;g[k+(b<<4)+8>>2]=l;g[k+(b<<4)+12>>2]=0.0;g[j+(b<<2)>>2]=1.0;b=b+1|0}while((b|0)<(h+2|0))}c[6432]=(c[6432]|0)+1;b=ec(1271)|0;if(!b)e=0;else{c[(b+4+15&-16)+-4>>2]=b;e=b+4+15&-16}oc(e,d,h+2|0,k,j);if(i&1|0){g[(c[e+720>>2]|0)+88>>2]=0.0;a[e+924>>0]=1}if(i&2|0){g[(c[e+720>>2]|0)+((h+1|0)*104|0)+88>>2]=0.0;a[e+924>>0]=1}if(k|0){c[6433]=(c[6433]|0)+1;Pc(c[k+-4>>2]|0)}VG(j);if((h+2|0)>1)b=1;else return e|0;do{Df(e,b+-1|0,b,0,0);b=b+1|0}while((b|0)!=(h+2|0));return e|0}function Ch(a,b,c,d,e,f){a=a|0;b=+b;c=c|0;d=+d;e=+e;f=+f;var h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0;p=+g[c>>2];o=+g[c+16>>2];n=+g[c+32>>2];m=+g[c+4>>2];l=+g[c+20>>2];k=+g[c+36>>2];j=+g[c+8>>2];i=+g[c+24>>2];h=+g[c+40>>2];g[a>>2]=b-((p*0.0+o*-f+n*e)*0.0+(m*0.0+l*-f+k*e)*f+(j*0.0+i*-f+h*e)*-e);g[a+4>>2]=0.0-((p*0.0+o*-f+n*e)*-f+(m*0.0+l*-f+k*e)*0.0+(j*0.0+i*-f+h*e)*d);g[a+8>>2]=0.0-((p*0.0+o*-f+n*e)*e+(m*0.0+l*-f+k*e)*-d+(j*0.0+i*-f+h*e)*0.0);g[a+12>>2]=0.0;g[a+16>>2]=0.0-((p*f+o*0.0+n*-d)*0.0+(m*f+l*0.0+k*-d)*f+(j*f+i*0.0+h*-d)*-e);g[a+20>>2]=b-((p*f+o*0.0+n*-d)*-f+(m*f+l*0.0+k*-d)*0.0+(j*f+i*0.0+h*-d)*d);g[a+24>>2]=0.0-((p*f+o*0.0+n*-d)*e+(m*f+l*0.0+k*-d)*-d+(j*f+i*0.0+h*-d)*0.0);g[a+28>>2]=0.0;g[a+32>>2]=0.0-((p*-e+o*d+n*0.0)*0.0+(m*-e+l*d+k*0.0)*f+(j*-e+i*d+h*0.0)*-e);g[a+36>>2]=0.0-((p*-e+o*d+n*0.0)*-f+(m*-e+l*d+k*0.0)*0.0+(j*-e+i*d+h*0.0)*d);g[a+40>>2]=b-((p*-e+o*d+n*0.0)*e+(m*-e+l*d+k*0.0)*-d+(j*-e+i*d+h*0.0)*0.0);g[a+44>>2]=0.0;return}function Dh(){var b=0,d=0,e=0;b=Or(288)|0;c[b+164>>2]=1065353216;c[b+168>>2]=1065353216;c[b+172>>2]=1065353216;g[b+176>>2]=0.0;c[b+180>>2]=0;g[b+184>>2]=999999984306749440.0;c[b+188>>2]=0;c[b+188+4>>2]=0;c[b+188+8>>2]=0;c[b+188+12>>2]=0;c[b+204>>2]=1;c[b+208>>2]=-1;c[b+212>>2]=-1;c[b+216>>2]=1;g[b+220>>2]=0.0;g[b+224>>2]=.5;g[b+228>>2]=0.0;g[b+232>>2]=0.0;c[b+240>>2]=0;g[b+244>>2]=1.0;c[b+248>>2]=0;c[b+248+4>>2]=0;c[b+248+8>>2]=0;c[b+248+12>>2]=0;c[b+4>>2]=1065353216;c[b+8>>2]=0;c[b+8+4>>2]=0;c[b+8+8>>2]=0;c[b+8+12>>2]=0;c[b+24>>2]=1065353216;c[b+28>>2]=0;c[b+28+4>>2]=0;c[b+28+8>>2]=0;c[b+28+12>>2]=0;c[b+44>>2]=1065353216;c[b+48>>2]=0;c[b+48+4>>2]=0;c[b+48+8>>2]=0;c[b+48+12>>2]=0;c[b+48+16>>2]=0;a[b+280>>0]=1;c[b+276>>2]=0;c[b+268>>2]=0;c[b+272>>2]=0;c[b+236>>2]=4;c[b>>2]=5212;c[6432]=(c[6432]|0)+1;d=ec(95)|0;if(!d){e=0;ki(e);d=b+284|0;c[d>>2]=e;return b|0}c[(d+4+15&-16)+-4>>2]=d;d=d+4+15&-16;ki(d);e=b+284|0;c[e>>2]=d;return b|0}function Eh(a,d,e,f){a=a|0;d=d|0;e=e|0;f=f|0;var h=0,i=0.0,j=0.0,k=0.0,m=0.0;h=l;l=l+96|0;g[h+4>>2]=1.0;c[h+8>>2]=0;b[h+12>>1]=1;b[h+14>>1]=-1;c[h+16>>2]=0;c[h>>2]=2904;c[h+20>>2]=c[d>>2];c[h+20+4>>2]=c[d+4>>2];c[h+20+8>>2]=c[d+8>>2];c[h+20+12>>2]=c[d+12>>2];c[h+36>>2]=c[e>>2];c[h+36+4>>2]=c[e+4>>2];c[h+36+8>>2]=c[e+8>>2];c[h+36+12>>2]=c[e+12>>2];a=c[a+4>>2]|0;Vb[c[(c[a>>2]|0)+32>>2]&127](a,d,e,h);d=c[h+8>>2]|0;if(!d){f=0;l=h;return f|0}if(!(c[d+236>>2]&2)){f=0;l=h;return f|0}if(c[d+204>>2]&4|0){f=0;l=h;return f|0}c[f>>2]=c[h+68>>2];c[f+4>>2]=c[h+68+4>>2];c[f+8>>2]=c[h+68+8>>2];c[f+12>>2]=c[h+68+12>>2];c[f+16>>2]=c[h+52>>2];c[f+16+4>>2]=c[h+52+4>>2];c[f+16+8>>2]=c[h+52+8>>2];c[f+16+12>>2]=c[h+52+12>>2];m=+g[f+16>>2];k=+g[f+20>>2];j=+g[f+24>>2];i=1.0/+C(+(m*m+k*k+j*j));g[f+16>>2]=m*i;g[f+20>>2]=k*i;g[f+24>>2]=j*i;c[f+32>>2]=c[h+4>>2];f=d;l=h;return f|0}function Fh(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;hb[c[(c[b>>2]|0)+32>>2]&511](b);e=vb[c[(c[b>>2]|0)+16>>2]&63](b,104,1)|0;d=c[e+8>>2]|0;f=d;g=f+104|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(g|0));c[d+88>>2]=c[a+248>>2];c[d+92>>2]=c[a+252>>2];c[d+96>>2]=c[a+256>>2];c[d+100>>2]=c[a+260>>2];c[d>>2]=c[a+92>>2];c[d+4>>2]=c[a+96>>2];c[d+8>>2]=c[a+100>>2];c[d+12>>2]=c[a+104>>2];c[d+16>>2]=c[a+108>>2];c[d+20>>2]=c[a+116>>2];c[d+24>>2]=c[a+120>>2];c[d+28>>2]=c[a+124>>2];c[d+32>>2]=c[a+128>>2];c[d+36>>2]=c[a+132>>2];c[d+40>>2]=c[a+140>>2];c[d+44>>2]=c[a+144>>2];c[d+48>>2]=c[a+148>>2];c[d+52>>2]=c[a+152>>2];c[d+56>>2]=c[a+168>>2];c[d+60>>2]=c[a+172>>2];c[d+64>>2]=c[a+112>>2];c[d+68>>2]=c[a+156>>2];c[d+72>>2]=c[a+160>>2];c[d+76>>2]=c[a+164>>2];c[d+80>>2]=c[a+136>>2];fb[c[(c[b>>2]|0)+20>>2]&31](b,e,12401,1145853764,d);Ni(a,b);ad(a,b);hb[c[(c[b>>2]|0)+36>>2]&511](b);return}function Gh(a){a=a|0;var b=0.0,d=0,e=0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0;e=Ds()|0;c[e+8>>2]=0;c[e+12>>2]=1065353216;c[e+16>>2]=1065353216;c[e+20>>2]=1065353216;g[e+24>>2]=0.0;g[e+44>>2]=.03999999910593033;c[e+52>>2]=0;c[e>>2]=7968;c[e+4>>2]=0;d=!(+g[a>>2]<+g[a+4>>2])&1;b=+g[a+((+g[a+(d<<2)>>2]<+g[a+8>>2]?d:2)<<2)>>2]*.10000000149011612;if(b<.03999999910593033){j=+HE(e);h=+zb[c[(c[e>>2]|0)+48>>2]&15](e);k=+zb[c[(c[e>>2]|0)+48>>2]&15](e);j=j+ +g[e+28>>2];h=h+ +g[e+32>>2];k=k+ +g[e+36>>2];g[e+44>>2]=b;i=+zb[c[(c[e>>2]|0)+48>>2]&15](e);f=+zb[c[(c[e>>2]|0)+48>>2]&15](e);b=k-+zb[c[(c[e>>2]|0)+48>>2]&15](e);g[e+28>>2]=j-i;g[e+32>>2]=h-f;g[e+36>>2]=b;g[e+40>>2]=0.0;d=c[e>>2]|0}else d=7968;i=+zb[c[d+48>>2]&15](e);j=+zb[c[(c[e>>2]|0)+48>>2]&15](e);k=+zb[c[(c[e>>2]|0)+48>>2]&15](e);j=+g[a+4>>2]*+g[e+16>>2]-j;k=+g[a+8>>2]*+g[e+20>>2]-k;g[e+28>>2]=+g[a>>2]*+g[e+12>>2]-i;g[e+32>>2]=j;g[e+36>>2]=k;g[e+40>>2]=0.0;return e|0}function Hh(a,b){a=a|0;b=b|0;var d=0,e=0,f=0.0;e=l;l=l+32|0;d=c[b+388>>2]|0;switch(c[a+388>>2]&48&d&63){case 32:{if((a|0)==(b|0)&(d&64|0)==0){l=e;return}g[e+4>>2]=1.0;c[e+8+4>>2]=0;c[e+8+4+4>>2]=0;c[e+8+4+8>>2]=0;c[e>>2]=3668;c[e+8>>2]=c[a+456>>2];d=c[a+192>>2]|0;f=+zb[c[(c[d>>2]|0)+48>>2]&15](d);d=c[b+192>>2]|0;g[e+12>>2]=f+ +zb[c[(c[d>>2]|0)+48>>2]&15](d);c[e+16>>2]=c[(+g[a+316>>2]<+g[b+316>>2]?a+316|0:b+316|0)>>2];c[e+24>>2]=a;c[e+28>>2]=b;re(c[a+1048>>2]|0,c[b+1048>>2]|0,e);l=e;return}case 16:{if((a|0)==(b|0)){l=e;return}c[e>>2]=3704;d=c[a+192>>2]|0;f=+zb[c[(c[d>>2]|0)+48>>2]&15](d);d=c[b+192>>2]|0;g[e+12>>2]=f+ +zb[c[(c[d>>2]|0)+48>>2]&15](d);c[e+4>>2]=a;c[e+8>>2]=b;re(c[a+928>>2]|0,c[b+988>>2]|0,e);c[e+4>>2]=b;c[e+8>>2]=a;re(c[b+928>>2]|0,c[a+988>>2]|0,e);l=e;return}default:{l=e;return}}}function Ih(a,b){a=a|0;b=b|0;var d=0.0,e=0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0;c[a+4>>2]=35;c[a+8>>2]=0;c[a+12>>2]=1065353216;c[a+16>>2]=1065353216;c[a+20>>2]=1065353216;g[a+24>>2]=0.0;g[a+44>>2]=.03999999910593033;c[a>>2]=8264;c[a+52>>2]=1;e=!(+g[b>>2]<+g[b+4>>2])&1;d=+g[b+((+g[b+(e<<2)>>2]<+g[b+8>>2]?e:2)<<2)>>2]*.10000000149011612;if(d<.03999999910593033){j=+HE(a);h=+zb[c[(c[a>>2]|0)+48>>2]&15](a);k=+zb[c[(c[a>>2]|0)+48>>2]&15](a);j=j+ +g[a+28>>2];h=h+ +g[a+32>>2];k=k+ +g[a+36>>2];g[a+44>>2]=d;i=+zb[c[(c[a>>2]|0)+48>>2]&15](a);f=+zb[c[(c[a>>2]|0)+48>>2]&15](a);d=k-+zb[c[(c[a>>2]|0)+48>>2]&15](a);g[a+28>>2]=j-i;g[a+32>>2]=h-f;g[a+36>>2]=d;g[a+40>>2]=0.0;e=c[a>>2]|0}else e=8264;i=+zb[c[e+48>>2]&15](a);j=+zb[c[(c[a>>2]|0)+48>>2]&15](a);k=+zb[c[(c[a>>2]|0)+48>>2]&15](a);j=+g[b+4>>2]*+g[a+16>>2]-j;k=+g[b+8>>2]*+g[a+20>>2]-k;g[a+28>>2]=+g[b>>2]*+g[a+12>>2]-i;g[a+32>>2]=j;g[a+36>>2]=k;g[a+40>>2]=0.0;c[a+4>>2]=13;return}function Jh(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0,j=0.0;i=l;l=l+32|0;c[i+16>>2]=c[d>>2];c[i+16+4>>2]=c[d+4>>2];c[i+16+8>>2]=c[d+8>>2];c[i+16+12>>2]=c[d+12>>2];e=+g[i+16>>2];h=+g[i+16+4>>2];f=+g[i+16+8>>2];if(e*e+h*h+f*f<1.4210854715202004e-14){c[i+16>>2]=-1082130432;c[i+16+4>>2]=-1082130432;c[i+16+8>>2]=-1082130432;g[i+16+12>>2]=0.0;e=-1.0;h=-1.0;f=-1.0}j=1.0/+C(+(e*e+h*h+f*f));g[i+16>>2]=e*j;g[i+16+4>>2]=h*j;g[i+16+8>>2]=f*j;md(i,b,i+16|0);switch(c[b+4>>2]|0){case 8:{e=+g[b+28>>2]*+g[b+12>>2];break}case 0:{e=+g[b+44>>2];break}case 1:{e=+g[b+44>>2];break}case 13:{e=+g[b+44>>2];break}case 11:{e=+g[b+44>>2];break}case 10:{e=+g[b+44>>2];break}case 4:case 5:{e=+g[b+44>>2];break}default:e=+zb[c[(c[b>>2]|0)+48>>2]&15](b)}h=e*+g[i+16+4>>2]+ +g[i+4>>2];j=e*+g[i+16+8>>2]+ +g[i+8>>2];g[a>>2]=e*+g[i+16>>2]+ +g[i>>2];g[a+4>>2]=h;g[a+8>>2]=j;g[a+12>>2]=0.0;l=i;return}function Kh(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0.0,h=0,i=0,k=0,m=0.0,n=0,o=0.0;n=l;l=l+80|0;c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;e=+g[d>>2];f=+g[d+4>>2];m=+g[d+8>>2];if(e*e+f*f+m*m<9.999999747378752e-05){i=1065353216;k=0;h=0;e=0.0}else{o=1.0/+C(+(e*e+f*f+m*m));i=(g[j>>2]=e*o,c[j>>2]|0);k=(g[j>>2]=f*o,c[j>>2]|0);h=(g[j>>2]=m*o,c[j>>2]|0);e=+g[d+12>>2]}c[n+32>>2]=7948;d=n+32+4|0;c[d>>2]=0;c[d+4>>2]=0;c[d+8>>2]=0;c[d+12>>2]=0;g[n+32+20>>2]=-999999984306749440.0;c[n+32+24>>2]=i;c[n+32+28>>2]=k;c[n+32+32>>2]=h;g[n+32+36>>2]=e;c[n+16>>2]=1566444395;c[n+16+4>>2]=1566444395;c[n+16+8>>2]=1566444395;g[n+16+12>>2]=0.0;b=c[b+92>>2]|0;k=c[(c[b>>2]|0)+8>>2]|0;g[n>>2]=-999999984306749440.0;g[n+4>>2]=-999999984306749440.0;g[n+8>>2]=-999999984306749440.0;g[n+12>>2]=0.0;Vb[k&127](b,n+32|0,n,n+16|0);c[a>>2]=c[d>>2];c[a+4>>2]=c[d+4>>2];c[a+8>>2]=c[d+8>>2];c[a+12>>2]=c[d+12>>2];l=n;return}function Lh(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;e=Gb[c[(c[d>>2]|0)+40>>2]&31](d,a)|0;g=Gb[c[(c[d>>2]|0)+28>>2]&31](d,e)|0;c[b>>2]=g;if(g|0)jb[c[(c[d>>2]|0)+48>>2]&127](d,e);c[b+4>>2]=c[a+4>>2];c[b+28>>2]=c[a+28>>2];c[b+32>>2]=c[a+32>>2];c[b+36>>2]=c[a+36>>2];c[b+40>>2]=c[a+40>>2];c[b+12>>2]=c[a+12>>2];c[b+16>>2]=c[a+16>>2];c[b+20>>2]=c[a+20>>2];c[b+24>>2]=c[a+24>>2];c[b+44>>2]=c[a+44>>2];f=c[a+96>>2]|0;c[b+60>>2]=f;if(!f){c[b+52>>2]=0;c[b+56>>2]=0;return 17427}c[b+52>>2]=Gb[c[(c[d>>2]|0)+28>>2]&31](d,c[a+104>>2]|0)|0;c[b+56>>2]=0;g=vb[c[(c[d>>2]|0)+16>>2]&63](d,16,f)|0;if((f|0)>0){e=c[a+104>>2]|0;b=0;a=c[g+8>>2]|0;while(1){c[a>>2]=c[e+(b<<4)>>2];c[a+4>>2]=c[e+(b<<4)+4>>2];c[a+8>>2]=c[e+(b<<4)+8>>2];c[a+12>>2]=c[e+(b<<4)+12>>2];b=b+1|0;if((b|0)==(f|0))break;else a=a+16|0}}else e=c[a+104>>2]|0;fb[c[(c[d>>2]|0)+20>>2]&31](d,g,19426,1497453121,e);return 17427}function Mh(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0.0,h=0,i=0,j=0.0,k=0.0,l=0.0,m=0.0;l=+g[b+60>>2]*.5;h=c[b+68>>2]|0;f=+g[d>>2];j=+g[d+4>>2];k=+g[d+8>>2];k=+C(+(f*f+j*j+k*k));i=c[b+64>>2]|0;do if(!(+g[d+(h<<2)>>2]>k*+g[b+52>>2])){j=+g[d+(i<<2)>>2];e=c[b+72>>2]|0;f=+g[d+(e<<2)>>2];k=+C(+(j*j+f*f));if(k>1.1920928955078125e-07){k=+g[b+56>>2]/k;g[a+(i<<2)>>2]=j*k;g[a+(h<<2)>>2]=-l;f=f*k;break}else{g[a+(i<<2)>>2]=0.0;g[a+(h<<2)>>2]=-l;f=0.0;break}}else{g[a+(i<<2)>>2]=0.0;g[a+(h<<2)>>2]=l;f=0.0;e=c[b+72>>2]|0}while(0);g[a+(e<<2)>>2]=f;if(!(+zb[c[(c[b>>2]|0)+48>>2]&15](b)!=0.0))return;j=+g[d>>2];k=+g[d+4>>2];l=+g[d+8>>2];m=j*j+k*k+l*l<1.4210854715202004e-14?-1.0:j;f=j*j+k*k+l*l<1.4210854715202004e-14?-1.0:k;l=j*j+k*k+l*l<1.4210854715202004e-14?-1.0:l;k=1.0/+C(+(l*l+(m*m+f*f)));j=+zb[c[(c[b>>2]|0)+48>>2]&15](b);g[a>>2]=+g[a>>2]+j*k*m;g[a+4>>2]=j*k*f+ +g[a+4>>2];g[a+8>>2]=j*k*l+ +g[a+8>>2];return}function Nh(a,b,d){a=a|0;b=b|0;d=d|0;c[a+300>>2]=c[b>>2];c[a+300+4>>2]=c[b+4>>2];c[a+300+8>>2]=c[b+8>>2];c[a+300+12>>2]=c[b+12>>2];c[a+316>>2]=c[b+16>>2];c[a+316+4>>2]=c[b+16+4>>2];c[a+316+8>>2]=c[b+16+8>>2];c[a+316+12>>2]=c[b+16+12>>2];c[a+332>>2]=c[b+32>>2];c[a+332+4>>2]=c[b+32+4>>2];c[a+332+8>>2]=c[b+32+8>>2];c[a+332+12>>2]=c[b+32+12>>2];c[a+348>>2]=c[b+48>>2];c[a+348+4>>2]=c[b+48+4>>2];c[a+348+8>>2]=c[b+48+8>>2];c[a+348+12>>2]=c[b+48+12>>2];c[a+364>>2]=c[d>>2];c[a+364+4>>2]=c[d+4>>2];c[a+364+8>>2]=c[d+8>>2];c[a+364+12>>2]=c[d+12>>2];c[a+380>>2]=c[d+16>>2];c[a+380+4>>2]=c[d+16+4>>2];c[a+380+8>>2]=c[d+16+8>>2];c[a+380+12>>2]=c[d+16+12>>2];c[a+396>>2]=c[d+32>>2];c[a+396+4>>2]=c[d+32+4>>2];c[a+396+8>>2]=c[d+32+8>>2];c[a+396+12>>2]=c[d+32+12>>2];c[a+412>>2]=c[d+48>>2];c[a+412+4>>2]=c[d+48+4>>2];c[a+412+8>>2]=c[d+48+8>>2];c[a+412+12>>2]=c[d+48+12>>2];hb[c[(c[a>>2]|0)+8>>2]&511](a);return}function Oh(b){b=b|0;var d=0;d=c[b>>2]|0;if(d|0)Sm(b,d);d=c[b+4>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+4>>2]=0;c[b+8>>2]=-1;d=c[b+32>>2]|0;if(d|0){if(a[b+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+32>>2]=0}a[b+36>>0]=1;c[b+32>>2]=0;c[b+24>>2]=0;c[b+28>>2]=0;c[b+16>>2]=0;d=c[b+52>>2]|0;if(!d){a[b+56>>0]=1;c[b+52>>2]=0;c[b+44>>2]=0;c[b+48>>2]=0;a[b+36>>0]=1;c[b+32>>2]=0;c[b+24>>2]=0;c[b+28>>2]=0;return}if(!(a[b+56>>0]|0)){a[b+56>>0]=1;c[b+52>>2]=0;c[b+44>>2]=0;c[b+48>>2]=0;a[b+36>>0]=1;c[b+32>>2]=0;c[b+24>>2]=0;c[b+28>>2]=0;return}c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0);d=c[b+32>>2]|0;a[b+56>>0]=1;c[b+52>>2]=0;c[b+44>>2]=0;c[b+48>>2]=0;if(!d){a[b+36>>0]=1;c[b+32>>2]=0;c[b+24>>2]=0;c[b+28>>2]=0;return}if(!((a[b+36>>0]|0)==0|(d|0)==0)){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+32>>2]=0;a[b+36>>0]=1;c[b+32>>2]=0;c[b+24>>2]=0;c[b+28>>2]=0;return}function Ph(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0,n=0.0;m=c[a+4>>2]|0;a=c[a+64>>2]|0;do if(!m)if(!a){f=0.0;h=0.0;n=0.0;k=0.0;l=0.0;j=0.0;i=0.0;e=0.0}else{f=+g[a+4>>2];h=+g[a+8>>2];n=+g[a+12>>2];k=+g[a+16>>2];l=+g[a+20>>2];j=+g[a+24>>2];i=+g[a+28>>2];e=+g[a>>2]}else{e=+g[m>>2];if(!a){f=+g[m+4>>2];h=+g[m+8>>2];n=+g[m+12>>2];k=+g[m+16>>2];l=+g[m+20>>2];j=+g[m+24>>2];i=+g[m+28>>2];break}j=+g[a>>2];e=e<j?e:j;j=+g[m+16>>2];k=+g[a+16>>2];k=j>k?j:k;j=+g[m+4>>2];f=+g[a+4>>2];f=j<f?j:f;j=+g[m+20>>2];l=+g[a+20>>2];l=j>l?j:l;j=+g[m+8>>2];h=+g[a+8>>2];h=j<h?j:h;j=+g[m+24>>2];i=+g[a+24>>2];if(j>i){n=0.0;i=0.0}else{n=0.0;j=i;i=0.0}}while(0);g[b>>2]=e;g[b+4>>2]=f;g[b+8>>2]=h;g[b+12>>2]=n;g[d>>2]=k;g[d+4>>2]=l;g[d+8>>2]=j;g[d+12>>2]=i;return}function Qh(a,b){a=a|0;b=b|0;var c=0,d=0.0,e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0;c=l;l=l+48|0;eh(a+364|0,c+16|0);h=-+g[c+16>>2];e=-+g[c+16+4>>2];m=-+g[c+16+8>>2];k=+g[c+16+12>>2];f=+g[b>>2];n=+g[b+12>>2];j=+g[b+8>>2];i=+g[b+4>>2];eh(a+300|0,c);p=+g[c>>2];q=+g[c+12>>2];d=+g[c+8>>2];o=+g[c+4>>2];g[c+32>>2]=(k*n-f*h-i*e-j*m)*p+(k*f+n*h+j*e-i*m)*q+(f*m+(n*e+k*i)-j*h)*d-(n*m+k*j+i*h-f*e)*o;g[c+32+4>>2]=p*(n*m+k*j+i*h-f*e)+(q*(f*m+(n*e+k*i)-j*h)+(k*n-f*h-i*e-j*m)*o)-(k*f+n*h+j*e-i*m)*d;g[c+32+8>>2]=(n*m+k*j+i*h-f*e)*q+(k*n-f*h-i*e-j*m)*d+(k*f+n*h+j*e-i*m)*o-p*(f*m+(n*e+k*i)-j*h);g[c+32+12>>2]=(k*n-f*h-i*e-j*m)*q-(k*f+n*h+j*e-i*m)*p-(f*m+(n*e+k*i)-j*h)*o-(n*m+k*j+i*h-f*e)*d;He(a,c+32|0);l=c;return}function Rh(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0;if(!e)e=c[b+188>>2]|0;j=c[d>>2]|0;f=c[b+268>>2]|0;a:do if((f|0)>0){h=c[b+276>>2]|0;g=0;while(1){if((c[h+(g<<2)>>2]|0)==(j|0))break;g=g+1|0;if((g|0)>=(f|0))break a}if((g|0)!=(f|0))return}while(0);if((f|0)==(c[b+272>>2]|0)?(i=f|0?f<<1:1,(f|0)<(i|0)):0){if(!i)h=0;else{c[6432]=(c[6432]|0)+1;f=ec((i<<2|3)+16|0)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}h=f;f=c[b+268>>2]|0}if((f|0)>0){g=0;do{c[h+(g<<2)>>2]=c[(c[b+276>>2]|0)+(g<<2)>>2];g=g+1|0}while((g|0)!=(f|0))}g=c[b+276>>2]|0;if(g){if(a[b+280>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[g+-4>>2]|0);f=c[b+268>>2]|0}c[b+276>>2]=0}a[b+280>>0]=1;c[b+276>>2]=h;c[b+272>>2]=i}c[(c[b+276>>2]|0)+(f<<2)>>2]=j;c[b+268>>2]=f+1;b=c[b+284>>2]|0;vb[c[(c[b>>2]|0)+8>>2]&63](b,e,d)|0;return}function Sh(a,b,e){a=a|0;b=b|0;e=e|0;var f=0,g=0;c[b>>2]=Gb[c[(c[e>>2]|0)+28>>2]&31](e,c[a+28>>2]|0)|0;c[b+4>>2]=Gb[c[(c[e>>2]|0)+28>>2]&31](e,c[a+32>>2]|0)|0;f=Gb[c[(c[e>>2]|0)+40>>2]&31](e,a)|0;g=Gb[c[(c[e>>2]|0)+28>>2]&31](e,f)|0;c[b+8>>2]=g;if(g|0)jb[c[(c[e>>2]|0)+48>>2]&127](e,f);c[b+12>>2]=c[a+4>>2];c[b+24>>2]=d[a+21>>0];c[b+40>>2]=c[a+24>>2];c[b+44>>2]=c[a+16>>2];c[b+48>>2]=d[a+20>>0];c[b+20>>2]=c[a+12>>2];c[b+16>>2]=c[a+8>>2];c[b+28>>2]=c[a+36>>2];c[b+32>>2]=c[a+40>>2];c[b+36>>2]=0;f=c[a+28>>2]|0;if((c[f+488>>2]|0)>0){e=0;do{if((c[(c[f+496>>2]|0)+(e<<2)>>2]|0)==(a|0)){c[b+36>>2]=1;f=c[a+28>>2]|0}e=e+1|0}while((e|0)<(c[f+488>>2]|0))}f=c[a+32>>2]|0;if((c[f+488>>2]|0)>0)e=0;else return 12776;do{if((c[(c[f+496>>2]|0)+(e<<2)>>2]|0)==(a|0)){c[b+36>>2]=1;f=c[a+32>>2]|0}e=e+1|0}while((e|0)<(c[f+488>>2]|0));return 12776}function Th(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;if((e|0)>=8192)return Xa(b|0,d|0,e|0)|0;h=b|0;g=b+e|0;if((b&3)==(d&3)){while(b&3){if(!e)return h|0;a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}e=g&-4|0;f=e-64|0;while((b|0)<=(f|0)){c[b>>2]=c[d>>2];c[b+4>>2]=c[d+4>>2];c[b+8>>2]=c[d+8>>2];c[b+12>>2]=c[d+12>>2];c[b+16>>2]=c[d+16>>2];c[b+20>>2]=c[d+20>>2];c[b+24>>2]=c[d+24>>2];c[b+28>>2]=c[d+28>>2];c[b+32>>2]=c[d+32>>2];c[b+36>>2]=c[d+36>>2];c[b+40>>2]=c[d+40>>2];c[b+44>>2]=c[d+44>>2];c[b+48>>2]=c[d+48>>2];c[b+52>>2]=c[d+52>>2];c[b+56>>2]=c[d+56>>2];c[b+60>>2]=c[d+60>>2];b=b+64|0;d=d+64|0}while((b|0)<(e|0)){c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0}}else{e=g-4|0;while((b|0)<(e|0)){a[b>>0]=a[d>>0]|0;a[b+1>>0]=a[d+1>>0]|0;a[b+2>>0]=a[d+2>>0]|0;a[b+3>>0]=a[d+3>>0]|0;b=b+4|0;d=d+4|0}}while((b|0)<(g|0)){a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0}return h|0}function Uh(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0;if(lb[c[(c[d>>2]|0)+16>>2]&127](d)|0)return;j=c[b+712>>2]|0;i=lb[c[(c[d>>2]|0)+36>>2]&127](d)|0;if(lb[c[(c[d>>2]|0)+8>>2]&127](d)|0?(f=lb[c[(c[d>>2]|0)+20>>2]&127](d)|0,h=lb[c[(c[d>>2]|0)+24>>2]&127](d)|0,(j|0)>0):0){e=c[b+720>>2]|0;g=0;a=i+(f<<2)|0;while(1){k=c[e+(g*104|0)+12>>2]|0;f=c[e+(g*104|0)+16>>2]|0;c[a>>2]=c[e+(g*104|0)+8>>2];c[a+4>>2]=k;c[a+8>>2]=f;g=g+1|0;if((g|0)==(j|0))break;else a=a+(h<<2)|0}}if(!(lb[c[(c[d>>2]|0)+12>>2]&127](d)|0))return;a=lb[c[(c[d>>2]|0)+28>>2]&127](d)|0;g=lb[c[(c[d>>2]|0)+32>>2]&127](d)|0;if((j|0)<=0)return;f=c[b+720>>2]|0;a=i+(a<<2)|0;e=0;while(1){b=c[f+(e*104|0)+76>>2]|0;k=c[f+(e*104|0)+80>>2]|0;c[a>>2]=c[f+(e*104|0)+72>>2];c[a+4>>2]=b;c[a+8>>2]=k;e=e+1|0;if((e|0)==(j|0))break;else a=a+(g<<2)|0}return}function Vh(b){b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0;c[b>>2]=9504;d=c[b+56>>2]|0;if(d|0){if(a[b+60>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+56>>2]=0}a[b+60>>0]=1;c[b+56>>2]=0;c[b+48>>2]=0;c[b+52>>2]=0;e=c[b+28>>2]|0;if((e|0)>0){h=0;do{f=c[b+36>>2]|0;j=f+(h*36|0)+4|0;i=f+(h*36|0)+12|0;g=c[i>>2]|0;d=f+(h*36|0)+16|0;if(g|0){if(a[d>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[g+-4>>2]|0)}c[i>>2]=0}a[d>>0]=1;c[i>>2]=0;c[j>>2]=0;c[f+(h*36|0)+8>>2]=0;h=h+1|0}while((h|0)!=(e|0))}d=c[b+36>>2]|0;if(d|0){if(a[b+40>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+36>>2]=0}a[b+40>>0]=1;c[b+36>>2]=0;c[b+28>>2]=0;c[b+32>>2]=0;d=c[b+16>>2]|0;if(!d){a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;b=b+12|0;c[b>>2]=0;return}if(a[b+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+16>>2]=0;a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;b=b+12|0;c[b>>2]=0;return}function Wh(b){b=b|0;var d=0;c[b>>2]=8576;d=c[b+156>>2]|0;if(d|0){if(a[b+160>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+156>>2]=0}a[b+160>>0]=1;c[b+156>>2]=0;c[b+148>>2]=0;c[b+152>>2]=0;d=c[b+136>>2]|0;if(d|0){if(a[b+140>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+136>>2]=0}a[b+140>>0]=1;c[b+136>>2]=0;c[b+128>>2]=0;c[b+132>>2]=0;d=c[b+116>>2]|0;if(d|0){if(a[b+120>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+116>>2]=0}a[b+120>>0]=1;c[b+116>>2]=0;c[b+108>>2]=0;c[b+112>>2]=0;d=c[b+96>>2]|0;if(d|0){if(a[b+100>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+96>>2]=0}a[b+100>>0]=1;c[b+96>>2]=0;c[b+88>>2]=0;c[b+92>>2]=0;c[b>>2]=9520;d=c[b+32>>2]|0;if(!d){a[b+36>>0]=1;c[b+32>>2]=0;c[b+24>>2]=0;b=b+28|0;c[b>>2]=0;return}if(a[b+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+32>>2]=0;a[b+36>>0]=1;c[b+32>>2]=0;c[b+24>>2]=0;b=b+28|0;c[b>>2]=0;return}function Xh(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;if((b|0)==0?1:(c[b+236>>2]|0)!=8){zj(a,b);return}f=c[a+328>>2]|0;a:do if((f|0)>0){g=c[a+336>>2]|0;d=0;while(1){e=g+(d<<2)|0;if((c[e>>2]|0)==(b|0))break;d=d+1|0;if((d|0)>=(f|0))break a}if((d|0)<(f|0)){c[e>>2]=c[g+(f+-1<<2)>>2];c[(c[a+336>>2]|0)+(f+-1<<2)>>2]=b;c[a+328>>2]=f+-1}}while(0);d=c[b+188>>2]|0;if(d|0){g=c[a+68>>2]|0;g=lb[c[(c[g>>2]|0)+36>>2]&127](g)|0;Rb[c[(c[g>>2]|0)+40>>2]&127](g,d,c[a+24>>2]|0);g=c[a+68>>2]|0;Rb[c[(c[g>>2]|0)+12>>2]&127](g,d,c[a+24>>2]|0);c[b+188>>2]=0}f=c[a+8>>2]|0;if((f|0)<=0)return;g=c[a+16>>2]|0;d=0;while(1){e=g+(d<<2)|0;if((c[e>>2]|0)==(b|0))break;d=d+1|0;if((d|0)>=(f|0)){h=17;break}}if((h|0)==17)return;if((d|0)>=(f|0))return;c[e>>2]=c[g+(f+-1<<2)>>2];c[(c[a+16>>2]|0)+(f+-1<<2)>>2]=b;c[a+8>>2]=f+-1;return}function Yh(b){b=b|0;var d=0;c[b>>2]=9136;d=c[b+160>>2]|0;if(d|0){if(a[b+164>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+160>>2]=0}a[b+164>>0]=1;c[b+160>>2]=0;c[b+152>>2]=0;c[b+156>>2]=0;d=c[b+136>>2]|0;if(d|0){if(a[b+140>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+136>>2]=0}a[b+140>>0]=1;c[b+136>>2]=0;c[b+128>>2]=0;c[b+132>>2]=0;d=c[b+116>>2]|0;if(d|0){if(a[b+120>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+116>>2]=0}a[b+120>>0]=1;c[b+116>>2]=0;c[b+108>>2]=0;c[b+112>>2]=0;d=c[b+96>>2]|0;if(d|0){if(a[b+100>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+96>>2]=0}a[b+100>>0]=1;c[b+96>>2]=0;c[b+88>>2]=0;c[b+92>>2]=0;d=c[b+76>>2]|0;if(!d){a[b+80>>0]=1;c[b+76>>2]=0;c[b+68>>2]=0;b=b+72|0;c[b>>2]=0;return}if(a[b+80>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+76>>2]=0;a[b+80>>0]=1;c[b+76>>2]=0;c[b+68>>2]=0;b=b+72|0;c[b>>2]=0;return}function Zh(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0.0,i=0,j=0,k=0.0,m=0.0,n=0.0,o=0,p=0;p=l;l=l+16|0;if((e|0)<=0){l=p;return}o=0;do{n=+g[a+60>>2]*.5;i=c[a+68>>2]|0;h=+g[b+(o<<4)>>2];k=+g[b+(o<<4)+4>>2];m=+g[b+(o<<4)+8>>2];m=+C(+(h*h+k*k+m*m));j=c[a+64>>2]|0;do if(!(+g[b+(o<<4)+(i<<2)>>2]>m*+g[a+52>>2])){k=+g[b+(o<<4)+(j<<2)>>2];f=c[a+72>>2]|0;h=+g[b+(o<<4)+(f<<2)>>2];m=+C(+(k*k+h*h));if(m>1.1920928955078125e-07){m=+g[a+56>>2]/m;g[p+(j<<2)>>2]=k*m;g[p+(i<<2)>>2]=-n;h=h*m;break}else{g[p+(j<<2)>>2]=0.0;g[p+(i<<2)>>2]=-n;h=0.0;break}}else{g[p+(j<<2)>>2]=0.0;g[p+(i<<2)>>2]=n;h=0.0;f=c[a+72>>2]|0}while(0);g[p+(f<<2)>>2]=h;j=d+(o<<4)|0;c[j>>2]=c[p>>2];c[j+4>>2]=c[p+4>>2];c[j+8>>2]=c[p+8>>2];c[j+12>>2]=c[p+12>>2];o=o+1|0}while((o|0)!=(e|0));l=p;return}function _h(b){b=b|0;var d=0;c[b>>2]=4944;d=c[b+144>>2]|0;if(d|0){if(a[b+148>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+144>>2]=0}a[b+148>>0]=1;c[b+144>>2]=0;c[b+136>>2]=0;c[b+140>>2]=0;d=c[b+76>>2]|0;if(d|0){if(a[b+80>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+76>>2]=0}a[b+80>>0]=1;c[b+76>>2]=0;c[b+68>>2]=0;c[b+72>>2]=0;d=c[b+56>>2]|0;if(d|0){if(a[b+60>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+56>>2]=0}a[b+60>>0]=1;c[b+56>>2]=0;c[b+48>>2]=0;c[b+52>>2]=0;d=c[b+36>>2]|0;if(d|0){if(a[b+40>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+36>>2]=0}a[b+40>>0]=1;c[b+36>>2]=0;c[b+28>>2]=0;c[b+32>>2]=0;d=c[b+16>>2]|0;if(!d){a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;b=b+12|0;c[b>>2]=0;return}if(a[b+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+16>>2]=0;a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;b=b+12|0;c[b>>2]=0;return}function $h(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0;o=(+g[a+32>>2]-+g[a+16>>2])*+g[a+108>>2]*.5;m=(+g[a+36>>2]-+g[a+20>>2])*+g[a+112>>2]*.5;k=(+g[a+40>>2]-+g[a+24>>2])*+g[a+116>>2]*.5;t=+B(+(+g[b>>2]));s=+B(+(+g[b+4>>2]));r=+B(+(+g[b+8>>2]));n=+B(+(+g[b+16>>2]));l=+B(+(+g[b+20>>2]));j=+B(+(+g[b+24>>2]));w=+B(+(+g[b+32>>2]));v=+B(+(+g[b+36>>2]));f=+B(+(+g[b+40>>2]));u=+g[b+48>>2];p=+g[b+52>>2];h=+g[b+56>>2];q=+zb[c[(c[a>>2]|0)+48>>2]&15](a);i=+zb[c[(c[a>>2]|0)+48>>2]&15](a);f=o*w+m*v+k*f+ +zb[c[(c[a>>2]|0)+48>>2]&15](a);g[d>>2]=u-(o*t+m*s+k*r+q);g[d+4>>2]=p-(o*n+m*l+k*j+i);g[d+8>>2]=h-f;g[d+12>>2]=0.0;g[e>>2]=u+(o*t+m*s+k*r+q);g[e+4>>2]=p+(o*n+m*l+k*j+i);g[e+8>>2]=h+f;g[e+12>>2]=0.0;return}function ai(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0;i=l;l=l+48|0;g=c[a+28>>2]|0;c[i+32>>2]=g;g=(c[a+20>>2]|0)-g|0;c[i+32+4>>2]=g;c[i+32+8>>2]=b;c[i+32+12>>2]=d;c[i>>2]=c[a+60>>2];c[i+4>>2]=i+32;c[i+8>>2]=2;b=hB(cb(146,i|0)|0)|0;a:do if((g+d|0)!=(b|0)){e=i+32|0;f=2;g=g+d|0;while(1){if((b|0)<0)break;g=g-b|0;j=c[e+4>>2]|0;k=b>>>0>j>>>0;e=k?e+8|0:e;f=(k<<31>>31)+f|0;j=b-(k?j:0)|0;c[e>>2]=(c[e>>2]|0)+j;c[e+4>>2]=(c[e+4>>2]|0)-j;c[i+16>>2]=c[a+60>>2];c[i+16+4>>2]=e;c[i+16+8>>2]=f;b=hB(cb(146,i+16|0)|0)|0;if((g|0)==(b|0)){h=3;break a}}c[a+16>>2]=0;c[a+28>>2]=0;c[a+20>>2]=0;c[a>>2]=c[a>>2]|32;if((f|0)==2)d=0;else d=d-(c[e+4>>2]|0)|0}else h=3;while(0);if((h|0)==3){k=c[a+44>>2]|0;c[a+16>>2]=k+(c[a+48>>2]|0);c[a+28>>2]=k;c[a+20>>2]=k}l=i;return d|0}function bi(b){b=b|0;var d=0;if((a[22648]|0)==0?jy(22648)|0:0){if((a[22600]|0)==0?jy(22600)|0:0){if((a[22608]|0)==0?jy(22608)|0:0){c[5728]=1065353216;c[5729]=0;c[5730]=0;c[5731]=0;c[5732]=0;c[5733]=1065353216;c[5734]=0;c[5735]=0;c[5736]=0;c[5737]=0;c[5738]=1065353216;g[5739]=0.0}c[5712]=c[5728];c[5713]=c[5729];c[5714]=c[5730];c[5715]=c[5731];c[5716]=c[5732];c[5717]=c[5733];c[5718]=c[5734];c[5719]=c[5735];c[5720]=c[5736];c[5721]=c[5737];c[5722]=c[5738];c[5723]=c[5739];c[5724]=0;c[5725]=0;c[5726]=0;c[5727]=0}c[5764]=c[5712];c[5765]=c[5713];c[5766]=c[5714];c[5767]=c[5715];c[5768]=c[5716];c[5769]=c[5717];c[5770]=c[5718];c[5771]=c[5719];c[5772]=c[5720];c[5773]=c[5721];c[5774]=c[5722];c[5775]=c[5723];c[5776]=c[5724];c[5777]=c[5725];c[5778]=c[5726];c[5779]=c[5727]}d=c[b+8>>2]|0;if(!d){b=c[b>>2]|0;return ((b|0)==0?23056:b+60|0)|0}else return d+4|0;return 0}function ci(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0;e=c[b>>2]|0;if((e|0)==(c[a+80>>2]|0)){f=1.0;return +f}if(c[e+204>>2]&4|0){f=1.0;return +f}if((+g[a+28>>2]-+g[a+12>>2])*+g[b+8>>2]+(+g[a+32>>2]-+g[a+16>>2])*+g[b+12>>2]+(+g[a+36>>2]-+g[a+20>>2])*+g[b+16>>2]>=-+g[a+84>>2]){f=1.0;return +f}c[a+4>>2]=c[b+40>>2];c[a+76>>2]=e;if(d){c[a+44>>2]=c[b+8>>2];c[a+44+4>>2]=c[b+8+4>>2];c[a+44+8>>2]=c[b+8+8>>2];c[a+44+12>>2]=c[b+8+12>>2]}else{k=+g[b+8>>2];j=+g[b+12>>2];i=+g[b+16>>2];h=k*+g[e+20>>2]+j*+g[e+24>>2]+i*+g[e+28>>2];f=k*+g[e+36>>2]+j*+g[e+40>>2]+i*+g[e+44>>2];g[a+44>>2]=+g[e+4>>2]*k+ +g[e+8>>2]*j+ +g[e+12>>2]*i;g[a+48>>2]=h;g[a+52>>2]=f;g[a+56>>2]=0.0}c[a+60>>2]=c[b+24>>2];c[a+60+4>>2]=c[b+24+4>>2];c[a+60+8>>2]=c[b+24+8>>2];c[a+60+12>>2]=c[b+24+12>>2];k=+g[b+40>>2];return +k}function di(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0,i=0,j=0,k=0;i=l;l=l+80|0;if((e|0)>0)f=0;else{l=i;return}do{g[d+(f<<4)+12>>2]=-999999984306749440.0;f=f+1|0}while((f|0)!=(e|0));f=i+32+4|0;h=0;do{j=b+(h<<4)|0;c[i+32>>2]=7948;c[f>>2]=0;c[f+4>>2]=0;c[f+8>>2]=0;c[f+12>>2]=0;g[i+32+20>>2]=-999999984306749440.0;c[i+32+24>>2]=c[j>>2];c[i+32+24+4>>2]=c[j+4>>2];c[i+32+24+8>>2]=c[j+8>>2];c[i+32+24+12>>2]=c[j+12>>2];c[i+16>>2]=1566444395;c[i+16+4>>2]=1566444395;c[i+16+8>>2]=1566444395;g[i+16+12>>2]=0.0;j=c[a+92>>2]|0;k=c[(c[j>>2]|0)+8>>2]|0;g[i>>2]=-999999984306749440.0;g[i+4>>2]=-999999984306749440.0;g[i+8>>2]=-999999984306749440.0;g[i+12>>2]=0.0;Vb[k&127](j,i+32|0,i,i+16|0);j=d+(h<<4)|0;c[j>>2]=c[f>>2];c[j+4>>2]=c[f+4>>2];c[j+8>>2]=c[f+8>>2];c[j+12>>2]=c[f+12>>2];h=h+1|0}while((h|0)<(e|0));l=i;return}function ei(b){b=b|0;var d=0,e=0,f=0,h=0;c[b+32>>2]=262144;h=c[b+4>>2]|0;if((h|0)<2383){if((c[b+8>>2]|0)<2383){c[6432]=(c[6432]|0)+1;d=ec(9551)|0;if(!d)f=0;else{c[(d+4+15&-16)+-4>>2]=d;f=d+4+15&-16}d=c[b+4>>2]|0;if((d|0)>0){e=0;do{c[f+(e<<2)>>2]=c[(c[b+12>>2]|0)+(e<<2)>>2];e=e+1|0}while((e|0)!=(d|0))}d=c[b+12>>2]|0;if(d|0){if(a[b+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+12>>2]=0}a[b+16>>0]=1;c[b+12>>2]=f;c[b+8>>2]=2383;e=b+12|0}else e=b+12|0;d=h;do{c[(c[e>>2]|0)+(d<<2)>>2]=0;d=d+1|0}while((d|0)!=2383)}c[b+4>>2]=2383;e=0;do{h=(c[b+12>>2]|0)+(e<<2)|0;d=c[h>>2]|0;c[h>>2]=0;if(d|0)do{h=d;d=c[d+280>>2]|0;YG(h)}while((d|0)!=0);e=e+1|0}while((e|0)!=2383);g[b+20>>2]=.25;c[b+24>>2]=0;c[b+28>>2]=0;c[b+36>>2]=1;c[b+40>>2]=1;return}function fi(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0;f=c[b+96>>2]|0;if((f|0)==(c[b+100>>2]|0)?(i=f|0?f<<1:1,(f|0)<(i|0)):0){if(!i)g=0;else{c[6432]=(c[6432]|0)+1;f=ec((i<<4|3)+16|0)|0;if(!f)g=0;else{c[(f+4+15&-16)+-4>>2]=f;g=f+4+15&-16}f=c[b+96>>2]|0}if((f|0)>0){h=0;do{j=g+(h<<4)|0;k=(c[b+104>>2]|0)+(h<<4)|0;c[j>>2]=c[k>>2];c[j+4>>2]=c[k+4>>2];c[j+8>>2]=c[k+8>>2];c[j+12>>2]=c[k+12>>2];h=h+1|0}while((h|0)!=(f|0))}f=c[b+104>>2]|0;if(f|0){if(a[b+108>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[b+104>>2]=0}a[b+108>>0]=1;c[b+104>>2]=g;c[b+100>>2]=i;f=c[b+96>>2]|0}k=(c[b+104>>2]|0)+(f<<4)|0;c[k>>2]=c[d>>2];c[k+4>>2]=c[d+4>>2];c[k+8>>2]=c[d+8>>2];c[k+12>>2]=c[d+12>>2];c[b+96>>2]=(c[b+96>>2]|0)+1;if(!e)return;ej(b);return}function gi(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;i=c[d+4>>2]|0;f=c[b+24>>2]|0;if((f|0)<(i|0)){if((c[b+28>>2]|0)<(i|0)){if(!i){g=f;h=0}else{c[6432]=(c[6432]|0)+1;e=ec((i<<2|3)+16|0)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}g=c[b+24>>2]|0;h=e}if((g|0)>0){e=0;do{c[h+(e<<2)>>2]=c[(c[b+32>>2]|0)+(e<<2)>>2];e=e+1|0}while((e|0)!=(g|0))}e=c[b+32>>2]|0;if(e|0){if(a[b+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}c[b+32>>2]=0}a[b+36>>0]=1;c[b+32>>2]=h;c[b+28>>2]=i;e=b+32|0}else e=b+32|0;do{c[(c[e>>2]|0)+(f<<2)>>2]=0;f=f+1|0}while((f|0)!=(i|0))}else e=b+32|0;c[b+24>>2]=i;e=c[e>>2]|0;if((i|0)<=0)return;f=0;do{c[e+(f<<2)>>2]=c[(c[d+12>>2]|0)+(f<<2)>>2];f=f+1|0}while((f|0)!=(i|0));return}function hi(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=l;l=l+96|0;b=c[b>>2]|0;if((b|0)==(c[a+4>>2]|0)){l=d;return 1}e=c[a+12>>2]|0;if(!(Gb[c[(c[e>>2]|0)+8>>2]&31](e,c[b+188>>2]|0)|0)){l=d;return 1}e=c[a+4>>2]|0;f=c[e+192>>2]|0;c[d+64>>2]=0;c[d+64+4>>2]=f;c[d+64+8>>2]=e;c[d+64+12>>2]=e+4;c[d+64+16>>2]=-1;c[d+64+20>>2]=-1;e=c[b+192>>2]|0;c[d+40>>2]=0;c[d+40+4>>2]=e;c[d+40+8>>2]=b;c[d+40+12>>2]=b+4;c[d+40+16>>2]=-1;c[d+40+20>>2]=-1;b=c[(c[a+8>>2]|0)+24>>2]|0;b=pb[c[(c[b>>2]|0)+8>>2]&31](b,d+64|0,d+40|0,0)|0;if(b|0){f=c[a+12>>2]|0;c[d+4>>2]=0;c[d+8>>2]=d+64;c[d+12>>2]=d+40;c[d>>2]=6100;c[d+32>>2]=f;fb[c[(c[b>>2]|0)+8>>2]&31](b,d+64|0,d+40|0,(c[a+8>>2]|0)+28|0,d);hb[c[c[b>>2]>>2]&511](b);f=c[(c[a+8>>2]|0)+24>>2]|0;jb[c[(c[f>>2]|0)+60>>2]&127](f,b)}l=d;return 1}function ii(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0,h=0,i=0,j=0,k=0;k=l;l=l+80|0;h=c[c[a>>2]>>2]|0;i=c[c[a+4>>2]>>2]|0;if(!(vb[c[(c[b>>2]|0)+24>>2]&63](b,h,i)|0)){l=k;return}f=c[h+192>>2]|0;c[k+56>>2]=0;c[k+56+4>>2]=f;c[k+56+8>>2]=h;c[k+56+12>>2]=h+4;c[k+56+16>>2]=-1;c[k+56+20>>2]=-1;f=c[i+192>>2]|0;c[k+32>>2]=0;c[k+32+4>>2]=f;c[k+32+8>>2]=i;c[k+32+12>>2]=i+4;c[k+32+16>>2]=-1;c[k+32+20>>2]=-1;f=c[a+8>>2]|0;if(!f){f=pb[c[(c[b>>2]|0)+8>>2]&31](b,k+56|0,k+32|0,0)|0;c[a+8>>2]=f;if(f|0)j=4}else j=4;if((j|0)==4){c[k>>2]=5728;c[k+4>>2]=0;c[k+8>>2]=k+56;c[k+12>>2]=k+32;if((c[d+8>>2]|0)!=1){e=+tb[c[(c[f>>2]|0)+12>>2]&15](f,h,i,d,k);if(+g[d+12>>2]>e)g[d+12>>2]=e}else fb[c[(c[f>>2]|0)+8>>2]&31](f,k+56|0,k+32|0,d,k)}l=k;return}function ji(a,b,c,d,e,f,h,i,j,k,l){a=a|0;b=b|0;c=+c;d=+d;e=+e;f=+f;h=+h;i=+i;j=j|0;k=k|0;l=+l;var m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0;x=+g[a>>2]*f+ +g[a+16>>2]*h+ +g[a+32>>2]*i;v=+g[a+4>>2]*f+ +g[a+20>>2]*h+ +g[a+36>>2]*i;t=+g[a+8>>2]*f+ +g[a+24>>2]*h+ +g[a+40>>2]*i;s=+g[b>>2]*f+ +g[b+16>>2]*h+ +g[b+32>>2]*i;q=+g[b+4>>2]*f+ +g[b+20>>2]*h+ +g[b+36>>2]*i;o=+g[b+8>>2]*f+ +g[b+24>>2]*h+ +g[b+40>>2]*i;w=+g[j+80>>2];u=+g[j+84>>2];p=+g[j+88>>2];r=+g[k+80>>2];m=+g[k+84>>2];n=+g[k+88>>2];p=x*(x<0.0?-w:w)+v*(v<0.0?-u:u)+t*(t<0.0?-p:p);n=s*(s<0.0?-r:r)+q*(q<0.0?-m:m)+o*(o<0.0?-n:n);o=+g[j+96>>2];m=+g[k+96>>2];m=(p>o?p:o)+(n>m?n:m);return !((c*f+d*h+e*i+m<m-(c*f+d*h+e*i)?c*f+d*h+e*i+m:m-(c*f+d*h+e*i))>l)|0}function ki(b){b=b|0;var d=0,e=0,f=0,g=0;c[b>>2]=8848;a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;c[b+12>>2]=0;c[b+24>>2]=0;a[b+28>>0]=0;a[b+48>>0]=1;c[b+44>>2]=0;c[b+36>>2]=0;c[b+40>>2]=0;a[b+68>>0]=1;c[b+64>>2]=0;c[b+56>>2]=0;c[b+60>>2]=0;c[b+72>>2]=0;c[6432]=(c[6432]|0)+1;d=ec(51)|0;if(!d)f=0;else{c[(d+4+15&-16)+-4>>2]=d;f=d+4+15&-16}d=c[b+8>>2]|0;if((d|0)>0){e=0;do{g=c[b+16>>2]|0;c[f+(e<<4)>>2]=c[g+(e<<4)>>2];c[f+(e<<4)+4>>2]=c[g+(e<<4)+4>>2];c[f+(e<<4)+8>>2]=c[g+(e<<4)+8>>2];c[f+(e<<4)+12>>2]=c[g+(e<<4)+12>>2];e=e+1|0}while((e|0)!=(d|0))}d=c[b+16>>2]|0;if(!d){a[b+20>>0]=1;c[b+16>>2]=f;c[b+12>>2]=2;sf(b);return}if(a[b+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+16>>2]=0;a[b+20>>0]=1;c[b+16>>2]=f;c[b+12>>2]=2;sf(b);return}function li(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0;while(1){n=c[a+12>>2]|0;m=c[n+(((b+d|0)/2|0)<<2)>>2]|0;f=b;e=d;while(1){l=c[m+740>>2]|0;l=c[((c[l+208>>2]|0)>-1?l:c[m+744>>2]|0)+208>>2]|0;while(1){i=n+(f<<2)|0;h=c[i>>2]|0;k=c[h+740>>2]|0;j=f+1|0;if((c[((c[k+208>>2]|0)>-1?k:c[h+744>>2]|0)+208>>2]|0)<(l|0))f=j;else{k=e;break}}while(1){g=c[n+(k<<2)>>2]|0;o=c[g+740>>2]|0;e=k+-1|0;if((l|0)<(c[((c[o+208>>2]|0)>-1?o:c[g+744>>2]|0)+208>>2]|0))k=e;else break}if((f|0)>(k|0))e=k;else{c[i>>2]=g;c[(c[a+12>>2]|0)+(k<<2)>>2]=h;f=j}if((f|0)>(e|0))break;n=c[a+12>>2]|0}if((e|0)>(b|0))li(a,b,e);if((f|0)<(d|0))b=f;else break}return}function mi(a,b,d){a=a|0;b=b|0;d=d|0;do if(!((b|0)==32&(d|0)==32)){if((b|0)==32){if((d|0)<20){b=a+96|0;break}if((d+-21|0)>>>0<9){b=a+104|0;break}}else{if((b|0)<20&(d|0)==32){b=a+100|0;break}if((b+-21|0)>>>0<9&(d|0)==32){b=a+108|0;break}if((b|0)==8&(d|0)==8){b=a+60|0;break}if((b|0)==8&(d|0)==1){b=a+76|0;break}if((b|0)==1&(d|0)==8){b=a+80|0;break}}if(!(d|b)){b=a+72|0;break}if((b|0)<20&(d|0)==28){b=a+88|0;break}if((b|0)==28&(d|0)<20){b=a+84|0;break}if((b|0)<20){if((d|0)<20){b=a+32|0;break}if((d+-21|0)>>>0<9){b=a+36|0;break}}else{if((d|0)<20&(b+-21|0)>>>0<9){b=a+40|0;break}if((b|0)==31)if((d|0)==31){b=a+48|0;break}else{b=a+44|0;break}}if((d|0)==31){b=a+52|0;break}else{b=a+56|0;break}}else b=a+92|0;while(0);return c[b>>2]|0}function ni(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=c[b+488>>2]|0;a:do if((e|0)>0){g=c[b+496>>2]|0;f=0;while(1){if((c[g+(f<<2)>>2]|0)==(d|0))break;f=f+1|0;if((f|0)>=(e|0))break a}if((f|0)!=(e|0)){b=b+256|0;c[b>>2]=1;return}}while(0);if((e|0)==(c[b+492>>2]|0)?(h=e|0?e<<1:1,(e|0)<(h|0)):0){if(!h)f=0;else{c[6432]=(c[6432]|0)+1;e=ec((h<<2|3)+16|0)|0;if(!e)f=0;else{c[(e+4+15&-16)+-4>>2]=e;f=e+4+15&-16}e=c[b+488>>2]|0}if((e|0)>0){g=0;do{c[f+(g<<2)>>2]=c[(c[b+496>>2]|0)+(g<<2)>>2];g=g+1|0}while((g|0)!=(e|0))}g=c[b+496>>2]|0;if(g){if(a[b+500>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[g+-4>>2]|0);e=c[b+488>>2]|0}c[b+496>>2]=0}a[b+500>>0]=1;c[b+496>>2]=f;c[b+492>>2]=h}c[(c[b+496>>2]|0)+(e<<2)>>2]=d;c[b+488>>2]=e+1;b=b+256|0;c[b>>2]=1;return}function oi(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0.0,i=0.0,j=0.0,k=0.0,l=0,m=0,n=0.0,o=0.0,p=0.0,q=0,r=0,s=0.0,t=0;if((e|0)>0)f=0;else return;do{g[d+(f<<4)+12>>2]=-999999984306749440.0;f=f+1|0}while((f|0)!=(e|0));r=0;do{i=+g[a+12>>2];n=+g[b+(r<<4)>>2]*i;j=+g[a+16>>2];p=+g[b+(r<<4)+4>>2]*j;k=+g[a+20>>2];o=+g[b+(r<<4)+8>>2]*k;f=c[a+96>>2]|0;if((f|0)>0){l=c[a+104>>2]|0;m=0;h=-3402823466385288598117041.0e14;q=-1;do{s=n*+g[l+(m<<4)>>2]+p*+g[l+(m<<4)+4>>2]+o*+g[l+(m<<4)+8>>2];t=s>h;q=t?m:q;h=t?s:h;m=m+1|0}while((m|0)!=(f|0));p=+g[l+(q<<4)+4>>2]*j;s=+g[l+(q<<4)+8>>2]*k;g[d+(r<<4)>>2]=+g[l+(q<<4)>>2]*i;g[d+(r<<4)+4>>2]=p;g[d+(r<<4)+8>>2]=s}else h=-999999984306749440.0;g[d+(r<<4)+12>>2]=h;r=r+1|0}while((r|0)!=(e|0));return}function pi(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0;while(1){n=c[a+12>>2]|0;m=c[n+(((b+d|0)/2|0)<<2)>>2]|0;f=b;e=d;while(1){l=c[m+28>>2]|0;l=c[((c[l+208>>2]|0)>-1?l:c[m+32>>2]|0)+208>>2]|0;while(1){i=n+(f<<2)|0;h=c[i>>2]|0;k=c[h+28>>2]|0;j=f+1|0;if((c[((c[k+208>>2]|0)>-1?k:c[h+32>>2]|0)+208>>2]|0)<(l|0))f=j;else{k=e;break}}while(1){g=c[n+(k<<2)>>2]|0;o=c[g+28>>2]|0;e=k+-1|0;if((l|0)<(c[((c[o+208>>2]|0)>-1?o:c[g+32>>2]|0)+208>>2]|0))k=e;else break}if((f|0)>(k|0))e=k;else{c[i>>2]=g;c[(c[a+12>>2]|0)+(k<<2)>>2]=h;f=j}if((f|0)>(e|0))break;n=c[a+12>>2]|0}if((e|0)>(b|0))pi(a,b,e);if((f|0)<(d|0))b=f;else break}return}function qi(b){b=b|0;var d=0;d=Or(616)|0;c[d+164>>2]=1065353216;c[d+168>>2]=1065353216;c[d+172>>2]=1065353216;g[d+176>>2]=0.0;c[d+180>>2]=0;g[d+184>>2]=999999984306749440.0;c[d+188>>2]=0;c[d+188+4>>2]=0;c[d+188+8>>2]=0;c[d+188+12>>2]=0;c[d+204>>2]=1;c[d+208>>2]=-1;c[d+212>>2]=-1;c[d+216>>2]=1;g[d+220>>2]=0.0;g[d+224>>2]=.5;g[d+228>>2]=0.0;g[d+232>>2]=0.0;c[d+236>>2]=1;c[d+240>>2]=0;g[d+244>>2]=1.0;c[d+248>>2]=0;c[d+248+4>>2]=0;c[d+248+8>>2]=0;c[d+248+12>>2]=0;c[d+4>>2]=1065353216;c[d+8>>2]=0;c[d+8+4>>2]=0;c[d+8+8>>2]=0;c[d+8+12>>2]=0;c[d+24>>2]=1065353216;c[d+28>>2]=0;c[d+28+4>>2]=0;c[d+28+8>>2]=0;c[d+28+12>>2]=0;c[d+44>>2]=1065353216;c[d+48>>2]=0;c[d+48+4>>2]=0;c[d+48+8>>2]=0;c[d+48+12>>2]=0;c[d+48+16>>2]=0;c[d>>2]=4236;a[d+500>>0]=1;c[d+496>>2]=0;c[d+488>>2]=0;c[d+492>>2]=0;sd(d,b);return d|0}function ri(a,b,d,e,f,h,i,j,k){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;j=j|0;k=k|0;var m=0,n=0,o=0;o=l;l=l+16|0;Yi(12944);Eb[c[(c[a>>2]|0)+32>>2]&1](a,b,d,e,f,h,i,j,k);n=c[a+184>>2]|0;m=c[j+20>>2]|0;m=(n|0)>(m|0)?n:m;if((m|0)>0){n=0;do{+Ib[c[(c[a>>2]|0)+40>>2]&3](a,n,b,d,e,f,h,i,j,k);n=n+1|0}while((n|0)<(m|0))}m=c[2395]|0;a=(c[m+16>>2]|0)+-1|0;c[m+16>>2]=a;if(a|0){l=o;return 0.0}do if(c[m+4>>2]|0){Va(o|0,0)|0;a=c[6431]|0;g[m+8>>2]=+g[m+8>>2]+ +(((c[o+4>>2]|0)-(c[a+4>>2]|0)+(((c[o>>2]|0)-(c[a>>2]|0)|0)*1e6|0)-(c[m+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[m+16>>2]|0)){m=c[2395]|0;break}else{l=o;return 0.0}}while(0);c[2395]=c[m+20>>2];l=o;return 0.0}function si(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;g=c[d>>2]|0;d=c[b+268>>2]|0;a:do if((d|0)>0){f=c[b+276>>2]|0;e=0;while(1){if((c[f+(e<<2)>>2]|0)==(g|0))break;e=e+1|0;if((e|0)>=(d|0))break a}if((e|0)!=(d|0))return}while(0);if((d|0)==(c[b+272>>2]|0)?(h=d|0?d<<1:1,(d|0)<(h|0)):0){if(!h)f=0;else{c[6432]=(c[6432]|0)+1;d=ec((h<<2|3)+16|0)|0;if(!d)d=0;else{c[(d+4+15&-16)+-4>>2]=d;d=d+4+15&-16}f=d;d=c[b+268>>2]|0}if((d|0)>0){e=0;do{c[f+(e<<2)>>2]=c[(c[b+276>>2]|0)+(e<<2)>>2];e=e+1|0}while((e|0)!=(d|0))}e=c[b+276>>2]|0;if(e){if(a[b+280>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0);d=c[b+268>>2]|0}c[b+276>>2]=0}a[b+280>>0]=1;c[b+276>>2]=f;c[b+272>>2]=h}c[(c[b+276>>2]|0)+(d<<2)>>2]=g;c[b+268>>2]=d+1;return}function ti(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;f=c[a+232>>2]|0;a:do if((f|0)>0){g=c[a+240>>2]|0;d=0;while(1){e=g+(d<<2)|0;if((c[e>>2]|0)==(b|0))break;d=d+1|0;if((d|0)>=(f|0))break a}if((d|0)<(f|0)){c[e>>2]=c[g+(f+-1<<2)>>2];c[(c[a+240>>2]|0)+(f+-1<<2)>>2]=b;c[a+232>>2]=f+-1}}while(0);d=c[b+188>>2]|0;if(d|0){g=c[a+68>>2]|0;g=lb[c[(c[g>>2]|0)+36>>2]&127](g)|0;Rb[c[(c[g>>2]|0)+40>>2]&127](g,d,c[a+24>>2]|0);g=c[a+68>>2]|0;Rb[c[(c[g>>2]|0)+12>>2]&127](g,d,c[a+24>>2]|0);c[b+188>>2]=0}f=c[a+8>>2]|0;if((f|0)<=0)return;g=c[a+16>>2]|0;d=0;while(1){e=g+(d<<2)|0;if((c[e>>2]|0)==(b|0))break;d=d+1|0;if((d|0)>=(f|0)){h=15;break}}if((h|0)==15)return;if((d|0)>=(f|0))return;c[e>>2]=c[g+(f+-1<<2)>>2];c[(c[a+16>>2]|0)+(f+-1<<2)>>2]=b;c[a+8>>2]=f+-1;return}function ui(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;f=c[a+328>>2]|0;a:do if((f|0)>0){g=c[a+336>>2]|0;d=0;while(1){e=g+(d<<2)|0;if((c[e>>2]|0)==(b|0))break;d=d+1|0;if((d|0)>=(f|0))break a}if((d|0)<(f|0)){c[e>>2]=c[g+(f+-1<<2)>>2];c[(c[a+336>>2]|0)+(f+-1<<2)>>2]=b;c[a+328>>2]=f+-1}}while(0);d=c[b+188>>2]|0;if(d|0){g=c[a+68>>2]|0;g=lb[c[(c[g>>2]|0)+36>>2]&127](g)|0;Rb[c[(c[g>>2]|0)+40>>2]&127](g,d,c[a+24>>2]|0);g=c[a+68>>2]|0;Rb[c[(c[g>>2]|0)+12>>2]&127](g,d,c[a+24>>2]|0);c[b+188>>2]=0}f=c[a+8>>2]|0;if((f|0)<=0)return;g=c[a+16>>2]|0;d=0;while(1){e=g+(d<<2)|0;if((c[e>>2]|0)==(b|0))break;d=d+1|0;if((d|0)>=(f|0)){h=15;break}}if((h|0)==15)return;if((d|0)>=(f|0))return;c[e>>2]=c[g+(f+-1<<2)>>2];c[(c[a+16>>2]|0)+(f+-1<<2)>>2]=b;c[a+8>>2]=f+-1;return}function vi(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0;i=c[d>>2]|0;i=Gb[c[(c[i>>2]|0)+56>>2]&31](i,28)|0;j=(a[b+4>>0]|0)==0;h=c[b+8>>2]|0;g=c[b+12>>2]|0;c[i>>2]=9172;b=c[d>>2]|0;c[i+4>>2]=b;c[i>>2]=5604;a[i+8>>0]=0;c[i+12>>2]=0;if(j){a[i+16>>0]=0;c[i+20>>2]=h;c[i+24>>2]=g;if(!(vb[c[(c[b>>2]|0)+24>>2]&63](b,c[e+8>>2]|0,c[f+8>>2]|0)|0))return i|0;j=c[i+4>>2]|0;c[i+12>>2]=vb[c[(c[j>>2]|0)+12>>2]&63](j,c[e+8>>2]|0,c[f+8>>2]|0)|0;a[i+8>>0]=1;return i|0}else{a[i+16>>0]=1;c[i+20>>2]=h;c[i+24>>2]=g;if(!(vb[c[(c[b>>2]|0)+24>>2]&63](b,c[f+8>>2]|0,c[e+8>>2]|0)|0))return i|0;j=c[i+4>>2]|0;c[i+12>>2]=vb[c[(c[j>>2]|0)+12>>2]&63](j,c[f+8>>2]|0,c[e+8>>2]|0)|0;a[i+8>>0]=1;return i|0}return 0}function wi(b,d,e,f,g){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0;do if(!(HB(b,c[d+8>>2]|0)|0)){if(!(HB(b,c[d>>2]|0)|0)){h=c[b+8>>2]|0;fb[c[(c[h>>2]|0)+24>>2]&31](h,d,e,f,g);break}if((c[d+16>>2]|0)!=(e|0)?(c[d+20>>2]|0)!=(e|0):0){c[d+32>>2]=f;if((c[d+44>>2]|0)==4)break;a[d+52>>0]=0;a[d+53>>0]=0;b=c[b+8>>2]|0;xb[c[(c[b>>2]|0)+20>>2]&7](b,d,e,e,1,g);if(a[d+53>>0]|0)if(!(a[d+52>>0]|0)){f=3;h=11}else f=3;else{f=4;h=11}if((h|0)==11){c[d+20>>2]=e;c[d+40>>2]=(c[d+40>>2]|0)+1;if((c[d+36>>2]|0)==1?(c[d+24>>2]|0)==2:0)a[d+54>>0]=1}c[d+44>>2]=f;break}if((f|0)==1)c[d+32>>2]=1}else rr(d,e,f);while(0);return}function xi(a,b,d){a=a|0;b=+b;d=d|0;var e=0,f=0,h=0,i=0,k=0.0,m=0.0,n=0.0;i=l;l=l+16|0;c[i>>2]=c[a+28>>2];c[i+4>>2]=c[a+28+4>>2];c[i+8>>2]=c[a+28+8>>2];c[i+12>>2]=c[a+28+12>>2];n=+zb[c[(c[a>>2]|0)+48>>2]&15](a);m=+zb[c[(c[a>>2]|0)+48>>2]&15](a);k=+zb[c[(c[a>>2]|0)+48>>2]&15](a);g[i>>2]=n+ +g[i>>2];g[i+4>>2]=m+ +g[i+4>>2];g[i+8>>2]=k+ +g[i+8>>2];f=c[a+52>>2]|0;switch(f|0){case 0:{a=0;e=1;break}case 2:{a=2;e=0;break}default:{a=1;e=0}}n=+g[i+(e<<2)>>2];m=+g[i+(a<<2)>>2];h=(g[j>>2]=b*.25*n*n+b/12.0*m*m*4.0,c[j>>2]|0);a=(g[j>>2]=b*.5*n*n,c[j>>2]|0);switch(f|0){case 0:{e=h;f=h;break}case 2:{e=a;f=h;a=h;break}default:{e=h;f=a;a=h}}c[d>>2]=a;c[d+4>>2]=f;c[d+8>>2]=e;g[d+12>>2]=0.0;l=i;return}function yi(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;c[a>>2]=3980;if((c[a+104>>2]|0)<=0){a=a+60|0;Qi(a);Ui(a);return}k=0;do{g=c[(c[a+4>>2]|0)+684>>2]|0;j=(c[a+112>>2]|0)+(k<<3)+4|0;b=c[j>>2]|0;if((c[g+60>>2]|0)>0){i=0;do{h=(c[g+68>>2]|0)+(i<<2)|0;d=c[h>>2]|0;a:do if(d|0){e=0;do{f=e|0?e+280|0:h;e=d;while(1){d=c[e+280>>2]|0;if((c[e+276>>2]|0)!=(b|0))break;c[f>>2]=d;YG(e);if(!d)break a;else e=d}}while((d|0)!=0)}while(0);i=i+1|0}while((i|0)<(c[g+60>>2]|0));b=c[j>>2]|0}if(b|0)hb[c[(c[b>>2]|0)+4>>2]&511](b);k=k+1|0}while((k|0)<(c[a+104>>2]|0));a=a+60|0;Qi(a);Ui(a);return}function zi(b){b=b|0;var d=0,e=0;d=c[b+92>>2]|0;if(d|0){if(a[b+96>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+92>>2]=0}a[b+96>>0]=1;c[b+92>>2]=0;c[b+84>>2]=0;c[b+88>>2]=0;d=c[b+64>>2]|0;if(d|0)do{c[b+64>>2]=c[d+8>>2];e=c[d>>2]|0;if(e|0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0);d=c[b+64>>2]|0}while((d|0)!=0);d=c[b+48>>2]|0;if(d|0)do{c[b+48>>2]=c[d+8>>2];e=c[d>>2]|0;if(e|0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0);d=c[b+48>>2]|0}while((d|0)!=0);d=c[b+32>>2]|0;if(!d)return;do{c[b+32>>2]=c[d+8>>2];e=c[d>>2]|0;if(e|0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0);d=c[b+32>>2]|0}while((d|0)!=0);return}function Ai(b,d,e,f,g,h){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var i=0,j=0,k=0,l=0;if(HB(b,c[d+8>>2]|0)|0)Wk(d,e,f,g);else{i=a[d+52>>0]|0;j=a[d+53>>0]|0;k=c[b+12>>2]|0;a[d+52>>0]=0;a[d+53>>0]=0;nn(b+16|0,d,e,f,g,h);a:do if((k|0)>1){l=b+24|0;do{if(a[d+54>>0]|0)break a;if(!(a[d+52>>0]|0)){if(a[d+53>>0]|0?(c[b+8>>2]&1|0)==0:0)break a}else{if((c[d+24>>2]|0)==1)break a;if(!(c[b+8>>2]&2))break a}a[d+52>>0]=0;a[d+53>>0]=0;nn(l,d,e,f,g,h);l=l+8|0}while(l>>>0<(b+16+(k<<3)|0)>>>0)}while(0);a[d+52>>0]=i;a[d+53>>0]=j}return}function Bi(){var b=0;b=Or(284)|0;c[b+164>>2]=1065353216;c[b+168>>2]=1065353216;c[b+172>>2]=1065353216;g[b+176>>2]=0.0;c[b+180>>2]=0;g[b+184>>2]=999999984306749440.0;c[b+188>>2]=0;c[b+188+4>>2]=0;c[b+188+8>>2]=0;c[b+188+12>>2]=0;c[b+204>>2]=1;c[b+208>>2]=-1;c[b+212>>2]=-1;c[b+216>>2]=1;g[b+220>>2]=0.0;g[b+224>>2]=.5;g[b+228>>2]=0.0;g[b+232>>2]=0.0;c[b+240>>2]=0;g[b+244>>2]=1.0;c[b+248>>2]=0;c[b+248+4>>2]=0;c[b+248+8>>2]=0;c[b+248+12>>2]=0;c[b+4>>2]=1065353216;c[b+8>>2]=0;c[b+8+4>>2]=0;c[b+8+8>>2]=0;c[b+8+12>>2]=0;c[b+24>>2]=1065353216;c[b+28>>2]=0;c[b+28+4>>2]=0;c[b+28+8>>2]=0;c[b+28+12>>2]=0;c[b+44>>2]=1065353216;c[b+48>>2]=0;c[b+48+4>>2]=0;c[b+48+8>>2]=0;c[b+48+12>>2]=0;c[b+48+16>>2]=0;c[b>>2]=5168;a[b+280>>0]=1;c[b+276>>2]=0;c[b+268>>2]=0;c[b+272>>2]=0;c[b+236>>2]=4;return b|0}function Ci(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;n=(c[b>>2]|0)+1794895138|0;f=Hz(c[b+8>>2]|0,n)|0;l=Hz(c[b+12>>2]|0,n)|0;m=Hz(c[b+16>>2]|0,n)|0;a:do if((f>>>0<d>>>2>>>0?l>>>0<(d-(f<<2)|0)>>>0&m>>>0<(d-(f<<2)|0)>>>0:0)?((m|l)&3|0)==0:0){k=0;while(1){i=f>>>1;j=k+i|0;g=Hz(c[b+((j<<1)+(l>>>2)<<2)>>2]|0,n)|0;h=Hz(c[b+((j<<1)+(l>>>2)+1<<2)>>2]|0,n)|0;if(!(h>>>0<d>>>0&g>>>0<(d-h|0)>>>0)){f=0;break a}if(a[b+(h+g)>>0]|0){f=0;break a}g=po(e,b+h|0)|0;if(!g)break;if((f|0)==1){f=0;break a}else{k=(g|0)<0?k:j;f=(g|0)<0?i:f-i|0}}g=Hz(c[b+((j<<1)+(m>>>2)<<2)>>2]|0,n)|0;f=Hz(c[b+((j<<1)+(m>>>2)+1<<2)>>2]|0,n)|0;if(f>>>0<d>>>0&g>>>0<(d-f|0)>>>0)f=(a[b+(f+g)>>0]|0)==0?b+f|0:0;else f=0}else f=0;while(0);return f|0}function Di(b,d){b=b|0;d=d|0;var e=0,f=0,h=0,i=0.0,j=0.0,k=0,m=0;f=l;l=l+48|0;if((c[b+136>>2]|0)<=0){l=f;return}e=0;do{m=c[b+144>>2]|0;c[f+32>>2]=(a[m+(e*284|0)+84>>0]|0)==0?1065353216:0;c[f+32+4>>2]=0;c[f+32+8>>2]=1065353216;g[f+32+12>>2]=0.0;k=m+(e*284|0)+140|0;c[f+16>>2]=c[k>>2];c[f+16+4>>2]=c[k+4>>2];c[f+16+8>>2]=c[k+8>>2];c[f+16+12>>2]=c[k+12>>2];k=c[b+120>>2]|0;h=c[(c[d>>2]|0)+8>>2]|0;j=+g[m+(e*284|0)+108+(k<<2)>>2]+ +g[f+16+4>>2];i=+g[m+(e*284|0)+124+(k<<2)>>2]+ +g[f+16+8>>2];g[f>>2]=+g[m+(e*284|0)+92+(k<<2)>>2]+ +g[f+16>>2];g[f+4>>2]=j;g[f+8>>2]=i;g[f+12>>2]=0.0;Vb[h&127](d,f+16|0,f,f+32|0);Vb[c[(c[d>>2]|0)+8>>2]&127](d,f+16|0,(c[b+144>>2]|0)+(e*284|0)+16|0,f+32|0);e=e+1|0}while((e|0)<(c[b+136>>2]|0));l=f;return}function Ei(a,b,d,e){a=a|0;b=b|0;d=+d;e=e|0;switch(b|0){case 2:{if((e|0)<1){g[a+232>>2]=d;c[a+300>>2]=c[a+300>>2]|512;return}if((e|0)<3){g[a+264>>2]=d;c[a+300>>2]=c[a+300>>2]|32;return}if((e|0)==3){g[a+248>>2]=d;c[a+300>>2]=c[a+300>>2]|2048;return}if((e|0)>=6)return;g[a+280>>2]=d;c[a+300>>2]=c[a+300>>2]|128;return}case 3:{if((e|0)<1){g[a+212>>2]=d;c[a+300>>2]=c[a+300>>2]|1;return}if((e|0)!=3)return;g[a+228>>2]=d;c[a+300>>2]=c[a+300>>2]|4;return}case 4:{if((e|0)<1){g[a+244>>2]=d;c[a+300>>2]=c[a+300>>2]|256;return}if((e|0)<3){g[a+276>>2]=d;c[a+300>>2]=c[a+300>>2]|16;return}if((e|0)==3){g[a+260>>2]=d;c[a+300>>2]=c[a+300>>2]|1024;return}if((e|0)>=6)return;g[a+292>>2]=d;c[a+300>>2]=c[a+300>>2]|64;return}default:return}}function Fi(a,b,d){a=a|0;b=+b;d=d|0;var e=0,f=0.0,h=0.0,i=0.0,j=0.0,k=0;e=l;l=l+96|0;c[e+32>>2]=1065353216;c[e+32+4>>2]=0;c[e+32+4+4>>2]=0;c[e+32+4+8>>2]=0;c[e+32+4+12>>2]=0;c[e+32+20>>2]=1065353216;c[e+32+24>>2]=0;c[e+32+24+4>>2]=0;c[e+32+24+8>>2]=0;c[e+32+24+12>>2]=0;c[e+32+40>>2]=1065353216;k=e+32+44|0;c[k>>2]=0;c[k+4>>2]=0;c[k+8>>2]=0;c[k+12>>2]=0;c[k+16>>2]=0;Vb[c[(c[a>>2]|0)+8>>2]&127](a,e+32|0,e+16|0,e);i=(+g[e>>2]-+g[e+16>>2])*.5;h=(+g[e+4>>2]-+g[e+16+4>>2])*.5;j=(+g[e+8>>2]-+g[e+16+8>>2])*.5;f=+zb[c[(c[a>>2]|0)+48>>2]&15](a);g[d>>2]=b*.0833333283662796*((h+f)*2.0*(h+f)*2.0+(j+f)*2.0*(j+f)*2.0);g[d+4>>2]=b*.0833333283662796*((i+f)*2.0*(i+f)*2.0+(j+f)*2.0*(j+f)*2.0);g[d+8>>2]=b*.0833333283662796*((i+f)*2.0*(i+f)*2.0+(h+f)*2.0*(h+f)*2.0);g[d+12>>2]=0.0;l=e;return}function Gi(){var b=0;b=es()|0;c[b>>2]=1025;c[b+116>>2]=0;a[b+120>>0]=0;c[b+124>>2]=0;c[b+124+4>>2]=0;c[b+124+8>>2]=0;c[b+124+12>>2]=0;c[b+124+16>>2]=0;c[b+124+20>>2]=0;c[b+124+24>>2]=0;c[b+124+28>>2]=0;c[b+300>>2]=0;a[b+304>>0]=0;c[b+308>>2]=0;c[b+308+4>>2]=0;c[b+308+8>>2]=0;c[b+308+12>>2]=0;c[b+308+16>>2]=0;c[b+308+20>>2]=0;c[b+308+24>>2]=0;c[b+308+28>>2]=0;c[b+484>>2]=0;a[b+488>>0]=0;c[b+492>>2]=0;c[b+492+4>>2]=0;c[b+492+8>>2]=0;c[b+492+12>>2]=0;c[b+492+16>>2]=0;c[b+492+20>>2]=0;c[b+492+24>>2]=0;c[b+492+28>>2]=0;c[b+668>>2]=0;a[b+672>>0]=0;c[b+676>>2]=0;c[b+676+4>>2]=0;c[b+676+8>>2]=0;c[b+676+12>>2]=0;c[b+676+16>>2]=0;c[b+676+20>>2]=0;c[b+676+24>>2]=0;c[b+676+28>>2]=0;c[b+740>>2]=0;c[b+744>>2]=0;c[b+748>>2]=0;c[b+768>>2]=0;return b|0}function Hi(b,d,e){b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0;if(!(a[b+84>>0]|0)){c[b+32>>2]=c[b+204>>2];g[b+272>>2]=0.0;o=-+g[b+56>>2];p=-+g[b+60>>2];g[b>>2]=-+g[b+52>>2];g[b+4>>2]=o;g[b+8>>2]=p;g[b+12>>2]=0.0;p=1.0;b=b+268|0;g[b>>2]=p;return}k=+g[b>>2];p=+g[b+4>>2];f=+g[b+8>>2];h=k*+g[b+52>>2]+p*+g[b+56>>2]+f*+g[b+60>>2];i=+g[b+16>>2]-+g[d+52>>2];j=+g[b+20>>2]-+g[d+56>>2];l=+g[b+24>>2]-+g[d+60>>2];m=+g[d+332>>2];n=+g[d+336>>2];o=+g[d+328>>2];if(!(h>=-.10000000149011612)){g[b+272>>2]=-1.0/h*(k*(m*l-j*n+ +g[d+312>>2])+p*(i*n-l*o+ +g[d+316>>2])+f*(j*o-i*m+ +g[d+320>>2]));p=-1.0/h;b=b+268|0;g[b>>2]=p;return}else{g[b+272>>2]=0.0;p=10.0;b=b+268|0;g[b>>2]=p;return}}function Ii(a,b,d,e,f,h,i,j,k,m){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;j=j|0;k=k|0;m=m|0;var n=0;n=l;l=l+16|0;Yi(13007);+Kb[c[(c[a>>2]|0)+44>>2]&3](a,b,d,e,f,h,i,j,k);+Kb[c[(c[a>>2]|0)+48>>2]&3](a,b,d,e,f,h,i,j,k);+Ob[c[(c[a>>2]|0)+36>>2]&1](a,b,d,j);m=c[2395]|0;a=(c[m+16>>2]|0)+-1|0;c[m+16>>2]=a;if(a|0){l=n;return 0.0}do if(c[m+4>>2]|0){Va(n|0,0)|0;a=c[6431]|0;g[m+8>>2]=+g[m+8>>2]+ +(((c[n+4>>2]|0)-(c[a+4>>2]|0)+(((c[n>>2]|0)-(c[a>>2]|0)|0)*1e6|0)-(c[m+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[m+16>>2]|0)){m=c[2395]|0;break}else{l=n;return 0.0}}while(0);c[2395]=c[m+20>>2];l=n;return 0.0}function Ji(a,b,c,d){a=a|0;b=b|0;c=c|0;d=+d;var e=0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0;e=l;l=l+96|0;j=+g[c>>2];k=+g[c+4>>2];m=+g[c+8>>2];Up(e+80|0,j,k,m,+dx(j,k,m,+g[b>>2],+g[b+4>>2],+g[b+8>>2]));m=+g[e+80>>2];k=+g[e+80+4>>2];j=+g[e+80+8>>2];rp(e+64|0,+g[b>>2],+g[b+4>>2],+g[b+8>>2],m,k,j);Fo(e+48|0,+g[c>>2],+g[c+4>>2],+g[c+8>>2],+g[b>>2],+g[b+4>>2],+g[b+8>>2]);i=+g[e+48>>2];h=+g[e+48+4>>2];f=+g[e+48+8>>2];n=+RG(d);Up(e+16|0,+g[e+64>>2],+g[e+64+4>>2],+g[e+64+8>>2],n);pp(e+32|0,m,k,j,+g[e+16>>2],+g[e+16+4>>2],+g[e+16+8>>2]);Up(e,i,h,f,+QG(d));pp(a,+g[e+32>>2],+g[e+32+4>>2],+g[e+32+8>>2],+g[e>>2],+g[e+4>>2],+g[e+8>>2]);l=e;return}function Ki(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0;e=c[a+4>>2]|0;if(e|0)Vk(e,b,d);e=c[a>>2]|0;if(!e)return;m=+g[b>>2];k=+g[e+128>>2];l=+g[b+4>>2];j=+g[b+8>>2];f=+g[d+4>>2];o=+g[d+8>>2];n=+g[d>>2];i=+g[e+180>>2]*(j*f-l*o)+ +g[e+184>>2]*(m*o-j*n)+(l*n-m*f)*+g[e+188>>2];h=(j*f-l*o)*+g[e+196>>2]+(m*o-j*n)*+g[e+200>>2]+(l*n-m*f)*+g[e+204>>2];f=(j*f-l*o)*+g[e+212>>2]+(m*o-j*n)*+g[e+216>>2]+(l*n-m*f)*+g[e+220>>2];g[e+276>>2]=m*k+ +g[e+276>>2];g[e+280>>2]=k*l+ +g[e+280>>2];g[e+284>>2]=k*j+ +g[e+284>>2];g[e+292>>2]=i+ +g[e+292>>2];g[e+296>>2]=h+ +g[e+296>>2];g[e+300>>2]=f+ +g[e+300>>2];c[e+312>>2]=(c[e+312>>2]|0)+1;return}function Li(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;f=c[b+212>>2]|0;if((f|0)==(c[b+216>>2]|0)?(i=f|0?f<<1:1,(f|0)<(i|0)):0){if(!i)g=0;else{c[6432]=(c[6432]|0)+1;f=ec((i<<2|3)+16|0)|0;if(!f)g=0;else{c[(f+4+15&-16)+-4>>2]=f;g=f+4+15&-16}f=c[b+212>>2]|0}if((f|0)>0){h=0;do{c[g+(h<<2)>>2]=c[(c[b+220>>2]|0)+(h<<2)>>2];h=h+1|0}while((h|0)!=(f|0))}h=c[b+220>>2]|0;if(h){if(a[b+224>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0);f=c[b+212>>2]|0}c[b+220>>2]=0}a[b+224>>0]=1;c[b+220>>2]=g;c[b+216>>2]=i}c[(c[b+220>>2]|0)+(f<<2)>>2]=d;c[b+212>>2]=f+1;if(!e)return;ni(c[d+28>>2]|0,d);ni(c[d+32>>2]|0,d);return}function Mi(a,b,c){a=a|0;b=b|0;c=c|0;var d=0.0,e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0;v=+g[a+552>>2];u=+g[a+568>>2];t=+g[a+584>>2];s=+g[b>>2];r=+g[b+4>>2];q=+g[b+8>>2];o=+g[b+16>>2];n=+g[b+20>>2];m=+g[b+24>>2];k=+g[b+32>>2];i=+g[b+36>>2];f=+g[b+40>>2];j=+g[a+556>>2];h=+g[a+572>>2];e=+g[a+588>>2];x=+g[a+620>>2];w=+g[a+636>>2];d=+g[a+652>>2];p=x*+g[c>>2]+w*+g[c+4>>2]+d*+g[c+8>>2];l=x*+g[c+16>>2]+w*+g[c+20>>2]+d*+g[c+24>>2];d=x*+g[c+32>>2]+w*+g[c+36>>2]+d*+g[c+40>>2];d=+K(+((v*s+u*r+t*q)*p+(v*o+u*n+t*m)*l+(v*k+u*i+t*f)*d),+((s*j+r*h+q*e)*p+(o*j+n*h+m*e)*l+(k*j+i*h+f*e)*d));return +(d*+g[a+732>>2])}function Ni(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;d=c[a+8>>2]|0;if((d|0)>0){f=0;do{e=c[(c[a+16>>2]|0)+(f<<2)>>2]|0;if(c[e+236>>2]&2){g=lb[c[(c[e>>2]|0)+16>>2]&127](e)|0;g=vb[c[(c[b>>2]|0)+16>>2]&63](b,g,1)|0;d=vb[c[(c[e>>2]|0)+20>>2]&63](e,c[g+8>>2]|0,b)|0;fb[c[(c[b>>2]|0)+20>>2]&31](b,g,d,1497645650,e);d=c[a+8>>2]|0}f=f+1|0}while((f|0)<(d|0))}if((c[a+212>>2]|0)<=0)return;d=0;do{g=c[(c[a+220>>2]|0)+(d<<2)>>2]|0;e=lb[c[(c[g>>2]|0)+36>>2]&127](g)|0;e=vb[c[(c[b>>2]|0)+16>>2]&63](b,e,1)|0;f=vb[c[(c[g>>2]|0)+40>>2]&63](g,c[e+8>>2]|0,b)|0;fb[c[(c[b>>2]|0)+20>>2]&31](b,e,f,1397641027,g);d=d+1|0}while((d|0)<(c[a+212>>2]|0));return}function Oi(a){a=a|0;var b=0.0,d=0,e=0,f=0,h=0;e=l;l=l+32|0;c[a+32>>2]=1566444395;c[a+36>>2]=1566444395;c[a+40>>2]=1566444395;g[a+44>>2]=0.0;c[a+48>>2]=-581039253;c[a+52>>2]=-581039253;c[a+56>>2]=-581039253;g[a+60>>2]=0.0;if((c[a+16>>2]|0)<=0){l=e;return}d=0;do{f=c[a+24>>2]|0;h=c[f+(d*80|0)+64>>2]|0;Vb[c[(c[h>>2]|0)+8>>2]&127](h,f+(d*80|0)|0,e+16|0,e);b=+g[e+16>>2];if(+g[a+32>>2]>b)g[a+32>>2]=b;b=+g[e>>2];if(+g[a+48>>2]<b)g[a+48>>2]=b;b=+g[e+16+4>>2];if(+g[a+36>>2]>b)g[a+36>>2]=b;b=+g[e+4>>2];if(+g[a+52>>2]<b)g[a+52>>2]=b;b=+g[e+16+8>>2];if(+g[a+40>>2]>b)g[a+40>>2]=b;b=+g[e+8>>2];if(+g[a+56>>2]<b)g[a+56>>2]=b;d=d+1|0}while((d|0)<(c[a+16>>2]|0));l=e;return}function Pi(d,e){d=d|0;e=e|0;var f=0,g=0,h=0,i=0;i=l;l=l+64|0;g=c[d>>2]|0;h=d+(c[g+-8>>2]|0)|0;g=c[g+-4>>2]|0;c[i>>2]=e;c[i+4>>2]=d;c[i+8>>2]=2760;e=HB(g,e)|0;d=i+12|0;f=d+40|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(f|0));b[i+12+40>>1]=0;a[i+12+42>>0]=0;a:do if(e){c[i+48>>2]=1;xb[c[(c[g>>2]|0)+20>>2]&7](g,i,h,h,1,0);e=(c[i+24>>2]|0)==1?h:0}else{fb[c[(c[g>>2]|0)+24>>2]&31](g,i,h,1,0);switch(c[i+36>>2]|0){case 0:{e=((c[i+40>>2]|0)==1?(c[i+28>>2]|0)==1:0)&(c[i+32>>2]|0)==1?c[i+20>>2]|0:0;break a}case 1:break;default:{e=0;break a}}if((c[i+24>>2]|0)!=1?!(((c[i+40>>2]|0)==0?(c[i+28>>2]|0)==1:0)&(c[i+32>>2]|0)==1):0){e=0;break}e=c[i+16>>2]|0}while(0);l=i;return e|0}function Qi(b){b=b|0;var d=0;d=c[b+12>>2]|0;if(d|0){if(a[b+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+12>>2]=0}a[b+16>>0]=1;c[b+12>>2]=0;c[b+4>>2]=0;c[b+8>>2]=0;d=c[b+32>>2]|0;if(d|0){if(a[b+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+32>>2]=0}a[b+36>>0]=1;c[b+32>>2]=0;c[b+24>>2]=0;c[b+28>>2]=0;d=c[b+52>>2]|0;if(d|0){if(a[b+56>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+52>>2]=0}a[b+56>>0]=1;c[b+52>>2]=0;c[b+44>>2]=0;c[b+48>>2]=0;d=c[b+72>>2]|0;if(!d){a[b+76>>0]=1;c[b+72>>2]=0;c[b+64>>2]=0;b=b+68|0;c[b>>2]=0;return}if(a[b+76>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+72>>2]=0;a[b+76>>0]=1;c[b+72>>2]=0;c[b+64>>2]=0;b=b+68|0;c[b>>2]=0;return}function Ri(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=c[b+12>>2]|0;if(!e)return;if(!(a[b+8>>0]|0))return;f=c[d+4>>2]|0;if((f|0)==(c[d+8>>2]|0)?(h=f|0?f<<1:1,(f|0)<(h|0)):0){if(!h){e=f;f=0}else{c[6432]=(c[6432]|0)+1;e=ec((h<<2|3)+16|0)|0;if(!e)f=0;else{c[(e+4+15&-16)+-4>>2]=e;f=e+4+15&-16}e=c[d+4>>2]|0}if((e|0)>0){g=0;do{c[f+(g<<2)>>2]=c[(c[d+12>>2]|0)+(g<<2)>>2];g=g+1|0}while((g|0)!=(e|0))}g=c[d+12>>2]|0;if(g){if(a[d+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[g+-4>>2]|0);e=c[d+4>>2]|0}c[d+12>>2]=0}a[d+16>>0]=1;c[d+12>>2]=f;c[d+8>>2]=h;f=e;e=c[b+12>>2]|0}c[(c[d+12>>2]|0)+(f<<2)>>2]=e;c[d+4>>2]=f+1;return}function Si(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=c[b+20>>2]|0;if(!e)return;if(!(a[b+16>>0]|0))return;f=c[d+4>>2]|0;if((f|0)==(c[d+8>>2]|0)?(h=f|0?f<<1:1,(f|0)<(h|0)):0){if(!h){e=f;f=0}else{c[6432]=(c[6432]|0)+1;e=ec((h<<2|3)+16|0)|0;if(!e)f=0;else{c[(e+4+15&-16)+-4>>2]=e;f=e+4+15&-16}e=c[d+4>>2]|0}if((e|0)>0){g=0;do{c[f+(g<<2)>>2]=c[(c[d+12>>2]|0)+(g<<2)>>2];g=g+1|0}while((g|0)!=(e|0))}g=c[d+12>>2]|0;if(g){if(a[d+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[g+-4>>2]|0);e=c[d+4>>2]|0}c[d+12>>2]=0}a[d+16>>0]=1;c[d+12>>2]=f;c[d+8>>2]=h;f=e;e=c[b+20>>2]|0}c[(c[d+12>>2]|0)+(f<<2)>>2]=e;c[d+4>>2]=f+1;return}function Ti(a,b,d){a=a|0;b=+b;d=d|0;var e=0,f=0.0,h=0.0,i=0.0,j=0;e=l;l=l+96|0;i=+zb[c[(c[a>>2]|0)+48>>2]&15](a);c[e+32>>2]=1065353216;c[e+32+4>>2]=0;c[e+32+4+4>>2]=0;c[e+32+4+8>>2]=0;c[e+32+4+12>>2]=0;c[e+32+20>>2]=1065353216;c[e+32+24>>2]=0;c[e+32+24+4>>2]=0;c[e+32+24+8>>2]=0;c[e+32+24+12>>2]=0;c[e+32+40>>2]=1065353216;j=e+32+44|0;c[j>>2]=0;c[j+4>>2]=0;c[j+8>>2]=0;c[j+12>>2]=0;c[j+16>>2]=0;Vb[c[(c[a>>2]|0)+8>>2]&127](a,e+32|0,e+16|0,e);h=(i+(+g[e>>2]-+g[e+16>>2])*.5)*2.0;f=(i+(+g[e+4>>2]-+g[e+16+4>>2])*.5)*2.0;i=(i+(+g[e+8>>2]-+g[e+16+8>>2])*.5)*2.0;g[d>>2]=b*.0833333283662796*(f*f+i*i);g[d+4>>2]=b*.0833333283662796*(h*h+i*i);g[d+8>>2]=b*.0833333283662796*(h*h+f*f);g[d+12>>2]=0.0;l=e;return}function Ui(b){b=b|0;var d=0;d=c[b+72>>2]|0;if(d|0){if(a[b+76>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+72>>2]=0}a[b+76>>0]=1;c[b+72>>2]=0;c[b+64>>2]=0;c[b+68>>2]=0;d=c[b+52>>2]|0;if(d|0){if(a[b+56>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+52>>2]=0}a[b+56>>0]=1;c[b+52>>2]=0;c[b+44>>2]=0;c[b+48>>2]=0;d=c[b+32>>2]|0;if(d|0){if(a[b+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+32>>2]=0}a[b+36>>0]=1;c[b+32>>2]=0;c[b+24>>2]=0;c[b+28>>2]=0;d=c[b+12>>2]|0;if(!d){a[b+16>>0]=1;c[b+12>>2]=0;c[b+4>>2]=0;b=b+8|0;c[b>>2]=0;return}if(a[b+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+12>>2]=0;a[b+16>>0]=1;c[b+12>>2]=0;c[b+4>>2]=0;b=b+8|0;c[b>>2]=0;return}function Vi(a,b){a=a|0;b=+b;var d=0,e=0,f=0,h=0.0,i=0.0,j=0.0,k=0,l=0,m=0,n=0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0;e=c[a+732>>2]|0;if((e|0)<=0)return;a=c[a+740>>2]|0;d=0;do{n=c[a+(d*52|0)+8>>2]|0;f=c[a+(d*52|0)+12>>2]|0;s=+g[n+40>>2];q=+g[n+44>>2];i=+g[n+48>>2];k=a+(d*52|0)+36|0;r=+g[k>>2];m=a+(d*52|0)+40|0;p=+g[m>>2];l=a+(d*52|0)+44|0;o=+g[l>>2];j=-(+g[a+(d*52|0)+32>>2]*((s-+g[f+40>>2])*r+(q-+g[f+44>>2])*p+(i-+g[f+48>>2])*o)*b);h=+g[n+88>>2]*j;g[n+40>>2]=s+r*h;g[n+44>>2]=q+p*h;g[n+48>>2]=o*h+i;j=+g[f+88>>2]*j;i=j*+g[m>>2];h=j*+g[l>>2];g[f+40>>2]=+g[f+40>>2]-+g[k>>2]*j;g[f+44>>2]=+g[f+44>>2]-i;g[f+48>>2]=+g[f+48>>2]-h;d=d+1|0}while((d|0)!=(e|0));return}function Wi(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0.0,j=0.0,k=0.0;j=+g[a+24>>2];k=+g[a+28>>2];i=+g[a+32>>2];f=j*+g[b>>2]+k*+g[b+4>>2]+i*+g[b+8>>2];h=+g[a+20>>2];if(f>h){g[a+20>>2]=f;c[a+4>>2]=c[b>>2];c[a+4+4>>2]=c[b+4>>2];c[a+4+8>>2]=c[b+8>>2];c[a+4+12>>2]=c[b+12>>2]}else f=h;h=j*+g[b+16>>2]+k*+g[b+20>>2]+i*+g[b+24>>2];if(h>f){g[a+20>>2]=h;c[a+4>>2]=c[b+16>>2];c[a+4+4>>2]=c[b+16+4>>2];c[a+4+8>>2]=c[b+16+8>>2];c[a+4+12>>2]=c[b+16+12>>2]}else h=f;f=j*+g[b+32>>2]+k*+g[b+36>>2]+i*+g[b+40>>2];if(!(f>h))return;g[a+20>>2]=f;c[a+4>>2]=c[b+32>>2];c[a+4+4>>2]=c[b+32+4>>2];c[a+4+8>>2]=c[b+32+8>>2];c[a+4+12>>2]=c[b+32+12>>2];return}function Xi(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0;g=c[b+328>>2]|0;if((g|0)==(c[b+332>>2]|0)?(j=g|0?g<<1:1,(g|0)<(j|0)):0){if(!j)h=0;else{c[6432]=(c[6432]|0)+1;g=ec((j<<2|3)+16|0)|0;if(!g)h=0;else{c[(g+4+15&-16)+-4>>2]=g;h=g+4+15&-16}g=c[b+328>>2]|0}if((g|0)>0){i=0;do{c[h+(i<<2)>>2]=c[(c[b+336>>2]|0)+(i<<2)>>2];i=i+1|0}while((i|0)!=(g|0))}i=c[b+336>>2]|0;if(i){if(a[b+340>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0);g=c[b+328>>2]|0}c[b+336>>2]=0}a[b+340>>0]=1;c[b+336>>2]=h;c[b+332>>2]=j}c[(c[b+336>>2]|0)+(g<<2)>>2]=d;c[b+328>>2]=g+1;c[d+284>>2]=c[b+452>>2];vg(b,d,e,f);return}function Yi(a){a=a|0;var b=0,d=0,e=0,f=0;f=l;l=l+16|0;b=c[2395]|0;if((c[b>>2]|0)!=(a|0)){d=c[b+24>>2]|0;a:do if(!d)e=5;else while(1){if((c[d>>2]|0)==(a|0)){b=d;break a}d=c[d+28>>2]|0;if(!d){e=5;break}}while(0);if((e|0)==5){e=Br(36)|0;c[e>>2]=a;c[e+4>>2]=0;c[e+4+4>>2]=0;c[e+4+8>>2]=0;c[e+4+12>>2]=0;c[e+20>>2]=b;c[e+24>>2]=0;c[e+28>>2]=0;c[e+32>>2]=0;Xq(e);c[e+28>>2]=c[b+24>>2];c[b+24>>2]=e;b=e}c[2395]=b}a=b+4|0;c[a>>2]=(c[a>>2]|0)+1;a=b+16|0;e=c[a>>2]|0;c[a>>2]=e+1;if(e|0){l=f;return}Va(f|0,0)|0;e=c[6431]|0;c[b+12>>2]=(c[f+4>>2]|0)-(c[e+4>>2]|0)+(((c[f>>2]|0)-(c[e>>2]|0)|0)*1e6|0);l=f;return}function Zi(b){b=b|0;var d=0;d=ns()|0;c[d+8>>2]=0;c[d>>2]=6416;a[d+28>>0]=1;c[d+24>>2]=0;c[d+16>>2]=0;c[d+20>>2]=0;c[d+32>>2]=1566444395;c[d+36>>2]=1566444395;c[d+40>>2]=1566444395;g[d+44>>2]=0.0;c[d+48>>2]=-581039253;c[d+52>>2]=-581039253;c[d+56>>2]=-581039253;g[d+60>>2]=0.0;c[d+64>>2]=0;c[d+68>>2]=1;g[d+72>>2]=0.0;c[d+76>>2]=1065353216;c[d+80>>2]=1065353216;c[d+84>>2]=1065353216;g[d+88>>2]=0.0;c[d+4>>2]=31;if(!b)return d|0;c[6432]=(c[6432]|0)+1;b=ec(79)|0;if(!b)b=0;else{c[(b+4+15&-16)+-4>>2]=b;b=b+4+15&-16}a[b+36>>0]=1;c[b+32>>2]=0;c[b+24>>2]=0;c[b+28>>2]=0;a[b+56>>0]=1;c[b+52>>2]=0;c[b+44>>2]=0;c[b+48>>2]=0;c[b>>2]=0;c[b+4>>2]=0;c[b+8>>2]=-1;c[b+12>>2]=0;c[b+16>>2]=0;c[d+64>>2]=b;return d|0}function _i(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=c[b+76>>2]|0;if(!e)return;f=c[d+4>>2]|0;if((f|0)==(c[d+8>>2]|0)?(h=f|0?f<<1:1,(f|0)<(h|0)):0){if(!h){e=f;f=0}else{c[6432]=(c[6432]|0)+1;e=ec((h<<2|3)+16|0)|0;if(!e)f=0;else{c[(e+4+15&-16)+-4>>2]=e;f=e+4+15&-16}e=c[d+4>>2]|0}if((e|0)>0){g=0;do{c[f+(g<<2)>>2]=c[(c[d+12>>2]|0)+(g<<2)>>2];g=g+1|0}while((g|0)!=(e|0))}g=c[d+12>>2]|0;if(g){if(a[d+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[g+-4>>2]|0);e=c[d+4>>2]|0}c[d+12>>2]=0}a[d+16>>0]=1;c[d+12>>2]=f;c[d+8>>2]=h;f=e;e=c[b+76>>2]|0}c[(c[d+12>>2]|0)+(f<<2)>>2]=e;c[d+4>>2]=f+1;return}function $i(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;while(1){k=c[a+12>>2]|0;j=c[k+(((b+d|0)/2|0)<<3)>>2]|0;e=b;f=d;while(1){while(1){h=e+1|0;if((c[k+(e<<3)>>2]|0)<(j|0))e=h;else{i=f;break}}while(1){g=k+(i<<3)|0;f=i+-1|0;if((j|0)<(c[g>>2]|0))i=f;else break}if((e|0)>(i|0))f=i;else{e=k+(e<<3)|0;l=c[e>>2]|0;k=c[e+4>>2]|0;m=c[g+4>>2]|0;c[e>>2]=c[g>>2];c[e+4>>2]=m;e=(c[a+12>>2]|0)+(i<<3)|0;c[e>>2]=l;c[e+4>>2]=k;e=h}if((e|0)>(f|0))break;k=c[a+12>>2]|0}if((f|0)>(b|0))$i(a,b,f);if((e|0)<(d|0))b=e;else break}return}function aj(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0;i=+zb[c[(c[a>>2]|0)+48>>2]&15](a);m=i+ +g[a+28>>2];k=i+ +g[a+32>>2];i=i+ +g[a+36>>2];u=+B(+(+g[b>>2]));t=+B(+(+g[b+4>>2]));s=+B(+(+g[b+8>>2]));q=+B(+(+g[b+16>>2]));p=+B(+(+g[b+20>>2]));o=+B(+(+g[b+24>>2]));l=+B(+(+g[b+32>>2]));j=+B(+(+g[b+36>>2]));h=+B(+(+g[b+40>>2]));r=+g[b+48>>2];n=+g[b+52>>2];f=+g[b+56>>2];g[d>>2]=r-(m*u+k*t+i*s);g[d+4>>2]=n-(m*q+k*p+i*o);g[d+8>>2]=f-(m*l+k*j+i*h);g[d+12>>2]=0.0;g[e>>2]=m*u+k*t+i*s+r;g[e+4>>2]=m*q+k*p+i*o+n;g[e+8>>2]=m*l+k*j+i*h+f;g[e+12>>2]=0.0;return}function bj(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0.0,j=0.0,k=0.0;i=+g[a+88>>2];j=+g[a+92>>2];k=+g[a+96>>2];h=i*+g[b>>2]+j*+g[b+4>>2]+k*+g[b+8>>2];f=+g[a+84>>2];if(h>f){g[a+84>>2]=h;c[a+4>>2]=c[b>>2];c[a+4+4>>2]=c[b+4>>2];c[a+4+8>>2]=c[b+8>>2];c[a+4+12>>2]=c[b+12>>2];f=h}h=i*+g[b+16>>2]+j*+g[b+20>>2]+k*+g[b+24>>2];if(h>f){g[a+84>>2]=h;c[a+4>>2]=c[b+16>>2];c[a+4+4>>2]=c[b+16+4>>2];c[a+4+8>>2]=c[b+16+8>>2];c[a+4+12>>2]=c[b+16+12>>2]}else h=f;f=i*+g[b+32>>2]+j*+g[b+36>>2]+k*+g[b+40>>2];if(!(f>h))return;g[a+84>>2]=f;c[a+4>>2]=c[b+32>>2];c[a+4+4>>2]=c[b+32+4>>2];c[a+4+8>>2]=c[b+32+8>>2];c[a+4+12>>2]=c[b+32+12>>2];return}function cj(a,c,d,e,f,h){a=a|0;c=c|0;d=+d;e=+e;f=+f;h=h|0;var i=0,j=0;d=(d-+g[a+8>>2])*+g[a+40>>2];e=(e-+g[a+12>>2])*+g[a+44>>2];f=(f-+g[a+16>>2])*+g[a+48>>2];do if(!(d<=0.0)){i=b[a+6>>1]|0;j=b[a+4>>1]|0;if(!(d>=+(i&65535))){i=j&(~~d&65535)&65535|h;break}else{i=j&i&65535|h;break}}else i=h;while(0);b[c>>1]=i;do if(!(e<=0.0)){i=b[a+6>>1]|0;j=b[a+4>>1]|0;if(!(e>=+(i&65535))){i=j&(~~e&65535)&65535|h;break}else{i=j&i&65535|h;break}}else i=h;while(0);b[c+2>>1]=i;if(f<=0.0){h=h&65535;c=c+4|0;b[c>>1]=h;return}j=b[a+6>>1]|0;i=b[a+4>>1]|0;if(!(f>=+(j&65535))){h=i&(~~f&65535)&65535|h;h=h&65535;c=c+4|0;b[c>>1]=h;return}else{h=i&j&65535|h;h=h&65535;c=c+4|0;b[c>>1]=h;return}}function dj(b){b=b|0;var d=0;c[b>>2]=8708;if(c[b+108>>2]|0){d=c[b+112>>2]|0;hb[c[c[d>>2]>>2]&511](d);d=c[b+112>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+108>>2]|0;hb[c[c[d>>2]>>2]&511](d);d=c[b+108>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}}d=c[b+88>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+84>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+80>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+60>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}if(!(a[b+100>>0]|0))return;d=c[b+92>>2]|0;hb[c[c[d>>2]>>2]&511](d);d=c[b+92>>2]|0;if(!d)return;c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0);return}function ej(b){b=b|0;var d=0,e=0,f=0,h=0.0;e=l;l=l+96|0;a[b+88>>0]=1;if((a[22712]|0)==0?jy(22712)|0:0){c[6136]=1065353216;c[6137]=0;c[6138]=0;c[6139]=0;c[6140]=0;c[6141]=1065353216;c[6142]=0;c[6143]=0;c[6144]=0;c[6145]=0;c[6146]=1065353216;g[6147]=0.0;c[6148]=-1082130432;c[6149]=0;c[6150]=0;c[6151]=0;c[6152]=0;c[6153]=-1082130432;c[6154]=0;c[6155]=0;c[6156]=0;c[6157]=0;c[6158]=-1082130432;g[6159]=0.0}d=e;f=d+96|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(f|0));Vb[c[(c[b>>2]|0)+76>>2]&127](b,24544,e,6);h=+g[b+44>>2];g[b+72>>2]=+g[e>>2]+h;g[b+56>>2]=+g[e+48>>2]-h;g[b+76>>2]=+g[e+20>>2]+h;g[b+60>>2]=+g[e+68>>2]-h;g[b+80>>2]=+g[e+40>>2]+h;g[b+64>>2]=+g[e+88>>2]-h;l=e;return}function fj(a,b,d){a=a|0;b=+b;d=+d;var e=0,f=0,h=0.0,i=0.0,j=0,k=0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0;f=c[a+732>>2]|0;if((f|0)<=0)return;a=c[a+740>>2]|0;e=0;do{d=+g[a+(e*52|0)+24>>2];if(d>0.0?(j=c[a+(e*52|0)+8>>2]|0,k=c[a+(e*52|0)+12>>2]|0,l=+g[j+8>>2],n=+g[k+8>>2]-l,m=+g[j+12>>2],p=+g[k+12>>2]-m,h=+g[j+16>>2],o=+g[k+16>>2]-h,i=+g[a+(e*52|0)+28>>2],i+(n*n+p*p+o*o)>1.1920928955078125e-07):0){d=(i-(n*n+p*p+o*o))/(d*(i+(n*n+p*p+o*o)))*b;q=d*+g[j+88>>2];g[j+8>>2]=l-n*q;g[j+12>>2]=m-p*q;g[j+16>>2]=h-o*q;d=d*+g[k+88>>2];g[k+8>>2]=+g[k+8>>2]+n*d;g[k+12>>2]=p*d+ +g[k+12>>2];g[k+16>>2]=o*d+ +g[k+16>>2]}e=e+1|0}while((e|0)!=(f|0));return}function gj(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,m=0.0,n=0;e=l;l=l+96|0;c[e+32>>2]=1065353216;c[e+32+4>>2]=0;c[e+32+4+4>>2]=0;c[e+32+4+8>>2]=0;c[e+32+4+12>>2]=0;c[e+32+20>>2]=1065353216;c[e+32+24>>2]=0;c[e+32+24+4>>2]=0;c[e+32+24+8>>2]=0;c[e+32+24+12>>2]=0;c[e+32+40>>2]=1065353216;n=e+32+44|0;c[n>>2]=0;c[n+4>>2]=0;c[n+8>>2]=0;c[n+12>>2]=0;c[n+16>>2]=0;Vb[c[(c[a>>2]|0)+8>>2]&127](a,e+32|0,e+16|0,e);k=+g[e>>2];m=+g[e+16>>2];i=+g[e+4>>2];j=+g[e+16+4>>2];f=+g[e+8>>2];h=+g[e+16+8>>2];g[d>>2]=+C(+((k-m)*(k-m)+(i-j)*(i-j)+(f-h)*(f-h)))*.5;g[b>>2]=(m+k)*.5;g[b+4>>2]=(j+i)*.5;g[b+8>>2]=(h+f)*.5;g[b+12>>2]=0.0;l=e;return}function hj(){var b=0,d=0;d=ns()|0;c[d+8>>2]=0;c[d>>2]=6416;a[d+28>>0]=1;c[d+24>>2]=0;c[d+16>>2]=0;c[d+20>>2]=0;c[d+32>>2]=1566444395;c[d+36>>2]=1566444395;c[d+40>>2]=1566444395;g[d+44>>2]=0.0;c[d+48>>2]=-581039253;c[d+52>>2]=-581039253;c[d+56>>2]=-581039253;g[d+60>>2]=0.0;c[d+64>>2]=0;c[d+68>>2]=1;g[d+72>>2]=0.0;c[d+76>>2]=1065353216;c[d+80>>2]=1065353216;c[d+84>>2]=1065353216;g[d+88>>2]=0.0;c[d+4>>2]=31;c[6432]=(c[6432]|0)+1;b=ec(79)|0;if(!b)b=0;else{c[(b+4+15&-16)+-4>>2]=b;b=b+4+15&-16}a[b+36>>0]=1;c[b+32>>2]=0;c[b+24>>2]=0;c[b+28>>2]=0;a[b+56>>0]=1;c[b+52>>2]=0;c[b+44>>2]=0;c[b+48>>2]=0;c[b>>2]=0;c[b+4>>2]=0;c[b+8>>2]=-1;c[b+12>>2]=0;c[b+16>>2]=0;c[d+64>>2]=b;return d|0}function ij(a,d,f,h){a=a|0;d=d|0;f=f|0;h=h|0;var i=0,j=0,k=0,l=0,m=0;i=c[a+108>>2]|0;if(i|0){Vb[c[(c[i>>2]|0)+28>>2]&127](i,d,f,h);return}i=b[a+56>>1]|0;if(!(i<<16>>16))return;k=1;m=1;do{j=c[a+68>>2]|0;if(b[j+(k<<2)>>1]&1){l=c[a+60>>2]|0;k=e[j+(k<<2)+2>>1]|0;if(!(+g[d>>2]>+g[l+(k<<6)+32>>2])?!(+g[f>>2]<+g[l+(k<<6)+16>>2]):0)j=1;else j=0;if(!(!(+g[d+8>>2]>+g[l+(k<<6)+40>>2])?!(+g[f+8>>2]<+g[l+(k<<6)+24>>2]):0))j=0;if(!(+g[d+4>>2]>+g[l+(k<<6)+36>>2])?!(+g[f+4>>2]<+g[l+(k<<6)+20>>2]|j^1):0){Gb[c[(c[h>>2]|0)+8>>2]&31](h,l+(k<<6)|0)|0;i=b[a+56>>1]|0}}m=m+1<<16>>16;k=m&65535}while(k>>>0<((i&65535)<<1|1)>>>0);return}function jj(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0.0,j=0.0,k=0;f=+g[b>>2];h=+g[b+16>>2];j=f<h?f:h;i=+g[b+32>>2];if((j<i?j:i)>+g[a+24>>2])return;k=f>h?b:b+16|0;if(+g[(+g[k>>2]>i?k:b+32|0)>>2]<+g[a+8>>2])return;i=+g[b+8>>2];f=+g[b+24>>2];j=i<f?i:f;h=+g[b+40>>2];if((j<h?j:h)>+g[a+32>>2])return;k=i>f?b+8|0:b+24|0;if(+g[(+g[k>>2]>h?k:b+40|0)>>2]<+g[a+16>>2])return;f=+g[b+4>>2];h=+g[b+20>>2];j=f<h?f:h;i=+g[b+36>>2];if((j<i?j:i)>+g[a+28>>2])return;k=f>h?b+4|0:b+20|0;if(+g[(+g[k>>2]>i?k:b+36|0)>>2]<+g[a+12>>2])return;k=c[a+4>>2]|0;Vb[c[(c[k>>2]|0)+8>>2]&127](k,b,d,e);return}function kj(b,d){b=b|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0;if(!(a[b+738>>0]|0)){c[d>>2]=5;c[d+4>>2]=1;e=+Mi(b,(c[b+28>>2]|0)+4|0,(c[b+32>>2]|0)+4|0);g[b+728>>2]=e;g[b+708>>2]=0.0;g[b+712>>2]=0.0;a[b+716>>0]=0;h=+g[b+692>>2];do if(!(h>=0.0))i=13;else{e=+Vg(e-+g[b+688>>2],6.2831854820251465);if(!(e<-3.1415927410125732)){if(e>3.1415927410125732)e=e+-6.2831854820251465}else e=e+6.2831854820251465;if(e<-h){a[b+716>>0]=1;f=1.0;e=-(e+h)}else{if(!(e>h)){i=13;break}a[b+716>>0]=1;f=-1.0;e=h-e}g[b+708>>2]=e;g[b+712>>2]=f}while(0);if((i|0)==13?(a[b+737>>0]|0)==0:0)return;c[d>>2]=6;d=d+4|0}else{c[d>>2]=0;d=d+4|0}c[d>>2]=0;return}function lj(b,d,e,f){b=b|0;d=d|0;e=e|0;f=+f;var h=0,i=0.0,j=0.0,k=0.0;h=l;l=l+16|0;g[b+32>>2]=f;c[b+8>>2]=c[d>>2];c[b+8+4>>2]=c[d+4>>2];c[b+8+8>>2]=c[d+8>>2];c[b+8+12>>2]=c[d+12>>2];i=+g[b+28>>2];k=+g[e+4>>2]-i*+g[d+4>>2];j=+g[e+8>>2]-i*+g[d+8>>2];g[h>>2]=+g[e>>2]-+g[d>>2]*i;g[h+4>>2]=k;g[h+8>>2]=j;g[h+12>>2]=0.0;f=+g[b+24>>2]+i+f;g[b+32>>2]=f;if(!(f<0.0)){b=b+4|0;b=c[b>>2]|0;e=c[b>>2]|0;e=e+16|0;e=c[e>>2]|0;Qb[e&15](b,d,h,f);l=h;return}a[b+36>>0]=1;b=b+4|0;b=c[b>>2]|0;e=c[b>>2]|0;e=e+16|0;e=c[e>>2]|0;Qb[e&15](b,d,h,f);l=h;return}function mj(b){b=b|0;var d=0,e=0,f=0,g=0,h=0;c[b>>2]=6352;d=c[b+8>>2]|0;e=c[d+8>>2]|0;if((e|0)>0){g=0;do{f=c[(c[d+16>>2]|0)+(g*12|0)+8>>2]|0;if(f|0){hb[c[c[f>>2]>>2]&511](f);h=c[b+4>>2]|0;jb[c[(c[h>>2]|0)+60>>2]&127](h,f)}g=g+1|0}while((g|0)!=(e|0));d=c[b+8>>2]|0}zh(d);d=c[b+8>>2]|0;hb[c[c[d>>2]>>2]&511](d);d=c[b+8>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+24>>2]|0;if(!d){a[b+28>>0]=1;c[b+24>>2]=0;c[b+16>>2]=0;h=b+20|0;c[h>>2]=0;return}if(a[b+28>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+24>>2]=0;a[b+28>>0]=1;c[b+24>>2]=0;c[b+16>>2]=0;h=b+20|0;c[h>>2]=0;return}function nj(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0.0;f=l;l=l+16|0;c[a+4>>2]=c[b+24>>2];e=c[b>>2]|0;c[a+8>>2]=e;if(d){c[a+52>>2]=c[b+8>>2];c[a+52+4>>2]=c[b+8+4>>2];c[a+52+8>>2]=c[b+8+8>>2];c[a+52+12>>2]=c[b+8+12>>2];e=a+68|0;d=a+20|0;a=a+36|0;h=+g[b+24>>2];op(e,d,a,h);h=+g[b+24>>2];l=f;return +h}else{e=bH(IG(e)|0)|0;Jl(f,e,+g[b+8>>2],+g[b+12>>2],+g[b+16>>2]);c[a+52>>2]=c[f>>2];c[a+52+4>>2]=c[f+4>>2];c[a+52+8>>2]=c[f+8>>2];c[a+52+12>>2]=c[f+12>>2];e=a+68|0;d=a+20|0;a=a+36|0;h=+g[b+24>>2];op(e,d,a,h);h=+g[b+24>>2];l=f;return +h}return 0.0}function oj(b,d){b=b|0;d=d|0;c[b+204>>2]=c[d+48>>2];c[b+208>>2]=c[d+52>>2];c[b+212>>2]=c[d+56>>2];c[b+216>>2]=c[d+60>>2];c[b+220>>2]=c[d+64>>2];c[b+224>>2]=c[d+68>>2];c[b+156>>2]=c[d>>2];c[b+156+4>>2]=c[d+4>>2];c[b+156+8>>2]=c[d+8>>2];c[b+156+12>>2]=c[d+12>>2];c[b+172>>2]=c[d+16>>2];c[b+172+4>>2]=c[d+16+4>>2];c[b+172+8>>2]=c[d+16+8>>2];c[b+172+12>>2]=c[d+16+12>>2];c[b+188>>2]=c[d+32>>2];c[b+188+4>>2]=c[d+32+4>>2];c[b+188+8>>2]=c[d+32+8>>2];c[b+188+12>>2]=c[d+32+12>>2];c[b+228>>2]=c[d+72>>2];g[b+232>>2]=0.0;g[b+252>>2]=0.0;g[b+236>>2]=0.0;g[b+240>>2]=0.0;g[b+256>>2]=0.0;g[b+244>>2]=.10000000149011612;a[b+260>>0]=a[d+80>>0]&1;c[b+248>>2]=c[d+76>>2];return}function pj(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,h=0.0,i=0.0;f=l;l=l+16|0;c[b+4>>2]=d;c[b>>2]=4560;c[b+8>>2]=-1;c[b+12>>2]=-1;g[b+16>>2]=3402823466385288598117041.0e14;a[b+20>>0]=1;a[b+21>>0]=0;c[b+24>>2]=-1;c[b+28>>2]=e;if((a[22688]|0)==0?jy(22688)|0:0){c[f>>2]=0;c[f+4>>2]=0;c[f+8>>2]=0;c[f+12>>2]=0;_f(23256,0.0,0,0,f)}c[5865]=c[5865]|1;g[5900]=0.0;h=+g[5910]*0.0;i=+g[5911]*0.0;g[5905]=+g[5909]*0.0;g[5906]=h;g[5907]=i;g[5908]=0.0;c[5913]=0;c[5914]=0;c[5915]=0;c[5916]=0;i=+g[5902]*0.0;h=+g[5903]*0.0;g[5954]=+g[5901]*0.0;g[5955]=i;g[5956]=h;g[5957]=0.0;c[b+32>>2]=23256;g[b+36>>2]=0.0;g[b+40>>2]=.30000001192092896;c[b+44>>2]=0;l=f;return}function qj(a){a=a|0;var b=0;c[a>>2]=3196;b=c[a+92>>2]|0;hb[c[c[b>>2]>>2]&511](b);b=c[a+92>>2]|0;if(b|0){c[6433]=(c[6433]|0)+1;Pc(c[b+-4>>2]|0)}b=c[a+96>>2]|0;hb[c[c[b>>2]>>2]&511](b);b=c[a+96>>2]|0;if(b|0){c[6433]=(c[6433]|0)+1;Pc(c[b+-4>>2]|0)}b=c[a+100>>2]|0;hb[c[c[b>>2]>>2]&511](b);b=c[a+100>>2]|0;if(b|0){c[6433]=(c[6433]|0)+1;Pc(c[b+-4>>2]|0)}b=c[a+104>>2]|0;hb[c[c[b>>2]>>2]&511](b);b=c[a+104>>2]|0;if(b|0){c[6433]=(c[6433]|0)+1;Pc(c[b+-4>>2]|0)}b=c[a+108>>2]|0;hb[c[c[b>>2]>>2]&511](b);b=c[a+108>>2]|0;if(!b){Ve(a);return}c[6433]=(c[6433]|0)+1;Pc(c[b+-4>>2]|0);Ve(a);return}function rj(b,d){b=b|0;d=d|0;var e=0,f=0;a:do if((d|0)!=0&(b&3|0)!=0){e=d;while(1){if(!(a[b>>0]|0))break a;b=b+1|0;d=e+-1|0;if((d|0)!=0&(b&3|0)!=0)e=d;else{e=d;d=(d|0)!=0;f=4;break}}}else{e=d;d=(d|0)!=0;f=4}while(0);b:do if((f|0)==4)if(d){if(a[b>>0]|0){c:do if(e>>>0>3)while(1){d=c[b>>2]|0;if((d&-2139062144^-2139062144)&d+-16843009|0)break;b=b+4|0;e=e+-4|0;if(e>>>0<=3){f=10;break c}}else f=10;while(0);if((f|0)==10)if(!e){e=0;break}while(1){if(!(a[b>>0]|0))break b;b=b+1|0;e=e+-1|0;if(!e){e=0;break}}}}else e=0;while(0);return (e|0?b:0)|0}function sj(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0;if((c[d+60>>2]|0)==2){f=c[d+48>>2]|0;Kg(b+64|0,f)|0;g=c[b+68>>2]|0;if(g|0){c[6433]=(c[6433]|0)+1;Pc(c[g+-4>>2]|0)}c[b+68>>2]=f;f=1}else{f=c[d+48>>2]|0;Kg(b+4|0,f)|0;g=c[b+8>>2]|0;if(g|0){c[6433]=(c[6433]|0)+1;Pc(c[g+-4>>2]|0)}c[b+8>>2]=f;f=0}f=b+4+(f*60|0)+12|0;c[f>>2]=(c[f>>2]|0)+-1;f=c[d+52>>2]|0;if(!f)f=b+124+(c[d+60>>2]<<2)|0;else f=f+56|0;c[f>>2]=c[d+56>>2];f=c[d+56>>2]|0;if(f|0)c[f+52>>2]=c[d+52>>2];g=c[b+136>>2]|0;Rb[c[(c[g>>2]|0)+16>>2]&127](g,d,e);c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0);a[b+194>>0]=1;return}function tj(a){a=a|0;var b=0.0,c=0.0,d=0.0,e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0;n=+g[a+4>>2];h=+g[a+396>>2];m=+g[a+8>>2];e=+g[a+400>>2];l=+g[a+12>>2];c=+g[a+404>>2];k=+g[a+20>>2];j=+g[a+24>>2];i=+g[a+28>>2];f=+g[a+36>>2];d=+g[a+40>>2];b=+g[a+44>>2];g[a+264>>2]=n*h*n+m*e*m+l*c*l;g[a+268>>2]=n*h*k+m*e*j+l*c*i;g[a+272>>2]=n*h*f+m*e*d+l*c*b;g[a+276>>2]=0.0;g[a+280>>2]=h*k*n+e*j*m+c*i*l;g[a+284>>2]=h*k*k+e*j*j+c*i*i;g[a+288>>2]=h*k*f+e*j*d+c*i*b;g[a+292>>2]=0.0;g[a+296>>2]=h*f*n+e*d*m+c*b*l;g[a+300>>2]=h*f*k+e*d*j+c*b*i;g[a+304>>2]=h*f*f+e*d*d+c*b*b;g[a+308>>2]=0.0;return}function uj(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0,i=0,j=0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0;h=l;l=l+16|0;if((e|0)<=0){l=h;return}f=0;do{p=+g[b+(f<<4)>>2];o=+g[b+(f<<4)+4>>2];n=+g[b+(f<<4)+8>>2];m=p*+g[a+56>>2]+o*+g[a+60>>2]+n*+g[a+64>>2];k=p*+g[a+72>>2]+o*+g[a+76>>2]+n*+g[a+80>>2];n=p*+g[a+88>>2]+o*+g[a+92>>2]+n*+g[a+96>>2];g[h>>2]=m;g[h+4>>2]=k;g[h+8>>2]=n;g[h+12>>2]=0.0;j=a+56+((+g[h+((m<k&1)<<2)>>2]<n?2:m<k&1)<<4)|0;i=d+(f<<4)|0;c[i>>2]=c[j>>2];c[i+4>>2]=c[j+4>>2];c[i+8>>2]=c[j+8>>2];c[i+12>>2]=c[j+12>>2];f=f+1|0}while((f|0)!=(e|0));l=h;return}function vj(b){b=b|0;var d=0,e=0,f=0,g=0,h=0;c[b>>2]=5756;e=c[b+8>>2]|0;d=c[b+16>>2]|0;if((e|0)>0){h=0;do{g=(c[d+(h<<2)>>2]|0)+188|0;f=c[g>>2]|0;if(f){e=c[b+68>>2]|0;e=lb[c[(c[e>>2]|0)+36>>2]&127](e)|0;Rb[c[(c[e>>2]|0)+40>>2]&127](e,f,c[b+24>>2]|0);e=c[b+68>>2]|0;Rb[c[(c[e>>2]|0)+12>>2]&127](e,f,c[b+24>>2]|0);c[g>>2]=0;e=c[b+8>>2]|0;d=c[b+16>>2]|0}h=h+1|0}while((h|0)<(e|0))}if(!d){a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;b=b+12|0;c[b>>2]=0;return}if(a[b+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+16>>2]=0;a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;b=b+12|0;c[b>>2]=0;return}function wj(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0.0,h=0,i=0.0,j=0,k=0,l=0.0,m=0.0;k=c[b+52>>2]|0;j=c[k+32>>2]|0;b=c[j>>2]|0;k=c[k+24>>2]|0;if((k|0)<=1){k=b;k=k+8|0;c[a>>2]=c[k>>2];c[a+4>>2]=c[k+4>>2];c[a+8>>2]=c[k+8>>2];c[a+12>>2]=c[k+12>>2];return}l=+g[d>>2];m=+g[d+4>>2];i=+g[d+8>>2];f=l*+g[b+8>>2]+m*+g[b+12>>2]+i*+g[b+16>>2];d=1;h=0;while(1){b=c[j+(d<<2)>>2]|0;e=l*+g[b+8>>2]+m*+g[b+12>>2]+i*+g[b+16>>2];b=e>f;h=b?d:h;d=d+1|0;if((d|0)==(k|0))break;else f=b?e:f}k=c[j+(h<<2)>>2]|0;k=k+8|0;c[a>>2]=c[k>>2];c[a+4>>2]=c[k+4>>2];c[a+8>>2]=c[k+8>>2];c[a+12>>2]=c[k+12>>2];return}function xj(a,b){a=a|0;b=b|0;var d=0,e=0.0,f=0,h=0,i=0.0,j=0.0;c[a+248>>2]=c[b>>2];c[a+248+4>>2]=c[b+4>>2];c[a+248+8>>2]=c[b+8>>2];c[a+248+12>>2]=c[b+12>>2];d=c[a+232>>2]|0;if((d|0)<=0)return;h=0;do{f=c[(c[a+240>>2]|0)+(h<<2)>>2]|0;switch(c[f+216>>2]|0){case 2:case 5:break;default:if(!(c[f+504>>2]&1)){e=+g[f+344>>2];if(e!=0.0){j=1.0/e*+g[b+4>>2];i=1.0/e*+g[b+8>>2];g[f+364>>2]=1.0/e*+g[b>>2];g[f+368>>2]=j;g[f+372>>2]=i;g[f+376>>2]=0.0}c[f+380>>2]=c[b>>2];c[f+380+4>>2]=c[b+4>>2];c[f+380+8>>2]=c[b+8>>2];c[f+380+12>>2]=c[b+12>>2];d=c[a+232>>2]|0}}h=h+1|0}while((h|0)<(d|0));return}function yj(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0;f=l;l=l+96|0;g=c[b+192>>2]|0;c[f+64>>2]=0;c[f+64+4>>2]=g;c[f+64+8>>2]=b;c[f+64+12>>2]=b+4;c[f+64+16>>2]=-1;c[f+64+20>>2]=-1;b=c[d+192>>2]|0;c[f+40>>2]=0;c[f+40+4>>2]=b;c[f+40+8>>2]=d;c[f+40+12>>2]=d+4;c[f+40+16>>2]=-1;c[f+40+20>>2]=-1;b=c[a+24>>2]|0;b=pb[c[(c[b>>2]|0)+8>>2]&31](b,f+64|0,f+40|0,0)|0;if(!b){l=f;return}c[f+4>>2]=0;c[f+8>>2]=f+64;c[f+12>>2]=f+40;c[f>>2]=6100;c[f+32>>2]=e;fb[c[(c[b>>2]|0)+8>>2]&31](b,f+64|0,f+40|0,a+28|0,f);hb[c[c[b>>2]>>2]&511](b);g=c[a+24>>2]|0;jb[c[(c[g>>2]|0)+60>>2]&127](g,b);l=f;return}function zj(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;if(!((b|0)==0?1:(c[b+236>>2]&2|0)==0)){jb[c[(c[a>>2]|0)+92>>2]&127](a,b);return}d=c[b+188>>2]|0;if(d|0){g=c[a+68>>2]|0;g=lb[c[(c[g>>2]|0)+36>>2]&127](g)|0;Rb[c[(c[g>>2]|0)+40>>2]&127](g,d,c[a+24>>2]|0);g=c[a+68>>2]|0;Rb[c[(c[g>>2]|0)+12>>2]&127](g,d,c[a+24>>2]|0);c[b+188>>2]=0}f=c[a+8>>2]|0;if((f|0)<=0)return;g=c[a+16>>2]|0;d=0;while(1){e=g+(d<<2)|0;if((c[e>>2]|0)==(b|0))break;d=d+1|0;if((d|0)>=(f|0)){h=11;break}}if((h|0)==11)return;if((d|0)>=(f|0))return;c[e>>2]=c[g+(f+-1<<2)>>2];c[(c[a+16>>2]|0)+(f+-1<<2)>>2]=b;c[a+8>>2]=f+-1;return}function Aj(a,b,d){a=a|0;b=+b;d=d|0;var e=0,f=0,h=0.0,i=0.0,k=0.0;e=c[a+204>>2]|0;if(b==0.0){c[a+204>>2]=e|1;h=0.0}else{c[a+204>>2]=e&-2;h=1.0/b}g[a+344>>2]=h;k=+g[a+384>>2]*b;i=+g[a+388>>2]*b;g[a+364>>2]=+g[a+380>>2]*b;g[a+368>>2]=k;g[a+372>>2]=i;g[a+376>>2]=0.0;b=+g[d>>2];f=b!=0.0?(g[j>>2]=1.0/b,c[j>>2]|0):0;b=+g[d+4>>2];e=b!=0.0?(g[j>>2]=1.0/b,c[j>>2]|0):0;b=+g[d+8>>2];d=b!=0.0?(g[j>>2]=1.0/b,c[j>>2]|0):0;c[a+396>>2]=f;c[a+400>>2]=e;c[a+404>>2]=d;g[a+408>>2]=0.0;i=h*+g[a+352>>2];k=h*+g[a+356>>2];g[a+560>>2]=+g[a+348>>2]*h;g[a+564>>2]=i;g[a+568>>2]=k;g[a+572>>2]=0.0;return}function Bj(a,b,d){a=a|0;b=b|0;d=+d;var e=0,f=0,h=0;f=l;l=l+256|0;e=c[b+212>>2]|0;if((e|0)>-1){a=e;l=f;return a|0}h=(c[b+236>>2]&2|0)==0;e=h?0:b;do if(!h){if(!(+g[e+344>>2]!=0.0)?(c[e+204>>2]&2|0)==0:0)break;h=c[a+8>>2]|0;Hk(f|0,0,244)|0;ue(of(a+4|0,f)|0,b,d);c[b+212>>2]=h;l=f;return h|0}while(0);e=c[a+188>>2]|0;if((e|0)>=0){h=e;l=f;return h|0}c[a+188>>2]=c[a+8>>2];Hk(f|0,0,244)|0;ue(of(a+4|0,f)|0,0,d);h=c[a+188>>2]|0;l=f;return h|0}function Cj(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0,h=0.0,i=0,j=0.0,k=0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0;k=c[b+96>>2]|0;if((k|0)<=0){c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;a=a+12|0;g[a>>2]=0.0;return}l=+g[b+12>>2];o=+g[d>>2]*l;m=+g[b+16>>2];p=+g[d+4>>2]*m;n=+g[b+20>>2];j=+g[d+8>>2]*n;d=c[b+104>>2]|0;f=0;h=-3402823466385288598117041.0e14;i=-1;while(1){e=o*+g[d+(f<<4)>>2]+p*+g[d+(f<<4)+4>>2]+j*+g[d+(f<<4)+8>>2];b=e>h;i=b?f:i;f=f+1|0;if((f|0)==(k|0))break;else h=b?e:h}o=+g[d+(i<<4)+4>>2]*m;p=+g[d+(i<<4)+8>>2]*n;g[a>>2]=+g[d+(i<<4)>>2]*l;g[a+4>>2]=o;g[a+8>>2]=p;a=a+12|0;g[a>>2]=0.0;return}function Dj(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0.0,h=0,i=0,j=0.0,k=0,l=0.0;l=+g[b+60>>2]*.5;h=c[b+68>>2]|0;e=+g[d>>2];f=+g[d+4>>2];j=+g[d+8>>2];j=+C(+(e*e+f*f+j*j));i=c[b+64>>2]|0;if(+g[d+(h<<2)>>2]>j*+g[b+52>>2]){g[a+(i<<2)>>2]=0.0;g[a+(h<<2)>>2]=l;l=0.0;b=c[b+72>>2]|0;b=a+(b<<2)|0;g[b>>2]=l;return}j=+g[d+(i<<2)>>2];k=c[b+72>>2]|0;e=+g[d+(k<<2)>>2];f=+C(+(j*j+e*e));if(f>1.1920928955078125e-07){f=+g[b+56>>2]/f;g[a+(i<<2)>>2]=j*f;g[a+(h<<2)>>2]=-l;l=e*f;b=k;b=a+(b<<2)|0;g[b>>2]=l;return}else{g[a+(i<<2)>>2]=0.0;g[a+(h<<2)>>2]=-l;l=0.0;b=k;b=a+(b<<2)|0;g[b>>2]=l;return}}function Ej(a,b,d){a=a|0;b=+b;d=d|0;var e=0,f=0.0,h=0.0,i=0.0,j=0;e=l;l=l+96|0;c[e+32>>2]=1065353216;c[e+32+4>>2]=0;c[e+32+4+4>>2]=0;c[e+32+4+8>>2]=0;c[e+32+4+12>>2]=0;c[e+32+20>>2]=1065353216;c[e+32+24>>2]=0;c[e+32+24+4>>2]=0;c[e+32+24+8>>2]=0;c[e+32+24+12>>2]=0;c[e+32+40>>2]=1065353216;j=e+32+44|0;c[j>>2]=0;c[j+4>>2]=0;c[j+8>>2]=0;c[j+12>>2]=0;c[j+16>>2]=0;Vb[c[(c[a>>2]|0)+8>>2]&127](a,e+32|0,e+16|0,e);h=(+g[e>>2]-+g[e+16>>2])*.5*2.0;f=(+g[e+4>>2]-+g[e+16+4>>2])*.5*2.0;i=(+g[e+8>>2]-+g[e+16+8>>2])*.5*2.0;g[d>>2]=b/12.0*(f*f+i*i);g[d+4>>2]=b/12.0*(h*h+i*i);g[d+8>>2]=b/12.0*(h*h+f*f);l=e;return}function Fj(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=c[b+280>>2]|0;if((e|0)==(c[b+284>>2]|0)?(h=e|0?e<<1:1,(e|0)<(h|0)):0){if(!h)f=0;else{c[6432]=(c[6432]|0)+1;e=ec((h<<2|3)+16|0)|0;if(!e)f=0;else{c[(e+4+15&-16)+-4>>2]=e;f=e+4+15&-16}e=c[b+280>>2]|0}if((e|0)>0){g=0;do{c[f+(g<<2)>>2]=c[(c[b+288>>2]|0)+(g<<2)>>2];g=g+1|0}while((g|0)!=(e|0))}g=c[b+288>>2]|0;if(g){if(a[b+292>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[g+-4>>2]|0);e=c[b+280>>2]|0}c[b+288>>2]=0}a[b+292>>0]=1;c[b+288>>2]=f;c[b+284>>2]=h}c[(c[b+288>>2]|0)+(e<<2)>>2]=d;c[b+280>>2]=e+1;return}function Gj(b,d){b=b|0;d=d|0;var e=0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0;e=$r()|0;pj(e,3,b);c[e>>2]=4672;c[e+300>>2]=c[d>>2];c[e+300+4>>2]=c[d+4>>2];c[e+300+8>>2]=c[d+8>>2];c[e+300+12>>2]=c[d+12>>2];k=+g[d>>2];j=+g[d+4>>2];i=+g[d+8>>2];h=k*+g[b+20>>2]+j*+g[b+24>>2]+i*+g[b+28>>2]+ +g[b+56>>2];f=k*+g[b+36>>2]+j*+g[b+40>>2]+i*+g[b+44>>2]+ +g[b+60>>2];g[e+316>>2]=k*+g[b+4>>2]+j*+g[b+8>>2]+i*+g[b+12>>2]+ +g[b+52>>2];g[e+320>>2]=h;g[e+324>>2]=f;g[e+328>>2]=0.0;c[e+332>>2]=0;a[e+344>>0]=0;g[e+348>>2]=.30000001192092896;g[e+352>>2]=1.0;g[e+356>>2]=0.0;return e|0}function Hj(a,b,c){a=+a;b=+b;c=+c;var d=0.0,e=0.0,f=0;if(b>=c)return +a;if(a<b){d=+Vg(b-a,6.2831854820251465);if(!(d<-3.1415927410125732)){if(d>3.1415927410125732)d=d+-6.2831854820251465}else d=d+6.2831854820251465;e=+B(+d);d=+Vg(c-a,6.2831854820251465);if(!(d<-3.1415927410125732)){if(d>3.1415927410125732)d=d+-6.2831854820251465}else d=d+6.2831854820251465;f=e<+B(+d);a=f?a:a+6.2831854820251465;return +a}if(!(a>c))return +a;d=+Vg(a-c,6.2831854820251465);if(!(d<-3.1415927410125732)){if(d>3.1415927410125732)d=d+-6.2831854820251465}else d=d+6.2831854820251465;e=+B(+d);d=+Vg(a-b,6.2831854820251465);if(!(d<-3.1415927410125732)){if(d>3.1415927410125732)d=d+-6.2831854820251465}else d=d+6.2831854820251465;f=+B(+d)<e;a=f?a+-6.2831854820251465:a;return +a}function Ij(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0;e=l;l=l+16|0;Rb[c[(c[b>>2]|0)+68>>2]&127](e,b,d);c[a>>2]=c[e>>2];c[a+4>>2]=c[e+4>>2];c[a+8>>2]=c[e+8>>2];c[a+12>>2]=c[e+12>>2];if(!(+zb[c[(c[b>>2]|0)+48>>2]&15](b)!=0.0)){l=e;return}i=+g[d>>2];h=+g[d+4>>2];f=+g[d+8>>2];k=i*i+h*h+f*f<1.4210854715202004e-14?-1.0:i;j=i*i+h*h+f*f<1.4210854715202004e-14?-1.0:h;f=i*i+h*h+f*f<1.4210854715202004e-14?-1.0:f;h=1.0/+C(+(f*f+(k*k+j*j)));i=+zb[c[(c[b>>2]|0)+48>>2]&15](b);g[a>>2]=+g[a>>2]+i*h*k;g[a+4>>2]=i*h*j+ +g[a+4>>2];g[a+8>>2]=i*h*f+ +g[a+8>>2];l=e;return}function Jj(a,b,d){a=a|0;b=+b;d=+d;var e=0.0,f=0.0,h=0.0;f=+g[a+692>>2];do if(f>0.0){h=+g[a+688>>2];e=+Vg(b-h,6.2831854820251465);if(!(e<-3.1415927410125732)){if(e>3.1415927410125732)e=e+-6.2831854820251465}else e=e+6.2831854820251465;if(!(!(e<-f)&e<=f))if(e>0.0){b=+Vg(f+h,6.2831854820251465);if(b<-3.1415927410125732){b=b+6.2831854820251465;break}if(!(b>3.1415927410125732))break;b=b+-6.2831854820251465;break}else{b=+Vg(h-f,6.2831854820251465);if(b<-3.1415927410125732){b=b+6.2831854820251465;break}if(!(b>3.1415927410125732))break;b=b+-6.2831854820251465;break}}while(0);g[a+680>>2]=(b-+Mi(a,(c[a+28>>2]|0)+4|0,(c[a+32>>2]|0)+4|0))/d;return}function Kj(a,b,c){a=a|0;b=b|0;c=c|0;var d=0.0;a:do switch(b|0){case 2:{if((c|0)<1){d=+g[a+232>>2];break a}if((c|0)<3){d=+g[a+264>>2];break a}if((c|0)==3){d=+g[a+248>>2];break a}if((c|0)<6)d=+g[a+280>>2];else d=3402823466385288598117041.0e14;break}case 3:{if((c|0)<1){d=+g[a+212>>2];break a}if((c|0)==3)d=+g[a+228>>2];else d=3402823466385288598117041.0e14;break}case 4:{if((c|0)<1){d=+g[a+244>>2];break a}if((c|0)<3){d=+g[a+276>>2];break a}if((c|0)==3){d=+g[a+260>>2];break a}if((c|0)<6)d=+g[a+292>>2];else d=3402823466385288598117041.0e14;break}default:d=3402823466385288598117041.0e14}while(0);return +d}function Lj(){var b=0;b=Jr()|0;c[b>>2]=4884;a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;c[b+12>>2]=0;a[b+40>>0]=1;c[b+36>>2]=0;c[b+28>>2]=0;c[b+32>>2]=0;a[b+60>>0]=1;c[b+56>>2]=0;c[b+48>>2]=0;c[b+52>>2]=0;a[b+80>>0]=1;c[b+76>>2]=0;c[b+68>>2]=0;c[b+72>>2]=0;a[b+100>>0]=1;c[b+96>>2]=0;c[b+88>>2]=0;c[b+92>>2]=0;a[b+120>>0]=1;c[b+116>>2]=0;c[b+108>>2]=0;c[b+112>>2]=0;a[b+140>>0]=1;c[b+136>>2]=0;c[b+128>>2]=0;c[b+132>>2]=0;a[b+160>>0]=1;c[b+156>>2]=0;c[b+148>>2]=0;c[b+152>>2]=0;a[b+180>>0]=1;c[b+176>>2]=0;c[b+168>>2]=0;c[b+172>>2]=0;c[b+192>>2]=0;return b|0}function Mj(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;c[6163]=(c[6163]|0)+1;e=(c[b+12>>2]|0)>(c[d+12>>2]|0);f=c[(e?d:b)+12>>2]|0;e=c[(e?b:d)+12>>2]|0;b=((e<<16|f)+~((e<<16|f)<<15)>>10^(e<<16|f)+~((e<<16|f)<<15))*9|0;b=((b>>6^b)+~((b>>6^b)<<11)>>16^(b>>6^b)+~((b>>6^b)<<11))&(c[a+12>>2]|0)+-1;if((b|0)>=(c[a+36>>2]|0)){g=0;return g|0}b=c[(c[a+44>>2]|0)+(b<<2)>>2]|0;if((b|0)==-1){g=0;return g|0}d=c[a+16>>2]|0;while(1){if((c[(c[d+(b<<4)>>2]|0)+12>>2]|0)==(f|0)?(c[(c[d+(b<<4)+4>>2]|0)+12>>2]|0)==(e|0):0)break;b=c[(c[a+64>>2]|0)+(b<<2)>>2]|0;if((b|0)==-1){b=0;g=8;break}}if((g|0)==8)return b|0;g=d+(b<<4)|0;return g|0}function Nj(b){b=b|0;var d=0;c[b>>2]=4e3;if(a[b+456>>0]|0?(d=c[b+452>>2]|0,hb[c[c[d>>2]>>2]&511](d),d=c[b+452>>2]|0,d|0):0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+420>>2]|0;if(d|0){if(a[b+424>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+420>>2]=0}a[b+424>>0]=1;c[b+420>>2]=0;c[b+412>>2]=0;c[b+416>>2]=0;d=c[b+336>>2]|0;if(!d){a[b+340>>0]=1;c[b+336>>2]=0;c[b+328>>2]=0;d=b+332|0;c[d>>2]=0;wg(b);return}if(a[b+340>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+336>>2]=0;a[b+340>>0]=1;c[b+336>>2]=0;c[b+328>>2]=0;d=b+332|0;c[d>>2]=0;wg(b);return}function Oj(a,b){a=a|0;b=b|0;var d=0,e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,m=0.0;d=l;l=l+64|0;c[d+48>>2]=0;c[d+48+4>>2]=0;c[d+48+8>>2]=0;c[d+48+12>>2]=0;i=+g[b>>2];f=+g[b+4>>2];m=+g[b+8>>2];j=+g[b+12>>2];h=i*(2.0/(i*i+f*f+m*m+j*j));e=f*(2.0/(i*i+f*f+m*m+j*j));k=m*(2.0/(i*i+f*f+m*m+j*j));g[d>>2]=1.0-(f*e+m*k);g[d+4>>2]=i*e-j*k;g[d+8>>2]=i*k+j*e;g[d+12>>2]=0.0;g[d+16>>2]=i*e+j*k;g[d+20>>2]=1.0-(i*h+m*k);g[d+24>>2]=f*k-j*h;g[d+28>>2]=0.0;g[d+32>>2]=i*k-j*e;g[d+36>>2]=f*k+j*h;g[d+40>>2]=1.0-(i*h+f*e);g[d+44>>2]=0.0;wd(a,d);l=d;return}function Pj(a,b){a=a|0;b=+b;var d=0,e=0,f=0;e=l;l=l+16|0;Yi(12052);if((c[a+280>>2]|0)>0){d=0;do{f=c[(c[a+288>>2]|0)+(d<<2)>>2]|0;Tb[c[(c[f>>2]|0)+8>>2]&7](f,a,b);d=d+1|0}while((d|0)<(c[a+280>>2]|0))}d=c[2395]|0;f=(c[d+16>>2]|0)+-1|0;c[d+16>>2]=f;if(f|0){l=e;return}do if(c[d+4>>2]|0){Va(e|0,0)|0;f=c[6431]|0;g[d+8>>2]=+g[d+8>>2]+ +(((c[e+4>>2]|0)-(c[f+4>>2]|0)+(((c[e>>2]|0)-(c[f>>2]|0)|0)*1e6|0)-(c[d+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[d+16>>2]|0)){d=c[2395]|0;break}else{l=e;return}}while(0);c[2395]=c[d+20>>2];l=e;return}function Qj(b,d,e,f){b=b|0;d=d|0;e=+e;f=f|0;var h=0;h=Mr()|0;c[h>>2]=5e3;a[h+144>>0]=1;c[h+140>>2]=0;c[h+132>>2]=0;c[h+136>>2]=0;c[h+176>>2]=f;g[h+56>>2]=.019999999552965164;c[h+60>>2]=0;c[h+60+4>>2]=0;c[h+60+8>>2]=0;c[h+60+12>>2]=0;a[h+170>>0]=1;c[h+8>>2]=b;g[h+52>>2]=e;g[h+48>>2]=0.0;c[h+12>>2]=d;a[h+171>>0]=1;g[h+172>>2]=0.0;g[h+16>>2]=0.0;g[h+20>>2]=0.0;g[h+44>>2]=29.399999618530273;g[h+24>>2]=55.0;g[h+28>>2]=10.0;a[h+168>>0]=0;a[h+169>>0]=0;a[h+180>>0]=1;g[h+36>>2]=.7853981852531433;g[h+40>>2]=.7071067690849304;g[h+108>>2]=0.0;a[h+181>>0]=0;a[h+182>>0]=0;return h|0}function Rj(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;b=c[d>>2]|0;b=Gb[c[(c[b>>2]|0)+56>>2]&31](b,156)|0;c[b>>2]=9172;c[b+4>>2]=c[d>>2];c[b>>2]=3768;a[b+8>>0]=1;d=c[d>>2]|0;c[b+12>>2]=3980;c[b+60>>2]=d;c[b+64>>2]=0;a[b+88>>0]=1;c[b+84>>2]=0;c[b+76>>2]=0;c[b+80>>2]=0;a[b+108>>0]=1;c[b+104>>2]=0;c[b+96>>2]=0;c[b+100>>2]=0;a[b+128>>0]=1;c[b+124>>2]=0;c[b+116>>2]=0;c[b+120>>2]=0;a[b+148>>0]=1;c[b+144>>2]=0;c[b+136>>2]=0;c[b+140>>2]=0;c[b+16>>2]=c[f+8>>2];c[b+20>>2]=c[e+8>>2];Qi(b+72|0);return b|0}function Sj(a,b,d){a=a|0;b=b|0;d=d|0;do if(!((b|0)==8&(d|0)==8)){if((b|0)==8&(d|0)==1){b=a+76|0;break}if((b|0)==1&(d|0)==8){b=a+80|0;break}if(!(d|b)){b=a+72|0;break}if((b|0)<20&(d|0)==28){b=a+88|0;break}if((b|0)==28&(d|0)<20){b=a+84|0;break}if((b|0)<20){if((d|0)<20){b=a+32|0;break}if((d+-21|0)>>>0<9){b=a+36|0;break}}else{if((d|0)<20&(b+-21|0)>>>0<9){b=a+40|0;break}if((b|0)==31)if((d|0)==31){b=a+48|0;break}else{b=a+44|0;break}}if((d|0)==31){b=a+52|0;break}else{b=a+56|0;break}}else b=a+60|0;while(0);return c[b>>2]|0}function Tj(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;b=c[d>>2]|0;b=Gb[c[(c[b>>2]|0)+56>>2]&31](b,156)|0;c[b>>2]=9172;c[b+4>>2]=c[d>>2];c[b>>2]=3768;a[b+8>>0]=0;d=c[d>>2]|0;c[b+12>>2]=3980;c[b+60>>2]=d;c[b+64>>2]=0;a[b+88>>0]=1;c[b+84>>2]=0;c[b+76>>2]=0;c[b+80>>2]=0;a[b+108>>0]=1;c[b+104>>2]=0;c[b+96>>2]=0;c[b+100>>2]=0;a[b+128>>0]=1;c[b+124>>2]=0;c[b+116>>2]=0;c[b+120>>2]=0;a[b+148>>0]=1;c[b+144>>2]=0;c[b+136>>2]=0;c[b+140>>2]=0;c[b+16>>2]=c[e+8>>2];c[b+20>>2]=c[f+8>>2];Qi(b+72|0);return b|0}function Uj(a,b,d,e,f){a=a|0;b=b|0;d=+d;e=e|0;f=f|0;var h=0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0;h=l;l=l+48|0;c[h+32>>2]=e;c[h+32+4>>2]=f;n=+g[b>>2];m=+g[b+4>>2];i=+g[b+8>>2];k=+g[a+56>>2]*n+ +g[a+60>>2]*m+ +g[a+64>>2]*i;j=n*+g[a+72>>2]+m*+g[a+76>>2]+i*+g[a+80>>2];i=n*+g[a+88>>2]+m*+g[a+92>>2]+i*+g[a+96>>2];c[h>>2]=c[a+48>>2];c[h+4>>2]=h+32;g[h+8>>2]=k;g[h+12>>2]=j;g[h+16>>2]=i;g[h+20>>2]=0.0;g[h+24>>2]=d;f=c[a+44>>2]|0;d=+Hb[c[(c[f>>2]|0)+12>>2]&15](f,h,1);l=h;return +d}function Vj(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;f=l;l=l+16|0;c[a+4>>2]=c[b+40>>2];e=c[b>>2]|0;c[a+76>>2]=e;if(d){c[a+44>>2]=c[b+8>>2];c[a+44+4>>2]=c[b+8+4>>2];c[a+44+8>>2]=c[b+8+8>>2];c[a+44+12>>2]=c[b+8+12>>2]}else{d=bH(IG(e)|0)|0;Jl(f,d,+g[b+8>>2],+g[b+12>>2],+g[b+16>>2]);c[a+44>>2]=c[f>>2];c[a+44+4>>2]=c[f+4>>2];c[a+44+8>>2]=c[f+8>>2];c[a+44+12>>2]=c[f+12>>2]}c[a+60>>2]=c[b+24>>2];c[a+60+4>>2]=c[b+24+4>>2];c[a+60+8>>2]=c[b+24+8>>2];c[a+60+12>>2]=c[b+24+12>>2];l=f;return +(+g[b+40>>2])}function Wj(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0.0,i=0.0,k=0.0,m=0,n=0;f=l;l=l+48|0;Rb[c[(c[a>>2]|0)+124>>2]&127](a,f+32|0,e);n=c[f+32>>2]|0;m=c[f+32+4>>2]|0;e=c[f+32+8>>2]|0;c[b>>2]=n;c[b+4>>2]=m;c[b+8>>2]=e;g[b+12>>2]=0.0;b=c[(c[a>>2]|0)+64>>2]|0;k=-(c[j>>2]=n,+g[j>>2]);i=-(c[j>>2]=m,+g[j>>2]);h=-(c[j>>2]=e,+g[j>>2]);g[f>>2]=k;g[f+4>>2]=i;g[f+8>>2]=h;g[f+12>>2]=0.0;Rb[b&127](f+16|0,a,f);c[d>>2]=c[f+16>>2];c[d+4>>2]=c[f+16+4>>2];c[d+8>>2]=c[f+16+8>>2];c[d+12>>2]=c[f+16+12>>2];l=f;return}function Xj(a,b,d,e){a=a|0;b=b|0;d=+d;e=e|0;if(e>>>0<3)switch(b|0){case 2:{g[a+756+(e<<2)>>2]=d;c[a+1304>>2]=c[a+1304>>2]|4<<e*3;return}case 4:{g[a+772+(e<<2)>>2]=d;c[a+1304>>2]=c[a+1304>>2]|2<<e*3;return}case 3:{g[a+740+(e<<2)>>2]=d;c[a+1304>>2]=c[a+1304>>2]|1<<e*3;return}default:return}if((e+-3|0)>>>0>=3)return;switch(b|0){case 2:{g[a+868+(e+-3<<6)+32>>2]=d;c[a+1304>>2]=c[a+1304>>2]|4<<e*3;return}case 4:{g[a+868+(e+-3<<6)+36>>2]=d;c[a+1304>>2]=c[a+1304>>2]|2<<e*3;return}case 3:{g[a+868+(e+-3<<6)+28>>2]=d;c[a+1304>>2]=c[a+1304>>2]|1<<e*3;return}default:return}}function Yj(b,d,e){b=b|0;d=d|0;e=+e;var f=0;f=Mr()|0;c[f>>2]=5e3;a[f+144>>0]=1;c[f+140>>2]=0;c[f+132>>2]=0;c[f+136>>2]=0;c[f+176>>2]=1;g[f+56>>2]=.019999999552965164;c[f+60>>2]=0;c[f+60+4>>2]=0;c[f+60+8>>2]=0;c[f+60+12>>2]=0;a[f+170>>0]=1;c[f+8>>2]=b;g[f+52>>2]=e;g[f+48>>2]=0.0;c[f+12>>2]=d;a[f+171>>0]=1;g[f+172>>2]=0.0;g[f+16>>2]=0.0;g[f+20>>2]=0.0;g[f+44>>2]=29.399999618530273;g[f+24>>2]=55.0;g[f+28>>2]=10.0;a[f+168>>0]=0;a[f+169>>0]=0;a[f+180>>0]=1;g[f+36>>2]=.7853981852531433;g[f+40>>2]=.7071067690849304;g[f+108>>2]=0.0;a[f+181>>0]=0;a[f+182>>0]=0;return f|0}function Zj(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0;h=$r()|0;c[h+4>>2]=3;c[h+8>>2]=-1;c[h+12>>2]=-1;g[h+16>>2]=3402823466385288598117041.0e14;a[h+20>>0]=1;a[h+21>>0]=0;c[h+24>>2]=-1;c[h+28>>2]=b;c[h+32>>2]=d;g[h+36>>2]=0.0;g[h+40>>2]=.30000001192092896;c[h+44>>2]=0;c[h>>2]=4672;c[h+300>>2]=c[e>>2];c[h+300+4>>2]=c[e+4>>2];c[h+300+8>>2]=c[e+8>>2];c[h+300+12>>2]=c[e+12>>2];c[h+316>>2]=c[f>>2];c[h+316+4>>2]=c[f+4>>2];c[h+316+8>>2]=c[f+8>>2];c[h+316+12>>2]=c[f+12>>2];c[h+332>>2]=0;a[h+344>>0]=0;g[h+348>>2]=.30000001192092896;g[h+352>>2]=1.0;g[h+356>>2]=0.0;return h|0}function _j(b){b=b|0;var d=0;c[b>>2]=4484;d=c[b+80>>2]|0;if(d|0){if(a[b+84>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+80>>2]=0}a[b+84>>0]=1;c[b+80>>2]=0;c[b+72>>2]=0;c[b+76>>2]=0;d=c[b+60>>2]|0;if(d|0){if(a[b+64>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+60>>2]=0}a[b+64>>0]=1;c[b+60>>2]=0;c[b+52>>2]=0;c[b+56>>2]=0;d=c[b+40>>2]|0;if(!d){a[b+44>>0]=1;c[b+40>>2]=0;c[b+32>>2]=0;b=b+36|0;c[b>>2]=0;return}if(a[b+44>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+40>>2]=0;a[b+44>>0]=1;c[b+40>>2]=0;c[b+32>>2]=0;b=b+36|0;c[b>>2]=0;return}function $j(b){b=b|0;var d=0;c[b>>2]=8848;d=c[b+64>>2]|0;if(d|0){if(a[b+68>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+64>>2]=0}a[b+68>>0]=1;c[b+64>>2]=0;c[b+56>>2]=0;c[b+60>>2]=0;d=c[b+44>>2]|0;if(d|0){if(a[b+48>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+44>>2]=0}a[b+48>>0]=1;c[b+44>>2]=0;c[b+36>>2]=0;c[b+40>>2]=0;d=c[b+16>>2]|0;if(!d){a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;b=b+12|0;c[b>>2]=0;return}if(a[b+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+16>>2]=0;a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;b=b+12|0;c[b>>2]=0;return}function ak(b){b=b|0;var d=0;c[b>>2]=5580;d=c[b+56>>2]|0;if(d|0){if(a[b+60>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+56>>2]=0}a[b+60>>0]=1;c[b+56>>2]=0;c[b+48>>2]=0;c[b+52>>2]=0;d=c[b+36>>2]|0;if(d|0){if(a[b+40>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+36>>2]=0}a[b+40>>0]=1;c[b+36>>2]=0;c[b+28>>2]=0;c[b+32>>2]=0;d=c[b+16>>2]|0;if(!d){d=b+12|0;a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;c[d>>2]=0;return}if(a[b+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+16>>2]=0;d=b+12|0;a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;c[d>>2]=0;return}function bk(b){b=b|0;var d=0;c[b>>2]=9476;d=c[b+60>>2]|0;if(d|0){if(a[b+64>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+60>>2]=0}a[b+64>>0]=1;c[b+60>>2]=0;c[b+52>>2]=0;c[b+56>>2]=0;d=c[b+40>>2]|0;if(d|0){if(a[b+44>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+40>>2]=0}a[b+44>>0]=1;c[b+40>>2]=0;c[b+32>>2]=0;c[b+36>>2]=0;d=c[b+16>>2]|0;if(!d){a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;b=b+12|0;c[b>>2]=0;return}if(a[b+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+16>>2]=0;a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;b=b+12|0;c[b>>2]=0;return}function ck(){var a=0,b=0,d=0,e=0;e=l;l=l+48|0;a=ur()|0;if(a|0?(d=c[a>>2]|0,d|0):0){a=c[d+48>>2]|0;b=c[d+48+4>>2]|0;if(!((a&-256|0)==1126902528&(b|0)==1129074247)){c[e+24>>2]=22101;Cv(22051,e+24|0)}if((a|0)==1126902529&(b|0)==1129074247)a=c[d+44>>2]|0;else a=d+80|0;c[e+36>>2]=a;d=c[d>>2]|0;a=c[d+4>>2]|0;if(Yk(2736,d,e+36|0)|0){d=c[e+36>>2]|0;d=lb[c[(c[d>>2]|0)+8>>2]&127](d)|0;c[e>>2]=22101;c[e+4>>2]=a;c[e+8>>2]=d;Cv(21965,e)}else{c[e+16>>2]=22101;c[e+16+4>>2]=a;Cv(22010,e+16|0)}}Cv(22089,e+32|0)}function dk(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=+e;f=f|0;h=h|0;var i=0;i=l;l=l+64|0;c[i+48>>2]=f;c[i+48+4>>2]=h;f=c[a+212>>2]|0;if(!(+g[f+4>>2]>=e)){l=i;return +e}c[i>>2]=c[a+216>>2];c[i+4>>2]=i+48;c[i+8>>2]=c[b>>2];c[i+8+4>>2]=c[b+4>>2];c[i+8+8>>2]=c[b+8>>2];c[i+8+12>>2]=c[b+12>>2];c[i+24>>2]=c[d>>2];c[i+24+4>>2]=c[d+4>>2];c[i+24+8>>2]=c[d+8>>2];c[i+24+12>>2]=c[d+12>>2];g[i+40>>2]=e;e=+Hb[c[(c[f>>2]|0)+12>>2]&15](f,i,0);l=i;return +e}function ek(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=+e;f=f|0;h=h|0;var i=0;i=l;l=l+64|0;c[i+48>>2]=f;c[i+48+4>>2]=h;f=c[a+212>>2]|0;if(!(+g[f+4>>2]>=e)){l=i;return +e}c[i>>2]=c[a+216>>2];c[i+4>>2]=i+48;c[i+8>>2]=c[b>>2];c[i+8+4>>2]=c[b+4>>2];c[i+8+8>>2]=c[b+8>>2];c[i+8+12>>2]=c[b+12>>2];c[i+24>>2]=c[d>>2];c[i+24+4>>2]=c[d+4>>2];c[i+24+8>>2]=c[d+8>>2];c[i+24+12>>2]=c[d+12>>2];g[i+40>>2]=e;e=+Hb[c[(c[f>>2]|0)+12>>2]&15](f,i,1);l=i;return +e}function fk(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0;i=Nr()|0;te(i,b,d,e,f,h);c[i>>2]=4612;c[i+4>>2]=9;a[i+1309>>0]=0;g[i+1316>>2]=0.0;g[i+1340>>2]=0.0;g[i+1364>>2]=1.0;a[i+1310>>0]=0;g[i+1320>>2]=0.0;g[i+1344>>2]=0.0;g[i+1368>>2]=1.0;a[i+1311>>0]=0;g[i+1324>>2]=0.0;g[i+1348>>2]=0.0;g[i+1372>>2]=1.0;a[i+1312>>0]=0;g[i+1328>>2]=0.0;g[i+1352>>2]=0.0;g[i+1376>>2]=1.0;a[i+1313>>0]=0;g[i+1332>>2]=0.0;g[i+1356>>2]=0.0;g[i+1380>>2]=1.0;a[i+1314>>0]=0;g[i+1336>>2]=0.0;g[i+1360>>2]=0.0;g[i+1384>>2]=1.0;return i|0}function gk(a,b){a=a|0;b=b|0;var c=0,d=0.0,e=0.0,f=0.0,h=0.0,i=0.0;c=l;l=l+48|0;d=2.0/+LD(b);f=+g[(bH(b)|0)>>2];e=+g[(IG(b)|0)>>2];i=+g[(HG(b)|0)>>2];h=+g[(GG(b)|0)>>2];g[c+32>>2]=1.0-(e*e*d+i*i*d);g[c+28>>2]=f*e*d-h*i*d;g[c+24>>2]=f*i*d+h*e*d;g[c+20>>2]=f*e*d+h*i*d;g[c+16>>2]=1.0-(f*f*d+i*i*d);g[c+12>>2]=e*i*d-h*f*d;g[c+8>>2]=f*i*d-h*e*d;g[c+4>>2]=e*i*d+h*f*d;g[c>>2]=1.0-(f*f*d+e*e*d);Oo(a,c+32|0,c+28|0,c+24|0,c+20|0,c+16|0,c+12|0,c+8|0,c+4|0,c);l=c;return}\nfunction vd(d,e,f){d=d|0;e=e|0;f=f|0;var g=0,i=0,j=0,k=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;t=l;l=l+32|0;g=lb[c[(c[d>>2]|0)+28>>2]&127](d)|0;c[e+20>>2]=g;c[e>>2]=0;if(!g){s=d+4|0;f=e+4|0;s=c[s>>2]|0;c[f>>2]=s;f=d+8|0;f=c[f>>2]|0;s=e+8|0;c[s>>2]=f;s=d+12|0;s=c[s>>2]|0;f=e+12|0;c[f>>2]=s;f=d+16|0;f=c[f>>2]|0;d=e+16|0;c[d>>2]=f;l=t;return 19480}s=vb[c[(c[f>>2]|0)+16>>2]&63](f,32,g)|0;g=c[s+8>>2]|0;c[e>>2]=Gb[c[(c[f>>2]|0)+28>>2]&31](f,g)|0;r=lb[c[(c[d>>2]|0)+28>>2]&127](d)|0;a:do if((r|0)>0){q=0;while(1){Fb[c[(c[d>>2]|0)+16>>2]&3](d,t+28|0,t+4|0,t+16|0,t+8|0,t+24|0,t+20|0,t,t+12|0,q);i=c[t>>2]|0;c[g+24>>2]=i;c[g+28>>2]=c[t+4>>2];j=g+12|0;m=g+16|0;p=g+4|0;c[g>>2]=0;c[g+4>>2]=0;c[g+8>>2]=0;c[g+12>>2]=0;c[g+16>>2]=0;c[g+20>>2]=0;switch(c[t+12>>2]|0){case 2:{if(i|0){k=vb[c[(c[f>>2]|0)+16>>2]&63](f,4,i*3|0)|0;i=c[k+8>>2]|0;c[g+8>>2]=Gb[c[(c[f>>2]|0)+28>>2]&31](f,i)|0;if((c[t>>2]|0)>0){j=c[t+24>>2]|0;m=0;do{n=j+(O(c[t+20>>2]|0,m)|0)|0;o=m*3|0;c[i+(o<<2)>>2]=c[n>>2];c[i+(o+1<<2)>>2]=c[n+4>>2];c[i+(o+2<<2)>>2]=c[n+8>>2];m=m+1|0}while((m|0)<(c[t>>2]|0))}fb[c[(c[f>>2]|0)+20>>2]&31](f,k,19361,1497453121,c[k+8>>2]|0)}break}case 3:{if(i|0){o=vb[c[(c[f>>2]|0)+16>>2]&63](f,8,i)|0;n=c[o+8>>2]|0;c[j>>2]=Gb[c[(c[f>>2]|0)+28>>2]&31](f,n)|0;i=c[t>>2]|0;if((i|0)>0){j=c[t+24>>2]|0;k=c[t+20>>2]|0;m=0;do{u=j+(O(k,m)|0)|0;b[n+(m<<3)>>1]=b[u>>1]|0;b[n+(m<<3)+2>>1]=b[u+2>>1]|0;b[n+(m<<3)+4>>1]=b[u+4>>1]|0;m=m+1|0}while((m|0)!=(i|0))}fb[c[(c[f>>2]|0)+20>>2]&31](f,o,19376,1497453121,c[o+8>>2]|0)}break}case 5:{if(i|0){k=vb[c[(c[f>>2]|0)+16>>2]&63](f,4,i)|0;j=c[k+8>>2]|0;c[m>>2]=Gb[c[(c[f>>2]|0)+28>>2]&31](f,j)|0;if((c[t>>2]|0)>0){i=0;do{u=(c[t+24>>2]|0)+(O(c[t+20>>2]|0,i)|0)|0;a[j+(i<<2)>>0]=a[u>>0]|0;a[j+(i<<2)+1>>0]=a[u+1>>0]|0;a[j+(i<<2)+2>>0]=a[u+2>>0]|0;i=i+1|0}while((i|0)<(c[t>>2]|0))}fb[c[(c[f>>2]|0)+20>>2]&31](f,k,19403,1497453121,c[k+8>>2]|0)}break}default:{}}switch(c[t+16>>2]|0){case 0:{i=c[t+4>>2]|0;if(i|0){n=vb[c[(c[f>>2]|0)+16>>2]&63](f,16,i)|0;i=c[n+8>>2]|0;c[g>>2]=Gb[c[(c[f>>2]|0)+28>>2]&31](f,i)|0;j=c[t+4>>2]|0;if((j|0)>0){k=c[t+28>>2]|0;m=c[t+8>>2]|0;o=0;do{u=k+(O(m,o)|0)|0;c[i+(o<<4)>>2]=c[u>>2];c[i+(o<<4)+4>>2]=c[u+4>>2];c[i+(o<<4)+8>>2]=c[u+8>>2];o=o+1|0}while((o|0)!=(j|0))}fb[c[(c[f>>2]|0)+20>>2]&31](f,n,19426,1497453121,c[n+8>>2]|0)}break}case 1:{i=c[t+4>>2]|0;if(i|0){o=vb[c[(c[f>>2]|0)+16>>2]&63](f,32,i)|0;n=c[o+8>>2]|0;c[p>>2]=Gb[c[(c[f>>2]|0)+28>>2]&31](f,n)|0;i=c[t+4>>2]|0;if((i|0)>0){j=c[t+28>>2]|0;k=c[t+8>>2]|0;m=0;do{u=j+(O(k,m)|0)|0;h[n+(m<<5)>>3]=+h[u>>3];h[n+(m<<5)+8>>3]=+h[u+8>>3];h[n+(m<<5)+16>>3]=+h[u+16>>3];m=m+1|0}while((m|0)!=(i|0))}fb[c[(c[f>>2]|0)+20>>2]&31](f,o,19445,1497453121,c[o+8>>2]|0)}break}default:{}}jb[c[(c[d>>2]|0)+24>>2]&127](d,q);q=q+1|0;if((q|0)==(r|0)){g=f;break a}else g=g+32|0}}else g=f;while(0);fb[c[(c[g>>2]|0)+20>>2]&31](f,s,19465,1497453121,c[s+8>>2]|0);f=d+4|0;u=e+4|0;f=c[f>>2]|0;c[u>>2]=f;u=d+8|0;u=c[u>>2]|0;f=e+8|0;c[f>>2]=u;f=d+12|0;f=c[f>>2]|0;u=e+12|0;c[u>>2]=f;d=d+16|0;d=c[d>>2]|0;u=e+16|0;c[u>>2]=d;l=t;return 19480}function wd(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,h=0,i=0,j=0,k=0.0,l=0.0,m=0.0,n=0.0,o=0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0;i=c[a+192>>2]|0;n=+zb[c[(c[i>>2]|0)+48>>2]&15](i);i=c[a+712>>2]|0;if((i|0)>0){o=0;do{j=c[a+720>>2]|0;f=j+(o*104|0)+8|0;q=+g[f>>2];h=j+(o*104|0)+12|0;p=+g[h>>2];d=j+(o*104|0)+16|0;l=+g[d>>2];k=q*+g[b>>2]+p*+g[b+4>>2]+l*+g[b+8>>2]+ +g[b+48>>2];m=q*+g[b+16>>2]+p*+g[b+20>>2]+l*+g[b+24>>2]+ +g[b+52>>2];l=q*+g[b+32>>2]+p*+g[b+36>>2]+l*+g[b+40>>2]+ +g[b+56>>2];g[f>>2]=k;g[h>>2]=m;g[d>>2]=l;g[j+(o*104|0)+20>>2]=0.0;d=j+(o*104|0)+24|0;p=+g[d>>2];h=j+(o*104|0)+28|0;q=+g[h>>2];f=j+(o*104|0)+32|0;r=+g[f>>2];s=p*+g[b+16>>2]+q*+g[b+20>>2]+r*+g[b+24>>2]+ +g[b+52>>2];t=p*+g[b+32>>2]+q*+g[b+36>>2]+r*+g[b+40>>2]+ +g[b+56>>2];g[d>>2]=p*+g[b>>2]+q*+g[b+4>>2]+r*+g[b+8>>2]+ +g[b+48>>2];g[h>>2]=s;g[f>>2]=t;g[j+(o*104|0)+36>>2]=0.0;f=j+(o*104|0)+72|0;t=+g[f>>2];h=j+(o*104|0)+76|0;s=+g[h>>2];d=j+(o*104|0)+80|0;r=+g[d>>2];q=t*+g[b+16>>2]+s*+g[b+20>>2]+r*+g[b+24>>2];p=t*+g[b+32>>2]+s*+g[b+36>>2]+r*+g[b+40>>2];g[f>>2]=+g[b>>2]*t+ +g[b+4>>2]*s+ +g[b+8>>2]*r;g[h>>2]=q;g[d>>2]=p;g[j+(o*104|0)+84>>2]=0.0;j=c[j+(o*104|0)+96>>2]|0;d=Kg(a+928|0,j)|0;a:do if(d){f=c[a+936>>2]|0;if((f|0)<=-1){d=c[a+928>>2]|0;break}if(f){h=0;while(1){e=c[d+32>>2]|0;h=h+1|0;if(!e)break a;if((h|0)>=(f|0)){d=e;break}else d=e}}}else d=0;while(0);g[j>>2]=k-n;g[j+4>>2]=m-n;g[j+8>>2]=l-n;g[j+12>>2]=0.0;g[j+16>>2]=n+k;g[j+20>>2]=n+m;g[j+24>>2]=n+l;g[j+28>>2]=0.0;We(a+928|0,d,j);o=o+1|0}while((o|0)!=(i|0))}gg(a);d=c[a+928>>2]|0;if(d){o=c[a+192>>2]|0;r=+zb[c[(c[o>>2]|0)+48>>2]&15](o);t=+g[d+4>>2]-r;s=+g[d+8>>2]-r;g[a+892>>2]=+g[d>>2]-r;g[a+896>>2]=t;g[a+900>>2]=s;g[a+904>>2]=0.0;s=r+ +g[d+20>>2];t=r+ +g[d+24>>2];g[a+908>>2]=r+ +g[d+16>>2];g[a+912>>2]=s;g[a+916>>2]=t;g[a+920>>2]=0.0;d=c[a+188>>2]|0;if(d|0){o=c[a+684>>2]|0;j=c[o+32>>2]|0;fb[c[(c[j>>2]|0)+16>>2]&31](j,d,a+892|0,a+908|0,c[o+36>>2]|0)}}else{c[a+892>>2]=0;c[a+892+4>>2]=0;c[a+892+8>>2]=0;c[a+892+12>>2]=0;c[a+892+16>>2]=0;c[a+892+20>>2]=0;c[a+892+24>>2]=0;c[a+892+28>>2]=0}e=c[a+732>>2]|0;if((e|0)<=0){Hf(a);o=a+1148|0;c[o>>2]=c[b>>2];c[o+4>>2]=c[b+4>>2];c[o+8>>2]=c[b+8>>2];c[o+12>>2]=c[b+12>>2];o=b+16|0;j=a+1164|0;c[j>>2]=c[o>>2];c[j+4>>2]=c[o+4>>2];c[j+8>>2]=c[o+8>>2];c[j+12>>2]=c[o+12>>2];j=b+32|0;o=a+1180|0;c[o>>2]=c[j>>2];c[o+4>>2]=c[j+4>>2];c[o+8>>2]=c[j+8>>2];c[o+12>>2]=c[j+12>>2];o=b+48|0;b=a+1196|0;c[b>>2]=c[o>>2];c[b+4>>2]=c[o+4>>2];c[b+8>>2]=c[o+8>>2];c[b+12>>2]=c[o+12>>2];return}f=c[a+740>>2]|0;d=0;do{j=c[f+(d*52|0)+8>>2]|0;o=c[f+(d*52|0)+12>>2]|0;r=+g[j+8>>2]-+g[o+8>>2];s=+g[j+12>>2]-+g[o+12>>2];t=+g[j+16>>2]-+g[o+16>>2];t=+C(+(r*r+s*s+t*t));g[f+(d*52|0)+16>>2]=t;g[f+(d*52|0)+28>>2]=t*t;d=d+1|0}while((d|0)!=(e|0));d=0;do{g[f+(d*52|0)+24>>2]=(+g[(c[f+(d*52|0)+8>>2]|0)+88>>2]+ +g[(c[f+(d*52|0)+12>>2]|0)+88>>2])/+g[(c[f+(d*52|0)+4>>2]|0)+4>>2];d=d+1|0}while((d|0)!=(e|0));Hf(a);o=a+1148|0;c[o>>2]=c[b>>2];c[o+4>>2]=c[b+4>>2];c[o+8>>2]=c[b+8>>2];c[o+12>>2]=c[b+12>>2];o=b+16|0;j=a+1164|0;c[j>>2]=c[o>>2];c[j+4>>2]=c[o+4>>2];c[j+8>>2]=c[o+8>>2];c[j+12>>2]=c[o+12>>2];j=b+32|0;o=a+1180|0;c[o>>2]=c[j>>2];c[o+4>>2]=c[j+4>>2];c[o+8>>2]=c[j+8>>2];c[o+12>>2]=c[j+12>>2];o=b+48|0;b=a+1196|0;c[b>>2]=c[o>>2];c[b+4>>2]=c[o+4>>2];c[b+8>>2]=c[o+8>>2];c[b+12>>2]=c[o+12>>2];return}function xd(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,h=0,i=0,j=0.0,k=0.0,l=0.0,m=0.0,n=0,o=0,p=0,q=0.0,r=0.0,s=0.0;if(a[b+165>>0]|0){f=c[b+88>>2]|0;a:do if((f|0)>0&e){h=c[b+96>>2]|0;j=+g[d>>2];k=+g[d+4>>2];l=+g[d+8>>2];m=+g[b+168>>2];e=0;while(1){s=+g[h+(e<<4)>>2]-j;r=+g[h+(e<<4)+4>>2]-k;q=+g[h+(e<<4)+8>>2]-l;if(s*s+r*r+q*q<=m)break;e=e+1|0;if((e|0)>=(f|0))break a}return e|0}while(0);p=(c[b+32>>2]|0)+12|0;c[p>>2]=(c[p>>2]|0)+1;if((f|0)==(c[b+92>>2]|0)?(i=f|0?f<<1:1,(f|0)<(i|0)):0){if(!i)h=0;else{c[6432]=(c[6432]|0)+1;e=ec((i<<4|3)+16|0)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}f=c[b+88>>2]|0;h=e}if((f|0)>0){e=0;do{p=h+(e<<4)|0;o=(c[b+96>>2]|0)+(e<<4)|0;c[p>>2]=c[o>>2];c[p+4>>2]=c[o+4>>2];c[p+8>>2]=c[o+8>>2];c[p+12>>2]=c[o+12>>2];e=e+1|0}while((e|0)!=(f|0))}e=c[b+96>>2]|0;if(e|0){if(a[b+100>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}c[b+96>>2]=0}a[b+100>>0]=1;c[b+96>>2]=h;c[b+92>>2]=i;e=c[b+88>>2]|0}else e=f;p=(c[b+96>>2]|0)+(e<<4)|0;c[p>>2]=c[d>>2];c[p+4>>2]=c[d+4>>2];c[p+8>>2]=c[d+8>>2];c[p+12>>2]=c[d+12>>2];d=c[b+88>>2]|0;c[b+88>>2]=d+1;c[(c[b+32>>2]|0)+16>>2]=c[b+96>>2];return d|0}h=c[b+108>>2]|0;b:do if((h|0)>0&e){e=c[b+116>>2]|0;j=+g[d>>2];k=+g[d+4>>2];l=+g[d+8>>2];m=+g[b+168>>2];i=0;while(1){q=+g[e+(i<<2)>>2]-j;r=+g[e+(i+1<<2)>>2]-k;s=+g[e+(i+2<<2)>>2]-l;f=i+3|0;if(q*q+r*r+s*s<=m)break;if((f|0)<(h|0))i=f;else break b}d=(i|0)/3|0;return d|0}while(0);e=c[b+112>>2]|0;if((h|0)==(e|0)){n=h|0?h<<1:1;if((h|0)<(n|0)){if(!n)i=0;else{c[6432]=(c[6432]|0)+1;e=ec((n<<2|3)+16|0)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}h=c[b+108>>2]|0;i=e}f=c[b+116>>2]|0;if((h|0)<=0)if(!f)e=b+120|0;else p=34;else{e=0;do{c[i+(e<<2)>>2]=c[f+(e<<2)>>2];e=e+1|0}while((e|0)!=(h|0));p=34}if((p|0)==34){if(a[b+120>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[b+116>>2]=0;e=b+120|0}a[e>>0]=1;c[b+116>>2]=i;c[b+112>>2]=n;f=c[b+108>>2]|0;e=n}else{f=h;e=h}}else f=h;i=c[b+116>>2]|0;c[i+(f<<2)>>2]=c[d>>2];f=f+1|0;c[b+108>>2]=f;if((f|0)==(e|0)){f=e|0?e<<1:1;if((e|0)<(f|0)){if(!f)n=0;else{c[6432]=(c[6432]|0)+1;e=ec((f<<2|3)+16|0)|0;if(!e)h=0;else{c[(e+4+15&-16)+-4>>2]=e;h=e+4+15&-16}e=c[b+108>>2]|0;i=c[b+116>>2]|0;n=h}if((e|0)<=0)if(!i)e=b+120|0;else p=48;else{h=0;do{c[n+(h<<2)>>2]=c[i+(h<<2)>>2];h=h+1|0}while((h|0)!=(e|0));p=48}if((p|0)==48){if(a[b+120>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[b+116>>2]=0;e=b+120|0}a[e>>0]=1;c[b+116>>2]=n;c[b+112>>2]=f;o=n;h=c[b+108>>2]|0;e=n}else{o=i;h=e;f=e;e=i}}else{o=i;h=f;f=e;e=i}c[o+(h<<2)>>2]=c[d+4>>2];h=h+1|0;c[b+108>>2]=h;if((h|0)==(f|0)){i=f|0?f<<1:1;if((f|0)<(i|0)){if(!i){h=o;n=0}else{c[6432]=(c[6432]|0)+1;e=ec((i<<2|3)+16|0)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}f=c[b+108>>2]|0;h=c[b+116>>2]|0;n=e}if((f|0)<=0)if(!h)e=b+120|0;else p=62;else{e=0;do{c[n+(e<<2)>>2]=c[h+(e<<2)>>2];e=e+1|0}while((e|0)!=(f|0));p=62}if((p|0)==62){if(a[b+120>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[b+116>>2]=0;e=b+120|0}a[e>>0]=1;c[b+116>>2]=n;c[b+112>>2]=i;i=n;f=c[b+108>>2]|0;e=n}else i=o}else{i=o;f=h}c[i+(f<<2)>>2]=c[d+8>>2];d=f+1|0;c[b+108>>2]=d;b=c[b+32>>2]|0;c[b+12>>2]=(c[b+12>>2]|0)+1;c[b+16>>2]=e;d=((d|0)/3|0)+-1|0;return d|0}function yd(b,d,e){b=b|0;d=d|0;e=e|0;var f=0.0,h=0,i=0,j=0,k=0,m=0,n=0,o=0.0,p=0,q=0,r=0,s=0;p=l;l=l+128|0;c[b+68>>2]=(c[b+68>>2]|0)+1;c[p>>2]=c[d>>2];c[p+4>>2]=c[d+4>>2];c[p+8>>2]=c[d+8>>2];c[p+12>>2]=c[d+12>>2];c[p+16>>2]=c[d+16>>2];c[p+16+4>>2]=c[d+16+4>>2];c[p+16+8>>2]=c[d+16+8>>2];c[p+16+12>>2]=c[d+16+12>>2];c[p+32>>2]=c[d+32>>2];c[p+32+4>>2]=c[d+32+4>>2];c[p+32+8>>2]=c[d+32+8>>2];c[p+32+12>>2]=c[d+32+12>>2];c[p+48>>2]=c[d+48>>2];c[p+48+4>>2]=c[d+48+4>>2];c[p+48+8>>2]=c[d+48+8>>2];c[p+48+12>>2]=c[d+48+12>>2];n=c[e+4>>2]|0;o=+zb[c[(c[e>>2]|0)+48>>2]&15](e);Vb[c[(c[e>>2]|0)+8>>2]&127](e,d,p+112|0,p+96|0);f=+g[p+112>>2];if(+g[b+32>>2]>f)g[b+32>>2]=f;f=+g[p+96>>2];if(+g[b+48>>2]<f)g[b+48>>2]=f;f=+g[p+112+4>>2];if(+g[b+36>>2]>f)g[b+36>>2]=f;f=+g[p+96+4>>2];if(+g[b+52>>2]<f)g[b+52>>2]=f;f=+g[p+112+8>>2];if(+g[b+40>>2]>f)g[b+40>>2]=f;f=+g[p+96+8>>2];if(+g[b+56>>2]<f)g[b+56>>2]=f;k=c[b+64>>2]|0;if(!k){j=0;k=b+16|0}else{c[p+64>>2]=c[p+112>>2];c[p+64+4>>2]=c[p+112+4>>2];c[p+64+8>>2]=c[p+112+8>>2];c[p+64+12>>2]=c[p+112+12>>2];c[p+64+16>>2]=c[p+96>>2];c[p+64+16+4>>2]=c[p+96+4>>2];c[p+64+16+8>>2]=c[p+96+8>>2];c[p+64+16+12>>2]=c[p+96+12>>2];j=c[b+16>>2]|0;d=c[k+4>>2]|0;if(!d){c[6432]=(c[6432]|0)+1;d=ec(63)|0;if(!d)d=0;else{c[(d+4+15&-16)+-4>>2]=d;d=d+4+15&-16}h=d;i=h+44|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(i|0))}else c[k+4>>2]=0;c[d+32>>2]=0;c[d+36>>2]=j;c[d+40>>2]=0;c[d>>2]=c[p+64>>2];c[d+4>>2]=c[p+64+4>>2];c[d+8>>2]=c[p+64+8>>2];c[d+12>>2]=c[p+64+12>>2];c[d+16>>2]=c[p+64+16>>2];c[d+20>>2]=c[p+64+20>>2];c[d+24>>2]=c[p+64+24>>2];c[d+28>>2]=c[p+64+28>>2];We(k,c[k>>2]|0,d);c[k+12>>2]=(c[k+12>>2]|0)+1;j=d;k=b+16|0}d=c[k>>2]|0;if((d|0)==(c[b+20>>2]|0)?(m=d|0?d<<1:1,(d|0)<(m|0)):0){if(!m)h=0;else{c[6432]=(c[6432]|0)+1;d=ec((m*80|3)+16|0)|0;if(!d)h=0;else{c[(d+4+15&-16)+-4>>2]=d;h=d+4+15&-16}d=c[k>>2]|0}if((d|0)>0){i=0;do{q=h+(i*80|0)|0;r=c[b+24>>2]|0;s=r+(i*80|0)|0;c[q>>2]=c[s>>2];c[q+4>>2]=c[s+4>>2];c[q+8>>2]=c[s+8>>2];c[q+12>>2]=c[s+12>>2];q=r+(i*80|0)+16|0;s=h+(i*80|0)+16|0;c[s>>2]=c[q>>2];c[s+4>>2]=c[q+4>>2];c[s+8>>2]=c[q+8>>2];c[s+12>>2]=c[q+12>>2];s=r+(i*80|0)+32|0;q=h+(i*80|0)+32|0;c[q>>2]=c[s>>2];c[q+4>>2]=c[s+4>>2];c[q+8>>2]=c[s+8>>2];c[q+12>>2]=c[s+12>>2];q=h+(i*80|0)+48|0;s=r+(i*80|0)+48|0;c[q>>2]=c[s>>2];c[q+4>>2]=c[s+4>>2];c[q+8>>2]=c[s+8>>2];c[q+12>>2]=c[s+12>>2];q=h+(i*80|0)+64|0;r=r+(i*80|0)+64|0;c[q>>2]=c[r>>2];c[q+4>>2]=c[r+4>>2];c[q+8>>2]=c[r+8>>2];c[q+12>>2]=c[r+12>>2];i=i+1|0}while((i|0)!=(d|0))}d=c[b+24>>2]|0;if(d|0){if(a[b+28>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+24>>2]=0}a[b+28>>0]=1;c[b+24>>2]=h;c[b+20>>2]=m;d=c[k>>2]|0}s=c[b+24>>2]|0;r=s+(d*80|0)|0;c[r>>2]=c[p>>2];c[r+4>>2]=c[p+4>>2];c[r+8>>2]=c[p+8>>2];c[r+12>>2]=c[p+12>>2];r=s+(d*80|0)+16|0;c[r>>2]=c[p+16>>2];c[r+4>>2]=c[p+16+4>>2];c[r+8>>2]=c[p+16+8>>2];c[r+12>>2]=c[p+16+12>>2];r=s+(d*80|0)+32|0;c[r>>2]=c[p+32>>2];c[r+4>>2]=c[p+32+4>>2];c[r+8>>2]=c[p+32+8>>2];c[r+12>>2]=c[p+32+12>>2];r=s+(d*80|0)+48|0;c[r>>2]=c[p+48>>2];c[r+4>>2]=c[p+48+4>>2];c[r+8>>2]=c[p+48+8>>2];c[r+12>>2]=c[p+48+12>>2];s=s+(d*80|0)+64|0;c[s>>2]=e;c[s+4>>2]=n;g[s+8>>2]=o;c[s+12>>2]=j;c[k>>2]=(c[k>>2]|0)+1;l=p;return}function zd(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,h=0,i=0,j=0,k=0,m=0,n=0.0,o=0.0;m=l;l=l+384|0;f=c[d+36>>2]|0;d=c[e+36>>2]|0;e=c[b+24>>2]|0;if(((e|0)==(c[b+28>>2]|0)?c[e+1132>>2]|0:0)?(j=(O(c[d+380>>2]|0,c[e+1112>>2]|0)|0)+(c[f+380>>2]|0)|0,a[(c[e+1140>>2]|0)+j>>0]|0):0){c[5799]=(c[5799]|0)+1;l=m;return}c[m+328+4>>2]=35;c[m+328+8>>2]=0;c[m+328+12>>2]=1065353216;c[m+328+16>>2]=1065353216;c[m+328+20>>2]=1065353216;g[m+328+24>>2]=0.0;c[m+328>>2]=3564;c[m+328+52>>2]=f;g[m+328+44>>2]=0.0;c[m+272+4>>2]=35;c[m+272+8>>2]=0;c[m+272+12>>2]=1065353216;c[m+272+16>>2]=1065353216;c[m+272+20>>2]=1065353216;g[m+272+24>>2]=0.0;c[m+272>>2]=3564;c[m+272+52>>2]=d;g[m+272+44>>2]=0.0;if((a[22600]|0)==0?jy(22600)|0:0){if((a[22608]|0)==0?jy(22608)|0:0){c[5728]=1065353216;c[5729]=0;c[5730]=0;c[5731]=0;c[5732]=0;c[5733]=1065353216;c[5734]=0;c[5735]=0;c[5736]=0;c[5737]=0;c[5738]=1065353216;g[5739]=0.0}c[5712]=c[5728];c[5713]=c[5729];c[5714]=c[5730];c[5715]=c[5731];c[5716]=c[5732];c[5717]=c[5733];c[5718]=c[5734];c[5719]=c[5735];c[5720]=c[5736];c[5721]=c[5737];c[5722]=c[5738];c[5723]=c[5739];c[5724]=0;c[5725]=0;c[5726]=0;c[5727]=0}if((a[22600]|0)==0?jy(22600)|0:0){if((a[22608]|0)==0?jy(22608)|0:0){c[5728]=1065353216;c[5729]=0;c[5730]=0;c[5731]=0;c[5732]=0;c[5733]=1065353216;c[5734]=0;c[5735]=0;c[5736]=0;c[5737]=0;c[5738]=1065353216;g[5739]=0.0}c[5712]=c[5728];c[5713]=c[5729];c[5714]=c[5730];c[5715]=c[5731];c[5716]=c[5732];c[5717]=c[5733];c[5718]=c[5734];c[5719]=c[5735];c[5720]=c[5736];c[5721]=c[5737];c[5722]=c[5738];c[5723]=c[5739];c[5724]=0;c[5725]=0;c[5726]=0;c[5727]=0}o=+g[f+232>>2]-+g[d+232>>2];n=+g[f+236>>2]-+g[d+236>>2];g[m>>2]=+g[f+228>>2]-+g[d+228>>2];g[m+4>>2]=o;g[m+8>>2]=n;g[m+12>>2]=0.0;if(!(!(qd(m+328|0,22848,m+272|0,22848,m,m+216|0)|0)?!(vc(m+328|0,22848,m+272|0,22848,m,m+216|0,0)|0):0))h=19;if((h|0)==19?(c[m+4>>2]=0,c[m+4+4>>2]=0,c[m+4+8>>2]=0,c[m+4+12>>2]=0,c[m+4+16>>2]=0,c[m+4+20>>2]=0,a[m+152>>0]=0,c[m>>2]=3384,id(b,m+216|0,f,0,0,d,0,0,m)|0):0){c[6432]=(c[6432]|0)+1;d=ec(235)|0;if(!d)j=0;else{c[(d+4+15&-16)+-4>>2]=d;j=d+4+15&-16}e=j+4|0;d=j+152|0;Hk(e|0,0,212)|0;c[j>>2]=3384;f=m+4|0;h=e+100|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(h|0));e=j+104|0;c[e>>2]=c[m+104>>2];c[e+4>>2]=c[m+104+4>>2];c[e+8>>2]=c[m+104+8>>2];c[e+12>>2]=c[m+104+12>>2];e=j+120|0;c[e>>2]=c[m+120>>2];c[e+4>>2]=c[m+120+4>>2];c[e+8>>2]=c[m+120+8>>2];c[e+12>>2]=c[m+120+12>>2];e=j+136|0;c[e>>2]=c[m+136>>2];c[e+4>>2]=c[m+136+4>>2];c[e+8>>2]=c[m+136+8>>2];c[e+12>>2]=c[m+136+12>>2];a[d>>0]=a[m+152>>0]|0;e=j+156|0;f=m+156|0;h=e+60|0;do{c[e>>2]=c[f>>2];e=e+4|0;f=f+4|0}while((e|0)<(h|0));h=c[b+24>>2]|0;i=j;d=c[h+852>>2]|0;if((d|0)==(c[h+856>>2]|0)?(k=d|0?d<<1:1,(d|0)<(k|0)):0){if(!k)e=0;else{c[6432]=(c[6432]|0)+1;d=ec((k<<2|3)+16|0)|0;if(!d)e=0;else{c[(d+4+15&-16)+-4>>2]=d;e=d+4+15&-16}d=c[h+852>>2]|0}if((d|0)>0){f=0;do{c[e+(f<<2)>>2]=c[(c[h+860>>2]|0)+(f<<2)>>2];f=f+1|0}while((f|0)!=(d|0))}f=c[h+860>>2]|0;if(f){if(a[h+864>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0);d=c[h+852>>2]|0}c[h+860>>2]=0}a[h+864>>0]=1;c[h+860>>2]=e;c[h+856>>2]=k}c[(c[h+860>>2]|0)+(d<<2)>>2]=i;c[h+852>>2]=d+1;i=c[b+24>>2]|0;k=c[b+28>>2]|0;n=+g[i+348>>2];o=+g[k+348>>2];b=j+64|0;g[b>>2]=+g[b>>2]*(n>o?n:o);b=j+68|0;g[b>>2]=+g[b>>2]*(+g[i+360>>2]+ +g[k+360>>2])*.5}l=m;return}function Ad(b){b=b|0;var d=0,e=0.0,f=0.0,h=0.0,i=0,j=0.0,k=0,m=0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0;m=l;l=l+16|0;if(!(a[b+1308>>0]|0)){l=m;return}g[b+928>>2]=0.0;g[b+992>>2]=0.0;g[b+1056>>2]=0.0;c[b+712>>2]=0;c[b+712+4>>2]=0;c[b+712+8>>2]=0;c[b+712+12>>2]=0;_c(b,(c[b+28>>2]|0)+4|0,(c[b+32>>2]|0)+4|0);hb[c[(c[b>>2]|0)+44>>2]&511](b);e=+g[b+1284>>2];f=+g[b+1288>>2];h=+g[b+1292>>2];if(+g[b+696>>2]>=+g[b+680>>2]){d=(a[b+1300>>0]|0)==0?b+1128|0:b+1064|0;i=c[d+16>>2]|0;k=c[d+32>>2]|0;c[m>>2]=c[d>>2];c[m+4>>2]=i;c[m+8>>2]=k;g[m+12>>2]=0.0;jh(c[b+28>>2]|0,c[b+32>>2]|0,b+176|0,m,e,f,h,e,f,h)}if(+g[b+700>>2]>=+g[b+684>>2]){d=(a[b+1300>>0]|0)==0?b+1128|0:b+1064|0;i=c[d+20>>2]|0;k=c[d+36>>2]|0;c[m>>2]=c[d+4>>2];c[m+4>>2]=i;c[m+8>>2]=k;g[m+12>>2]=0.0;jh(c[b+28>>2]|0,c[b+32>>2]|0,b+260|0,m,e,f,h,e,f,h)}if(+g[b+704>>2]>=+g[b+688>>2]){d=(a[b+1300>>0]|0)==0?b+1128|0:b+1064|0;i=c[d+24>>2]|0;k=c[d+40>>2]|0;c[m>>2]=c[d+8>>2];c[m+4>>2]=i;c[m+8>>2]=k;g[m+12>>2]=0.0;jh(c[b+28>>2]|0,c[b+32>>2]|0,b+344|0,m,e,f,h,e,f,h)}k=0;do{f=+g[b+868+(k<<6)>>2];h=+g[b+868+(k<<6)+4>>2];j=+Hj(+g[b+1192+(k<<2)>>2],f,h);g[b+868+(k<<6)+52>>2]=j;do if(!(f>h)){if(f>j){c[b+868+(k<<6)+56>>2]=1;d=b+868+(k<<6)+48|0;g[d>>2]=j-f;if(!(j-f>3.1415927410125732))if(j-f<-3.1415927410125732)e=6.2831854820251465;else{i=16;break}else e=-6.2831854820251465;g[d>>2]=j-f+e;i=16;break}d=b+868+(k<<6)+56|0;if(h<j){c[d>>2]=2;d=b+868+(k<<6)+48|0;g[d>>2]=j-h;if(!(j-h>3.1415927410125732))if(j-h<-3.1415927410125732)e=6.2831854820251465;else{i=16;break}else e=-6.2831854820251465;g[d>>2]=j-h+e;i=16}else i=15}else{d=b+868+(k<<6)+56|0;i=15}while(0);if((i|0)==15?(i=0,c[d>>2]=0,a[b+868+(k<<6)+44>>0]|0):0)i=16;if((i|0)==16){K=b+1208+(k<<4)|0;c[m>>2]=c[K>>2];c[m+4>>2]=c[K+4>>2];c[m+8>>2]=c[K+8>>2];c[m+12>>2]=c[K+12>>2];K=b+428+(k*84|0)|0;d=c[b+28>>2]|0;J=+g[d+4>>2];I=+g[d+20>>2];H=+g[d+36>>2];F=+g[d+8>>2];E=+g[d+24>>2];D=+g[d+40>>2];B=+g[d+12>>2];A=+g[d+28>>2];z=+g[d+44>>2];i=c[b+32>>2]|0;x=+g[i+4>>2];w=+g[i+20>>2];v=+g[i+36>>2];t=+g[i+8>>2];s=+g[i+24>>2];r=+g[i+40>>2];p=+g[i+12>>2];n=+g[i+28>>2];f=+g[i+44>>2];c[K>>2]=0;c[K+4>>2]=0;c[K+8>>2]=0;c[K+12>>2]=0;o=+g[m>>2];e=+g[m+4>>2];h=+g[m+8>>2];g[b+428+(k*84|0)+16>>2]=J*o+I*e+H*h;g[b+428+(k*84|0)+20>>2]=F*o+E*e+D*h;g[b+428+(k*84|0)+24>>2]=B*o+A*e+z*h;g[b+428+(k*84|0)+28>>2]=0.0;g[b+428+(k*84|0)+32>>2]=x*-o+w*-e+v*-h;g[b+428+(k*84|0)+36>>2]=t*-o+s*-e+r*-h;g[b+428+(k*84|0)+40>>2]=p*-o+n*-e+f*-h;g[b+428+(k*84|0)+44>>2]=0.0;G=(J*o+I*e+H*h)*+g[d+396>>2];C=(F*o+E*e+D*h)*+g[d+400>>2];y=(B*o+A*e+z*h)*+g[d+404>>2];g[b+428+(k*84|0)+48>>2]=G;g[b+428+(k*84|0)+52>>2]=C;g[b+428+(k*84|0)+56>>2]=y;g[b+428+(k*84|0)+60>>2]=0.0;u=(x*-o+w*-e+v*-h)*+g[i+396>>2];q=(t*-o+s*-e+r*-h)*+g[i+400>>2];j=(p*-o+n*-e+f*-h)*+g[i+404>>2];g[b+428+(k*84|0)+64>>2]=u;g[b+428+(k*84|0)+68>>2]=q;g[b+428+(k*84|0)+72>>2]=j;g[b+428+(k*84|0)+76>>2]=0.0;g[b+428+(k*84|0)+80>>2]=(J*o+I*e+H*h)*G+(F*o+E*e+D*h)*C+(B*o+A*e+z*h)*y+((x*-o+w*-e+v*-h)*u+(t*-o+s*-e+r*-h)*q+(p*-o+n*-e+f*-h)*j)}k=k+1|0}while((k|0)!=3);l=m;return}function Bd(b,d,e,f,h,i){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;var k=0,m=0.0,n=0,o=0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,D=0,E=0;D=l;l=l+272|0;z=+g[e+48>>2]-+g[d+48>>2];B=+g[e+52>>2]-+g[d+52>>2];A=+g[e+56>>2]-+g[d+56>>2];rf(d,e,D+256|0,D+208|0);v=+g[D+208>>2];t=+g[D+256>>2]*v;u=v*+g[D+256+4>>2];v=v*+g[D+256+8>>2];g[D+192>>2]=t;g[D+192+4>>2]=u;g[D+192+8>>2]=v;g[D+192+12>>2]=0.0;w=+g[h+48>>2]-+g[f+48>>2];y=+g[h+52>>2]-+g[f+52>>2];x=+g[h+56>>2]-+g[f+56>>2];rf(f,h,D+256|0,D+208|0);s=+g[D+208>>2];q=+g[D+256>>2]*s;r=s*+g[D+256+4>>2];s=s*+g[D+256+8>>2];g[D+176>>2]=q;g[D+176+4>>2]=r;g[D+176+8>>2]=s;g[D+176+12>>2]=0.0;e=c[b+12>>2]|0;p=+zb[c[(c[e>>2]|0)+16>>2]&15](e);e=c[b+16>>2]|0;if(!e)m=0.0;else m=+zb[c[(c[e>>2]|0)+16>>2]&15](e);s=p*+C(+(t*t+u*u+v*v))+m*+C(+(q*q+r*r+s*s));if(s+ +C(+((w-z)*(w-z)+(y-B)*(y-B)+(x-A)*(x-A)))==0.0){i=0;l=D;return i|0}c[D+208>>2]=9312;g[D+208+36>>2]=999999984306749440.0;a[D+208+40>>0]=0;td(b,d,f,D+208|0);h=(a[D+208+40>>0]|0)==0;c[D+256>>2]=c[D+208+20>>2];c[D+256+4>>2]=c[D+208+20+4>>2];c[D+256+8>>2]=c[D+208+20+8>>2];c[D+256+12>>2]=c[D+208+20+12>>2];a:do if(!h?(o=c[D+208+4>>2]|0,k=c[D+208+8>>2]|0,n=c[D+208+12>>2]|0,v=(w-z)*(c[j>>2]=o,+g[j>>2]),v=v+(y-B)*(c[j>>2]=k,+g[j>>2]),!(s+(v+(x-A)*(c[j>>2]=n,+g[j>>2]))<=1.1920928955078125e-07)):0){m=+g[D+208+16>>2];p=+g[D+208+36>>2]+ +g[i+172>>2];b:do if(p>1.0000000474974513e-03){q=p;r=0.0;h=0;while(1){e=c[i+168>>2]|0;if(e|0){E=c[(c[e>>2]|0)+20>>2]|0;c[D+112>>2]=1065353216;c[D+112+4>>2]=1065353216;c[D+112+8>>2]=1065353216;g[D+112+12>>2]=0.0;mb[E&7](e,D+256|0,.20000000298023224,D+112|0)}m=(w-z)*(c[j>>2]=o,+g[j>>2]);m=m+(y-B)*(c[j>>2]=k,+g[j>>2]);m=s+(m+(x-A)*(c[j>>2]=n,+g[j>>2]));if(m<=1.1920928955078125e-07){k=0;break a}p=r+q/m;if(!(!(p<=r)&(!(p<0.0)&!(p>1.0)))){k=0;break a}Cg(d,z,B,A,D+192|0,p,D+112|0);Cg(f,w,y,x,D+176|0,p,D+48|0);k=c[i+168>>2]|0;if(k|0){E=c[(c[k>>2]|0)+20>>2]|0;c[D>>2]=1065353216;c[D+4>>2]=0;c[D+8>>2]=0;g[D+12>>2]=0.0;mb[E&7](k,D+112+48|0,.20000000298023224,D)}gb[c[c[i>>2]>>2]&31](i,p);c[D>>2]=9312;g[D+36>>2]=999999984306749440.0;a[D+40>>0]=0;td(b,D+112|0,D+48|0,D);if(!(a[D+40>>0]|0)){k=15;break}m=+g[D+36>>2];q=+g[i+172>>2];c[D+256>>2]=c[D+20>>2];c[D+256+4>>2]=c[D+20+4>>2];c[D+256+8>>2]=c[D+20+8>>2];c[D+256+12>>2]=c[D+20+12>>2];e=h+1|0;if((h|0)>63){k=16;break}n=c[D+12>>2]|0;k=c[D+8>>2]|0;o=c[D+4>>2]|0;q=m+q;if(!(q>1.0000000474974513e-03)){m=+g[D+16>>2];break b}else{r=p;h=e}}if((k|0)==15)Rb[c[(c[i>>2]|0)+8>>2]&127](i,-1,h);else if((k|0)==16)Rb[c[(c[i>>2]|0)+8>>2]&127](i,-2,e);k=0;break a}else p=0.0;while(0);g[i+164>>2]=p;c[i+132>>2]=o;c[i+136>>2]=k;c[i+140>>2]=n;g[i+144>>2]=m;c[i+148>>2]=c[D+256>>2];c[i+148+4>>2]=c[D+256+4>>2];c[i+148+8>>2]=c[D+256+8>>2];c[i+148+12>>2]=c[D+256+12>>2];k=1}else k=0;while(0);E=k;l=D;return E|0}function Cd(a,b){a=a|0;b=b|0;var d=0,e=0.0,f=0,h=0,i=0,j=0,k=0,m=0,n=0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0;F=l;l=l+16|0;Yi(11198);E=c[a+712>>2]|0;if((E|0)>0){c[6432]=(c[6432]|0)+1;d=ec((E<<4|3)+16|0)|0;if(!d)h=0;else{c[(d+4+15&-16)+-4>>2]=d;h=d+4+15&-16}Hk(h|0,0,E<<4|0)|0;f=c[a+712>>2]|0;if((f|0)>0){c[6432]=(c[6432]|0)+1;d=ec((f<<2|3)+16|0)|0;if(!d)d=0;else{c[(d+4+15&-16)+-4>>2]=d;d=d+4+15&-16}Hk(d|0,0,f<<2|0)|0;C=d;D=h;B=h;A=d}else{C=0;D=h;B=h;A=0}}else{C=0;D=0;B=0;A=0}z=c[a+1112>>2]|0;if(b){if((z|0)>0){h=c[a+1120>>2]|0;i=0;do{d=c[h+(i<<2)>>2]|0;f=c[d+312>>2]|0;if(f|0){g[d+276>>2]=1.0/+(f|0)*+g[d+276>>2];g[d+280>>2]=1.0/+(f|0)*+g[d+280>>2];g[d+284>>2]=1.0/+(f|0)*+g[d+284>>2];g[d+292>>2]=+g[d+292>>2]*(1.0/+(f|0));g[d+296>>2]=1.0/+(f|0)*+g[d+296>>2];g[d+300>>2]=1.0/+(f|0)*+g[d+300>>2]}i=i+1|0}while((i|0)!=(z|0));i=11}}else i=11;if((i|0)==11?(z|0)>0:0){k=c[a+1120>>2]|0;if(b){b=0;do{d=c[k+(b<<2)>>2]|0;if((c[d+312>>2]|0)>0?(w=+g[a+452>>2],q=+g[d+276>>2]*w,u=w*+g[d+280>>2],y=w*+g[d+284>>2],o=w*+g[d+292>>2],s=w*+g[d+296>>2],w=w*+g[d+300>>2],m=c[d+24>>2]|0,(m|0)>0):0){f=c[d+32>>2]|0;h=c[a+720>>2]|0;i=c[d+12>>2]|0;j=0;do{n=c[f+(j<<2)>>2]|0;x=+g[i+(j<<2)>>2];v=+g[n+8>>2]-+g[d+228>>2];t=+g[n+12>>2]-+g[d+232>>2];r=+g[n+16>>2]-+g[d+236>>2];G=B+(((n-h|0)/104|0)<<4)|0;g[G>>2]=+g[G>>2]+x*(q+(s*r-w*t));G=B+(((n-h|0)/104|0)<<4)+4|0;g[G>>2]=+g[G>>2]+x*(u+(w*v-o*r));G=B+(((n-h|0)/104|0)<<4)+8|0;g[G>>2]=x*(y+(o*t-s*v))+ +g[G>>2];n=A+(((n-h|0)/104|0)<<2)|0;g[n>>2]=x+ +g[n>>2];j=j+1|0}while((j|0)!=(m|0))}b=b+1|0}while((b|0)!=(z|0))}else{b=0;do{d=c[k+(b<<2)>>2]|0;if((c[d+308>>2]|0)>0?(v=+g[a+452>>2],p=+g[d+244>>2]*v,t=v*+g[d+248>>2],x=v*+g[d+252>>2],e=v*+g[d+260>>2],r=v*+g[d+264>>2],v=v*+g[d+268>>2],n=c[d+24>>2]|0,(n|0)>0):0){f=c[d+32>>2]|0;h=c[a+720>>2]|0;i=c[d+12>>2]|0;j=0;do{G=c[f+(j<<2)>>2]|0;y=+g[i+(j<<2)>>2];w=+g[G+8>>2]-+g[d+228>>2];u=+g[G+12>>2]-+g[d+232>>2];s=+g[G+16>>2]-+g[d+236>>2];m=B+(((G-h|0)/104|0)<<4)|0;g[m>>2]=+g[m>>2]+y*(p+(r*s-v*u));m=B+(((G-h|0)/104|0)<<4)+4|0;g[m>>2]=+g[m>>2]+y*(t+(v*w-e*s));m=B+(((G-h|0)/104|0)<<4)+8|0;g[m>>2]=y*(x+(e*u-r*w))+ +g[m>>2];G=A+(((G-h|0)/104|0)<<2)|0;g[G>>2]=y+ +g[G>>2];j=j+1|0}while((j|0)!=(n|0))}b=b+1|0}while((b|0)!=(z|0))}}if((E|0)>0){d=0;do{e=+g[A+(d<<2)>>2];if(e>0.0){x=1.0/e*+g[B+(d<<4)+4>>2];y=1.0/e*+g[B+(d<<4)+8>>2];G=c[a+720>>2]|0;z=G+(d*104|0)+8|0;g[z>>2]=1.0/e*+g[B+(d<<4)>>2]+ +g[z>>2];z=G+(d*104|0)+12|0;g[z>>2]=x+ +g[z>>2];G=G+(d*104|0)+16|0;g[G>>2]=y+ +g[G>>2]}d=d+1|0}while((d|0)!=(E|0))}if(!((A|0)==0|(C|0)==0)){c[6433]=(c[6433]|0)+1;Pc(c[C+-4>>2]|0)}if(!((B|0)==0|(D|0)==0)){c[6433]=(c[6433]|0)+1;Pc(c[D+-4>>2]|0)}d=c[2395]|0;G=(c[d+16>>2]|0)+-1|0;c[d+16>>2]=G;if(G|0){l=F;return}do if(c[d+4>>2]|0){Va(F|0,0)|0;G=c[6431]|0;g[d+8>>2]=+g[d+8>>2]+ +(((c[F+4>>2]|0)-(c[G+4>>2]|0)+(((c[F>>2]|0)-(c[G>>2]|0)|0)*1e6|0)-(c[d+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[d+16>>2]|0)){d=c[2395]|0;break}else{l=F;return}}while(0);c[2395]=c[d+20>>2];l=F;return}function Dd(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=+h;var i=0,j=0,k=0,m=0,n=0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0,E=0;D=l;l=l+80|0;o=+g[e+4>>2];u=+g[e+20>>2];v=+g[e+36>>2];w=+g[e+8>>2];x=+g[e+24>>2];y=+g[e+40>>2];z=+g[e+12>>2];p=+g[e+28>>2];q=+g[e+44>>2];A=-+g[e+52>>2];B=-+g[e+56>>2];C=-+g[e+60>>2];k=c[b+720>>2]|0;r=+g[k+(d*104|0)+8>>2];s=+g[k+(d*104|0)+12>>2];t=+g[k+(d*104|0)+16>>2];a:do if(f){f=c[b+268>>2]|0;b:do if((f|0)>0){j=c[b+276>>2]|0;i=0;while(1){if((c[j+(i<<2)>>2]|0)==(e|0))break;i=i+1|0;if((i|0)>=(f|0))break b}if((i|0)!=(f|0)){f=k;break a}}while(0);if((f|0)==(c[b+272>>2]|0)?(m=f|0?f<<1:1,(f|0)<(m|0)):0){if(!m)i=0;else{c[6432]=(c[6432]|0)+1;f=ec((m<<2|3)+16|0)|0;if(!f)i=0;else{c[(f+4+15&-16)+-4>>2]=f;i=f+4+15&-16}f=c[b+268>>2]|0}if((f|0)>0){j=0;do{c[i+(j<<2)>>2]=c[(c[b+276>>2]|0)+(j<<2)>>2];j=j+1|0}while((j|0)!=(f|0))}j=c[b+276>>2]|0;if(j){if(a[b+280>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0);f=c[b+268>>2]|0}c[b+276>>2]=0}a[b+280>>0]=1;c[b+276>>2]=i;c[b+272>>2]=m}c[(c[b+276>>2]|0)+(f<<2)>>2]=e;c[b+268>>2]=f+1;f=c[b+720>>2]|0}else f=k;while(0);k=f+(d*104|0)|0;f=f+(d*104|0)+100|0;a[f>>0]=a[f>>0]|1;f=c[b+792>>2]|0;if((f|0)==(c[b+796>>2]|0)?(n=f|0?f<<1:1,(f|0)<(n|0)):0){if(!n)i=0;else{c[6432]=(c[6432]|0)+1;f=ec(n*96|19)|0;if(!f)i=0;else{c[(f+4+15&-16)+-4>>2]=f;i=f+4+15&-16}f=c[b+792>>2]|0}if((f|0)>0){j=0;do{d=i+(j*96|0)|0;m=c[b+800>>2]|0;E=m+(j*96|0)|0;c[d>>2]=c[E>>2];c[d+4>>2]=c[E+4>>2];c[d+8>>2]=c[E+8>>2];c[d+12>>2]=c[E+12>>2];c[d+16>>2]=c[E+16>>2];c[d+20>>2]=c[E+20>>2];c[d+24>>2]=c[E+24>>2];d=i+(j*96|0)+28|0;E=m+(j*96|0)+28|0;c[d>>2]=c[E>>2];c[d+4>>2]=c[E+4>>2];c[d+8>>2]=c[E+8>>2];c[d+12>>2]=c[E+12>>2];d=m+(j*96|0)+44|0;E=i+(j*96|0)+44|0;c[E>>2]=c[d>>2];c[E+4>>2]=c[d+4>>2];c[E+8>>2]=c[d+8>>2];c[E+12>>2]=c[d+12>>2];E=m+(j*96|0)+60|0;d=i+(j*96|0)+60|0;c[d>>2]=c[E>>2];c[d+4>>2]=c[E+4>>2];c[d+8>>2]=c[E+8>>2];c[d+12>>2]=c[E+12>>2];d=i+(j*96|0)+76|0;m=m+(j*96|0)+76|0;c[d>>2]=c[m>>2];c[d+4>>2]=c[m+4>>2];c[d+8>>2]=c[m+8>>2];c[d+12>>2]=c[m+12>>2];c[d+16>>2]=c[m+16>>2];j=j+1|0}while((j|0)!=(f|0))}f=c[b+800>>2]|0;if(f|0){if(a[b+804>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[b+800>>2]=0}a[b+804>>0]=1;c[b+800>>2]=i;c[b+796>>2]=n;f=c[b+792>>2]|0}E=c[b+800>>2]|0;c[E+(f*96|0)>>2]=k;g[E+(f*96|0)+4>>2]=o*A+u*B+v*C+(o*r+u*s+v*t);g[E+(f*96|0)+8>>2]=w*A+x*B+y*C+(w*r+x*s+y*t);g[E+(f*96|0)+12>>2]=z*A+p*B+q*C+(z*r+p*s+q*t);g[E+(f*96|0)+16>>2]=0.0;c[E+(f*96|0)+20>>2]=e;g[E+(f*96|0)+24>>2]=h;e=E+(f*96|0)+28|0;c[e>>2]=c[D+56>>2];c[e+4>>2]=c[D+56+4>>2];c[e+8>>2]=c[D+56+8>>2];c[e+12>>2]=c[D+56+12>>2];e=E+(f*96|0)+44|0;c[e>>2]=c[D+40>>2];c[e+4>>2]=c[D+40+4>>2];c[e+8>>2]=c[D+40+8>>2];c[e+12>>2]=c[D+40+12>>2];e=E+(f*96|0)+60|0;c[e>>2]=c[D+24>>2];c[e+4>>2]=c[D+24+4>>2];c[e+8>>2]=c[D+24+8>>2];c[e+12>>2]=c[D+24+12>>2];E=E+(f*96|0)+76|0;c[E>>2]=c[D>>2];c[E+4>>2]=c[D+4>>2];c[E+8>>2]=c[D+8>>2];c[E+12>>2]=c[D+12>>2];c[E+16>>2]=c[D+16>>2];c[b+792>>2]=(c[b+792>>2]|0)+1;l=D;return}function Ed(b,d){b=b|0;d=d|0;var e=0,f=0,h=0,i=0,j=0,k=0,l=0,m=0;c[b>>2]=5348;c[6432]=(c[6432]|0)+1;e=ec(379)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}g[e+308>>2]=9.999999747378752e-05;l=e+332|0;a[l>>0]=a[l>>0]&-16;c[b+24>>2]=e;l=(c[d+20>>2]|0)==0?9224:9272;c[6432]=(c[6432]|0)+1;e=ec(23)|0;c[(e+4+15&-16)+-4>>2]=e;c[(e+4+15&-16)>>2]=l;c[b+28>>2]=e+4+15&-16;c[6432]=(c[6432]|0)+1;e=ec(43)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}k=c[b+24>>2]|0;l=c[b+28>>2]|0;a[e+4>>0]=0;c[e>>2]=6156;c[e+16>>2]=0;c[e+20>>2]=3;c[e+12>>2]=k;c[e+8>>2]=l;c[b+32>>2]=e;c[6432]=(c[6432]|0)+1;e=ec(27)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}a[e+4>>0]=0;c[e>>2]=5380;c[b+36>>2]=e;c[6432]=(c[6432]|0)+1;e=ec(27)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}a[e+4>>0]=0;c[e>>2]=5400;c[b+40>>2]=e;c[6432]=(c[6432]|0)+1;e=ec(27)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}a[e+4>>0]=0;c[e>>2]=5420;c[b+44>>2]=e;c[6432]=(c[6432]|0)+1;e=ec(27)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}a[e+4>>0]=0;c[e>>2]=5440;c[b+48>>2]=e;c[6432]=(c[6432]|0)+1;e=ec(27)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}a[e+4>>0]=0;c[e>>2]=5460;c[b+52>>2]=e;c[6432]=(c[6432]|0)+1;e=ec(27)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}a[e+4>>0]=0;c[e>>2]=5480;c[b+56>>2]=e;c[6432]=(c[6432]|0)+1;e=ec(27)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}a[e+4>>0]=0;c[e>>2]=5500;c[b+60>>2]=e;c[6432]=(c[6432]|0)+1;e=ec(27)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}a[e+4>>0]=0;c[e>>2]=5520;c[b+76>>2]=e;c[6432]=(c[6432]|0)+1;e=ec(27)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}c[e>>2]=5520;c[b+80>>2]=e;a[e+4>>0]=1;c[6432]=(c[6432]|0)+1;e=ec(27)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}a[e+4>>0]=0;c[e>>2]=5540;c[b+72>>2]=e;c[6432]=(c[6432]|0)+1;e=ec(35)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}a[e+4>>0]=0;c[e>>2]=5560;c[e+8>>2]=1;c[e+12>>2]=0;c[b+88>>2]=e;c[6432]=(c[6432]|0)+1;e=ec(35)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}c[e>>2]=5560;c[e+8>>2]=1;c[e+12>>2]=0;c[b+84>>2]=e;a[e+4>>0]=1;l=c[d+16>>2]|0;l=(l|0)>80?l:80;e=c[d>>2]|0;if(!e){a[b+12>>0]=1;c[6432]=(c[6432]|0)+1;e=ec(39)|0;if(!e)k=0;else{c[(e+4+15&-16)+-4>>2]=e;k=e+4+15&-16}e=c[d+8>>2]|0;c[k>>2]=772;f=k+4|0;c[f>>2]=e;c[6432]=(c[6432]|0)+1;e=ec((e*772|3)+16|0)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}c[k+16>>2]=e;c[k+12>>2]=e;f=c[f>>2]|0;c[k+8>>2]=f;if(f+-1|0){h=c[k>>2]|0;i=e;j=f+-1|0;do{m=i;i=i+h|0;c[m>>2]=i;j=j+-1|0}while((j|0)!=0);e=e+(O(h,f+-1|0)|0)|0}c[e>>2]=0;c[b+8>>2]=k}else{a[b+12>>0]=0;c[b+8>>2]=e}e=c[d+4>>2]|0;if(e|0){a[b+20>>0]=0;c[b+16>>2]=e;return}a[b+20>>0]=1;c[6432]=(c[6432]|0)+1;e=ec(39)|0;if(!e)k=0;else{c[(e+4+15&-16)+-4>>2]=e;k=e+4+15&-16}e=c[d+12>>2]|0;c[k>>2]=l;f=k+4|0;c[f>>2]=e;e=O(e,l)|0;c[6432]=(c[6432]|0)+1;e=ec(e+19|0)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}c[k+16>>2]=e;c[k+12>>2]=e;f=c[f>>2]|0;c[k+8>>2]=f;if(f+-1|0){h=c[k>>2]|0;i=e;j=f+-1|0;do{m=i;i=i+h|0;c[m>>2]=i;j=j+-1|0}while((j|0)!=0);e=e+(O(h,f+-1|0)|0)|0}c[e>>2]=0;c[b+16>>2]=k;return}function Fd(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var h=0.0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0,A=0.0,B=0.0,D=0.0,E=0.0,F=0,G=0;F=l;l=l+32|0;A=+g[b+48>>2]-+g[b+112>>2];h=+g[b+52>>2]-+g[b+116>>2];E=+g[b+56>>2]-+g[b+120>>2];B=A*+g[b+64>>2]+h*+g[b+80>>2]+E*+g[b+96>>2];D=A*+g[b+68>>2]+h*+g[b+84>>2]+E*+g[b+100>>2];E=A*+g[b+72>>2]+h*+g[b+88>>2]+E*+g[b+104>>2];e=c[a+8>>2]|0;z=c[a+4>>2]|0;h=+g[z+28>>2]*+g[z+12>>2];A=h+ +g[a+12>>2];p=+g[e+72>>2];q=+g[e+56>>2];r=+g[e+76>>2];s=+g[e+60>>2];t=+g[e+80>>2];u=+g[e+64>>2];v=+g[e+88>>2];w=+g[e+92>>2];x=+g[e+96>>2];j=(r-s)*(x-u)-(t-u)*(w-s);k=(t-u)*(v-q)-(p-q)*(x-u);o=(p-q)*(w-s)-(r-s)*(v-q);n=1.0/+C(+(o*o+(j*j+k*k)));i=(B-q)*n*j+(D-s)*n*k+n*o*(E-u);if(i<0.0){i=-i;m=-(n*j);j=-(n*k);k=-(n*o)}else{m=n*j;j=n*k;k=n*o}if(!(i<A)){l=F;return}o=(E-u)*(j*(p-q)-m*(r-s))+((B-q)*(k*(r-s)-j*(t-u))+(D-s)*(m*(t-u)-k*(p-q)));y=(E-t)*(j*(v-p)-m*(w-r))+((B-p)*(k*(w-r)-j*(x-t))+(D-r)*(m*(x-t)-k*(v-p)));x=(E-x)*(j*(q-v)-m*(s-w))+((B-v)*(k*(s-w)-j*(u-x))+(D-w)*(m*(u-x)-k*(q-v)));if(!(x>0.0&(o>0.0&y>0.0)|x<=0.0&(o<=0.0&y<=0.0))){if((lb[c[(c[e>>2]|0)+100>>2]&127](e)|0)<=0){l=F;return}o=0.0;n=0.0;i=0.0;e=0;z=0;do{G=c[a+8>>2]|0;Vb[c[(c[G>>2]|0)+104>>2]&127](G,z,F+16|0,F);p=+g[F+16>>2];w=+g[F+16+4>>2];u=+g[F+16+8>>2];t=+g[F>>2]-p;x=+g[F+4>>2]-w;v=+g[F+8>>2]-u;do if((B-p)*t+(D-w)*x+(E-u)*v>0.0)if((B-p)*t+(D-w)*x+(E-u)*v<t*t+x*x+v*v){y=((B-p)*t+(D-w)*x+(E-u)*v)/(t*t+x*x+v*v);q=B-p-t*y;r=D-w-x*y;s=E-u-v*y;break}else{q=B-p-t;r=D-w-x;s=E-u-v;y=1.0;break}else{q=B-p;r=D-w;s=E-u;y=0.0}while(0);if(q*q+r*r+s*s<A*A){o=p+t*y;n=u+v*y;i=w+x*y;e=1}z=z+1|0;G=c[a+8>>2]|0}while((z|0)<(lb[c[(c[G>>2]|0)+100>>2]&127](G)|0));if(!(e&1)){l=F;return}else{s=o;r=n;q=i;n=A*A}}else{s=B-i*m;r=E-i*k;q=D-i*j;n=A*A}o=B-s;p=D-q;i=E-r;if(!(o*o+p*p+i*i<n)){l=F;return}if(o*o+p*p+i*i>1.1920928955078125e-07){j=+C(+(o*o+p*p+i*i));h=h-j;m=o*(1.0/j);k=i*(1.0/j);j=p*(1.0/j)}i=-h;h=+g[b+64>>2];if(f){y=+g[b+68>>2];A=+g[b+72>>2];B=h*m+y*j+A*k;p=+g[b+80>>2];t=+g[b+84>>2];u=+g[b+88>>2];D=m*p+j*t+k*u;v=+g[b+96>>2];w=+g[b+100>>2];x=+g[b+104>>2];E=m*v+j*w+k*x;g[F+16>>2]=-B;g[F+16+4>>2]=-D;g[F+16+8>>2]=-E;g[F+16+12>>2]=0.0;D=s*p+q*t+r*u+ +g[b+116>>2]+D*i;E=s*v+q*w+r*x+ +g[b+120>>2]+E*i;g[F>>2]=s*h+q*y+r*A+ +g[b+112>>2]+B*i;g[F+4>>2]=D;g[F+8>>2]=E;g[F+12>>2]=0.0;Qb[c[(c[d>>2]|0)+16>>2]&15](d,F+16|0,F,i);l=F;return}else{G=c[(c[d>>2]|0)+16>>2]|0;A=+g[b+68>>2];B=+g[b+72>>2];v=+g[b+80>>2];w=+g[b+84>>2];D=+g[b+88>>2];x=+g[b+96>>2];y=+g[b+100>>2];E=+g[b+104>>2];g[F+16>>2]=h*m+A*j+B*k;g[F+16+4>>2]=m*v+j*w+k*D;g[F+16+8>>2]=m*x+j*y+k*E;g[F+16+12>>2]=0.0;D=s*v+q*w+r*D+ +g[b+116>>2];E=s*x+q*y+r*E+ +g[b+120>>2];g[F>>2]=s*h+q*A+r*B+ +g[b+112>>2];g[F+4>>2]=D;g[F+8>>2]=E;g[F+12>>2]=0.0;Qb[G&15](d,F+16|0,F,i);l=F;return}}function Gd(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0,i=0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0;i=l;l=l+16|0;if((a[22688]|0)==0?jy(22688)|0:0){c[i>>2]=0;c[i+4>>2]=0;c[i+8>>2]=0;c[i+12>>2]=0;_f(23256,0.0,0,0,i)}c[5865]=c[5865]|1;g[5900]=0.0;j=+g[5910]*0.0;k=+g[5911]*0.0;g[5905]=+g[5909]*0.0;g[5906]=j;g[5907]=k;g[5908]=0.0;c[5913]=0;c[5914]=0;c[5915]=0;c[5916]=0;k=+g[5902]*0.0;j=+g[5903]*0.0;g[5954]=+g[5901]*0.0;g[5955]=k;g[5956]=j;g[5957]=0.0;c[b+4>>2]=6;c[b+8>>2]=-1;c[b+12>>2]=-1;g[b+16>>2]=3402823466385288598117041.0e14;a[b+20>>0]=1;a[b+21>>0]=0;c[b+24>>2]=-1;c[b+28>>2]=23256;c[b+32>>2]=d;g[b+36>>2]=0.0;g[b+40>>2]=.30000001192092896;c[b+44>>2]=0;c[b>>2]=4504;c[b+112>>2]=c[e>>2];c[b+112+4>>2]=c[e+4>>2];c[b+112+8>>2]=c[e+8>>2];c[b+112+12>>2]=c[e+12>>2];c[b+128>>2]=c[e+16>>2];c[b+128+4>>2]=c[e+16+4>>2];c[b+128+8>>2]=c[e+16+8>>2];c[b+128+12>>2]=c[e+16+12>>2];c[b+144>>2]=c[e+32>>2];c[b+144+4>>2]=c[e+32+4>>2];c[b+144+8>>2]=c[e+32+8>>2];c[b+144+12>>2]=c[e+32+12>>2];c[b+160>>2]=c[e+48>>2];c[b+160+4>>2]=c[e+48+4>>2];c[b+160+8>>2]=c[e+48+8>>2];c[b+160+12>>2]=c[e+48+12>>2];e=b+680|0;h=e+48|0;do{c[e>>2]=0;e=e+4|0}while((e|0)<(h|0));c[b+740>>2]=0;c[b+740+4>>2]=0;c[b+740+8>>2]=0;c[b+740+12>>2]=0;c[b+756>>2]=1045220557;c[b+760>>2]=1045220557;c[b+764>>2]=1045220557;c[b+768>>2]=0;c[b+768+4>>2]=0;c[b+768+8>>2]=0;c[b+768+12>>2]=0;c[b+768+16>>2]=0;g[b+728>>2]=.699999988079071;g[b+732>>2]=1.0;g[b+736>>2]=.5;a[b+788>>0]=0;g[b+792>>2]=0.0;g[b+808>>2]=0.0;a[b+789>>0]=0;g[b+796>>2]=0.0;g[b+812>>2]=0.0;a[b+790>>0]=0;g[b+800>>2]=0.0;g[b+816>>2]=0.0;g[b+928>>2]=0.0;g[b+876>>2]=0.0;g[b+880>>2]=.10000000149011612;g[b+884>>2]=300.0;g[b+868>>2]=1.0;g[b+872>>2]=-1.0;g[b+896>>2]=0.0;g[b+900>>2]=.20000000298023224;g[b+904>>2]=0.0;g[b+908>>2]=0.0;g[b+888>>2]=1.0;g[b+892>>2]=.5;c[b+924>>2]=0;g[b+916>>2]=0.0;a[b+912>>0]=0;g[b+992>>2]=0.0;g[b+940>>2]=0.0;g[b+944>>2]=.10000000149011612;g[b+948>>2]=300.0;g[b+932>>2]=1.0;g[b+936>>2]=-1.0;g[b+960>>2]=0.0;g[b+964>>2]=.20000000298023224;g[b+968>>2]=0.0;g[b+972>>2]=0.0;g[b+952>>2]=1.0;g[b+956>>2]=.5;c[b+988>>2]=0;g[b+980>>2]=0.0;a[b+976>>0]=0;g[b+1056>>2]=0.0;g[b+1004>>2]=0.0;g[b+1008>>2]=.10000000149011612;g[b+1012>>2]=300.0;g[b+996>>2]=1.0;g[b+1e3>>2]=-1.0;g[b+1024>>2]=0.0;g[b+1028>>2]=.20000000298023224;g[b+1032>>2]=0.0;g[b+1036>>2]=0.0;g[b+1016>>2]=1.0;g[b+1020>>2]=.5;c[b+1052>>2]=0;g[b+1044>>2]=0.0;a[b+1040>>0]=0;a[b+1300>>0]=f&1;a[b+1301>>0]=1;c[b+1304>>2]=0;a[b+1308>>0]=0;y=+g[b+112>>2];E=+g[d+4>>2];x=+g[b+128>>2];D=+g[d+8>>2];w=+g[b+144>>2];C=+g[d+12>>2];v=+g[b+116>>2];u=+g[b+132>>2];t=+g[b+148>>2];s=+g[b+120>>2];q=+g[b+136>>2];o=+g[b+152>>2];B=+g[d+20>>2];A=+g[d+24>>2];z=+g[d+28>>2];r=+g[d+36>>2];p=+g[d+40>>2];n=+g[d+44>>2];G=+g[b+160>>2];F=+g[b+164>>2];k=+g[b+168>>2];m=+g[d+52>>2]+(E*G+D*F+C*k);j=B*G+A*F+z*k+ +g[d+56>>2];k=r*G+p*F+n*k+ +g[d+60>>2];g[b+48>>2]=y*E+x*D+w*C;g[b+52>>2]=E*v+D*u+C*t;g[b+56>>2]=E*s+D*q+C*o;g[b+60>>2]=0.0;g[b+64>>2]=y*B+x*A+w*z;g[b+68>>2]=v*B+u*A+t*z;g[b+72>>2]=s*B+q*A+o*z;g[b+76>>2]=0.0;g[b+80>>2]=y*r+x*p+w*n;g[b+84>>2]=v*r+u*p+t*n;g[b+88>>2]=s*r+q*p+o*n;g[b+92>>2]=0.0;g[b+96>>2]=m;g[b+100>>2]=j;g[b+104>>2]=k;g[b+108>>2]=0.0;_c(b,(c[b+28>>2]|0)+4|0,(c[b+32>>2]|0)+4|0);l=i;return}function Hd(b,d,e,f,h,i,j,k){b=b|0;d=d|0;e=e|0;f=f|0;h=+h;i=+i;j=j|0;k=k|0;var m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;w=l;l=l+288|0;c[w+208>>2]=c[d>>2];c[w+208+4>>2]=c[d+4>>2];c[w+208+8>>2]=c[d+8>>2];c[w+208+12>>2]=c[d+12>>2];o=w+208+16|0;c[o>>2]=c[e>>2];c[o+4>>2]=c[e+4>>2];c[o+8>>2]=c[e+8>>2];c[o+12>>2]=c[e+12>>2];d=w+208+32|0;c[d>>2]=c[f>>2];c[d+4>>2]=c[f+4>>2];c[d+8>>2]=c[f+8>>2];c[d+12>>2]=c[f+12>>2];q=c[j>>2]|0;r=c[j+4>>2]|0;s=c[j+8>>2]|0;t=c[j+16>>2]|0;u=c[j+12>>2]|0;p=c[j+20>>2]|0;c[w+156>>2]=c[w+208>>2];c[w+156+4>>2]=c[w+208+4>>2];c[w+156+8>>2]=c[w+208+8>>2];c[w+156+12>>2]=c[w+208+12>>2];c[w+172>>2]=c[o>>2];c[w+172+4>>2]=c[o+4>>2];c[w+172+8>>2]=c[o+8>>2];c[w+172+12>>2]=c[o+12>>2];c[w+188>>2]=c[d>>2];c[w+188+4>>2]=c[d+4>>2];c[w+188+8>>2]=c[d+8>>2];c[w+188+12>>2]=c[d+12>>2];d=c[b+136>>2]|0;if((d|0)==(c[b+140>>2]|0)?(v=d|0?d<<1:1,(d|0)<(v|0)):0){if(!v)e=0;else{c[6432]=(c[6432]|0)+1;d=ec((v*284|3)+16|0)|0;if(!d)e=0;else{c[(d+4+15&-16)+-4>>2]=d;e=d+4+15&-16}d=c[b+136>>2]|0}if((d|0)>0){j=0;do{f=c[b+144>>2]|0;m=e+(j*284|0)|0;n=f+(j*284|0)|0;o=m+92|0;do{c[m>>2]=c[n>>2];m=m+4|0;n=n+4|0}while((m|0)<(o|0));m=e+(j*284|0)+92|0;n=f+(j*284|0)+92|0;c[m>>2]=c[n>>2];c[m+4>>2]=c[n+4>>2];c[m+8>>2]=c[n+8>>2];c[m+12>>2]=c[n+12>>2];m=f+(j*284|0)+108|0;n=e+(j*284|0)+108|0;c[n>>2]=c[m>>2];c[n+4>>2]=c[m+4>>2];c[n+8>>2]=c[m+8>>2];c[n+12>>2]=c[m+12>>2];n=f+(j*284|0)+124|0;m=e+(j*284|0)+124|0;c[m>>2]=c[n>>2];c[m+4>>2]=c[n+4>>2];c[m+8>>2]=c[n+8>>2];c[m+12>>2]=c[n+12>>2];m=e+(j*284|0)+140|0;n=f+(j*284|0)+140|0;c[m>>2]=c[n>>2];c[m+4>>2]=c[n+4>>2];c[m+8>>2]=c[n+8>>2];c[m+12>>2]=c[n+12>>2];m=e+(j*284|0)+156|0;n=f+(j*284|0)+156|0;o=m+128|0;do{c[m>>2]=c[n>>2];m=m+4|0;n=n+4|0}while((m|0)<(o|0));j=j+1|0}while((j|0)!=(d|0))}d=c[b+144>>2]|0;if(d|0){if(a[b+148>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+144>>2]=0}a[b+148>>0]=1;c[b+144>>2]=e;c[b+140>>2]=v;d=c[b+136>>2]|0}e=c[b+144>>2]|0;m=e+(d*284|0)|0;n=w;o=m+92|0;do{c[m>>2]=c[n>>2];m=m+4|0;n=n+4|0}while((m|0)<(o|0));m=e+(d*284|0)+92|0;c[m>>2]=c[w+92>>2];c[m+4>>2]=c[w+92+4>>2];c[m+8>>2]=c[w+92+8>>2];c[m+12>>2]=c[w+92+12>>2];m=e+(d*284|0)+108|0;c[m>>2]=c[w+108>>2];c[m+4>>2]=c[w+108+4>>2];c[m+8>>2]=c[w+108+8>>2];c[m+12>>2]=c[w+108+12>>2];m=e+(d*284|0)+124|0;c[m>>2]=c[w+124>>2];c[m+4>>2]=c[w+124+4>>2];c[m+8>>2]=c[w+124+8>>2];c[m+12>>2]=c[w+124+12>>2];m=e+(d*284|0)+140|0;c[m>>2]=c[w+140>>2];c[m+4>>2]=c[w+140+4>>2];c[m+8>>2]=c[w+140+8>>2];c[m+12>>2]=c[w+140+12>>2];d=e+(d*284|0)+156|0;m=d;n=w+156|0;o=m+48|0;do{c[m>>2]=c[n>>2];m=m+4|0;n=n+4|0}while((m|0)<(o|0));g[d+48>>2]=h;c[d+52>>2]=u;g[d+56>>2]=i;c[d+60>>2]=q;c[d+64>>2]=r;c[d+68>>2]=s;c[d+72>>2]=t;g[d+76>>2]=0.0;g[d+80>>2]=0.0;g[d+84>>2]=0.0;g[d+88>>2]=.10000000149011612;c[d+92>>2]=p;g[d+96>>2]=0.0;g[d+100>>2]=0.0;a[d+104>>0]=k&1;m=d+105|0;n=w+256|0;o=m+23|0;do{a[m>>0]=a[n>>0]|0;m=m+1|0;n=n+1|0}while((m|0)<(o|0));k=c[b+136>>2]|0;c[b+136>>2]=k+1;k=(c[b+144>>2]|0)+(k*284|0)|0;xg(c[b+116>>2]|0,k,0);ge(c[b+116>>2]|0,c[b+144>>2]|0,(c[b+136>>2]|0)+-1|0,0);l=w;return k|0}function Id(a,d,f,h,i){a=a|0;d=d|0;f=f|0;h=h|0;i=i|0;var j=0,k=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0;I=l;l=l+16|0;c[d+16>>2]=c[f>>2];c[d+16+4>>2]=c[f+4>>2];c[d+16+8>>2]=c[f+8>>2];c[d+16+12>>2]=c[f+12>>2];c[d+32>>2]=c[h>>2];c[d+32+4>>2]=c[h+4>>2];c[d+32+8>>2]=c[h+8>>2];c[d+32+12>>2]=c[h+12>>2];D=c[a+60>>2]|0;E=c[d+12>>2]&65535;cj(a,I+6|0,+g[f>>2],+g[f+4>>2],+g[f+8>>2],0);cj(a,I,+g[h>>2],+g[h+4>>2],+g[h+8>>2],1);H=0;do{t=b[D+(E<<6)+48+(H<<1)>>1]|0;w=b[D+(E<<6)+54+(H<<1)>>1]|0;q=b[I+6+(H<<1)>>1]|0;n=a+68+(H<<2)|0;s=c[n>>2]|0;o=(q&65535)-(e[s+((t&65535)<<2)>>1]|0)|0;r=b[I+(H<<1)>>1]|0;y=(r&65535)-(e[s+((w&65535)<<2)>>1]|0)|0;b[s+((t&65535)<<2)>>1]=q;b[s+((w&65535)<<2)>>1]=r;if((o|0)<0)ch(a,H,t);a:do if((y|0)>0?(z=c[n>>2]|0,A=c[a+60>>2]|0,B=e[z+((w&65535)<<2)+2>>1]|0,C=b[z+((w&65535)+1<<2)+2>>1]|0,C<<16>>16):0){p=1<<H&3;q=A+(B<<6)+54+(H<<1)|0;j=C;r=z+((w&65535)<<2)|0;s=z+((w&65535)+1<<2)|0;while(1){k=b[s>>1]|0;if((e[r>>1]|0)<(k&65535))break a;m=c[a+60>>2]|0;j=j&65535;if(!(k&1)){if(((((e[A+(B<<6)+54+(p<<1)>>1]|0)>=(e[m+(j<<6)+48+(p<<1)>>1]|0)?(e[m+(j<<6)+54+(p<<1)>>1]|0)>=(e[A+(B<<6)+48+(p<<1)>>1]|0):0)?(e[A+(B<<6)+54+((1<<p&3)<<1)>>1]|0)>=(e[m+(j<<6)+48+((1<<p&3)<<1)>>1]|0):0)?(e[m+(j<<6)+54+((1<<p&3)<<1)>>1]|0)>=(e[A+(B<<6)+48+((1<<p&3)<<1)>>1]|0):0)?(G=c[a+92>>2]|0,F=m+((e[r+2>>1]|0)<<6)|0,vb[c[(c[G>>2]|0)+8>>2]&63](G,F,m+(j<<6)|0)|0,G=c[a+96>>2]|0,G|0):0)vb[c[(c[G>>2]|0)+8>>2]&63](G,F,m+(j<<6)|0)|0;j=m+(j<<6)+48+(H<<1)|0}else j=m+(j<<6)+54+(H<<1)|0;b[j>>1]=(b[j>>1]|0)+-1<<16>>16;b[q>>1]=(b[q>>1]|0)+1<<16>>16;j=e[r>>1]|e[r+2>>1]<<16;m=e[s>>1]|e[s+2>>1]<<16;b[r>>1]=m;b[r+2>>1]=m>>>16;b[s>>1]=j;b[s+2>>1]=j>>>16;j=b[s+6>>1]|0;if(!(j<<16>>16))break;else{r=r+4|0;s=s+4|0}}}while(0);b:do if((o|0)>0?(u=c[n>>2]|0,v=b[u+((t&65535)+1<<2)+2>>1]|0,v<<16>>16):0){o=(c[a+60>>2]|0)+((e[u+((t&65535)<<2)+2>>1]|0)<<6)+48+(H<<1)|0;p=1<<H&3;k=v;q=u+((t&65535)<<2)|0;n=u+((t&65535)+1<<2)|0;while(1){j=b[n>>1]|0;if((e[q>>1]|0)<(j&65535))break b;m=c[a+60>>2]|0;k=k&65535;if(!(j&1))j=m+(k<<6)+48+(H<<1)|0;else{j=e[q+2>>1]|0;if(((((e[m+(j<<6)+54+(p<<1)>>1]|0)>=(e[m+(k<<6)+48+(p<<1)>>1]|0)?(e[m+(k<<6)+54+(p<<1)>>1]|0)>=(e[m+(j<<6)+48+(p<<1)>>1]|0):0)?(e[m+(j<<6)+54+((1<<p&3)<<1)>>1]|0)>=(e[m+(k<<6)+48+((1<<p&3)<<1)>>1]|0):0)?(e[m+(k<<6)+54+((1<<p&3)<<1)>>1]|0)>=(e[m+(j<<6)+48+((1<<p&3)<<1)>>1]|0):0)?(x=c[a+92>>2]|0,pb[c[(c[x>>2]|0)+12>>2]&31](x,m+(j<<6)|0,m+(k<<6)|0,i)|0,x=c[a+96>>2]|0,x|0):0)pb[c[(c[x>>2]|0)+12>>2]&31](x,m+(j<<6)|0,m+(k<<6)|0,i)|0;j=m+(k<<6)+54+(H<<1)|0}b[j>>1]=(b[j>>1]|0)+-1<<16>>16;b[o>>1]=(b[o>>1]|0)+1<<16>>16;k=e[q>>1]|e[q+2>>1]<<16;t=e[n>>1]|e[n+2>>1]<<16;b[q>>1]=t;b[q+2>>1]=t>>>16;b[n>>1]=k;b[n+2>>1]=k>>>16;k=b[n+6>>1]|0;if(!(k<<16>>16))break;else{q=q+4|0;n=n+4|0}}}while(0);if((y|0)<0)_g(a,H,w,i);H=H+1|0}while((H|0)!=3);j=c[a+108>>2]|0;if(!j){l=I;return}fb[c[(c[j>>2]|0)+16>>2]&31](j,c[d+60>>2]|0,f,h,i);l=I;return}function Jd(d,f,h,i){d=d|0;f=f|0;h=h|0;i=i|0;var j=0,k=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0;w=l;l=l+80|0;v=c[d+48>>2]|0;c[w>>2]=6988;c[w+4>>2]=v;c[w+8>>2]=f;v=c[d+52>>2]|0;if(!(a[v+60>>0]|0)){f=c[v+56>>2]|0;if((f|0)>0){d=f;o=0;p=c[v+96>>2]|0;f=0;while(1){f=f+1|0;if(!(+g[h>>2]>+g[p+16>>2])?!(+g[i>>2]<+g[p>>2]):0)j=1;else j=0;if(!(!(+g[h+8>>2]>+g[p+24>>2])?!(+g[i+8>>2]<+g[p+8>>2]):0))j=0;if(!(+g[h+4>>2]>+g[p+20>>2])?!(+g[i+4>>2]<+g[p+4>>2]):0){k=c[p+32>>2]|0;if(j&(k|0)==-1){Rb[c[(c[w>>2]|0)+8>>2]&127](w,c[p+36>>2]|0,c[p+40>>2]|0);d=c[v+56>>2]|0;n=43}else{m=k;k=(k|0)==-1;n=42}}else{k=c[p+32>>2]|0;m=k;k=(k|0)==-1;j=0;n=42}if((n|0)==42){n=0;if(k|j)n=43;else{k=m+o|0;j=p+(m<<6)|0}}if((n|0)==43){k=o+1|0;j=p+64|0}if((k|0)<(d|0)){o=k;p=j}else break}}else f=0;if((c[6164]|0)>=(f|0)){l=w;return}c[6164]=f;l=w;return}z=+g[h>>2];D=+g[h+4>>2];H=+g[h+8>>2];G=+g[v+4>>2];z=z<G?G:z;C=+g[v+8>>2];D=D<C?C:D;y=+g[v+12>>2];H=H<y?y:H;I=+g[v+20>>2];E=+g[v+24>>2];A=+g[v+28>>2];F=+g[v+36>>2];B=+g[v+40>>2];x=+g[v+44>>2];s=~~(((I<z?I:z)-G)*F)&65535&-2;b[w+66>>1]=s;t=~~(((E<D?E:D)-C)*B)&65535&-2;u=~~(((A<H?A:H)-y)*x)&65535&-2;b[w+66+2>>1]=t;b[w+66+4>>1]=u;H=+g[i>>2];D=+g[i+4>>2];z=+g[i+8>>2];H=H<G?G:H;D=D<C?C:D;z=z<y?y:z;i=~~(((I<H?I:H)-G)*F+1.0)&65535|1;b[w+60>>1]=i;q=~~(((E<D?E:D)-C)*B+1.0)&65535|1;r=~~(((A<z?A:z)-y)*x+1.0)&65535|1;b[w+60+2>>1]=q;b[w+60+4>>1]=r;switch(c[v+144>>2]|0){case 0:{o=c[v+56>>2]|0;if((o|0)>0){d=0;j=c[v+136>>2]|0;f=0;do{f=f+1|0;m=((i&65535)>=(e[j>>1]|0)?(s&65535)<=(e[j+6>>1]|0):0)&(u&65535)<=(e[j+10>>1]|0)&(r&65535)>=(e[j+4>>1]|0)&(t&65535)<=(e[j+8>>1]|0)&(q&65535)>=(e[j+2>>1]|0);n=j+12|0;k=c[n>>2]|0;if((k|0)>-1&m)Rb[c[(c[w>>2]|0)+8>>2]&127](w,k>>>21,k&2097151);if(m|(k|0)>-1){d=d+1|0;j=j+16|0}else{v=c[n>>2]|0;d=d-v|0;j=j+(0-v<<4)|0}}while((d|0)<(o|0))}else f=0;if((c[6164]|0)<(f|0))c[6164]=f;break}case 1:{if((c[v+152>>2]|0)>0){h=0;do{f=c[v+160>>2]|0;if(((i&65535)>=(e[f+(h<<5)>>1]|0)?(s&65535)<=(e[f+(h<<5)+6>>1]|0):0)&(u&65535)<=(e[f+(h<<5)+10>>1]|0)&(r&65535)>=(e[f+(h<<5)+4>>1]|0)&(t&65535)<=(e[f+(h<<5)+8>>1]|0)&(q&65535)>=(e[f+(h<<5)+2>>1]|0)){p=c[f+(h<<5)+12>>2]|0;o=c[f+(h<<5)+16>>2]|0;if((o|0)>0){d=p;j=(c[v+136>>2]|0)+(p<<4)|0;f=0;do{f=f+1|0;m=((i&65535)>=(e[j>>1]|0)?(s&65535)<=(e[j+6>>1]|0):0)&(u&65535)<=(e[j+10>>1]|0)&(r&65535)>=(e[j+4>>1]|0)&(t&65535)<=(e[j+8>>1]|0)&(q&65535)>=(e[j+2>>1]|0);n=j+12|0;k=c[n>>2]|0;if((k|0)>-1&m)Rb[c[(c[w>>2]|0)+8>>2]&127](w,k>>>21,k&2097151);if(m|(k|0)>-1){d=d+1|0;j=j+16|0}else{n=c[n>>2]|0;d=d-n|0;j=j+(0-n<<4)|0}}while((d|0)<(o+p|0))}else f=0;if((c[6164]|0)<(f|0))c[6164]=f}h=h+1|0}while((h|0)<(c[v+152>>2]|0))}break}case 2:{pk(c[v+136>>2]|0,w,w+66|0,w+60|0);break}default:{}}l=w;return}function Kd(b,d,e,f,g,h){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var i=0,j=0,k=0,l=0,m=0,n=0,o=0;if((h|0)<0){o=c[b+8>>2]|0;+Ib[c[(c[o>>2]|0)+12>>2]&3](o,d,e,f,g,c[b+12>>2]|0,c[b+16>>2]|0,c[b+4>>2]|0,c[b+20>>2]|0,c[b+24>>2]|0);return}l=c[b+16>>2]|0;a:do if((l|0)>0){j=c[b+12>>2]|0;i=0;while(1){k=j+(i<<2)|0;o=c[k>>2]|0;n=c[o+28>>2]|0;if((c[((c[n+208>>2]|0)>-1?n:c[o+32>>2]|0)+208>>2]|0)==(h|0)){o=k;break a}i=i+1|0;if((i|0)>=(l|0)){o=0;break}}}else{i=0;o=0}while(0);if((i|0)<(l|0)){k=c[b+12>>2]|0;j=0;do{n=c[k+(i<<2)>>2]|0;m=c[n+28>>2]|0;j=((c[((c[m+208>>2]|0)>-1?m:c[n+32>>2]|0)+208>>2]|0)==(h|0)&1)+j|0;i=i+1|0}while((i|0)!=(l|0));n=j}else n=0;i=c[b+4>>2]|0;if((c[i+72>>2]|0)<2){m=c[b+8>>2]|0;+Ib[c[(c[m>>2]|0)+12>>2]&3](m,d,e,f,g,o,n,i,c[b+20>>2]|0,c[b+24>>2]|0);return}if((e|0)>0){j=c[b+32>>2]|0;i=c[b+36>>2]|0;m=0;do{h=d+(m<<2)|0;if((j|0)==(i|0)){l=i|0?i<<1:1;if((i|0)<(l|0)){if(!l)j=0;else{c[6432]=(c[6432]|0)+1;i=ec((l<<2|3)+16|0)|0;if(!i)j=0;else{c[(i+4+15&-16)+-4>>2]=i;j=i+4+15&-16}i=c[b+32>>2]|0}if((i|0)>0){k=0;do{c[j+(k<<2)>>2]=c[(c[b+40>>2]|0)+(k<<2)>>2];k=k+1|0}while((k|0)!=(i|0))}k=c[b+40>>2]|0;if(k){if(a[b+44>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[k+-4>>2]|0);i=c[b+32>>2]|0}c[b+40>>2]=0}a[b+44>>0]=1;c[b+40>>2]=j;c[b+36>>2]=l;j=i;i=l}else j=i}c[(c[b+40>>2]|0)+(j<<2)>>2]=c[h>>2];j=j+1|0;c[b+32>>2]=j;m=m+1|0}while((m|0)!=(e|0))}if((g|0)>0){j=c[b+52>>2]|0;i=c[b+56>>2]|0;m=0;do{h=f+(m<<2)|0;if((j|0)==(i|0)){l=i|0?i<<1:1;if((i|0)<(l|0)){if(!l)j=0;else{c[6432]=(c[6432]|0)+1;i=ec((l<<2|3)+16|0)|0;if(!i)j=0;else{c[(i+4+15&-16)+-4>>2]=i;j=i+4+15&-16}i=c[b+52>>2]|0}if((i|0)>0){k=0;do{c[j+(k<<2)>>2]=c[(c[b+60>>2]|0)+(k<<2)>>2];k=k+1|0}while((k|0)!=(i|0))}k=c[b+60>>2]|0;if(k){if(a[b+64>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[k+-4>>2]|0);i=c[b+52>>2]|0}c[b+60>>2]=0}a[b+64>>0]=1;c[b+60>>2]=j;c[b+56>>2]=l;j=i;i=l}else j=i}c[(c[b+60>>2]|0)+(j<<2)>>2]=c[h>>2];j=j+1|0;c[b+52>>2]=j;m=m+1|0}while((m|0)!=(g|0))}if((n|0)>0){i=c[b+72>>2]|0;j=c[b+76>>2]|0;m=0;do{h=o+(m<<2)|0;if((i|0)==(j|0)){l=j|0?j<<1:1;if((j|0)<(l|0)){if(!l){i=j;j=0}else{c[6432]=(c[6432]|0)+1;i=ec((l<<2|3)+16|0)|0;if(!i)j=0;else{c[(i+4+15&-16)+-4>>2]=i;j=i+4+15&-16}i=c[b+72>>2]|0}if((i|0)>0){k=0;do{c[j+(k<<2)>>2]=c[(c[b+80>>2]|0)+(k<<2)>>2];k=k+1|0}while((k|0)!=(i|0))}k=c[b+80>>2]|0;if(k){if(a[b+84>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[k+-4>>2]|0);i=c[b+72>>2]|0}c[b+80>>2]=0}a[b+84>>0]=1;c[b+80>>2]=j;c[b+76>>2]=l;j=l}else i=j}c[(c[b+80>>2]|0)+(i<<2)>>2]=c[h>>2];i=i+1|0;c[b+72>>2]=i;m=m+1|0}while((m|0)!=(n|0))}else i=c[b+72>>2]|0;if(((c[b+52>>2]|0)+i|0)<=(c[(c[b+4>>2]|0)+72>>2]|0))return;Pg(b);return}function Ld(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0;a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;c[b+12>>2]=0;c[b+24>>2]=d;g[b+28>>2]=0.0;c[b+32>>2]=0;c[b+36>>2]=1;g[b+40>>2]=1.0;a[b+44>>0]=1;c[b+48>>2]=0;a[b+52>>0]=0;a[b+53>>0]=1;a[b+54>>0]=1;g[b+56>>2]=.03999999910593033;a[b+60>>0]=0;g[b+64>>2]=0.0;c[b+68>>2]=e;c[b+72>>2]=0;a[b+76>>0]=1;c[b+80>>2]=0;c[b+84>>2]=0;c[b+88>>2]=0;g[b+92>>2]=.6000000238418579;g[b+96>>2]=1.0;g[b+100>>2]=.30000001192092896;g[b+104>>2]=.01666666753590107;g[b+108>>2]=0.0;g[b+116>>2]=20.0;c[b+112>>2]=10;g[b+124>>2]=.20000000298023224;g[b+128>>2]=.800000011920929;g[b+132>>2]=0.0;g[b+120>>2]=1.0;c[b+136>>2]=1;g[b+140>>2]=-.03999999910593033;g[b+144>>2]=.10000000149011612;g[b+148>>2]=0.0;g[b+152>>2]=.8500000238418579;c[b+156>>2]=260;c[b+160>>2]=2;c[b+164>>2]=128;g[b+168>>2]=100.0;g[b+172>>2]=1000000015047466219876688.0e6;c[b>>2]=4272;a[b+192>>0]=1;c[b+188>>2]=0;c[b+180>>2]=0;c[b+184>>2]=0;c[b+196>>2]=0;c[b+200>>2]=f;a[b+224>>0]=1;c[b+220>>2]=0;c[b+212>>2]=0;c[b+216>>2]=0;a[b+244>>0]=1;c[b+240>>2]=0;c[b+232>>2]=0;c[b+236>>2]=0;c[b+248>>2]=0;c[b+252>>2]=-1054867456;a[b+274>>0]=0;a[b+275>>0]=0;c[b+256>>2]=0;c[b+256+4>>2]=0;c[b+256+8>>2]=0;c[b+256+12>>2]=0;a[b+292>>0]=1;c[b+288>>2]=0;c[b+280>>2]=0;c[b+284>>2]=0;c[b+296>>2]=0;a[b+300>>0]=1;a[b+320>>0]=1;c[b+316>>2]=0;c[b+308>>2]=0;c[b+312>>2]=0;if(!f){c[6432]=(c[6432]|0)+1;f=ec(215)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}c[f>>2]=4884;a[f+20>>0]=1;c[f+16>>2]=0;c[f+8>>2]=0;c[f+12>>2]=0;a[f+40>>0]=1;c[f+36>>2]=0;c[f+28>>2]=0;c[f+32>>2]=0;a[f+60>>0]=1;c[f+56>>2]=0;c[f+48>>2]=0;c[f+52>>2]=0;a[f+80>>0]=1;c[f+76>>2]=0;c[f+68>>2]=0;c[f+72>>2]=0;a[f+100>>0]=1;c[f+96>>2]=0;c[f+88>>2]=0;c[f+92>>2]=0;a[f+120>>0]=1;c[f+116>>2]=0;c[f+108>>2]=0;c[f+112>>2]=0;a[f+140>>0]=1;c[f+136>>2]=0;c[f+128>>2]=0;c[f+132>>2]=0;a[f+160>>0]=1;c[f+156>>2]=0;c[f+148>>2]=0;c[f+152>>2]=0;a[f+180>>0]=1;c[f+176>>2]=0;c[f+168>>2]=0;c[f+172>>2]=0;c[f+192>>2]=0;c[b+200>>2]=f;f=1}else f=0;a[b+273>>0]=f;c[6432]=(c[6432]|0)+1;f=ec(87)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}c[f>>2]=5580;a[f+20>>0]=1;c[f+16>>2]=0;c[f+8>>2]=0;c[f+12>>2]=0;a[f+40>>0]=1;c[f+36>>2]=0;c[f+28>>2]=0;c[f+32>>2]=0;a[f+60>>0]=1;c[f+56>>2]=0;c[f+48>>2]=0;c[f+52>>2]=0;a[f+64>>0]=1;c[b+204>>2]=f;a[b+272>>0]=1;c[6432]=(c[6432]|0)+1;f=ec(107)|0;if(!f){e=0;h=c[b+200>>2]|0;c[e>>2]=4484;f=e+4|0;c[f>>2]=0;f=e+8|0;c[f>>2]=h;f=e+12|0;c[f>>2]=0;f=e+16|0;c[f>>2]=0;f=e+20|0;c[f>>2]=0;f=e+24|0;c[f>>2]=d;d=e+44|0;a[d>>0]=1;d=e+40|0;c[d>>2]=0;d=e+32|0;c[d>>2]=0;d=e+36|0;c[d>>2]=0;d=e+64|0;a[d>>0]=1;d=e+60|0;c[d>>2]=0;d=e+52|0;c[d>>2]=0;d=e+56|0;c[d>>2]=0;d=e+84|0;a[d>>0]=1;d=e+80|0;c[d>>2]=0;d=e+72|0;c[d>>2]=0;d=e+76|0;c[d>>2]=0;c[b+196>>2]=e;return}c[(f+4+15&-16)+-4>>2]=f;h=f+4+15&-16;f=c[b+200>>2]|0;c[h>>2]=4484;e=h+4|0;c[e>>2]=0;e=h+8|0;c[e>>2]=f;e=h+12|0;c[e>>2]=0;e=h+16|0;c[e>>2]=0;e=h+20|0;c[e>>2]=0;e=h+24|0;c[e>>2]=d;d=h+44|0;a[d>>0]=1;d=h+40|0;c[d>>2]=0;d=h+32|0;c[d>>2]=0;d=h+36|0;c[d>>2]=0;d=h+64|0;a[d>>0]=1;d=h+60|0;c[d>>2]=0;d=h+52|0;c[d>>2]=0;d=h+56|0;c[d>>2]=0;d=h+84|0;a[d>>0]=1;d=h+80|0;c[d>>2]=0;d=h+72|0;c[d>>2]=0;d=h+76|0;c[d>>2]=0;c[b+196>>2]=h;return}function Md(b,d){b=b|0;d=d|0;var e=0,f=0,h=0.0,i=0,j=0.0,k=0,m=0,n=0.0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0.0,w=0.0;u=l;l=l+96|0;s=c[b+12>>2]|0;Vb[c[(c[s>>2]|0)+8>>2]&127](s,(c[b+8>>2]|0)+4|0,u+80|0,u+64|0);s=c[d+68>>2]|0;fb[c[(c[s>>2]|0)+16>>2]&31](s,c[(c[b+8>>2]|0)+188>>2]|0,u+80|0,u+64|0,c[d+24>>2]|0);s=c[d+24>>2]|0;Vb[c[(c[s>>2]|0)+32>>2]&127](s,c[(c[b+8>>2]|0)+284>>2]|0,d+28|0,s);s=c[b+8>>2]|0;c[b+92>>2]=c[s+52>>2];c[b+92+4>>2]=c[s+52+4>>2];c[b+92+8>>2]=c[s+52+8>>2];c[b+92+12>>2]=c[s+52+12>>2];s=c[s+284>>2]|0;if((lb[c[(c[s>>2]|0)+36>>2]&127](s)|0)>0){s=0;h=0.0;d=0;do{e=c[b+132>>2]|0;if((e|0)<0){if((c[b+136>>2]|0)<0){f=c[b+140>>2]|0;if(f|0){if(a[b+144>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[b+140>>2]=0}a[b+144>>0]=1;c[b+140>>2]=0;c[b+136>>2]=0}do{c[(c[b+140>>2]|0)+(e<<2)>>2]=0;e=e+1|0}while((e|0)!=0)}c[b+132>>2]=0;e=c[(c[b+8>>2]|0)+284>>2]|0;e=c[(lb[c[(c[e>>2]|0)+28>>2]&127](e)|0)+12>>2]|0;r=c[c[e+(s<<4)>>2]>>2]|0;f=c[c[e+(s<<4)+4>>2]>>2]|0;if(!((r|0)!=0?(c[r+204>>2]&4|0)!=0:0))t=14;do if((t|0)==14){t=0;if(f|0?c[f+204>>2]&4|0:0)break;e=c[e+(s<<4)+8>>2]|0;if(e|0)jb[c[(c[e>>2]|0)+16>>2]&127](e,b+128|0);q=c[b+132>>2]|0;if((q|0)>0){o=c[b+140>>2]|0;p=c[b+8>>2]|0;r=0;do{m=c[o+(r<<2)>>2]|0;n=(c[m+740>>2]|0)==(p|0)?-1.0:1.0;e=c[m+748>>2]|0;if((e|0)>0){k=0;do{j=+g[m+4+(k*184|0)+80>>2];if(j<0.0){i=m+4+(k*184|0)+64|0;if(j<h){d=m+4+(k*184|0)+68|0;v=n*+g[d>>2];f=m+4+(k*184|0)+72|0;h=n*+g[f>>2];g[b+152>>2]=n*+g[i>>2];g[b+156>>2]=v;g[b+160>>2]=h;g[b+164>>2]=0.0;e=c[m+748>>2]|0;h=j}else{d=m+4+(k*184|0)+68|0;f=m+4+(k*184|0)+72|0}w=j*n*+g[d>>2]*.20000000298023224;v=j*n*+g[f>>2]*.20000000298023224;g[b+92>>2]=j*n*+g[i>>2]*.20000000298023224+ +g[b+92>>2];g[b+96>>2]=w+ +g[b+96>>2];g[b+100>>2]=v+ +g[b+100>>2];d=1}k=k+1|0}while((k|0)<(e|0))}r=r+1|0}while((r|0)!=(q|0))}}while(0);s=s+1|0;r=c[(c[b+8>>2]|0)+284>>2]|0}while((s|0)<(lb[c[(c[r>>2]|0)+36>>2]&127](r)|0))}else d=0;t=c[b+8>>2]|0;c[u>>2]=c[t+4>>2];c[u+4>>2]=c[t+4+4>>2];c[u+8>>2]=c[t+4+8>>2];c[u+12>>2]=c[t+4+12>>2];c[u+16>>2]=c[t+20>>2];c[u+16+4>>2]=c[t+20+4>>2];c[u+16+8>>2]=c[t+20+8>>2];c[u+16+12>>2]=c[t+20+12>>2];c[u+32>>2]=c[t+36>>2];c[u+32+4>>2]=c[t+36+4>>2];c[u+32+8>>2]=c[t+36+8>>2];c[u+32+12>>2]=c[t+36+12>>2];c[u+48>>2]=c[b+92>>2];c[u+48+4>>2]=c[b+92+4>>2];c[u+48+8>>2]=c[b+92+8>>2];c[u+48+12>>2]=c[b+92+12>>2];c[t+260>>2]=(c[t+260>>2]|0)+1;c[t+4>>2]=c[u>>2];c[t+4+4>>2]=c[u+4>>2];c[t+4+8>>2]=c[u+8>>2];c[t+4+12>>2]=c[u+12>>2];c[t+20>>2]=c[u+16>>2];c[t+20+4>>2]=c[u+16+4>>2];c[t+20+8>>2]=c[u+16+8>>2];c[t+20+12>>2]=c[u+16+12>>2];c[t+36>>2]=c[u+32>>2];c[t+36+4>>2]=c[u+32+4>>2];c[t+36+8>>2]=c[u+32+8>>2];c[t+36+12>>2]=c[u+32+12>>2];c[t+52>>2]=c[u+48>>2];c[t+52+4>>2]=c[u+48+4>>2];c[t+52+8>>2]=c[u+48+8>>2];c[t+52+12>>2]=c[u+48+12>>2];l=u;return d|0}function Nd(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0,j=0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0,r=0,s=0,t=0.0,u=0.0;s=l;l=l+64|0;c[s+32>>2]=c[e>>2];c[s+32+4>>2]=c[e+4>>2];c[s+32+8>>2]=c[e+8>>2];c[s+32+12>>2]=c[e+12>>2];c[s+32+16>>2]=c[f>>2];c[s+32+16+4>>2]=c[f+4>>2];c[s+32+16+8>>2]=c[f+8>>2];c[s+32+16+12>>2]=c[f+12>>2];do if((c[d+60>>2]|0)==2){h=c[d+48>>2]|0;Kg(b+64|0,h)|0;i=c[b+68>>2]|0;if(i|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[b+68>>2]=h;c[b+76>>2]=(c[b+76>>2]|0)+-1;h=c[b+8>>2]|0;if(!h){c[6432]=(c[6432]|0)+1;h=ec(63)|0;if(!h)h=0;else{c[(h+4+15&-16)+-4>>2]=h;h=h+4+15&-16}i=h;j=i+44|0;do{c[i>>2]=0;i=i+4|0}while((i|0)<(j|0))}else c[b+8>>2]=0;c[h+32>>2]=0;c[h+36>>2]=d;c[h+40>>2]=0;c[h>>2]=c[s+32>>2];c[h+4>>2]=c[s+32+4>>2];c[h+8>>2]=c[s+32+8>>2];c[h+12>>2]=c[s+32+12>>2];c[h+16>>2]=c[s+32+16>>2];c[h+20>>2]=c[s+32+20>>2];c[h+24>>2]=c[s+32+24>>2];c[h+28>>2]=c[s+32+28>>2];We(b+4|0,c[b+4>>2]|0,h);c[b+16>>2]=(c[b+16>>2]|0)+1;c[d+48>>2]=h;j=1}else{c[b+168>>2]=(c[b+168>>2]|0)+1;r=c[d+48>>2]|0;if(((((+g[r>>2]<=+g[s+32+16>>2]?+g[r+16>>2]>=+g[s+32>>2]:0)?+g[r+4>>2]<=+g[s+32+20>>2]:0)?+g[r+20>>2]>=+g[s+32+4>>2]:0)?+g[r+8>>2]<=+g[s+32+24>>2]:0)?+g[r+24>>2]>=+g[s+32+8>>2]:0){n=+g[d+16>>2];t=+g[e>>2]-n;o=+g[d+20>>2];k=+g[e+4>>2]-o;p=+g[d+24>>2];m=+g[e+8>>2]-p;u=+g[b+140>>2];n=(+g[d+32>>2]-n)*.5*u;o=u*(+g[d+36>>2]-o)*.5;p=u*(+g[d+40>>2]-p)*.5;g[s+16>>2]=n;g[s+16+4>>2]=o;g[s+16+8>>2]=p;g[s+16+12>>2]=0.0;if(t<0.0)g[s+16>>2]=-n;if(k<0.0)g[s+16+4>>2]=-o;if(m<0.0)g[s+16+8>>2]=-p;if(!(Ug(b+4|0,r,s+32|0,s+16|0,.05000000074505806)|0)){j=0;break}c[b+172>>2]=(c[b+172>>2]|0)+1;j=1;break}h=Kg(b+4|0,r)|0;a:do if(h){j=c[b+12>>2]|0;if((j|0)<=-1){h=c[b+4>>2]|0;break}if(j){q=0;while(1){i=c[h+32>>2]|0;q=q+1|0;if(!i)break a;if((q|0)>=(j|0)){h=i;break}else h=i}}}else h=0;while(0);c[r>>2]=c[s+32>>2];c[r+4>>2]=c[s+32+4>>2];c[r+8>>2]=c[s+32+8>>2];c[r+12>>2]=c[s+32+12>>2];c[r+16>>2]=c[s+32+16>>2];c[r+20>>2]=c[s+32+20>>2];c[r+24>>2]=c[s+32+24>>2];c[r+28>>2]=c[s+32+28>>2];We(b+4|0,h,r);c[b+172>>2]=(c[b+172>>2]|0)+1;j=1}while(0);h=c[d+52>>2]|0;if(!h)h=b+124+(c[d+60>>2]<<2)|0;else h=h+56|0;c[h>>2]=c[d+56>>2];h=c[d+56>>2]|0;if(h|0)c[h+52>>2]=c[d+52>>2];c[d+16>>2]=c[e>>2];c[d+16+4>>2]=c[e+4>>2];c[d+16+8>>2]=c[e+8>>2];c[d+16+12>>2]=c[e+12>>2];c[d+32>>2]=c[f>>2];c[d+32+4>>2]=c[f+4>>2];c[d+32+8>>2]=c[f+8>>2];c[d+32+12>>2]=c[f+12>>2];h=c[b+144>>2]|0;c[d+60>>2]=h;c[d+52>>2]=0;c[d+56>>2]=c[b+124+(h<<2)>>2];i=c[b+124+(h<<2)>>2]|0;if(i|0)c[i+52>>2]=d;c[b+124+(h<<2)>>2]=d;if(!j){l=s;return}a[b+194>>0]=1;if(a[b+193>>0]|0){l=s;return}c[s>>2]=9028;c[s+4>>2]=b;ae(b+64|0,c[b+64>>2]|0,c[d+48>>2]|0,s);ae(b+4|0,c[b+4>>2]|0,c[d+48>>2]|0,s);l=s;return}function Od(d,e,f,h,i){d=d|0;e=e|0;f=+f;h=+h;i=+i;var j=0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0,r=0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0;q=l;l=l+240|0;o=+g[d+96>>2]+h;p=+g[d+100>>2]+i;g[d+112>>2]=+g[d+92>>2]+f;g[d+116>>2]=o;g[d+120>>2]=p;g[d+124>>2]=0.0;c[q+168>>2]=1065353216;c[q+168+4>>2]=0;c[q+168+4+4>>2]=0;c[q+168+4+8>>2]=0;c[q+168+4+12>>2]=0;c[q+168+20>>2]=1065353216;c[q+168+24>>2]=0;c[q+168+24+4>>2]=0;c[q+168+24+8>>2]=0;c[q+168+24+12>>2]=0;c[q+168+40>>2]=1065353216;j=q+168+44|0;c[j>>2]=0;c[j+4>>2]=0;c[j+8>>2]=0;c[j+12>>2]=0;c[j+16>>2]=0;c[q+104>>2]=1065353216;c[q+104+4>>2]=0;c[q+104+4+4>>2]=0;c[q+104+4+8>>2]=0;c[q+104+4+12>>2]=0;c[q+104+20>>2]=1065353216;c[q+104+24>>2]=0;c[q+104+24+4>>2]=0;c[q+104+24+8>>2]=0;c[q+104+24+12>>2]=0;c[q+104+40>>2]=1065353216;j=q+104+44|0;c[j>>2]=0;c[j+4>>2]=0;c[j+8>>2]=0;c[j+12>>2]=0;c[j+16>>2]=0;p=1.0;j=10;while(1){if((j|0)<=0){j=14;break}j=j+-1|0;c[q+168+48>>2]=c[d+92>>2];c[q+168+48+4>>2]=c[d+92+4>>2];c[q+168+48+8>>2]=c[d+92+8>>2];c[q+168+48+12>>2]=c[d+92+12>>2];c[q+104+48>>2]=c[d+112>>2];c[q+104+48+4>>2]=c[d+112+4>>2];c[q+104+48+8>>2]=c[d+112+8>>2];c[q+104+48+12>>2]=c[d+112+12>>2];n=+g[d+92>>2]-+g[d+112>>2];o=+g[d+96>>2]-+g[d+116>>2];f=+g[d+100>>2]-+g[d+120>>2];r=c[d+8>>2]|0;g[q+4>>2]=1.0;c[q+76>>2]=0;c[q+12>>2]=0;c[q+12+4>>2]=0;c[q+12+8>>2]=0;c[q+12+12>>2]=0;c[q+12+16>>2]=0;c[q+12+20>>2]=0;c[q+12+24>>2]=0;c[q+12+28>>2]=0;c[q>>2]=5064;c[q+80>>2]=r;g[q+84>>2]=n;g[q+88>>2]=o;g[q+92>>2]=f;g[q+96>>2]=0.0;g[q+100>>2]=0.0;r=c[r+188>>2]|0;b[q+8>>1]=b[r+4>>1]|0;b[q+10>>1]=b[r+6>>1]|0;r=c[d+12>>2]|0;f=+zb[c[(c[r>>2]|0)+48>>2]&15](r);r=c[d+12>>2]|0;gb[c[(c[r>>2]|0)+44>>2]&31](r,f+ +g[d+56>>2]);if(!(a[d+170>>0]|0))ud(e,c[d+12>>2]|0,q+168|0,q+104|0,q,+g[e+56>>2]);else cd(c[d+8>>2]|0,c[d+12>>2]|0,q+168|0,q+104|0,q,+g[e+56>>2]);r=c[d+12>>2]|0;gb[c[(c[r>>2]|0)+44>>2]&31](r,f);o=+g[q+4>>2];p=p-o;if(o<1.0){f=+g[d+112>>2];m=+g[d+92>>2];i=+g[d+116>>2];n=+g[d+96>>2];k=+g[d+120>>2];o=+g[d+100>>2];h=+C(+((f-m)*(f-m)+(i-n)*(i-n)+(k-o)*(k-o)));if(h>1.1920928955078125e-07){v=+g[q+44>>2];t=+g[q+48>>2];x=+g[q+52>>2];w=((f-m)*(1.0/h)*v+(i-n)*(1.0/h)*t+(k-o)*(1.0/h)*x)*2.0;u=(f-m)*(1.0/h)-v*w;s=(i-n)*(1.0/h)-t*w;w=(k-o)*(1.0/h)-x*w;k=1.0/+C(+(w*w+(u*u+s*s)));c[d+112>>2]=c[d+92>>2];c[d+112+4>>2]=c[d+92+4>>2];c[d+112+8>>2]=c[d+92+8>>2];c[d+112+12>>2]=c[d+92+12>>2];f=h*(k*u-v*(x*k*w+(v*k*u+t*k*s)))+ +g[d+112>>2];g[d+112>>2]=f;i=h*(k*s-t*(x*k*w+(v*k*u+t*k*s)))+ +g[d+116>>2];g[d+116>>2]=i;k=h*(k*w-x*(x*k*w+(v*k*u+t*k*s)))+ +g[d+120>>2];g[d+120>>2]=k;h=i}else h=i;i=f-m;h=h-n;f=k-o;if(!(i*i+h*h+f*f>1.1920928955078125e-07)){j=11;break}x=1.0/+C(+(i*i+h*h+f*f));if(+g[d+76>>2]*i*x+h*x*+g[d+80>>2]+f*x*+g[d+84>>2]<=0.0){j=11;break}}else{c[d+92>>2]=c[d+112>>2];c[d+92+4>>2]=c[d+112+4>>2];c[d+92+8>>2]=c[d+112+8>>2];c[d+92+12>>2]=c[d+112+12>>2]}if(!(p>.009999999776482582)){j=14;break}}if((j|0)==11){l=q;return}else if((j|0)==14){l=q;return}}function Pd(b,d,e){b=b|0;d=+d;e=+e;var f=0,h=0,i=0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0;t=l;l=l+80|0;f=c[b+8>>2]|0;if(!f){f=c[b+4>>2]|0;if(!f){d=0.0;m=0.0;o=0.0;j=0.0;n=0.0;k=0.0}else{j=+g[f+336>>2];m=+g[b+172>>2];s=+g[f+340>>2];k=+g[b+168>>2];o=+g[b+164>>2];n=+g[f+332>>2];d=j*m-s*k;m=s*o-m*n;o=k*n-j*o;j=+g[f+316>>2];n=+g[f+320>>2];k=+g[f+324>>2]}}else{j=+g[f+332>>2];m=+g[b+172>>2];s=+g[f+336>>2];k=+g[b+168>>2];o=+g[b+164>>2];n=+g[f+328>>2];d=j*m-s*k;m=s*o-m*n;o=k*n-j*o;j=+g[f+312>>2];n=+g[f+316>>2];k=+g[f+320>>2]}s=j+d;r=n+m;q=k+o;f=c[b+20>>2]|0;if(!f){f=c[b+16>>2]|0;if(!f){d=0.0;m=0.0;p=0.0;j=0.0;n=0.0;k=0.0}else{j=+g[f+336>>2];m=+g[b+188>>2];o=+g[f+340>>2];k=+g[b+184>>2];p=+g[b+180>>2];n=+g[f+332>>2];d=j*m-o*k;m=o*p-m*n;p=k*n-j*p;j=+g[f+316>>2];n=+g[f+320>>2];k=+g[f+324>>2]}}else{j=+g[f+332>>2];m=+g[b+188>>2];o=+g[f+336>>2];k=+g[b+184>>2];p=+g[b+180>>2];n=+g[f+328>>2];d=j*m-o*k;m=o*p-m*n;p=k*n-j*p;j=+g[f+312>>2];n=+g[f+316>>2];k=+g[f+320>>2]}o=s-(j+d);n=r-(n+m);m=q-(k+p);d=+g[b+196>>2];j=+g[b+200>>2];k=+g[b+204>>2];a[t+36+32>>0]=1;c[t+36+16>>2]=0;c[t+36+16+4>>2]=0;c[t+36+16+8>>2]=0;c[t+36+16+12>>2]=0;c[t+36>>2]=c[b+72>>2];c[t+36+4>>2]=c[b+72+4>>2];c[t+36+8>>2]=c[b+72+8>>2];c[t+36+12>>2]=c[b+72+12>>2];if(d*o+n*j+m*k<0.0){q=+g[b+212>>2];r=+g[t+36>>2]+((d*o+n*j+m*k)*d+(o-(d*o+n*j+m*k)*d)*q);g[t+36>>2]=r;s=(d*o+n*j+m*k)*j+q*(n-(d*o+n*j+m*k)*j)+ +g[t+36+4>>2];g[t+36+4>>2]=s;k=(d*o+n*j+m*k)*k+q*(m-(d*o+n*j+m*k)*k)+ +g[t+36+8>>2];g[t+36+8>>2]=k;d=r;j=s;f=t+36+8|0;h=t+36|0;i=t+36+4|0}else{d=+g[t+36>>2];j=+g[t+36+4>>2];k=+g[t+36+8>>2];f=t+36+8|0;h=t+36|0;i=t+36+4|0}m=(+g[b+104>>2]*d+ +g[b+108>>2]*j+ +g[b+112>>2]*k)*e;n=(d*+g[b+120>>2]+j*+g[b+124>>2]+k*+g[b+128>>2])*e;d=(d*+g[b+136>>2]+j*+g[b+140>>2]+k*+g[b+144>>2])*e;g[h>>2]=m;g[i>>2]=n;g[f>>2]=d;g[t+36+12>>2]=0.0;f=c[b+4>>2]|0;if((f|0)!=(c[b+16>>2]|0)){f=t;h=t+36|0;i=f+36|0;do{c[f>>2]=c[h>>2];f=f+4|0;h=h+4|0}while((f|0)<(i|0));e=-+g[t+4>>2];s=-+g[t+8>>2];g[t>>2]=-+g[t>>2];g[t+4>>2]=e;g[t+8>>2]=s;g[t+12>>2]=0.0;s=-+g[t+20>>2];e=-+g[t+24>>2];g[t+16>>2]=-+g[t+16>>2];g[t+20>>2]=s;g[t+24>>2]=e;g[t+28>>2]=0.0;vh(b+4|0,t,b+164|0);vh(b+16|0,t+36|0,b+180|0);l=t;return}if(!(m==m&n==n&(d==d&0.0==0.0))){l=t;return}e=+C(+(m*m+n*n+d*d));if(e<+g[f+368>>2]){l=t;return}h=c[t+36+32>>2]|0;e=+g[f+372>>2];g[t+12>>2]=0.0;g[t+28>>2]=0.0;c[t+32>>2]=h;g[t>>2]=-(m*e);g[t+4>>2]=-(n*e);g[t+8>>2]=-(d*e);g[t+16>>2]=e*-0.0;g[t+20>>2]=e*-0.0;g[t+24>>2]=e*-0.0;vh(b+4|0,t,b+164|0);d=+g[(c[b+4>>2]|0)+372>>2];f=t;h=t+36|0;i=f+36|0;do{c[f>>2]=c[h>>2];f=f+4|0;h=h+4|0}while((f|0)<(i|0));g[t>>2]=d*+g[t>>2];g[t+4>>2]=d*+g[t+4>>2];g[t+8>>2]=d*+g[t+8>>2];g[t+16>>2]=d*+g[t+16>>2];g[t+20>>2]=d*+g[t+20>>2];g[t+24>>2]=d*+g[t+24>>2];vh(b+16|0,t,b+180|0);l=t;return}function Qd(b){b=b|0;var d=0.0,e=0,f=0,h=0,i=0,j=0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0,r=0;q=l;l=l+80|0;if((lb[c[(c[b>>2]|0)+20>>2]&127](b)|0?(j=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0,(lb[c[(c[j>>2]|0)+48>>2]&127](j)|0)&8|0):0)?(f=c[b+24>>2]|0,f=lb[c[(c[f>>2]|0)+36>>2]&127](f)|0,c[q+64>>2]=1065353216,c[q+64+4>>2]=1065353216,c[q+64+8>>2]=0,g[q+64+12>>2]=0.0,(f|0)>0):0){i=0;do{h=c[b+24>>2]|0;h=Gb[c[(c[h>>2]|0)+40>>2]&31](h,i)|0;e=c[h+748>>2]|0;if((e|0)>0){j=0;do{r=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;ib[c[(c[r>>2]|0)+32>>2]&0](r,h+4+(j*184|0)+32|0,h+4+(j*184|0)+64|0,+g[h+4+(j*184|0)+80>>2],c[h+4+(j*184|0)+148>>2]|0,q+64|0);j=j+1|0}while((j|0)!=(e|0))}i=i+1|0}while((i|0)!=(f|0))}if(!(lb[c[(c[b>>2]|0)+20>>2]&127](b)|0)){l=q;return}r=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;if(!((lb[c[(c[r>>2]|0)+48>>2]&127](r)|0)&3)){l=q;return}if((c[b+8>>2]|0)<=0){l=q;return}j=0;do{i=c[(c[b+16>>2]|0)+(j<<2)>>2]|0;if(!(c[i+204>>2]&32)){if(lb[c[(c[b>>2]|0)+20>>2]&127](b)|0?(r=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0,(lb[c[(c[r>>2]|0)+48>>2]&127](r)|0)&1|0):0){c[q+64>>2]=1065353216;c[q+64+4>>2]=1065353216;c[q+64+8>>2]=1065353216;g[q+64+12>>2]=0.0;switch(c[i+216>>2]|0){case 1:{e=1065353216;f=1065353216;h=1065353216;break}case 2:{e=0;f=1065353216;h=0;break}case 3:{e=1065353216;f=1065353216;h=0;break}case 4:{e=0;f=0;h=1065353216;break}case 5:{e=0;f=1065353216;h=1065353216;break}default:{e=0;f=0;h=1065353216}}c[q+64>>2]=h;c[q+64+4>>2]=f;c[q+64+8>>2]=e;g[q+64+12>>2]=0.0;Vb[c[(c[b>>2]|0)+28>>2]&127](b,i+4|0,c[i+192>>2]|0,q+64|0)}e=c[b+72>>2]|0;if(e|0?(lb[c[(c[e>>2]|0)+48>>2]&127](e)|0)&2|0:0){c[q+32>>2]=1065353216;c[q+32+4>>2]=0;c[q+32+8>>2]=0;g[q+32+12>>2]=0.0;r=c[i+192>>2]|0;Vb[c[(c[r>>2]|0)+8>>2]&127](r,i+4|0,q+64|0,q+48|0);g[q+64>>2]=+g[q+64>>2]+-.019999999552965164;g[q+64+4>>2]=+g[q+64+4>>2]+-.019999999552965164;g[q+64+8>>2]=+g[q+64+8>>2]+-.019999999552965164;g[q+48>>2]=+g[q+48>>2]+.019999999552965164;g[q+48+4>>2]=+g[q+48+4>>2]+.019999999552965164;g[q+48+8>>2]=+g[q+48+8>>2]+.019999999552965164;do if((a[b+44>>0]|0?(c[i+236>>2]|0)==2:0)?(c[i+204>>2]&3|0)==0:0){r=c[i+192>>2]|0;Vb[c[(c[r>>2]|0)+8>>2]&127](r,i+68|0,q+16|0,q);d=+g[q+16>>2]+-.019999999552965164;g[q+16>>2]=d;m=+g[q+16+4>>2]+-.019999999552965164;g[q+16+4>>2]=m;k=+g[q+16+8>>2]+-.019999999552965164;g[q+16+8>>2]=k;n=+g[q>>2]+.019999999552965164;g[q>>2]=n;p=+g[q+4>>2]+.019999999552965164;g[q+4>>2]=p;o=+g[q+8>>2]+.019999999552965164;g[q+8>>2]=o;if(d<+g[q+64>>2])g[q+64>>2]=d;if(m<+g[q+64+4>>2])g[q+64+4>>2]=m;if(k<+g[q+64+8>>2])g[q+64+8>>2]=k;d=+g[q+16+12>>2];if(d<+g[q+64+12>>2])g[q+64+12>>2]=d;if(+g[q+48>>2]<n)g[q+48>>2]=n;if(+g[q+48+4>>2]<p)g[q+48+4>>2]=p;if(+g[q+48+8>>2]<o)g[q+48+8>>2]=o;d=+g[q+12>>2];if(!(+g[q+48+12>>2]<d))break;g[q+48+12>>2]=d}while(0);r=c[b+72>>2]|0;Vb[c[(c[r>>2]|0)+52>>2]&127](r,q+64|0,q+48|0,q+32|0)}}j=j+1|0}while((j|0)<(c[b+8>>2]|0));l=q;return}function Rd(b,d,e,f,h,i,j,k,l,m,n){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;var o=0,p=0,q=0.0,r=0.0,s=0,t=0,u=0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0;if((j|0)<2|(k|0)<2){n=0;return n|0}u=O(k,j)|0;c[6432]=(c[6432]|0)+1;b=ec(u>>>0>268435455?18:(u<<4|3)+16|0)|0;if(!b)t=0;else{c[(b+4+15&-16)+-4>>2]=b;t=b+4+15&-16}s=UG(u>>>0>1073741823?-1:u<<2)|0;if((k|0)>0?(j|0)>0:0){o=0;do{z=+(o|0)/+(k+-1|0);q=+g[e>>2];q=q+z*(+g[h>>2]-q);r=+g[e+4>>2];r=r+z*(+g[h+4>>2]-r);v=+g[e+8>>2];v=v+z*(+g[h+8>>2]-v);w=+g[f>>2];x=+g[f+4>>2];y=+g[f+8>>2];w=w+z*(+g[i>>2]-w)-q;x=x+z*(+g[i+4>>2]-x)-r;y=y+z*(+g[i+8>>2]-y)-v;p=O(o,j)|0;b=0;do{z=+(b|0)/+(j+-1|0);A=b+p|0;g[t+(A<<4)>>2]=q+w*z;g[t+(A<<4)+4>>2]=r+x*z;g[t+(A<<4)+8>>2]=v+y*z;g[t+(A<<4)+12>>2]=0.0;g[s+(A<<2)>>2]=1.0;b=b+1|0}while((b|0)!=(j|0));o=o+1|0}while((o|0)!=(k|0))}c[6432]=(c[6432]|0)+1;b=ec(1271)|0;if(!b)b=0;else{c[(b+4+15&-16)+-4>>2]=b;b=b+4+15&-16}oc(b,d,u,t,s);if(l&1|0){g[(c[b+720>>2]|0)+88>>2]=0.0;a[b+924>>0]=1}if(l&2|0){g[(c[b+720>>2]|0)+((j+-1|0)*104|0)+88>>2]=0.0;a[b+924>>0]=1}if(l&4|0){A=O(k+-1|0,j)|0;g[(c[b+720>>2]|0)+(A*104|0)+88>>2]=0.0;a[b+924>>0]=1}if(l&8|0){A=j+-1+(O(k+-1|0,j)|0)|0;g[(c[b+720>>2]|0)+(A*104|0)+88>>2]=0.0;a[b+924>>0]=1}if(l&16|0){g[(c[b+720>>2]|0)+(((j+-1|0)/2|0)*104|0)+88>>2]=0.0;a[b+924>>0]=1}if(l&32|0){A=O((k+-1|0)/2|0,j)|0;g[(c[b+720>>2]|0)+(A*104|0)+88>>2]=0.0;a[b+924>>0]=1}if(l&64|0){A=j+-1+(O((k+-1|0)/2|0,j)|0)|0;g[(c[b+720>>2]|0)+(A*104|0)+88>>2]=0.0;a[b+924>>0]=1}if(l&128|0){A=(O(k+-1|0,j)|0)+((j+-1|0)/2|0)|0;g[(c[b+720>>2]|0)+(A*104|0)+88>>2]=0.0;a[b+924>>0]=1}if(l&256|0){A=(O((k+-1|0)/2|0,j)|0)+((j+-1|0)/2|0)|0;g[(c[b+720>>2]|0)+(A*104|0)+88>>2]=0.0;a[b+924>>0]=1}if(t|0){c[6433]=(c[6433]|0)+1;Pc(c[t+-4>>2]|0)}VG(s);if((k|0)<=0){A=b;return A|0}u=j+-1|0;d=0;o=0;while(1){p=d;d=d+1|0;a:do if((j|0)>0){t=O(p,j)|0;s=O(d,j)|0;r=1.0/+(k+-1|0)*+(k+-1-p|0);q=1.0/+(k+-1|0)*+(k+-2-p|0);if((d|0)<(k|0)){h=0;i=o}else{p=0;while(1){e=p;p=p+1|0;if((p|0)<(j|0))Df(b,e+t|0,p+t|0,0,0);if((p|0)==(j|0))break a}}while(1){p=h+1|0;e=h+t|0;f=h+s|0;if((h|0)==(j+-1|0))break;Df(b,e,p+t|0,0,0);Df(b,e,f,0,0);Mf(b,e,f,p+s|0,0);if(!n)Mf(b,p+s|0,p+t|0,e,0);else{z=1.0/+(j+-1|0)*+(h|0);g[n+(i<<2)>>2]=z;g[n+(i+1<<2)>>2]=r;g[n+(i+2<<2)>>2]=z;g[n+(i+3<<2)>>2]=q;y=1.0/+(j+-1|0)*+(p|0);g[n+(i+4<<2)>>2]=y;g[n+(i+5<<2)>>2]=q;Mf(b,p+s|0,p+t|0,e,0);g[n+(i+6<<2)>>2]=y;g[n+(i+7<<2)>>2]=q;g[n+(i+8<<2)>>2]=y;g[n+(i+9<<2)>>2]=r;g[n+(i+10<<2)>>2]=z;g[n+(i+11<<2)>>2]=r}if(m)Df(b,e,p+s|0,0,0);h=p;i=i+12|0}Df(b,u,f,0,0);o=(j*12|0)+-12+o|0}while(0);if((d|0)==(k|0))break;else u=u+j|0}return b|0}function Sd(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,h=0,i=0,j=0,k=0,m=0,n=0,o=0,p=0,q=0.0,r=0.0;p=l;l=l+144|0;if((c[a+16>>2]|0)<=0){o=a+76|0;c[o>>2]=c[b>>2];c[o+4>>2]=c[b+4>>2];c[o+8>>2]=c[b+8>>2];c[o+12>>2]=c[b+12>>2];b=c[a>>2]|0;b=b+68|0;b=c[b>>2]|0;hb[b&511](a);l=p;return}m=p+16+16|0;k=p+16+32|0;o=p+16+48|0;n=0;do{j=c[a+24>>2]|0;i=j+(n*80|0)|0;c[p+16>>2]=c[i>>2];c[p+16+4>>2]=c[i+4>>2];c[p+16+8>>2]=c[i+8>>2];c[p+16+12>>2]=c[i+12>>2];i=j+(n*80|0)+16|0;c[m>>2]=c[i>>2];c[m+4>>2]=c[i+4>>2];c[m+8>>2]=c[i+8>>2];c[m+12>>2]=c[i+12>>2];i=j+(n*80|0)+32|0;c[k>>2]=c[i>>2];c[k+4>>2]=c[i+4>>2];c[k+8>>2]=c[i+8>>2];c[k+12>>2]=c[i+12>>2];i=j+(n*80|0)+48|0;c[o>>2]=c[i>>2];c[o+4>>2]=c[i+4>>2];c[o+8>>2]=c[i+8>>2];c[o+12>>2]=c[i+12>>2];j=c[j+(n*80|0)+64>>2]|0;j=lb[c[(c[j>>2]|0)+28>>2]&127](j)|0;c[p>>2]=c[j>>2];c[p+4>>2]=c[j+4>>2];c[p+8>>2]=c[j+8>>2];q=+g[p+4>>2]*+g[b+4>>2]/+g[a+80>>2];r=+g[p+8>>2]*+g[b+8>>2]/+g[a+84>>2];g[p>>2]=+g[p>>2]*+g[b>>2]/+g[a+76>>2];g[p+4>>2]=q;g[p+8>>2]=r;g[p+12>>2]=0.0;j=c[(c[a+24>>2]|0)+(n*80|0)+64>>2]|0;jb[c[(c[j>>2]|0)+24>>2]&127](j,p);r=+g[p+16+52>>2]*+g[b+4>>2]/+g[a+80>>2];q=+g[p+16+56>>2]*+g[b+8>>2]/+g[a+84>>2];g[p+16+48>>2]=+g[o>>2]*+g[b>>2]/+g[a+76>>2];g[p+16+52>>2]=r;g[p+16+56>>2]=q;g[p+16+60>>2]=0.0;j=c[a+24>>2]|0;i=j+(n*80|0)|0;c[i>>2]=c[p+16>>2];c[i+4>>2]=c[p+16+4>>2];c[i+8>>2]=c[p+16+8>>2];c[i+12>>2]=c[p+16+12>>2];i=j+(n*80|0)+16|0;c[i>>2]=c[m>>2];c[i+4>>2]=c[m+4>>2];c[i+8>>2]=c[m+8>>2];c[i+12>>2]=c[m+12>>2];i=j+(n*80|0)+32|0;c[i>>2]=c[k>>2];c[i+4>>2]=c[k+4>>2];c[i+8>>2]=c[k+8>>2];c[i+12>>2]=c[k+12>>2];j=j+(n*80|0)+48|0;c[j>>2]=c[o>>2];c[j+4>>2]=c[o+4>>2];c[j+8>>2]=c[o+8>>2];c[j+12>>2]=c[o+12>>2];if(c[a+64>>2]|0){i=c[(c[a+24>>2]|0)+(n*80|0)+64>>2]|0;Vb[c[(c[i>>2]|0)+8>>2]&127](i,p+16|0,p+128|0,p+112|0);c[p+80>>2]=c[p+128>>2];c[p+80+4>>2]=c[p+128+4>>2];c[p+80+8>>2]=c[p+128+8>>2];c[p+80+12>>2]=c[p+128+12>>2];c[p+80+16>>2]=c[p+112>>2];c[p+80+16+4>>2]=c[p+112+4>>2];c[p+80+16+8>>2]=c[p+112+8>>2];c[p+80+16+12>>2]=c[p+112+12>>2];i=c[a+64>>2]|0;j=c[(c[a+24>>2]|0)+(n*80|0)+76>>2]|0;d=Kg(i,j)|0;a:do if(d){f=c[i+8>>2]|0;if((f|0)<=-1){d=c[i>>2]|0;break}if(f){h=0;while(1){e=c[d+32>>2]|0;h=h+1|0;if(!e)break a;if((h|0)>=(f|0)){d=e;break}else d=e}}}else d=0;while(0);c[j>>2]=c[p+80>>2];c[j+4>>2]=c[p+80+4>>2];c[j+8>>2]=c[p+80+8>>2];c[j+12>>2]=c[p+80+12>>2];c[j+16>>2]=c[p+80+16>>2];c[j+20>>2]=c[p+80+20>>2];c[j+24>>2]=c[p+80+24>>2];c[j+28>>2]=c[p+80+28>>2];We(i,d,j)}n=n+1|0}while((n|0)<(c[a+16>>2]|0));o=a+76|0;c[o>>2]=c[b>>2];c[o+4>>2]=c[b+4>>2];c[o+8>>2]=c[b+8>>2];c[o+12>>2]=c[b+12>>2];b=c[a>>2]|0;b=b+68|0;b=c[b>>2]|0;hb[b&511](a);l=p;return}function Td(d,f,h,i,j,k){d=d|0;f=f|0;h=h|0;i=i|0;j=j|0;k=k|0;var l=0.0,m=0.0,n=0.0;c[d>>2]=8708;b[d+4>>1]=-2;b[d+6>>1]=-1;c[d+92>>2]=j;c[d+96>>2]=0;a[d+100>>0]=0;c[d+104>>2]=0;c[d+108>>2]=0;if(!j){c[6432]=(c[6432]|0)+1;j=ec(95)|0;if(!j)j=0;else{c[(j+4+15&-16)+-4>>2]=j;j=j+4+15&-16}ki(j);c[d+92>>2]=j;a[d+100>>0]=1}if(!k){c[6432]=(c[6432]|0)+1;j=ec(43)|0;if(!j)j=0;else{c[(j+4+15&-16)+-4>>2]=j;j=j+4+15&-16}k=j+4|0;c[k>>2]=0;c[k+4>>2]=0;c[k+8>>2]=0;c[k+12>>2]=0;c[k+16>>2]=0;c[j>>2]=8772;a[j+20>>0]=1;c[j+16>>2]=0;c[j+8>>2]=0;c[j+12>>2]=0;c[d+112>>2]=j;c[6432]=(c[6432]|0)+1;j=ec(215)|0;if(!j)j=0;else{c[(j+4+15&-16)+-4>>2]=j;j=j+4+15&-16}xh(j,c[d+112>>2]|0);c[d+108>>2]=j;a[j+193>>0]=1}c[d+8>>2]=c[f>>2];c[d+8+4>>2]=c[f+4>>2];c[d+8+8>>2]=c[f+8>>2];c[d+8+12>>2]=c[f+12>>2];c[d+24>>2]=c[h>>2];c[d+24+4>>2]=c[h+4>>2];c[d+24+8>>2]=c[h+8>>2];c[d+24+12>>2]=c[h+12>>2];n=+(e[d+6>>1]|0);m=n/(+g[d+28>>2]-+g[d+12>>2]);l=n/(+g[d+32>>2]-+g[d+16>>2]);g[d+40>>2]=n/(+g[d+24>>2]-+g[d+8>>2]);g[d+44>>2]=m;g[d+48>>2]=l;g[d+52>>2]=0.0;f=(i&65535)+1&65535;c[6432]=(c[6432]|0)+1;j=ec(f<<6|19)|0;if(!j)h=0;else{c[(j+4+15&-16)+-4>>2]=j;h=j+4+15&-16}if(f|0){j=h+(f<<6)|0;k=h;do{c[k>>2]=0;c[k+8>>2]=0;k=k+64|0}while((k|0)!=(j|0))}c[d+60>>2]=h;b[d+58>>1]=(i&65535)+1;b[d+56>>1]=0;b[d+64>>1]=1;if(f>>>0>1){j=1;k=1;do{b[h+(j<<6)+48>>1]=j+1;k=k+1<<16>>16;j=k&65535}while(j>>>0<f>>>0)}b[h+(f+-1<<6)+48>>1]=0;c[6432]=(c[6432]|0)+1;j=ec((f<<3|3)+16|0)|0;if(!j)j=0;else{c[(j+4+15&-16)+-4>>2]=j;j=j+4+15&-16}c[d+80>>2]=j;c[d+68>>2]=j;c[6432]=(c[6432]|0)+1;j=ec((f<<3|3)+16|0)|0;if(!j)j=0;else{c[(j+4+15&-16)+-4>>2]=j;j=j+4+15&-16}c[d+84>>2]=j;c[d+72>>2]=j;c[6432]=(c[6432]|0)+1;j=ec((f<<3|3)+16|0)|0;if(!j){h=0;i=d+88|0;c[i>>2]=h;i=d+76|0;c[i>>2]=h;h=c[d+60>>2]|0;c[h>>2]=0;f=h+48|0;b[f>>1]=0;f=h+54|0;b[f>>1]=1;f=c[d+68>>2]|0;b[f>>1]=0;k=f+2|0;b[k>>1]=0;k=b[d+6>>1]|0;j=f+4|0;b[j>>1]=k;f=f+6|0;b[f>>1]=0;f=h+50|0;b[f>>1]=0;f=h+56|0;b[f>>1]=1;f=c[d+72>>2]|0;b[f>>1]=0;j=f+2|0;b[j>>1]=0;j=b[d+6>>1]|0;k=f+4|0;b[k>>1]=j;f=f+6|0;b[f>>1]=0;f=h+52|0;b[f>>1]=0;h=h+58|0;b[h>>1]=1;i=c[i>>2]|0;b[i>>1]=0;h=i+2|0;b[h>>1]=0;h=b[d+6>>1]|0;f=i+4|0;b[f>>1]=h;i=i+6|0;b[i>>1]=0;c[d>>2]=8644;return}c[(j+4+15&-16)+-4>>2]=j;h=j+4+15&-16;i=d+88|0;c[i>>2]=h;i=d+76|0;c[i>>2]=h;h=c[d+60>>2]|0;c[h>>2]=0;f=h+48|0;b[f>>1]=0;f=h+54|0;b[f>>1]=1;f=c[d+68>>2]|0;b[f>>1]=0;k=f+2|0;b[k>>1]=0;k=b[d+6>>1]|0;j=f+4|0;b[j>>1]=k;f=f+6|0;b[f>>1]=0;f=h+50|0;b[f>>1]=0;f=h+56|0;b[f>>1]=1;f=c[d+72>>2]|0;b[f>>1]=0;j=f+2|0;b[j>>1]=0;j=b[d+6>>1]|0;k=f+4|0;b[k>>1]=j;f=f+6|0;b[f>>1]=0;f=h+52|0;b[f>>1]=0;h=h+58|0;b[h>>1]=1;i=c[i>>2]|0;b[i>>1]=0;h=i+2|0;b[h>>1]=0;h=b[d+6>>1]|0;f=i+4|0;b[f>>1]=h;i=i+6|0;b[i>>1]=0;c[d>>2]=8644;return}function Ud(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0.0,O=0.0,P=0.0,Q=0.0,R=0.0,S=0.0,T=0.0,U=0.0,V=0.0,W=0,X=0.0,Y=0.0;W=l;l=l+240|0;f=(a[b+8>>0]|0)!=0;h=f?e:d;f=f?d:e;S=+g[h+116>>2]-+g[h+52>>2];T=+g[h+120>>2]-+g[h+56>>2];U=+g[h+124>>2]-+g[h+60>>2];V=+g[h+252>>2];if(S*S+T*T+U*U<V*V){X=1.0;l=W;return +X}P=+g[f+4>>2];p=+g[f+20>>2];q=+g[f+36>>2];r=+g[f+8>>2];s=+g[f+24>>2];t=+g[f+40>>2];u=+g[f+12>>2];v=+g[f+28>>2];w=+g[f+44>>2];j=-+g[f+52>>2];k=-+g[f+56>>2];m=-+g[f+60>>2];x=+g[h+4>>2];y=+g[h+20>>2];z=+g[h+36>>2];A=+g[h+8>>2];B=+g[h+24>>2];C=+g[h+40>>2];D=+g[h+12>>2];E=+g[h+28>>2];F=+g[h+44>>2];H=+g[h+52>>2];G=+g[h+56>>2];T=+g[h+60>>2];R=P*j+p*k+q*m+(P*H+p*G+q*T);V=r*j+s*k+t*m+(r*H+s*G+t*T);T=u*j+v*k+w*m+(u*H+v*G+w*T);G=+g[h+68>>2];H=+g[h+84>>2];I=+g[h+100>>2];J=+g[h+72>>2];K=+g[h+88>>2];L=+g[h+104>>2];M=+g[h+76>>2];N=+g[h+92>>2];O=+g[h+108>>2];n=+g[h+116>>2];o=+g[h+120>>2];S=+g[h+124>>2];Q=P*j+p*k+q*m+(P*n+p*o+q*S);U=r*j+s*k+t*m+(r*n+s*o+t*S);S=u*j+v*k+w*m+(u*n+v*o+w*S);f=c[f+192>>2]|0;if(((c[f+4>>2]|0)+-21|0)>>>0>=9){X=1.0;l=W;return +X}g[W+224>>2]=R;g[W+224+4>>2]=V;g[W+224+8>>2]=T;g[W+224+12>>2]=0.0;if(Q<R){g[W+224>>2]=Q;i=Q}else i=R;if(U<V){g[W+224+4>>2]=U;j=U}else j=V;if(S<T){g[W+224+8>>2]=S;k=S}else k=T;g[W+208>>2]=R;g[W+208+4>>2]=V;g[W+208+8>>2]=T;g[W+208+12>>2]=0.0;if(R<Q){g[W+208>>2]=Q;m=Q}else m=R;if(V<U){g[W+208+4>>2]=U;n=U}else n=V;if(T<S){g[W+208+8>>2]=S;o=S}else o=T;Y=+g[h+248>>2];g[W+224>>2]=i-Y;g[W+224+4>>2]=j-Y;g[W+224+8>>2]=k-Y;g[W+208>>2]=Y+m;g[W+208+4>>2]=Y+n;g[W+208+8>>2]=Y+o;c[W>>2]=3796;g[W+4>>2]=P*x+p*y+q*z;g[W+8>>2]=P*A+p*B+q*C;g[W+12>>2]=P*D+p*E+q*F;g[W+16>>2]=0.0;g[W+20>>2]=r*x+s*y+t*z;g[W+24>>2]=r*A+s*B+t*C;g[W+28>>2]=r*D+s*E+t*F;g[W+32>>2]=0.0;g[W+36>>2]=u*x+v*y+w*z;g[W+40>>2]=u*A+v*B+w*C;g[W+44>>2]=u*D+v*E+w*F;g[W+48>>2]=0.0;g[W+52>>2]=R;g[W+56>>2]=V;g[W+60>>2]=T;g[W+64>>2]=0.0;g[W+68>>2]=P*G+p*H+q*I;g[W+72>>2]=P*J+p*K+q*L;g[W+76>>2]=P*M+p*N+q*O;g[W+80>>2]=0.0;g[W+84>>2]=r*G+s*H+t*I;g[W+88>>2]=r*J+s*K+t*L;g[W+92>>2]=r*M+s*N+t*O;g[W+96>>2]=0.0;g[W+100>>2]=u*G+v*H+w*I;g[W+104>>2]=u*J+v*K+w*L;g[W+108>>2]=u*M+v*N+w*O;g[W+112>>2]=0.0;g[W+116>>2]=Q;g[W+120>>2]=U;g[W+124>>2]=S;g[W+128>>2]=0.0;g[W+196>>2]=Y;c[W+200>>2]=c[h+244>>2];if(f|0?(Vb[c[(c[f>>2]|0)+64>>2]&127](f,W,W+224|0,W+208|0),X=+g[W+200>>2],X<+g[h+244>>2]):0){g[h+244>>2]=X;Y=X;l=W;return +Y}Y=1.0;l=W;return +Y}function Vd(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0.0,O=0.0,P=0.0,Q=0.0,R=0.0,S=0.0,T=0.0,U=0.0,V=0.0,W=0,X=0.0,Y=0.0;W=l;l=l+240|0;f=(a[b+8>>0]|0)!=0;h=f?e:d;f=f?d:e;S=+g[h+116>>2]-+g[h+52>>2];T=+g[h+120>>2]-+g[h+56>>2];U=+g[h+124>>2]-+g[h+60>>2];V=+g[h+252>>2];if(S*S+T*T+U*U<V*V){X=1.0;l=W;return +X}P=+g[f+4>>2];p=+g[f+20>>2];q=+g[f+36>>2];r=+g[f+8>>2];s=+g[f+24>>2];t=+g[f+40>>2];u=+g[f+12>>2];v=+g[f+28>>2];w=+g[f+44>>2];j=-+g[f+52>>2];k=-+g[f+56>>2];m=-+g[f+60>>2];x=+g[h+4>>2];y=+g[h+20>>2];z=+g[h+36>>2];A=+g[h+8>>2];B=+g[h+24>>2];C=+g[h+40>>2];D=+g[h+12>>2];E=+g[h+28>>2];F=+g[h+44>>2];H=+g[h+52>>2];G=+g[h+56>>2];T=+g[h+60>>2];R=P*j+p*k+q*m+(P*H+p*G+q*T);V=r*j+s*k+t*m+(r*H+s*G+t*T);T=u*j+v*k+w*m+(u*H+v*G+w*T);G=+g[h+68>>2];H=+g[h+84>>2];I=+g[h+100>>2];J=+g[h+72>>2];K=+g[h+88>>2];L=+g[h+104>>2];M=+g[h+76>>2];N=+g[h+92>>2];O=+g[h+108>>2];n=+g[h+116>>2];o=+g[h+120>>2];S=+g[h+124>>2];Q=P*j+p*k+q*m+(P*n+p*o+q*S);U=r*j+s*k+t*m+(r*n+s*o+t*S);S=u*j+v*k+w*m+(u*n+v*o+w*S);f=c[f+192>>2]|0;if(((c[f+4>>2]|0)+-21|0)>>>0>=9){X=1.0;l=W;return +X}g[W+224>>2]=R;g[W+224+4>>2]=V;g[W+224+8>>2]=T;g[W+224+12>>2]=0.0;if(Q<R){g[W+224>>2]=Q;i=Q}else i=R;if(U<V){g[W+224+4>>2]=U;j=U}else j=V;if(S<T){g[W+224+8>>2]=S;k=S}else k=T;g[W+208>>2]=R;g[W+208+4>>2]=V;g[W+208+8>>2]=T;g[W+208+12>>2]=0.0;if(R<Q){g[W+208>>2]=Q;m=Q}else m=R;if(V<U){g[W+208+4>>2]=U;n=U}else n=V;if(T<S){g[W+208+8>>2]=S;o=S}else o=T;Y=+g[h+248>>2];g[W+224>>2]=i-Y;g[W+224+4>>2]=j-Y;g[W+224+8>>2]=k-Y;g[W+208>>2]=Y+m;g[W+208+4>>2]=Y+n;g[W+208+8>>2]=Y+o;c[W>>2]=5660;g[W+4>>2]=P*x+p*y+q*z;g[W+8>>2]=P*A+p*B+q*C;g[W+12>>2]=P*D+p*E+q*F;g[W+16>>2]=0.0;g[W+20>>2]=r*x+s*y+t*z;g[W+24>>2]=r*A+s*B+t*C;g[W+28>>2]=r*D+s*E+t*F;g[W+32>>2]=0.0;g[W+36>>2]=u*x+v*y+w*z;g[W+40>>2]=u*A+v*B+w*C;g[W+44>>2]=u*D+v*E+w*F;g[W+48>>2]=0.0;g[W+52>>2]=R;g[W+56>>2]=V;g[W+60>>2]=T;g[W+64>>2]=0.0;g[W+68>>2]=P*G+p*H+q*I;g[W+72>>2]=P*J+p*K+q*L;g[W+76>>2]=P*M+p*N+q*O;g[W+80>>2]=0.0;g[W+84>>2]=r*G+s*H+t*I;g[W+88>>2]=r*J+s*K+t*L;g[W+92>>2]=r*M+s*N+t*O;g[W+96>>2]=0.0;g[W+100>>2]=u*G+v*H+w*I;g[W+104>>2]=u*J+v*K+w*L;g[W+108>>2]=u*M+v*N+w*O;g[W+112>>2]=0.0;g[W+116>>2]=Q;g[W+120>>2]=U;g[W+124>>2]=S;g[W+128>>2]=0.0;g[W+196>>2]=Y;c[W+200>>2]=c[h+244>>2];if(f|0?(Vb[c[(c[f>>2]|0)+64>>2]&127](f,W,W+224|0,W+208|0),X=+g[W+200>>2],X<+g[h+244>>2]):0){g[h+244>>2]=X;Y=X;l=W;return +Y}Y=1.0;l=W;return +Y}function Wd(b,d,e,f){b=b|0;d=d|0;e=e|0;f=+f;var h=0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,D=0.0,E=0,F=0;v=l;l=l+192|0;u=c[b+4>>2]|0;i=+g[u+752>>2];if(i<f){l=v;return}s=c[u+740>>2]|0;r=(c[b+8>>2]|0)+8|0;t=c[r>>2]|0;D=+g[e>>2];w=+g[d>>2]*f+D;A=+g[e+4>>2];j=+g[d+4>>2]*f+A;x=+g[e+8>>2];k=+g[d+8>>2]*f+x;q=(c[b+12>>2]|0)+8|0;h=c[q>>2]|0;p=(s|0)!=(t|0)?h:s;h=(s|0)!=(t|0)?t:h;y=w-+g[p+52>>2];z=j-+g[p+56>>2];m=k-+g[p+60>>2];o=y*+g[p+4>>2]+z*+g[p+20>>2]+m*+g[p+36>>2];n=y*+g[p+8>>2]+z*+g[p+24>>2]+m*+g[p+40>>2];m=y*+g[p+12>>2]+z*+g[p+28>>2]+m*+g[p+44>>2];D=D-+g[h+52>>2];A=A-+g[h+56>>2];x=x-+g[h+60>>2];z=D*+g[h+4>>2]+A*+g[h+20>>2]+x*+g[h+36>>2];y=D*+g[h+8>>2]+A*+g[h+24>>2]+x*+g[h+40>>2];x=D*+g[h+12>>2]+A*+g[h+28>>2]+x*+g[h+44>>2];g[v>>2]=o;g[v+4>>2]=n;g[v+8>>2]=m;g[v+12>>2]=0.0;g[v+16>>2]=z;g[v+20>>2]=y;g[v+24>>2]=x;g[v+28>>2]=0.0;c[v+64>>2]=c[d>>2];c[v+64+4>>2]=c[d+4>>2];c[v+64+8>>2]=c[d+8>>2];c[v+64+12>>2]=c[d+12>>2];g[v+80>>2]=f;g[v+84>>2]=0.0;g[v+88>>2]=0.0;g[v+92>>2]=0.0;c[v+112>>2]=0;a[v+116>>0]=0;c[v+120>>2]=0;c[v+120+4>>2]=0;c[v+120+8>>2]=0;c[v+120+12>>2]=0;c[v+120+16>>2]=0;c[v+120+20>>2]=0;c[v+120+24>>2]=0;c[v+120+28>>2]=0;g[v+48>>2]=w;g[v+52>>2]=j;g[v+56>>2]=k;g[v+60>>2]=0.0;c[v+32>>2]=c[e>>2];c[v+32+4>>2]=c[e+4>>2];c[v+32+8>>2]=c[e+8>>2];c[v+32+12>>2]=c[e+12>>2];h=c[u+748>>2]|0;if((h|0)>0){p=0;d=-1;f=i*i;while(1){i=+g[u+4+(p*184|0)>>2]-o;k=+g[u+4+(p*184|0)+4>>2]-n;j=+g[u+4+(p*184|0)+8>>2]-m;e=i*i+k*k+j*j<f;d=e?p:d;p=p+1|0;if((p|0)==(h|0)){p=d;break}else f=e?i*i+k*k+j*j:f}}else p=-1;h=c[r>>2]|0;r=c[q>>2]|0;f=+g[h+224>>2]*+g[r+224>>2];f=f<-10.0?-10.0:f;g[v+84>>2]=f>10.0?10.0:f;g[v+92>>2]=+g[h+228>>2]*+g[r+228>>2];f=+g[h+232>>2]*+g[r+232>>2];f=f<-10.0?-10.0:f;g[v+88>>2]=f>10.0?10.0:f;f=+g[v+72>>2];r=+B(+f)>.7071067690849304;i=+g[v+68>>2];if(r){D=1.0/+C(+(f*f+i*i));A=+g[v+64>>2];j=D*i;k=0.0;m=-(D*f);n=(f*f+i*i)*D;o=-(D*i*A);f=A*-(D*f)}else{A=+g[v+64>>2];D=1.0/+C(+(A*A+i*i));j=0.0;k=-(i*D);m=D*A;n=-(D*A*f);o=f*-(i*D);f=(A*A+i*i)*D}g[v+152>>2]=k;g[v+156>>2]=m;g[v+160>>2]=j;g[v+168>>2]=n;g[v+172>>2]=o;g[v+176>>2]=f;e=c[b+20>>2]|0;d=c[b+16>>2]|0;if((s|0)!=(t|0)){c[v+96>>2]=e;h=b+28|0;e=d;d=b+24|0}else{c[v+96>>2]=d;h=b+24|0;d=b+28|0}b=c[h>>2]|0;c[v+100>>2]=e;c[v+104>>2]=b;c[v+108>>2]=c[d>>2];if((p|0)>-1){b=u+4+(p*184|0)+148|0;t=c[b>>2]|0;e=u+4+(p*184|0)+120|0;d=c[e>>2]|0;q=u+4+(p*184|0)+124|0;h=c[q>>2]|0;s=u+4+(p*184|0)+128|0;r=c[s>>2]|0;E=u+4+(p*184|0)+112|0;F=c[E>>2]|0;Th(u+4+(p*184|0)|0,v|0,184)|0;c[E>>2]=F;c[e>>2]=d;c[q>>2]=h;c[s>>2]=r;c[b>>2]=t}else Ye(u,v)|0;l=v;return}function Xd(d,e,f,h){d=d|0;e=e|0;f=f|0;h=h|0;var i=0,k=0,l=0,m=0.0,n=0,o=0.0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0;o=+g[e>>2];k=(g[j>>2]=o,c[j>>2]|0);u=o<999999984306749440.0?k:1566444395;m=+g[e+4>>2];n=(g[j>>2]=m,c[j>>2]|0);v=m<999999984306749440.0?n:1566444395;y=+g[e+8>>2];q=(g[j>>2]=y,c[j>>2]|0);w=y<999999984306749440.0?q:1566444395;k=o>-999999984306749440.0?k:-581039253;n=m>-999999984306749440.0?n:-581039253;q=y>-999999984306749440.0?q:-581039253;y=+g[e+16>>2];t=y<(c[j>>2]=u,+g[j>>2]);i=(g[j>>2]=y,c[j>>2]|0);u=t?i:u;m=+g[e+20>>2];t=m<(c[j>>2]=v,+g[j>>2]);l=(g[j>>2]=m,c[j>>2]|0);v=t?l:v;o=+g[e+24>>2];t=o<(c[j>>2]=w,+g[j>>2]);p=(g[j>>2]=o,c[j>>2]|0);w=t?p:w;k=(c[j>>2]=k,+g[j>>2])<y?i:k;i=(c[j>>2]=n,+g[j>>2])<m?l:n;r=(c[j>>2]=q,+g[j>>2])<o?p:q;y=+g[e+32>>2];s=y<(c[j>>2]=u,+g[j>>2]);p=(g[j>>2]=y,c[j>>2]|0);m=+g[e+36>>2];t=m<(c[j>>2]=v,+g[j>>2]);q=(g[j>>2]=m,c[j>>2]|0);o=+g[e+40>>2];n=o<(c[j>>2]=w,+g[j>>2]);l=(g[j>>2]=o,c[j>>2]|0);k=(c[j>>2]=k,+g[j>>2])<y?p:k;i=(c[j>>2]=i,+g[j>>2])<m?q:i;r=(c[j>>2]=r,+g[j>>2])<o?l:r;G=(c[j>>2]=k,+g[j>>2]);H=(c[j>>2]=s?p:u,+g[j>>2]);C=(c[j>>2]=i,+g[j>>2]);D=(c[j>>2]=t?q:v,+g[j>>2]);m=(c[j>>2]=r,+g[j>>2]);z=(c[j>>2]=n?l:w,+g[j>>2]);p=c[d+8>>2]|0;F=+g[p+4>>2];B=+g[p+8>>2];o=+g[p+12>>2];E=+g[p+36>>2];A=+g[p+40>>2];y=+g[p+44>>2];p=~~(((G-H<2.0000000949949026e-03?H+-1.0000000474974513e-03:H)-F)*E)&65535&-2;q=~~(((C-D<2.0000000949949026e-03?D+-1.0000000474974513e-03:D)-B)*A)&65535&-2;r=~~(((m-z<2.0000000949949026e-03?z+-1.0000000474974513e-03:z)-o)*y)&65535&-2;s=~~(((G-H<2.0000000949949026e-03?G+1.0000000474974513e-03:G)-F)*E+1.0)&65535|1;t=~~(((C-D<2.0000000949949026e-03?C+1.0000000474974513e-03:C)-B)*A+1.0)&65535|1;e=~~(((m-z<2.0000000949949026e-03?m+1.0000000474974513e-03:m)-o)*y+1.0)&65535|1;n=c[d+4>>2]|0;i=c[n+4>>2]|0;if((i|0)==(c[n+8>>2]|0)?(x=i|0?i<<1:1,(i|0)<(x|0)):0){if(!x)k=0;else{c[6432]=(c[6432]|0)+1;i=ec((x<<4|3)+16|0)|0;if(!i)k=0;else{c[(i+4+15&-16)+-4>>2]=i;k=i+4+15&-16}i=c[n+4>>2]|0}if((i|0)>0){l=0;do{d=k+(l<<4)|0;w=(c[n+12>>2]|0)+(l<<4)|0;c[d>>2]=c[w>>2];c[d+4>>2]=c[w+4>>2];c[d+8>>2]=c[w+8>>2];c[d+12>>2]=c[w+12>>2];l=l+1|0}while((l|0)!=(i|0))}i=c[n+12>>2]|0;if(i|0){if(a[n+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[n+12>>2]=0}a[n+16>>0]=1;c[n+12>>2]=k;c[n+8>>2]=x;i=c[n+4>>2]|0}x=c[n+12>>2]|0;b[x+(i<<4)>>1]=p;b[x+(i<<4)+2>>1]=q;b[x+(i<<4)+4>>1]=r;b[x+(i<<4)+6>>1]=s;b[x+(i<<4)+8>>1]=t;b[x+(i<<4)+10>>1]=e;c[x+(i<<4)+12>>2]=f<<21|h;c[n+4>>2]=(c[n+4>>2]|0)+1;return}function Yd(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;l=c[b>>2]|0;m=c[b+4>>2]|0;i=c[b+8>>2]|0;n=c[a+4>>2]|0;p=sh(a,d,m,i)|0;c[p+12>>2]=c[b+12>>2];c[p+16>>2]=n+1;c[p+20>>2]=n+2;h=c[(c[a+12>>2]|0)+(c[b+12>>2]<<2)>>2]|0;e=c[h>>2]|0;f=c[h+4>>2]|0;do if(!((e|0)==(m|0)&(f|0)==(i|0))){if((e|0)==(i|0)?(f|0)==(m|0):0){e=h+12+8|0;break}g=c[h+8>>2]|0;if(!((f|0)==(m|0)&(g|0)==(i|0)))if(!((f|0)==(i|0)&(g|0)==(m|0)))if((g|0)!=(m|0)|(e|0)==(i|0)^1){if((g|0)==(i|0)?(e|0)==(m|0):0){e=h+12+4|0;break}e=9584}else{e=1;o=2}else e=h+12|0;else{e=0;o=2}}else{e=2;o=2}while(0);if((o|0)==2)e=h+12+(e<<2)|0;c[e>>2]=n;k=sh(a,d,i,l)|0;c[k+12>>2]=c[b+12+4>>2];c[k+16>>2]=n+2;c[k+20>>2]=n;h=c[(c[a+12>>2]|0)+(c[b+12+4>>2]<<2)>>2]|0;e=c[h>>2]|0;f=c[h+4>>2]|0;do if(!((e|0)==(i|0)&(f|0)==(l|0))){if((e|0)==(l|0)?(f|0)==(i|0):0){e=h+12+8|0;break}g=c[h+8>>2]|0;if(!((f|0)==(i|0)&(g|0)==(l|0)))if(!((f|0)==(l|0)&(g|0)==(i|0)))if((g|0)!=(i|0)|(e|0)==(l|0)^1){if((g|0)==(l|0)?(e|0)==(i|0):0){e=h+12+4|0;break}e=9584}else{e=1;o=12}else e=h+12|0;else{e=0;o=12}}else{e=2;o=12}while(0);if((o|0)==12)e=h+12+(e<<2)|0;c[e>>2]=n+1;j=sh(a,d,l,m)|0;c[j+12>>2]=c[b+12+8>>2];c[j+16>>2]=n;c[j+20>>2]=n+1;e=c[a+12>>2]|0;i=c[e+(c[b+12+8>>2]<<2)>>2]|0;f=c[i>>2]|0;g=c[i+4>>2]|0;do if(!((f|0)==(l|0)&(g|0)==(m|0))){if((f|0)==(m|0)?(g|0)==(l|0):0){f=i+12+8|0;break}h=c[i+8>>2]|0;if(!((g|0)==(l|0)&(h|0)==(m|0)))if(!((g|0)==(m|0)&(h|0)==(l|0)))if((h|0)!=(l|0)|(f|0)==(m|0)^1){if((h|0)==(m|0)?(f|0)==(l|0):0){f=i+12+4|0;break}f=9584}else{f=1;o=22}else f=i+12|0;else{f=0;o=22}}else{f=2;o=22}while(0);if((o|0)==22)f=i+12+(f<<2)|0;c[f>>2]=n+2;f=c[e+(c[p+12>>2]<<2)>>2]|0;if(!(((c[f>>2]|0)!=(d|0)?(c[f+4>>2]|0)!=(d|0):0)?(c[f+8>>2]|0)!=(d|0):0)){$d(e,p,f);c[(c[a+12>>2]|0)+(c[p+24>>2]<<2)>>2]=0;c[6433]=(c[6433]|0)+1;Pc(c[p+-4>>2]|0);c[(c[a+12>>2]|0)+(c[f+24>>2]<<2)>>2]=0;if(f|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}e=c[a+12>>2]|0}f=c[e+(c[k+12>>2]<<2)>>2]|0;if(!(((c[f>>2]|0)!=(d|0)?(c[f+4>>2]|0)!=(d|0):0)?(c[f+8>>2]|0)!=(d|0):0)){$d(e,k,f);c[(c[a+12>>2]|0)+(c[k+24>>2]<<2)>>2]=0;c[6433]=(c[6433]|0)+1;Pc(c[k+-4>>2]|0);c[(c[a+12>>2]|0)+(c[f+24>>2]<<2)>>2]=0;if(f|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}e=c[a+12>>2]|0}f=c[e+(c[j+12>>2]<<2)>>2]|0;if(!(((c[f>>2]|0)!=(d|0)?(c[f+4>>2]|0)!=(d|0):0)?(c[f+8>>2]|0)!=(d|0):0)){$d(e,j,f);c[(c[a+12>>2]|0)+(c[j+24>>2]<<2)>>2]=0;c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0);c[(c[a+12>>2]|0)+(c[f+24>>2]<<2)>>2]=0;if(f|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}e=c[a+12>>2]|0}c[e+(c[b+24>>2]<<2)>>2]=0;if(!b)return;c[6433]=(c[6433]|0)+1;Pc(c[b+-4>>2]|0);return}function Zd(b,d){b=b|0;d=d|0;var e=0,f=0.0,h=0,i=0,j=0,k=0,m=0,n=0;n=l;l=l+336|0;d=c[d+36>>2]|0;c[n+272+4>>2]=35;c[n+272+8>>2]=0;c[n+272+12>>2]=1065353216;c[n+272+16>>2]=1065353216;c[n+272+20>>2]=1065353216;g[n+272+24>>2]=0.0;c[n+272>>2]=3564;c[n+272+52>>2]=d;g[n+272+44>>2]=0.0;k=c[b+28>>2]|0;e=c[k+4>>2]|0;if(c[(c[k+8>>2]|0)+204>>2]&3|0?a[d+376>>0]|0:0){l=n;return}if((a[22600]|0)==0?jy(22600)|0:0){if((a[22608]|0)==0?jy(22608)|0:0){c[5728]=1065353216;c[5729]=0;c[5730]=0;c[5731]=0;c[5732]=0;c[5733]=1065353216;c[5734]=0;c[5735]=0;c[5736]=0;c[5737]=0;c[5738]=1065353216;g[5739]=0.0}c[5712]=c[5728];c[5713]=c[5729];c[5714]=c[5730];c[5715]=c[5731];c[5716]=c[5732];c[5717]=c[5733];c[5718]=c[5734];c[5719]=c[5735];c[5720]=c[5736];c[5721]=c[5737];c[5722]=c[5738];c[5723]=c[5739];c[5724]=0;c[5725]=0;c[5726]=0;c[5727]=0}h=c[(c[b+28>>2]|0)+12>>2]|0;c[n>>2]=1065353216;c[n+4>>2]=0;c[n+8>>2]=0;g[n+12>>2]=0.0;if(!(!(qd(n+272|0,22848,e,h,n,n+216|0)|0)?!(vc(n+272|0,22848,e,h,n,n+216|0,0)|0):0))i=12;if((i|0)==12?(c[n+4>>2]=0,c[n+4+4>>2]=0,c[n+4+8>>2]=0,c[n+4+12>>2]=0,c[n+4+16>>2]=0,c[n+4+20>>2]=0,a[n+152>>0]=0,c[n>>2]=3384,k=c[(c[b+28>>2]|0)+8>>2]|0,id(b,n+216|0,d,0,0,0,(c[k+236>>2]&2|0)==0?0:k,k,n)|0):0){c[6432]=(c[6432]|0)+1;d=ec(235)|0;if(!d)k=0;else{c[(d+4+15&-16)+-4>>2]=d;k=d+4+15&-16}e=k+4|0;d=k+152|0;Hk(e|0,0,212)|0;c[k>>2]=3384;h=n+4|0;i=e+100|0;do{c[e>>2]=c[h>>2];e=e+4|0;h=h+4|0}while((e|0)<(i|0));e=k+104|0;c[e>>2]=c[n+104>>2];c[e+4>>2]=c[n+104+4>>2];c[e+8>>2]=c[n+104+8>>2];c[e+12>>2]=c[n+104+12>>2];e=k+120|0;c[e>>2]=c[n+120>>2];c[e+4>>2]=c[n+120+4>>2];c[e+8>>2]=c[n+120+8>>2];c[e+12>>2]=c[n+120+12>>2];e=k+136|0;c[e>>2]=c[n+136>>2];c[e+4>>2]=c[n+136+4>>2];c[e+8>>2]=c[n+136+8>>2];c[e+12>>2]=c[n+136+12>>2];a[d>>0]=a[n+152>>0]|0;e=k+156|0;h=n+156|0;i=e+60|0;do{c[e>>2]=c[h>>2];e=e+4|0;h=h+4|0}while((e|0)<(i|0));i=c[b+24>>2]|0;j=k;d=c[i+852>>2]|0;if((d|0)==(c[i+856>>2]|0)?(m=d|0?d<<1:1,(d|0)<(m|0)):0){if(!m)e=0;else{c[6432]=(c[6432]|0)+1;d=ec((m<<2|3)+16|0)|0;if(!d)e=0;else{c[(d+4+15&-16)+-4>>2]=d;e=d+4+15&-16}d=c[i+852>>2]|0}if((d|0)>0){h=0;do{c[e+(h<<2)>>2]=c[(c[i+860>>2]|0)+(h<<2)>>2];h=h+1|0}while((h|0)!=(d|0))}h=c[i+860>>2]|0;if(h){if(a[i+864>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0);d=c[i+852>>2]|0}c[i+860>>2]=0}a[i+864>>0]=1;c[i+860>>2]=e;c[i+856>>2]=m}c[(c[i+860>>2]|0)+(d<<2)>>2]=j;c[i+852>>2]=d+1;d=c[b+24>>2]|0;e=k+64|0;f=+g[e>>2];if(!(c[(c[(c[b+28>>2]|0)+8>>2]|0)+204>>2]&3)){g[e>>2]=f*+g[d+340>>2];d=d+352|0}else{g[e>>2]=f*+g[d+344>>2];d=d+356|0}b=k+68|0;g[b>>2]=+g[d>>2]*+g[b>>2]}l=n;return}function _d(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,h=0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0;h=l;l=l+16|0;f=gs()|0;if((a[22688]|0)==0?jy(22688)|0:0){c[h>>2]=0;c[h+4>>2]=0;c[h+8>>2]=0;c[h+12>>2]=0;_f(23256,0.0,0,0,h)}c[5865]=c[5865]|1;g[5900]=0.0;x=+g[5910]*0.0;D=+g[5911]*0.0;g[5905]=+g[5909]*0.0;g[5906]=x;g[5907]=D;g[5908]=0.0;c[5913]=0;c[5914]=0;c[5915]=0;c[5916]=0;D=+g[5902]*0.0;x=+g[5903]*0.0;g[5954]=+g[5901]*0.0;g[5955]=D;g[5956]=x;g[5957]=0.0;c[f+4>>2]=7;c[f+8>>2]=-1;c[f+12>>2]=-1;g[f+16>>2]=3402823466385288598117041.0e14;a[f+20>>0]=1;a[f+21>>0]=0;c[f+24>>2]=-1;c[f+28>>2]=23256;c[f+32>>2]=b;g[f+36>>2]=0.0;g[f+40>>2]=.30000001192092896;c[f+44>>2]=0;c[f>>2]=4724;a[f+48>>0]=0;c[f+116>>2]=c[d>>2];c[f+116+4>>2]=c[d+4>>2];c[f+116+8>>2]=c[d+8>>2];c[f+116+12>>2]=c[d+12>>2];c[f+132>>2]=c[d+16>>2];c[f+132+4>>2]=c[d+16+4>>2];c[f+132+8>>2]=c[d+16+8>>2];c[f+132+12>>2]=c[d+16+12>>2];c[f+148>>2]=c[d+32>>2];c[f+148+4>>2]=c[d+32+4>>2];c[f+148+8>>2]=c[d+32+8>>2];c[f+148+12>>2]=c[d+32+12>>2];c[f+164>>2]=c[d+48>>2];c[f+164+4>>2]=c[d+48+4>>2];c[f+164+8>>2]=c[d+48+8>>2];c[f+164+12>>2]=c[d+48+12>>2];a[f+180>>0]=e&1;x=+g[f+116>>2];D=+g[b+4>>2];w=+g[f+132>>2];C=+g[b+8>>2];v=+g[f+148>>2];B=+g[b+12>>2];u=+g[f+120>>2];t=+g[f+136>>2];s=+g[f+152>>2];r=+g[f+124>>2];p=+g[f+140>>2];n=+g[f+156>>2];A=+g[b+20>>2];z=+g[b+24>>2];y=+g[b+28>>2];q=+g[b+36>>2];o=+g[b+40>>2];m=+g[b+44>>2];F=+g[f+164>>2];E=+g[f+168>>2];i=+g[f+172>>2];k=+g[b+52>>2]+(D*F+C*E+B*i);j=A*F+z*E+y*i+ +g[b+56>>2];i=q*F+o*E+m*i+ +g[b+60>>2];g[f+52>>2]=x*D+w*C+v*B;g[f+56>>2]=D*u+C*t+B*s;g[f+60>>2]=D*r+C*p+B*n;g[f+64>>2]=0.0;g[f+68>>2]=x*A+w*z+v*y;g[f+72>>2]=u*A+t*z+s*y;g[f+76>>2]=r*A+p*z+n*y;g[f+80>>2]=0.0;g[f+84>>2]=x*q+w*o+v*m;g[f+88>>2]=u*q+t*o+s*m;g[f+92>>2]=r*q+p*o+n*m;g[f+96>>2]=0.0;g[f+100>>2]=k;g[f+104>>2]=j;g[f+108>>2]=i;g[f+112>>2]=0.0;g[f+184>>2]=1.0;g[f+188>>2]=-1.0;g[f+192>>2]=0.0;g[f+196>>2]=0.0;g[f+200>>2]=1.0;g[f+204>>2]=.699999988079071;g[f+208>>2]=0.0;g[f+212>>2]=0.0;g[f+216>>2]=1.0;g[f+220>>2]=.699999988079071;g[f+224>>2]=0.0;g[f+228>>2]=0.0;g[f+264>>2]=1.0;g[f+268>>2]=.699999988079071;g[f+272>>2]=1.0;g[f+276>>2]=0.0;g[f+280>>2]=1.0;g[f+284>>2]=.699999988079071;g[f+288>>2]=1.0;g[f+292>>2]=0.0;g[f+232>>2]=1.0;g[f+236>>2]=.699999988079071;g[f+240>>2]=1.0;g[f+244>>2]=0.0;g[f+248>>2]=1.0;g[f+252>>2]=.699999988079071;g[f+256>>2]=1.0;g[f+260>>2]=0.0;a[f+1096>>0]=0;g[f+1116>>2]=0.0;g[f+1120>>2]=0.0;g[f+1124>>2]=0.0;c[f+300>>2]=0;c[f+1100>>2]=0;c[f+1100+4>>2]=0;c[f+1100+8>>2]=0;a[f+1100+12>>0]=0;a[f+49>>0]=1;Qc(f,(c[f+28>>2]|0)+4|0,(c[f+32>>2]|0)+4|0);l=h;return f|0}function $d(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;m=0;do{k=m;m=m+1|0;l=(m|0)==3;j=c[b+((l?0:m)<<2)>>2]|0;k=c[b+(((k+2|0)%3|0)<<2)>>2]|0;e=c[d>>2]|0;f=c[d+4>>2]|0;if(!((e|0)==(k|0)&(f|0)==(j|0)))if(!((e|0)==(j|0)&(f|0)==(k|0))){g=c[d+8>>2]|0;if(!((f|0)==(k|0)&(g|0)==(j|0)))if(!((f|0)==(j|0)&(g|0)==(k|0)))if((g|0)!=(k|0)|(e|0)==(j|0)^1)e=(g|0)!=(j|0)|(e|0)==(k|0)^1?9584:d+12+4|0;else{e=1;n=3}else e=d+12|0;else{e=0;n=3}}else e=d+12+8|0;else{e=2;n=3}if((n|0)==3){n=0;e=d+12+(e<<2)|0}i=c[e>>2]|0;e=c[b>>2]|0;f=c[b+4>>2]|0;if(!((e|0)==(j|0)&(f|0)==(k|0)))if(!((e|0)==(k|0)&(f|0)==(j|0))){g=c[b+8>>2]|0;if(!((f|0)==(j|0)&(g|0)==(k|0)))if(!((f|0)==(k|0)&(g|0)==(j|0)))if((g|0)!=(j|0)|(e|0)==(k|0)^1)e=(g|0)!=(k|0)|(e|0)==(j|0)^1?9584:b+12+4|0;else{e=1;n=10}else e=b+12|0;else{e=0;n=10}}else e=b+12+8|0;else{e=2;n=10}if((n|0)==10){n=0;e=b+12+(e<<2)|0}h=c[a+(c[e>>2]<<2)>>2]|0;e=c[h>>2]|0;f=c[h+4>>2]|0;do if(!((e|0)==(k|0)&(f|0)==(j|0))){if((e|0)==(j|0)?(f|0)==(k|0):0){e=h+12+8|0;break}g=c[h+8>>2]|0;if(!((f|0)==(k|0)&(g|0)==(j|0)))if(!((f|0)==(j|0)&(g|0)==(k|0)))if((g|0)!=(k|0)|(e|0)==(j|0)^1){if((g|0)==(j|0)?(e|0)==(k|0):0){e=h+12+4|0;break}e=9584}else{e=1;n=17}else e=h+12|0;else{e=0;n=17}}else{e=2;n=17}while(0);if((n|0)==17){n=0;e=h+12+(e<<2)|0}c[e>>2]=i;e=c[b>>2]|0;f=c[b+4>>2]|0;if(!((e|0)==(j|0)&(f|0)==(k|0)))if(!((e|0)==(k|0)&(f|0)==(j|0))){g=c[b+8>>2]|0;if(!((f|0)==(j|0)&(g|0)==(k|0)))if(!((f|0)==(k|0)&(g|0)==(j|0)))if((g|0)!=(j|0)|(e|0)==(k|0)^1)e=(g|0)!=(k|0)|(e|0)==(j|0)^1?9584:b+12+4|0;else{e=1;n=27}else e=b+12|0;else{e=0;n=27}}else e=b+12+8|0;else{e=2;n=27}if((n|0)==27){n=0;e=b+12+(e<<2)|0}i=c[e>>2]|0;e=c[d>>2]|0;f=c[d+4>>2]|0;if(!((e|0)==(k|0)&(f|0)==(j|0)))if(!((e|0)==(j|0)&(f|0)==(k|0))){g=c[d+8>>2]|0;if(!((f|0)==(k|0)&(g|0)==(j|0)))if(!((f|0)==(j|0)&(g|0)==(k|0)))if((g|0)!=(k|0)|(e|0)==(j|0)^1)e=(g|0)!=(j|0)|(e|0)==(k|0)^1?9584:d+12+4|0;else{e=1;n=34}else e=d+12|0;else{e=0;n=34}}else e=d+12+8|0;else{e=2;n=34}if((n|0)==34){n=0;e=d+12+(e<<2)|0}h=c[a+(c[e>>2]<<2)>>2]|0;e=c[h>>2]|0;f=c[h+4>>2]|0;do if(!((e|0)==(j|0)&(f|0)==(k|0))){if((e|0)==(k|0)?(f|0)==(j|0):0){e=h+12+8|0;break}g=c[h+8>>2]|0;if(!((f|0)==(j|0)&(g|0)==(k|0)))if(!((f|0)==(k|0)&(g|0)==(j|0)))if((g|0)!=(j|0)|(e|0)==(k|0)^1){if((g|0)==(k|0)?(e|0)==(j|0):0){e=h+12+4|0;break}e=9584}else{e=1;n=41}else e=h+12|0;else{e=0;n=41}}else{e=2;n=41}while(0);if((n|0)==41){n=0;e=h+12+(e<<2)|0}c[e>>2]=i}while(!l);return}function ae(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;if(!((d|0)!=0&(e|0)!=0))return;if((c[b+24>>2]|0)<128?(c[b+28>>2]|0)<128:0){c[6432]=(c[6432]|0)+1;h=ec(1043)|0;if(!h)j=0;else{c[(h+4+15&-16)+-4>>2]=h;j=h+4+15&-16}h=c[b+24>>2]|0;if((h|0)>0){i=0;do{l=(c[b+32>>2]|0)+(i<<3)|0;m=c[l+4>>2]|0;n=j+(i<<3)|0;c[n>>2]=c[l>>2];c[n+4>>2]=m;i=i+1|0}while((i|0)!=(h|0))}h=c[b+32>>2]|0;if(h|0){if(a[b+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[b+32>>2]=0}a[b+36>>0]=1;c[b+32>>2]=j;c[b+28>>2]=128}c[b+24>>2]=128;n=c[b+32>>2]|0;c[n>>2]=d;c[n+4>>2]=e;n=1;j=124;while(1){h=n+-1|0;i=c[b+32>>2]|0;l=c[i+(h<<3)>>2]|0;m=c[i+(h<<3)+4>>2]|0;if((h|0)>(j|0)){e=c[b+24>>2]|0;if((e|0)<(e<<1|0)?(c[b+28>>2]|0)<(e<<1|0):0){if(e){c[6432]=(c[6432]|0)+1;i=ec((e<<4|3)+16|0)|0;if(!i)i=0;else{c[(i+4+15&-16)+-4>>2]=i;i=i+4+15&-16}j=c[b+24>>2]|0;if((j|0)>0){d=0;do{p=(c[b+32>>2]|0)+(d<<3)|0;o=c[p+4>>2]|0;k=i+(d<<3)|0;c[k>>2]=c[p>>2];c[k+4>>2]=o;d=d+1|0}while((d|0)!=(j|0))}}else i=0;j=c[b+32>>2]|0;if(j|0){if(a[b+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0)}c[b+32>>2]=0}a[b+36>>0]=1;c[b+32>>2]=i;c[b+28>>2]=e<<1}c[b+24>>2]=e<<1;j=(e<<1)+-4|0}do if((l|0)==(m|0)){if(c[l+40>>2]|0){p=c[l+36>>2]|0;c[i+(h<<3)>>2]=p;c[i+(h<<3)+4>>2]=p;h=n+1|0;p=c[b+32>>2]|0;o=c[l+40>>2]|0;c[p+(n<<3)>>2]=o;c[p+(n<<3)+4>>2]=o;p=c[b+32>>2]|0;o=c[l+40>>2]|0;c[p+(h<<3)>>2]=c[l+36>>2];c[p+(h<<3)+4>>2]=o;h=n+2|0}}else if(((((+g[l>>2]<=+g[m+16>>2]?+g[l+16>>2]>=+g[m>>2]:0)?+g[l+4>>2]<=+g[m+20>>2]:0)?+g[l+20>>2]>=+g[m+4>>2]:0)?+g[l+8>>2]<=+g[m+24>>2]:0)?+g[l+24>>2]>=+g[m+8>>2]:0){d=(c[m+40>>2]|0)!=0;if(!(c[l+40>>2]|0))if(d){p=c[m+36>>2]|0;c[i+(h<<3)>>2]=l;c[i+(h<<3)+4>>2]=p;h=c[b+32>>2]|0;p=c[m+40>>2]|0;c[h+(n<<3)>>2]=l;c[h+(n<<3)+4>>2]=p;h=n+1|0;break}else{Rb[c[(c[f>>2]|0)+8>>2]&127](f,l,m);break}else{e=i+(h<<3)|0;k=c[l+36>>2]|0;if(d){p=c[m+36>>2]|0;c[e>>2]=k;c[i+(h<<3)+4>>2]=p;p=n+1|0;h=c[b+32>>2]|0;o=c[m+36>>2]|0;c[h+(n<<3)>>2]=c[l+40>>2];c[h+(n<<3)+4>>2]=o;h=n+2|0;o=c[b+32>>2]|0;k=c[m+40>>2]|0;c[o+(p<<3)>>2]=c[l+36>>2];c[o+(p<<3)+4>>2]=k;p=c[b+32>>2]|0;o=c[m+40>>2]|0;c[p+(h<<3)>>2]=c[l+40>>2];c[p+(h<<3)+4>>2]=o;h=n+3|0;break}else{c[e>>2]=k;c[i+(h<<3)+4>>2]=m;h=c[b+32>>2]|0;c[h+(n<<3)>>2]=c[l+40>>2];c[h+(n<<3)+4>>2]=m;h=n+1|0;break}}}while(0);if(!h)break;else n=h}return}function be(b,d){b=b|0;d=d|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;o=c[b+92>>2]|0;if(!(lb[c[(c[o>>2]|0)+56>>2]&127](o)|0))return;o=c[b+92>>2]|0;o=lb[c[(c[o>>2]|0)+28>>2]&127](o)|0;f=c[o+4>>2]|0;if((f|0)>1){Ee(o,0,f+-1|0);j=c[o+4>>2]|0}else j=f;m=c[b+104>>2]|0;f=j-m|0;if((m|0)<0){if((c[o+8>>2]|0)<(f|0)){if(!f){g=0;h=j}else{c[6432]=(c[6432]|0)+1;g=ec((f<<4|3)+16|0)|0;if(!g)g=0;else{c[(g+4+15&-16)+-4>>2]=g;g=g+4+15&-16}h=c[o+4>>2]|0}if((h|0)>0){i=0;do{m=c[o+12>>2]|0;c[g+(i<<4)>>2]=c[m+(i<<4)>>2];c[g+(i<<4)+4>>2]=c[m+(i<<4)+4>>2];c[g+(i<<4)+8>>2]=c[m+(i<<4)+8>>2];c[g+(i<<4)+12>>2]=c[m+(i<<4)+12>>2];i=i+1|0}while((i|0)!=(h|0))}h=c[o+12>>2]|0;if(h|0){if(a[o+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[o+12>>2]=0}a[o+16>>0]=1;c[o+12>>2]=g;c[o+8>>2]=f;h=o+12|0}else h=o+12|0;g=j;do{m=(c[h>>2]|0)+(g<<4)|0;g=g+1|0;c[m>>2]=0;c[m+4>>2]=0;c[m+8>>2]=0;c[m+12>>2]=0}while((g|0)!=(f|0))}c[o+4>>2]=f;c[b+104>>2]=0;if((f|0)>0){g=0;l=0;i=0;m=0;while(1){k=c[o+12>>2]|0;j=k+(m<<4)|0;p=l;l=c[j>>2]|0;k=k+(m<<4)+4|0;h=c[k>>2]|0;if(!((l|0)==(p|0)&(h|0)==(i|0))){p=l+54|0;i=l+48|0;if(!((((((e[p>>1]|0)>=(e[h+48>>1]|0)?(e[h+54>>1]|0)>=(e[i>>1]|0):0)?(e[p+2>>1]|0)>=(e[h+48+2>>1]|0):0)?(e[h+54+2>>1]|0)>=(e[i+2>>1]|0):0)?(e[p+4>>1]|0)>=(e[h+52>>1]|0):0)?(e[h+54+4>>1]|0)>=(e[l+52>>1]|0):0))n=29}else{h=i;n=29}if((n|0)==29){n=0;g=c[b+92>>2]|0;Rb[c[(c[g>>2]|0)+32>>2]&127](g,j,d);c[j>>2]=0;c[k>>2]=0;g=(c[b+104>>2]|0)+1|0;c[b+104>>2]=g;c[6160]=(c[6160]|0)+-1;f=c[o+4>>2]|0}m=m+1|0;if((m|0)>=(f|0))break;else i=h}if((f|0)>1){Ee(o,0,f+-1|0);g=c[b+104>>2]|0;j=c[o+4>>2]|0}else j=f;f=j-g|0;if((g|0)<0){if((c[o+8>>2]|0)<(f|0)){if(!f){g=0;h=j}else{c[6432]=(c[6432]|0)+1;g=ec((f<<4|3)+16|0)|0;if(!g)g=0;else{c[(g+4+15&-16)+-4>>2]=g;g=g+4+15&-16}h=c[o+4>>2]|0}if((h|0)>0){i=0;do{p=c[o+12>>2]|0;c[g+(i<<4)>>2]=c[p+(i<<4)>>2];c[g+(i<<4)+4>>2]=c[p+(i<<4)+4>>2];c[g+(i<<4)+8>>2]=c[p+(i<<4)+8>>2];c[g+(i<<4)+12>>2]=c[p+(i<<4)+12>>2];i=i+1|0}while((i|0)!=(h|0))}h=c[o+12>>2]|0;if(h|0){if(a[o+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[o+12>>2]=0}a[o+16>>0]=1;c[o+12>>2]=g;c[o+8>>2]=f;h=o+12|0}else h=o+12|0;g=j;do{p=(c[h>>2]|0)+(g<<4)|0;g=g+1|0;c[p>>2]=0;c[p+4>>2]=0;c[p+8>>2]=0;c[p+12>>2]=0}while((g|0)!=(f|0))}}c[o+4>>2]=f;c[b+104>>2]=0;return}function ce(b){b=b|0;var d=0,e=0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0,v=0.0,w=0.0,x=0;u=l;l=l+176|0;if(!(a[b+527>>0]|0)){l=u;return}g[b+36>>2]=0.0;g[b+520>>2]=0.0;g[b+516>>2]=0.0;c[b+576>>2]=0;c[b+576+4>>2]=0;c[b+576+8>>2]=0;c[b+576+12>>2]=0;if(!(a[b+524>>0]|0)){d=c[b+28>>2]|0;j=+g[b+348>>2];k=+g[b+352>>2];q=+g[b+356>>2];s=j*+g[d+20>>2]+k*+g[d+24>>2]+q*+g[d+28>>2]+ +g[d+56>>2];e=c[b+32>>2]|0;m=+g[b+412>>2];n=+g[b+416>>2];p=+g[b+420>>2];t=m*+g[e+20>>2]+n*+g[e+24>>2]+p*+g[e+28>>2]+ +g[e+56>>2];r=m*+g[e+36>>2]+n*+g[e+40>>2]+p*+g[e+44>>2]+ +g[e+60>>2];o=j*+g[d+4>>2]+k*+g[d+8>>2]+q*+g[d+12>>2]+ +g[d+52>>2];q=j*+g[d+36>>2]+k*+g[d+40>>2]+q*+g[d+44>>2]+ +g[d+60>>2];p=m*+g[e+4>>2]+n*+g[e+8>>2]+p*+g[e+12>>2]+ +g[e+52>>2];if((p-o)*(p-o)+(t-s)*(t-s)+(r-q)*(r-q)>1.1920928955078125e-07){j=1.0/+C(+((p-o)*(p-o)+(t-s)*(t-s)+(r-q)*(r-q)));g[u+128>>2]=(p-o)*j;g[u+128+4>>2]=(t-s)*j;g[u+128+8>>2]=(r-q)*j;c[u+128+12>>2]=0;h=(r-q)*j;f=(t-s)*j;j=(p-o)*j}else{c[u+128>>2]=1065353216;c[u+128+4>>2]=0;c[u+128+8>>2]=0;g[u+128+12>>2]=0.0;h=0.0;f=0.0;j=1.0}if(+B(+h)>.7071067690849304){w=h*h+f*f;n=1.0/+C(+w);v=-(n*h);h=n*f;i=h;k=0.0;m=v;n=w*n;h=-(h*j);f=j*v}else{v=j*j+f*f;w=1.0/+C(+v);f=-(f*w);n=w*j;i=0.0;k=f;m=n;n=-(n*h);h=h*f;f=v*w}g[u+128+16>>2]=k;g[u+128+20>>2]=m;g[u+128+24>>2]=i;g[u+128+32>>2]=n;g[u+128+36>>2]=h;g[u+128+40>>2]=f;d=0;while(1){x=c[b+28>>2]|0;c[u+80>>2]=c[x+4>>2];c[u+80+4>>2]=c[x+20>>2];c[u+80+8>>2]=c[x+36>>2];g[u+80+12>>2]=0.0;c[u+80+16>>2]=c[x+8>>2];c[u+80+20>>2]=c[x+24>>2];c[u+80+24>>2]=c[x+40>>2];g[u+80+28>>2]=0.0;c[u+80+32>>2]=c[x+12>>2];c[u+80+36>>2]=c[x+28>>2];c[u+80+40>>2]=c[x+44>>2];g[u+80+44>>2]=0.0;c[u+32>>2]=c[e+4>>2];c[u+32+4>>2]=c[e+20>>2];c[u+32+8>>2]=c[e+36>>2];g[u+32+12>>2]=0.0;c[u+32+16>>2]=c[e+8>>2];c[u+32+20>>2]=c[e+24>>2];c[u+32+24>>2]=c[e+40>>2];g[u+32+28>>2]=0.0;c[u+32+32>>2]=c[e+12>>2];c[u+32+36>>2]=c[e+28>>2];c[u+32+40>>2]=c[e+44>>2];g[u+32+44>>2]=0.0;w=s-+g[x+56>>2];v=q-+g[x+60>>2];g[u+16>>2]=o-+g[x+52>>2];g[u+16+4>>2]=w;g[u+16+8>>2]=v;g[u+16+12>>2]=0.0;v=t-+g[e+56>>2];w=r-+g[e+60>>2];g[u>>2]=p-+g[e+52>>2];g[u+4>>2]=v;g[u+8>>2]=w;g[u+12>>2]=0.0;x=c[b+28>>2]|0;e=c[b+32>>2]|0;ug(b+48+(d*84|0)|0,u+80|0,u+32|0,u+16|0,u,u+128+(d<<4)|0,x+396|0,+g[x+344>>2],e+396|0,+g[e+344>>2]);d=d+1|0;if((d|0)==3)break;e=c[b+32>>2]|0}d=b+32|0}else d=b+32|0;e=c[b+28>>2]|0;x=c[d>>2]|0;kc(b,e+4|0,x+4|0,e+264|0,x+264|0);l=u;return}function de(b,d,e,f,h,i){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;var j=0,k=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0;t=l;l=l+64|0;if((h|0)>0){j=0;b=0;do{s=c[f+(j<<2)>>2]|0;b=(s|0)>(b|0)?s:b;j=j+1|0}while((j|0)<(h*3|0))}else b=0;p=b+1|0;k=O(p,p)|0;if(!k)j=0;else{c[6432]=(c[6432]|0)+1;j=ec(k+19|0)|0;if(!j)j=0;else{c[(j+4+15&-16)+-4>>2]=j;j=j+4+15&-16}Hk(j|0,0,k|0)|0}if((b|0)>-1){c[6432]=(c[6432]|0)+1;b=ec((p<<4|3)+16|0)|0;if(!b)m=0;else{c[(b+4+15&-16)+-4>>2]=b;m=b+4+15&-16}b=0;do{s=m+(b<<4)|0;c[s>>2]=c[t>>2];c[s+4>>2]=c[t+4>>2];c[s+8>>2]=c[t+8>>2];c[s+12>>2]=c[t+12>>2];b=b+1|0}while((b|0)!=(p|0));b=0;k=0;while(1){r=c[e+(b+1<<2)>>2]|0;s=c[e+(b+2<<2)>>2]|0;c[m+(k<<4)>>2]=c[e+(b<<2)>>2];c[m+(k<<4)+4>>2]=r;c[m+(k<<4)+8>>2]=s;g[m+(k<<4)+12>>2]=0.0;b=b+3|0;if((b|0)>=(p*3|0)){s=m;r=m;break}else k=k+1|0}}else{s=0;r=0}c[6432]=(c[6432]|0)+1;b=ec(1271)|0;if(!b)q=0;else{c[(b+4+15&-16)+-4>>2]=b;q=b+4+15&-16}oc(q,d,p,r,0);if((h|0)>0){o=0;do{e=c[f+(o<<2)>>2]|0;d=c[f+(o+1<<2)>>2]|0;n=c[f+(o+2<<2)>>2]|0;m=O(e,p)|0;b=j+(m+n)|0;if(!(a[b>>0]|0)){a[b>>0]=1;a[j+((O(n,p)|0)+e)>>0]=1;Df(q,n,e,0,0)}k=O(d,p)|0;b=j+(k+e)|0;if(!(a[b>>0]|0)){a[b>>0]=1;a[j+(m+d)>>0]=1;Df(q,e,d,0,0)}b=j+((O(n,p)|0)+d)|0;if(!(a[b>>0]|0)){a[b>>0]=1;a[j+(k+n)>>0]=1;Df(q,d,n,0,0)}Mf(q,e,d,n,0);o=o+3|0}while((o|0)<(h*3|0))}if(i){k=c[q+732>>2]|0;if((k|0)>0){n=q+740|0;d=0;b=243703;do{m=c[n>>2]|0;e=m+(d*52|0)|0;b=(O(b,1664525)|0)+1013904223|0;o=t;p=e;f=o+52|0;do{c[o>>2]=c[p>>2];o=o+4|0;p=p+4|0}while((o|0)<(f|0));o=e;p=m+(((b>>>0)%(k>>>0)|0)*52|0)|0;f=o+52|0;do{c[o>>2]=c[p>>2];o=o+4|0;p=p+4|0}while((o|0)<(f|0));o=m+(((b>>>0)%(k>>>0)|0)*52|0)|0;p=t;f=o+52|0;do{c[o>>2]=c[p>>2];o=o+4|0;p=p+4|0}while((o|0)<(f|0));d=d+1|0}while((d|0)!=(k|0))}else b=243703;e=c[q+752>>2]|0;if((e|0)>0){n=q+760|0;d=0;do{k=c[n>>2]|0;m=k+(d*44|0)|0;b=(O(b,1664525)|0)+1013904223|0;k=k+(((b>>>0)%(e>>>0)|0)*44|0)|0;o=t;p=m;f=o+44|0;do{c[o>>2]=c[p>>2];o=o+4|0;p=p+4|0}while((o|0)<(f|0));o=m;p=k;f=o+44|0;do{c[o>>2]=c[p>>2];o=o+4|0;p=p+4|0}while((o|0)<(f|0));o=k;p=t;f=o+44|0;do{c[o>>2]=c[p>>2];o=o+4|0;p=p+4|0}while((o|0)<(f|0));d=d+1|0}while((d|0)!=(e|0))}}if(!((r|0)==0|(s|0)==0)){c[6433]=(c[6433]|0)+1;Pc(c[s+-4>>2]|0)}if(!j){l=t;return q|0}c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0);l=t;return q|0}function ee(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;g=l;l=l+80|0;c[a+68>>2]=(c[a+68>>2]|0)+1;d=c[a+64>>2]|0;if(d|0){e=c[(c[a+24>>2]|0)+(b*80|0)+76>>2]|0;Kg(d,e)|0;f=c[d+4>>2]|0;if(f|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[d+4>>2]=e;c[d+12>>2]=(c[d+12>>2]|0)+-1}f=(c[a+16>>2]|0)+-1|0;e=c[a+24>>2]|0;c[g>>2]=c[e+(b*80|0)>>2];c[g+4>>2]=c[e+(b*80|0)+4>>2];c[g+8>>2]=c[e+(b*80|0)+8>>2];c[g+12>>2]=c[e+(b*80|0)+12>>2];c[g+16>>2]=c[e+(b*80|0)+16>>2];c[g+16+4>>2]=c[e+(b*80|0)+16+4>>2];c[g+16+8>>2]=c[e+(b*80|0)+16+8>>2];c[g+16+12>>2]=c[e+(b*80|0)+16+12>>2];c[g+32>>2]=c[e+(b*80|0)+32>>2];c[g+32+4>>2]=c[e+(b*80|0)+32+4>>2];c[g+32+8>>2]=c[e+(b*80|0)+32+8>>2];c[g+32+12>>2]=c[e+(b*80|0)+32+12>>2];c[g+48>>2]=c[e+(b*80|0)+48>>2];c[g+48+4>>2]=c[e+(b*80|0)+48+4>>2];c[g+48+8>>2]=c[e+(b*80|0)+48+8>>2];c[g+48+12>>2]=c[e+(b*80|0)+48+12>>2];c[g+64>>2]=c[e+(b*80|0)+64>>2];c[g+64+4>>2]=c[e+(b*80|0)+64+4>>2];c[g+64+8>>2]=c[e+(b*80|0)+64+8>>2];c[g+64+12>>2]=c[e+(b*80|0)+64+12>>2];c[e+(b*80|0)>>2]=c[e+(f*80|0)>>2];c[e+(b*80|0)+4>>2]=c[e+(f*80|0)+4>>2];c[e+(b*80|0)+8>>2]=c[e+(f*80|0)+8>>2];c[e+(b*80|0)+12>>2]=c[e+(f*80|0)+12>>2];c[e+(b*80|0)+16>>2]=c[e+(f*80|0)+16>>2];c[e+(b*80|0)+16+4>>2]=c[e+(f*80|0)+16+4>>2];c[e+(b*80|0)+16+8>>2]=c[e+(f*80|0)+16+8>>2];c[e+(b*80|0)+16+12>>2]=c[e+(f*80|0)+16+12>>2];c[e+(b*80|0)+32>>2]=c[e+(f*80|0)+32>>2];c[e+(b*80|0)+32+4>>2]=c[e+(f*80|0)+32+4>>2];c[e+(b*80|0)+32+8>>2]=c[e+(f*80|0)+32+8>>2];c[e+(b*80|0)+32+12>>2]=c[e+(f*80|0)+32+12>>2];c[e+(b*80|0)+48>>2]=c[e+(f*80|0)+48>>2];c[e+(b*80|0)+48+4>>2]=c[e+(f*80|0)+48+4>>2];c[e+(b*80|0)+48+8>>2]=c[e+(f*80|0)+48+8>>2];c[e+(b*80|0)+48+12>>2]=c[e+(f*80|0)+48+12>>2];c[e+(b*80|0)+64>>2]=c[e+(f*80|0)+64>>2];c[e+(b*80|0)+64+4>>2]=c[e+(f*80|0)+64+4>>2];c[e+(b*80|0)+64+8>>2]=c[e+(f*80|0)+64+8>>2];c[e+(b*80|0)+64+12>>2]=c[e+(f*80|0)+64+12>>2];e=c[a+24>>2]|0;c[e+(f*80|0)>>2]=c[g>>2];c[e+(f*80|0)+4>>2]=c[g+4>>2];c[e+(f*80|0)+8>>2]=c[g+8>>2];c[e+(f*80|0)+12>>2]=c[g+12>>2];c[e+(f*80|0)+16>>2]=c[g+16>>2];c[e+(f*80|0)+16+4>>2]=c[g+16+4>>2];c[e+(f*80|0)+16+8>>2]=c[g+16+8>>2];c[e+(f*80|0)+16+12>>2]=c[g+16+12>>2];c[e+(f*80|0)+32>>2]=c[g+32>>2];c[e+(f*80|0)+32+4>>2]=c[g+32+4>>2];c[e+(f*80|0)+32+8>>2]=c[g+32+8>>2];c[e+(f*80|0)+32+12>>2]=c[g+32+12>>2];c[e+(f*80|0)+48>>2]=c[g+48>>2];c[e+(f*80|0)+48+4>>2]=c[g+48+4>>2];c[e+(f*80|0)+48+8>>2]=c[g+48+8>>2];c[e+(f*80|0)+48+12>>2]=c[g+48+12>>2];c[e+(f*80|0)+64>>2]=c[g+64>>2];c[e+(f*80|0)+64+4>>2]=c[g+64+4>>2];c[e+(f*80|0)+64+8>>2]=c[g+64+8>>2];c[e+(f*80|0)+64+12>>2]=c[g+64+12>>2];if(!(c[a+64>>2]|0)){b=c[a+16>>2]|0;b=b+-1|0;c[a+16>>2]=b;l=g;return}c[(c[(c[a+24>>2]|0)+(b*80|0)+76>>2]|0)+36>>2]=b;b=c[a+16>>2]|0;b=b+-1|0;c[a+16>>2]=b;l=g;return}function fe(a,d,f,h,i,j,k,m,n){a=a|0;d=d|0;f=f|0;h=+h;i=+i;j=+j;k=k|0;m=m|0;n=n|0;var o=0,p=0,q=0.0,r=0.0,s=0.0,t=0.0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0.0,D=0.0,E=0,F=0,G=0.0,H=0,I=0,J=0,K=0,L=0.0,M=0.0,N=0.0,O=0.0,P=0,Q=0.0,R=0.0,S=0.0,T=0,U=0.0,V=0,W=0,X=0.0,Y=0.0,Z=0.0,_=0.0,$=0.0,aa=0.0,ba=0.0,ca=0.0,da=0.0,ea=0.0,fa=0.0;W=l;l=l+32|0;B=+g[f>>2];D=+g[f+4>>2];G=+g[f+8>>2];Q=1.0/+C(+((h-B)*(h-B)+(i-D)*(i-D)+(j-G)*(j-G)));M=(h-B)*Q==0.0?999999984306749440.0:1.0/((h-B)*Q);N=(i-D)*Q==0.0?999999984306749440.0:1.0/((i-D)*Q);O=(j-G)*Q==0.0?999999984306749440.0:1.0/((j-G)*Q);fa=(B>h?h:B)+ +g[k>>2];ea=(D>i?i:D)+ +g[k+4>>2];da=(G>j?j:G)+ +g[k+8>>2];ba=(B<h?h:B)+ +g[m>>2];Z=(D<i?i:D)+ +g[m+4>>2];r=(G<j?j:G)+ +g[m+8>>2];aa=+g[a+4>>2];fa=fa<aa?aa:fa;Y=+g[a+8>>2];ea=ea<Y?Y:ea;s=+g[a+12>>2];da=da<s?s:da;ca=+g[a+20>>2];_=+g[a+24>>2];q=+g[a+28>>2];$=+g[a+36>>2];X=+g[a+40>>2];t=+g[a+44>>2];E=~~(((ca<fa?ca:fa)-aa)*$)&65535&-2;F=~~(((_<ea?_:ea)-Y)*X)&65535&-2;H=~~(((q<da?q:da)-s)*t)&65535&-2;ba=ba<aa?aa:ba;Z=Z<Y?Y:Z;r=r<s?s:r;I=~~(((ca<ba?ca:ba)-aa)*$+1.0)&65535|1;J=~~(((_<Z?_:Z)-Y)*X+1.0)&65535|1;K=~~(((q<r?q:r)-s)*t+1.0)&65535|1;if((n|0)>0){P=0;T=c[a+136>>2]|0;o=0;while(1){o=o+1|0;w=T+6|0;p=b[T>>1]|0;x=T+10|0;u=b[T+4>>1]|0;y=T+8|0;v=b[T+2>>1]|0;A=T+12|0;z=(c[A>>2]|0)>-1;do if(((I&65535)>=(p&65535)?(E&65535)<=(e[w>>1]|0):0)&(H&65535)<=(e[x>>1]|0)&(K&65535)>=(u&65535)&(F&65535)<=(e[y>>1]|0)&(J&65535)>=(v&65535)){ba=+g[a+36>>2];da=+g[a+40>>2];fa=+g[a+44>>2];ca=+g[a+4>>2];ea=+g[a+8>>2];s=+g[a+12>>2];g[W+12>>2]=0.0;t=+(e[w>>1]|0)/ba+ca;q=+(e[y>>1]|0)/da+ea;r=+(e[x>>1]|0)/fa+s;g[W+28>>2]=0.0;g[W>>2]=+(p&65535)/ba+ca-+g[m>>2];g[W+4>>2]=+(v&65535)/da+ea-+g[m+4>>2];g[W+8>>2]=+(u&65535)/fa+s-+g[m+8>>2];g[W+16>>2]=t-+g[k>>2];g[W+20>>2]=q-+g[k+4>>2];g[W+24>>2]=r-+g[k+8>>2];r=+g[f>>2];q=M*(+g[W+((M<0.0&1)<<4)>>2]-r);r=M*(+g[W+((M<0.0^1)<<4)>>2]-r);t=+g[f+4>>2];s=N*(+g[W+((N<0.0&1)<<4)+4>>2]-t);t=N*(+g[W+((N<0.0^1)<<4)+4>>2]-t);if(!(s>r|q>t)?(L=s>q?s:q,U=t<r?t:r,S=+g[f+8>>2],R=O*(+g[W+((O<0.0&1)<<4)+8>>2]-S),S=O*(+g[W+((O<0.0^1)<<4)+8>>2]-S),!(R>U|L>S)):0){p=(S<U?S:U)>0.0?(R>L?R:L)<(j-G)*(j-G)*Q+((h-B)*(h-B)*Q+(i-D)*(i-D)*Q):0;if(!(z&p)){V=9;break}p=c[A>>2]|0;Rb[c[(c[d>>2]|0)+8>>2]&127](d,p>>21,p&2097151);p=1;break}p=0;V=9}else{p=0;V=9}while(0);if((V|0)==9){V=0;if(z|p)p=1;else p=0-(c[A>>2]|0)|0}P=p+P|0;if((P|0)>=(n|0))break;else T=T+(p<<4)|0}}else o=0;if((c[6164]|0)>=(o|0)){l=W;return}c[6164]=o;l=W;return}function ge(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,D=0.0,G=0.0,H=0.0,I=0.0,J=0.0;xg(a,b+(c*284|0)|0,d);m=+g[b+(c*284|0)+52>>2];h=+g[b+(c*284|0)+56>>2];q=+g[b+(c*284|0)+60>>2];J=+g[b+(c*284|0)+76>>2];x=+g[b+(c*284|0)+72>>2];z=+g[b+(c*284|0)+68>>2];w=1.0/+C(+((x*-m-z*-h)*(x*-m-z*-h)+((J*-h-x*-q)*(J*-h-x*-q)+(z*-q-J*-m)*(z*-q-J*-m))));v=(J*-h-x*-q)*w;u=w*(z*-q-J*-m);w=w*(x*-m-z*-h);e=+g[b+(c*284|0)+232>>2]*.5;k=+F(+e)/+C(+(m*m+h*h+q*q));e=+E(+e);l=2.0/(e*e+(k*-q*k*-q+(k*-m*k*-m+k*-h*k*-h)));H=1.0-(k*-h*k*-h*l+k*-q*k*-q*l);G=k*-m*k*-h*l-e*k*-q*l;I=k*-m*k*-q*l+e*k*-h*l;B=k*-m*k*-h*l+e*k*-q*l;A=1.0-(k*-m*k*-m*l+k*-q*k*-q*l);D=k*-h*k*-q*l-e*k*-m*l;j=k*-m*k*-q*l-e*k*-h*l;e=k*-h*k*-q*l+e*k*-m*l;l=1.0-(k*-m*k*-m*l+k*-h*k*-h*l);k=+g[b+(c*284|0)+236>>2]*-.5;y=+F(+k)/+C(+(J*J+(x*x+z*z)));k=+E(+k);r=2.0/(k*k+(J*y*J*y+(z*y*z*y+x*y*x*y)));n=1.0-(x*y*x*y*r+J*y*J*y*r);i=z*y*x*y*r-k*J*y*r;t=z*y*J*y*r+k*x*y*r;o=z*y*x*y*r+k*J*y*r;f=1.0-(z*y*z*y*r+J*y*J*y*r);s=x*y*J*y*r-k*z*y*r;p=z*y*J*y*r-k*x*y*r;k=x*y*J*y*r+k*z*y*r;r=1.0-(z*y*z*y*r+x*y*x*y*r);y=+g[b+(c*284|0)+68>>2];x=+g[b+(c*284|0)+72>>2];z=+g[b+(c*284|0)+76>>2];g[b+(c*284|0)+92>>2]=z*(H*t+G*s+I*r)+(y*(I*p+(G*o+H*n))+x*(I*k+(H*i+G*f)));g[b+(c*284|0)+96>>2]=w*(H*t+G*s+I*r)+(v*(I*p+(G*o+H*n))+u*(I*k+(H*i+G*f)));g[b+(c*284|0)+100>>2]=(H*t+G*s+I*r)*-q+((I*p+(G*o+H*n))*-m+(I*k+(H*i+G*f))*-h);g[b+(c*284|0)+104>>2]=0.0;g[b+(c*284|0)+108>>2]=z*(B*t+A*s+D*r)+(y*(D*p+(A*o+B*n))+x*(D*k+(B*i+A*f)));g[b+(c*284|0)+112>>2]=w*(B*t+A*s+D*r)+(v*(D*p+(A*o+B*n))+u*(D*k+(B*i+A*f)));g[b+(c*284|0)+116>>2]=(B*t+A*s+D*r)*-q+((D*p+(A*o+B*n))*-m+(D*k+(B*i+A*f))*-h);g[b+(c*284|0)+120>>2]=0.0;g[b+(c*284|0)+124>>2]=z*(j*t+e*s+l*r)+(y*(l*p+(e*o+j*n))+x*(l*k+(j*i+e*f)));g[b+(c*284|0)+128>>2]=w*(j*t+e*s+l*r)+(v*(l*p+(e*o+j*n))+u*(l*k+(j*i+e*f)));g[b+(c*284|0)+132>>2]=(j*t+e*s+l*r)*-q+((l*p+(e*o+j*n))*-m+(l*k+(j*i+e*f))*-h);g[b+(c*284|0)+136>>2]=0.0;h=+g[b+(c*284|0)+32>>2];f=h*+g[b+(c*284|0)+56>>2]+ +g[b+(c*284|0)+40>>2];e=h*+g[b+(c*284|0)+60>>2]+ +g[b+(c*284|0)+44>>2];g[b+(c*284|0)+140>>2]=+g[b+(c*284|0)+52>>2]*h+ +g[b+(c*284|0)+36>>2];g[b+(c*284|0)+144>>2]=f;g[b+(c*284|0)+148>>2]=e;g[b+(c*284|0)+152>>2]=0.0;return}function he(b,d,e,f,h,i,j,k,m){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=+i;j=j|0;k=k|0;m=m|0;var n=0,o=0,p=0,q=0,r=0.0,s=0.0,t=0.0,u=0.0,v=0,w=0,x=0.0,y=0.0,z=0.0,A=0.0,B=0,C=0.0;B=l;l=l+32|0;if(!d){l=B;return}q=c[b+44>>2]|0;if((q|0)<128){if((c[b+48>>2]|0)<128){c[6432]=(c[6432]|0)+1;n=ec(531)|0;if(!n)p=0;else{c[(n+4+15&-16)+-4>>2]=n;p=n+4+15&-16}n=c[b+44>>2]|0;if((n|0)>0){o=0;do{c[p+(o<<2)>>2]=c[(c[b+52>>2]|0)+(o<<2)>>2];o=o+1|0}while((o|0)!=(n|0))}n=c[b+52>>2]|0;if(n|0){if(a[b+56>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[n+-4>>2]|0)}c[b+52>>2]=0}a[b+56>>0]=1;c[b+52>>2]=p;c[b+48>>2]=128;o=b+52|0}else o=b+52|0;n=q;do{c[(c[o>>2]|0)+(n<<2)>>2]=0;n=n+1|0}while((n|0)!=128)}c[b+44>>2]=128;c[c[b+52>>2]>>2]=d;w=1;n=126;while(1){o=w+-1|0;p=c[b+52>>2]|0;v=c[p+(o<<2)>>2]|0;s=+g[v+4>>2]-+g[k+4>>2];u=+g[v+8>>2]-+g[k+8>>2];g[B>>2]=+g[v>>2]-+g[k>>2];g[B+4>>2]=s;g[B+8>>2]=u;g[B+12>>2]=0.0;u=+g[v+20>>2]-+g[j+4>>2];s=+g[v+24>>2]-+g[j+8>>2];g[B+16>>2]=+g[v+16>>2]-+g[j>>2];g[B+20>>2]=u;g[B+24>>2]=s;g[B+28>>2]=0.0;d=c[h>>2]|0;s=+g[e>>2];u=+g[f>>2];r=(+g[B+(d<<4)>>2]-s)*u;s=u*(+g[B+(1-d<<4)>>2]-s);d=c[h+4>>2]|0;u=+g[e+4>>2];C=+g[f+4>>2];t=(+g[B+(d<<4)+4>>2]-u)*C;u=C*(+g[B+(1-d<<4)+4>>2]-u);do if((!(t>s|r>u)?(z=t>r?t:r,A=u<s?u:s,d=c[h+8>>2]|0,y=+g[e+8>>2],C=+g[f+8>>2],x=(+g[B+(d<<4)+8>>2]-y)*C,y=C*(+g[B+(1-d<<4)+8>>2]-y),!(x>A|z>y)):0)?((y<A?y:A)>0.0?(x>z?x:z)<i:0):0){if(!(c[v+40>>2]|0)){jb[c[(c[m>>2]|0)+12>>2]&127](m,v);break}if((o|0)>(n|0)){d=c[b+44>>2]|0;if((d|0)<(d<<1|0)){if((c[b+48>>2]|0)<(d<<1|0)){if(d){c[6432]=(c[6432]|0)+1;n=ec((d<<3|3)+16|0)|0;if(!n)n=0;else{c[(n+4+15&-16)+-4>>2]=n;n=n+4+15&-16}p=c[b+44>>2]|0;if((p|0)>0){q=0;do{c[n+(q<<2)>>2]=c[(c[b+52>>2]|0)+(q<<2)>>2];q=q+1|0}while((q|0)!=(p|0))}}else n=0;p=c[b+52>>2]|0;if(p|0){if(a[b+56>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[p+-4>>2]|0)}c[b+52>>2]=0}a[b+56>>0]=1;c[b+52>>2]=n;c[b+48>>2]=d<<1;p=d}else{n=p;p=d}do{c[n+(p<<2)>>2]=0;p=p+1|0;n=c[b+52>>2]|0}while((p|0)!=(d<<1|0))}else n=p;c[b+44>>2]=d<<1;p=n;n=(d<<1)+-2|0}c[p+(o<<2)>>2]=c[v+36>>2];c[(c[b+52>>2]|0)+(w<<2)>>2]=c[v+40>>2];o=w+1|0}while(0);if(!o)break;else w=o}l=B;return}function ie(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0,i=0,k=0,m=0,n=0,o=0,p=0.0,q=0.0,r=0.0,s=0.0,t=0,u=0,v=0,w=0,x=0,y=0.0,z=0,A=0,B=0,C=0,D=0,E=0.0;D=l;l=l+32|0;q=+g[d>>2];i=(g[j>>2]=q,c[j>>2]|0);t=q<999999984306749440.0?i:1566444395;p=+g[d+4>>2];m=(g[j>>2]=p,c[j>>2]|0);u=p<999999984306749440.0?m:1566444395;E=+g[d+8>>2];o=(g[j>>2]=E,c[j>>2]|0);w=E<999999984306749440.0?o:1566444395;s=+g[d+12>>2];y=s<0.0?s:0.0;i=q>-999999984306749440.0?i:-581039253;m=p>-999999984306749440.0?m:-581039253;o=E>-999999984306749440.0?o:-581039253;s=s>0.0?s:0.0;E=+g[d+16>>2];B=E<(c[j>>2]=t,+g[j>>2]);h=(g[j>>2]=E,c[j>>2]|0);t=B?h:t;p=+g[d+20>>2];B=p<(c[j>>2]=u,+g[j>>2]);k=(g[j>>2]=p,c[j>>2]|0);u=B?k:u;q=+g[d+24>>2];B=q<(c[j>>2]=w,+g[j>>2]);n=(g[j>>2]=q,c[j>>2]|0);w=B?n:w;r=+g[d+28>>2];y=r<y?r:y;x=(c[j>>2]=i,+g[j>>2])<E?h:i;v=(c[j>>2]=m,+g[j>>2])<p?k:m;m=(c[j>>2]=o,+g[j>>2])<q?n:o;s=s<r?r:s;E=+g[d+32>>2];B=E<(c[j>>2]=t,+g[j>>2]);h=(g[j>>2]=E,c[j>>2]|0);B=B?h:t;q=+g[d+36>>2];A=q<(c[j>>2]=u,+g[j>>2]);i=(g[j>>2]=q,c[j>>2]|0);A=A?i:u;r=+g[d+40>>2];z=r<(c[j>>2]=w,+g[j>>2]);k=(g[j>>2]=r,c[j>>2]|0);z=z?k:w;p=+g[d+44>>2];y=p<y?p:y;w=(c[j>>2]=x,+g[j>>2])<E?h:x;v=(c[j>>2]=v,+g[j>>2])<q?i:v;u=(c[j>>2]=m,+g[j>>2])<r?k:m;p=s<p?p:s;t=c[b+4>>2]|0;h=c[t+4>>2]|0;if((h|0)==(c[t+8>>2]|0)?(C=h|0?h<<1:1,(h|0)<(C|0)):0){if(!C)i=0;else{c[6432]=(c[6432]|0)+1;h=ec(C<<6|19)|0;if(!h)i=0;else{c[(h+4+15&-16)+-4>>2]=h;i=h+4+15&-16}h=c[t+4>>2]|0}if((h|0)>0){k=0;do{m=i+(k<<6)|0;n=(c[t+12>>2]|0)+(k<<6)|0;o=m+64|0;do{c[m>>2]=c[n>>2];m=m+4|0;n=n+4|0}while((m|0)<(o|0));k=k+1|0}while((k|0)!=(h|0))}h=c[t+12>>2]|0;if(h|0){if(a[t+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[t+12>>2]=0}a[t+16>>0]=1;c[t+12>>2]=i;c[t+8>>2]=C;h=c[t+4>>2]|0}C=c[t+12>>2]|0;c[C+(h<<6)>>2]=B;c[C+(h<<6)+4>>2]=A;c[C+(h<<6)+8>>2]=z;g[C+(h<<6)+12>>2]=y;c[C+(h<<6)+16>>2]=w;c[C+(h<<6)+20>>2]=v;c[C+(h<<6)+24>>2]=u;g[C+(h<<6)+28>>2]=p;c[C+(h<<6)+32>>2]=-1;c[C+(h<<6)+36>>2]=e;c[C+(h<<6)+40>>2]=f;f=C+(h<<6)+44|0;c[f>>2]=c[D>>2];c[f+4>>2]=c[D+4>>2];c[f+8>>2]=c[D+8>>2];c[f+12>>2]=c[D+12>>2];c[f+16>>2]=c[D+16>>2];c[t+4>>2]=(c[t+4>>2]|0)+1;l=D;return}function je(b,d,e,f){b=b|0;d=d|0;e=e|0;f=+f;var h=0.0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0;o=l;l=l+16|0;i=+g[d>>2];j=+g[d+4>>2];k=+g[d+8>>2];m=+g[e>>2];n=+g[e+4>>2];h=+g[e+8>>2];if(!(a[b+228>>0]|0)){z=+g[b+100>>2];w=+g[b+116>>2];C=+g[b+132>>2];y=+g[b+104>>2];u=+g[b+120>>2];B=+g[b+136>>2];x=+g[b+108>>2];s=+g[b+124>>2];A=+g[b+140>>2];F=-+g[b+148>>2];E=-+g[b+152>>2];D=-+g[b+156>>2];J=+g[b+164>>2];I=+g[b+168>>2];r=+g[b+172>>2];H=+g[b+180>>2];G=+g[b+184>>2];q=+g[b+188>>2];v=+g[b+196>>2];t=+g[b+200>>2];p=+g[b+204>>2];r=h*(C*J+B*I+A*r)+(m*(z*J+y*I+x*r)+n*(w*J+u*I+s*r))+(J*(z*F+w*E+C*D)+(y*F+u*E+B*D)*I+(x*F+s*E+A*D)*r+ +g[b+212>>2]);q=h*(C*H+B*G+A*q)+(m*(z*H+y*G+x*q)+n*(w*H+u*G+s*q))+((z*F+w*E+C*D)*H+(y*F+u*E+B*D)*G+(x*F+s*E+A*D)*q+ +g[b+216>>2]);p=(z*F+w*E+C*D)*v+(y*F+u*E+B*D)*t+(x*F+s*E+A*D)*p+ +g[b+220>>2]+(h*(C*v+B*t+A*p)+(m*(z*v+y*t+x*p)+n*(w*v+u*t+s*p)));g[o>>2]=r;g[o+4>>2]=q;g[o+8>>2]=p;f=(i*f+m-r)*+g[d>>2]+(j*f+n-q)*+g[d+4>>2]+(k*f+h-p)*+g[d+8>>2];e=o+12|0;g[e>>2]=0.0;b=b+32|0;b=c[b>>2]|0;e=c[b>>2]|0;e=e+16|0;e=c[e>>2]|0;Qb[e&15](b,d,o,f);l=o;return}else{z=+g[b+36>>2];C=+g[b+52>>2];w=+g[b+68>>2];A=+g[b+40>>2];E=+g[b+56>>2];x=+g[b+72>>2];B=+g[b+44>>2];G=+g[b+60>>2];y=+g[b+76>>2];t=-+g[b+84>>2];u=-+g[b+88>>2];v=-+g[b+92>>2];p=+g[b+164>>2];q=+g[b+168>>2];H=+g[b+172>>2];r=+g[b+180>>2];s=+g[b+184>>2];I=+g[b+188>>2];D=+g[b+196>>2];F=+g[b+200>>2];J=+g[b+204>>2];H=(k*f+h)*(w*p+x*q+y*H)+((i*f+m)*(z*p+A*q+B*H)+(j*f+n)*(C*p+E*q+G*H))+(p*(z*t+C*u+w*v)+(A*t+E*u+x*v)*q+(B*t+G*u+y*v)*H+ +g[b+212>>2]);I=(k*f+h)*(w*r+x*s+y*I)+((i*f+m)*(z*r+A*s+B*I)+(j*f+n)*(C*r+E*s+G*I))+((z*t+C*u+w*v)*r+(A*t+E*u+x*v)*s+(B*t+G*u+y*v)*I+ +g[b+216>>2]);J=(z*t+C*u+w*v)*D+(A*t+E*u+x*v)*F+(B*t+G*u+y*v)*J+ +g[b+220>>2]+((k*f+h)*(w*D+x*F+y*J)+((i*f+m)*(z*D+A*F+B*J)+(j*f+n)*(C*D+E*F+G*J)));g[o>>2]=H+i*(i*(H-m)+j*(I-n)+k*(J-h));g[o+4>>2]=I+j*(i*(H-m)+j*(I-n)+k*(J-h));g[o+8>>2]=J+k*(i*(H-m)+j*(I-n)+k*(J-h));J=i*(H-m)+j*(I-n)+k*(J-h);e=o+12|0;g[e>>2]=0.0;b=b+32|0;b=c[b>>2]|0;e=c[b>>2]|0;e=e+16|0;e=c[e>>2]|0;Qb[e&15](b,d,o,J);l=o;return}}function ke(b,d){b=b|0;d=+d;var e=0,f=0,h=0,i=0,j=0,k=0,m=0,n=0,o=0,p=0;p=l;l=l+16|0;o=c[b+452>>2]|0;Rb[c[(c[o>>2]|0)+16>>2]&127](o,b+324|0,0);o=c[b+452>>2]|0;lb[c[(c[o>>2]|0)+12>>2]&127](o)|0;Ic(b,d);Yi(11788);o=c[b+328>>2]|0;if((o|0)>0){e=c[b+336>>2]|0;f=0;k=0;do{n=c[(c[e+(f<<2)>>2]|0)+384>>2]|0;k=(k|0)>(n|0)?k:n;f=f+1|0}while((f|0)!=(o|0));f=0;while(1){e=c[e+(f<<2)>>2]|0;if((c[e+852>>2]|0)>0){h=0;do{n=c[(c[e+860>>2]|0)+(h<<2)>>2]|0;qb[c[(c[n>>2]|0)+8>>2]&15](n,+g[e+452>>2],k);h=h+1|0}while((h|0)<(c[e+852>>2]|0))}f=f+1|0;if((f|0)==(o|0))break;e=c[b+336>>2]|0}if((k|0)>0){i=0;do{j=0;do{f=c[(c[b+336>>2]|0)+(j<<2)>>2]|0;e=c[f+852>>2]|0;if((e|0)>0){h=0;do{n=c[(c[f+860>>2]|0)+(h<<2)>>2]|0;ub[c[(c[n>>2]|0)+12>>2]&7](n,+g[f+452>>2],1.0);h=h+1|0}while((h|0)!=(e|0))}j=j+1|0}while((j|0)!=(o|0));i=i+1|0}while((i|0)!=(k|0));n=0}else n=0;do{m=c[(c[b+336>>2]|0)+(n<<2)>>2]|0;if((c[m+852>>2]|0)>0){h=0;do{e=c[(c[m+860>>2]|0)+(h<<2)>>2]|0;gb[c[(c[e>>2]|0)+16>>2]&31](e,+g[m+452>>2]);e=c[m+860>>2]|0;f=c[e+(h<<2)>>2]|0;a:do if(a[f+152>>0]|0){if(!f)k=e;else{c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0);k=c[m+860>>2]|0}e=h+-1|0;f=c[m+852>>2]|0;if((f|0)>0){j=c[k+(h<<2)>>2]|0;h=0;while(1){i=k+(h<<2)|0;if((c[i>>2]|0)==(j|0))break;h=h+1|0;if((h|0)>=(f|0))break a}if((h|0)<(f|0)){c[i>>2]=c[k+(f+-1<<2)>>2];c[(c[m+860>>2]|0)+(f+-1<<2)>>2]=j;c[m+852>>2]=f+-1;f=f+-1|0}}}else{f=c[m+852>>2]|0;e=h}while(0);h=e+1|0}while((h|0)<(f|0))}n=n+1|0}while((n|0)!=(o|0))}e=c[b+452>>2]|0;gb[c[(c[e>>2]|0)+28>>2]&31](e,+g[e+12>>2]*d);e=c[2395]|0;o=(c[e+16>>2]|0)+-1|0;c[e+16>>2]=o;do if(!o){if(c[e+4>>2]|0){Va(p|0,0)|0;o=c[6431]|0;g[e+8>>2]=+g[e+8>>2]+ +(((c[p+4>>2]|0)-(c[o+4>>2]|0)+(((c[p>>2]|0)-(c[o>>2]|0)|0)*1e6|0)-(c[e+12>>2]|0)|0)>>>0)/1.0e3;if(c[e+16>>2]|0)break;e=c[2395]|0}c[2395]=c[e+20>>2]}while(0);if((c[b+328>>2]|0)<=0){b=c[b+452>>2]|0;o=c[b>>2]|0;o=o+32|0;o=c[o>>2]|0;hb[o&511](b);l=p;return}e=0;do{o=c[(c[b+336>>2]|0)+(e<<2)>>2]|0;Hh(o,o);e=e+1|0}while((e|0)<(c[b+328>>2]|0));b=c[b+452>>2]|0;o=c[b>>2]|0;o=o+32|0;o=c[o>>2]|0;hb[o&511](b);l=p;return}function le(b){b=b|0;var d=0,e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,m=0.0,n=0,o=0,p=0,q=0,r=0;r=l;l=l+64|0;Yi(15103);d=c[b+8>>2]|0;if((d|0)>0){o=0;do{n=c[(c[b+16>>2]|0)+(o<<2)>>2]|0;if(!(a[b+76>>0]|0))switch(c[n+216>>2]|0){case 2:case 5:break;default:q=11}else q=11;if((q|0)==11){q=0;d=c[n+192>>2]|0;Vb[c[(c[d>>2]|0)+8>>2]&127](d,n+4|0,r+48|0,r+32|0);e=+g[r+48>>2]+-.019999999552965164;g[r+48>>2]=e;f=+g[r+48+4>>2]+-.019999999552965164;g[r+48+4>>2]=f;h=+g[r+48+8>>2]+-.019999999552965164;g[r+48+8>>2]=h;i=+g[r+32>>2]+.019999999552965164;g[r+32>>2]=i;j=+g[r+32+4>>2]+.019999999552965164;g[r+32+4>>2]=j;k=+g[r+32+8>>2]+.019999999552965164;g[r+32+8>>2]=k;if(((a[b+44>>0]|0)!=0?(c[n+236>>2]|0)==2:0)?(c[n+204>>2]&3|0)==0:0){d=c[n+192>>2]|0;Vb[c[(c[d>>2]|0)+8>>2]&127](d,n+68|0,r+16|0,r);f=+g[r+16>>2]+-.019999999552965164;g[r+16>>2]=f;h=+g[r+16+4>>2]+-.019999999552965164;g[r+16+4>>2]=h;i=+g[r+16+8>>2]+-.019999999552965164;g[r+16+8>>2]=i;j=+g[r>>2]+.019999999552965164;g[r>>2]=j;k=+g[r+4>>2]+.019999999552965164;g[r+4>>2]=k;m=+g[r+8>>2]+.019999999552965164;g[r+8>>2]=m;e=+g[r+48>>2];if(f<e){g[r+48>>2]=f;e=f}f=+g[r+48+4>>2];if(h<f){g[r+48+4>>2]=h;f=h}h=+g[r+48+8>>2];if(i<h){g[r+48+8>>2]=i;h=i}i=+g[r+16+12>>2];if(i<+g[r+48+12>>2])g[r+48+12>>2]=i;i=+g[r+32>>2];if(i<j){g[r+32>>2]=j;i=j}j=+g[r+32+4>>2];if(j<k){g[r+32+4>>2]=k;j=k}k=+g[r+32+8>>2];if(k<m){g[r+32+8>>2]=m;k=m}m=+g[r+12>>2];if(+g[r+32+12>>2]<m)g[r+32+12>>2]=m}d=c[b+68>>2]|0;if((c[n+204>>2]&1|0)==0?(i=i-e,j=j-f,m=k-h,!(i*i+j*j+m*m<999999995904.0)):0){if((c[n+216>>2]&-2|0)!=4)c[n+216>>2]=5;if(a[15115]|0?(p=c[b+72>>2]|0,p|0):0){a[15115]=0;jb[c[(c[p>>2]|0)+36>>2]&127](p,15116);n=c[b+72>>2]|0;jb[c[(c[n>>2]|0)+36>>2]&127](n,15165);n=c[b+72>>2]|0;jb[c[(c[n>>2]|0)+36>>2]&127](n,15233);n=c[b+72>>2]|0;jb[c[(c[n>>2]|0)+36>>2]&127](n,15298)}}else fb[c[(c[d>>2]|0)+16>>2]&31](d,c[n+188>>2]|0,r+48|0,r+32|0,c[b+24>>2]|0);d=c[b+8>>2]|0}o=o+1|0}while((o|0)<(d|0))}d=c[2395]|0;q=(c[d+16>>2]|0)+-1|0;c[d+16>>2]=q;if(q|0){l=r;return}do if(c[d+4>>2]|0){Va(r+48|0,0)|0;q=c[6431]|0;g[d+8>>2]=+g[d+8>>2]+ +(((c[r+48+4>>2]|0)-(c[q+4>>2]|0)+(((c[r+48>>2]|0)-(c[q>>2]|0)|0)*1e6|0)-(c[d+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[d+16>>2]|0)){d=c[2395]|0;break}else{l=r;return}}while(0);c[2395]=c[d+20>>2];l=r;return}function me(b,d,e,f,h,i,k,l){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;k=k|0;l=l|0;var m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,D=0.0;c[b+4>>2]=4;c[b+8>>2]=-1;c[b+12>>2]=-1;g[b+16>>2]=3402823466385288598117041.0e14;a[b+20>>0]=1;a[b+21>>0]=0;c[b+24>>2]=-1;c[b+28>>2]=d;c[b+32>>2]=e;g[b+36>>2]=0.0;g[b+40>>2]=.30000001192092896;c[b+44>>2]=0;c[b>>2]=4832;g[b+688>>2]=0.0;g[b+692>>2]=-1.0;g[b+696>>2]=.8999999761581421;g[b+700>>2]=.30000001192092896;g[b+704>>2]=1.0;g[b+708>>2]=0.0;g[b+712>>2]=0.0;a[b+716>>0]=0;a[b+736>>0]=0;a[b+737>>0]=0;a[b+738>>0]=0;a[b+739>>0]=1;a[b+740>>0]=l&1;c[b+748>>2]=0;c[b+600>>2]=c[f>>2];c[b+600+4>>2]=c[f+4>>2];c[b+600+8>>2]=c[f+8>>2];c[b+600+12>>2]=c[f+12>>2];o=+g[d+4>>2];p=+g[d+20>>2];m=+g[d+36>>2];q=+g[i>>2];r=+g[i+4>>2];n=+g[i+8>>2];do if(!(o*q+p*r+m*n>=.9999998807907104))if(!(o*q+p*r+m*n<=-.9999998807907104)){s=(g[j>>2]=m*r-p*n,c[j>>2]|0);f=(g[j>>2]=o*n-m*q,c[j>>2]|0);x=n*(o*n-m*q)-r*(p*q-o*r);y=q*(p*q-o*r)-n*(m*r-p*n);w=r*(m*r-p*n)-q*(o*n-m*q);e=(g[j>>2]=p*q-o*r,c[j>>2]|0);break}else{x=+g[d+12>>2];y=+g[d+28>>2];w=+g[d+44>>2];s=c[d+8>>2]|0;e=c[d+40>>2]|0;f=c[d+24>>2]|0;break}else{x=-+g[d+12>>2];y=-+g[d+28>>2];w=-+g[d+44>>2];s=c[d+8>>2]|0;e=c[d+40>>2]|0;f=c[d+24>>2]|0}while(0);g[b+552>>2]=x;c[b+556>>2]=s;c[b+560>>2]=c[i>>2];g[b+564>>2]=0.0;g[b+568>>2]=y;c[b+572>>2]=f;c[b+576>>2]=c[i+4>>2];g[b+580>>2]=0.0;g[b+584>>2]=w;c[b+588>>2]=e;c[b+592>>2]=c[i+8>>2];g[b+596>>2]=0.0;p=+g[i+4>>2];t=+g[k+8>>2];q=+g[i+8>>2];u=+g[k+4>>2];v=+g[k>>2];m=+g[i>>2];do if(t*q+(p*u+v*m)<-.9999998807907104)if(+B(+q)>.7071067690849304){n=1.0/+C(+(p*p+q*q));o=-(q*n);r=0.0;n=p*n;m=0.0;break}else{q=1.0/+C(+(p*p+m*m));o=m*q;r=0.0;n=0.0;m=-(p*q);break}else{z=+C(+((t*q+(p*u+v*m)+1.0)*2.0));o=(q*v-t*m)*(1.0/z);r=z*.5;n=(u*m-p*v)*(1.0/z);m=(p*t-q*u)*(1.0/z)}while(0);D=w*o+x*r-y*n;q=x*n+y*r-w*m;p=y*m+w*r-x*o;A=-(x*m)-y*o-w*n;x=-m;o=-o;w=-n;z=q*w+(A*x+r*D)-p*o;y=p*x+(A*o+r*q)-D*w;x=D*o+(A*w+r*p)-q*x;c[b+664>>2]=c[h>>2];c[b+664+4>>2]=c[h+4>>2];c[b+664+8>>2]=c[h+8>>2];c[b+664+12>>2]=c[h+12>>2];g[b+616>>2]=z;g[b+620>>2]=u*x-t*y;c[b+624>>2]=c[k>>2];g[b+628>>2]=0.0;g[b+632>>2]=y;g[b+636>>2]=t*z-v*x;c[b+640>>2]=c[k+4>>2];g[b+644>>2]=0.0;g[b+648>>2]=x;g[b+652>>2]=v*y-u*z;c[b+656>>2]=c[k+8>>2];g[b+660>>2]=0.0;g[b+732>>2]=l?-1.0:1.0;return}function ne(b,d){b=b|0;d=+d;var e=0,f=0,h=0.0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0,p=0,q=0,r=0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0;r=l;l=l+32|0;e=c[b+136>>2]|0;if((e|0)>0){f=0;do{ge(c[b+116>>2]|0,c[b+144>>2]|0,f,0);f=f+1|0;e=c[b+136>>2]|0}while((f|0)<(e|0))}q=c[b+116>>2]|0;m=+g[q+312>>2];n=+g[q+316>>2];h=+g[q+320>>2];h=+C(+(m*m+n*n+h*h))*3.5999999046325684;g[b+112>>2]=h;p=c[b+128>>2]|0;if(+g[q+4+(p<<2)>>2]*+g[q+312>>2]+ +g[q+20+(p<<2)>>2]*+g[q+316>>2]+ +g[q+36+(p<<2)>>2]*+g[q+320>>2]<0.0)g[b+112>>2]=-h;if((e|0)>0){e=0;do{+jf(b,(c[b+144>>2]|0)+(e*284|0)|0);e=e+1|0;f=c[b+136>>2]|0}while((e|0)<(f|0));i=1.0/+g[(c[b+116>>2]|0)+344>>2];if((f|0)>0){f=0;do{e=c[b+144>>2]|0;if(!(a[e+(f*284|0)+84>>0]|0))h=0.0;else{h=+g[e+(f*284|0)+272>>2];h=i*(+g[e+(f*284|0)+216>>2]*(+g[e+(f*284|0)+204>>2]-+g[e+(f*284|0)+32>>2])*+g[e+(f*284|0)+268>>2]-h*+g[(h<0.0?e+(f*284|0)+220|0:e+(f*284|0)+224|0)>>2]);h=h<0.0?0.0:h}g[e+(f*284|0)+276>>2]=h;f=f+1|0;e=c[b+136>>2]|0}while((f|0)<(e|0));if((e|0)>0){e=0;do{p=c[b+144>>2]|0;k=+g[p+(e*284|0)+276>>2];n=+g[p+(e*284|0)+248>>2];k=k>n?n:k;n=k*+g[p+(e*284|0)+4>>2]*d;m=k*+g[p+(e*284|0)+8>>2]*d;g[r+16>>2]=+g[p+(e*284|0)>>2]*k*d;g[r+16+4>>2]=n;g[r+16+8>>2]=m;g[r+16+12>>2]=0.0;q=c[b+116>>2]|0;m=+g[p+(e*284|0)+20>>2]-+g[q+56>>2];n=+g[p+(e*284|0)+24>>2]-+g[q+60>>2];g[r>>2]=+g[p+(e*284|0)+16>>2]-+g[q+52>>2];g[r+4>>2]=m;g[r+8>>2]=n;g[r+12>>2]=0.0;Vk(q,r+16|0,r);e=e+1|0}while((e|0)<(c[b+136>>2]|0))}}}gb[c[(c[b>>2]|0)+20>>2]&31](b,d);f=c[b+136>>2]|0;if((f|0)<=0){l=r;return}o=c[b+144>>2]|0;p=c[b+116>>2]|0;q=0;do{k=+g[o+(q*284|0)+36>>2]-+g[p+52>>2];n=+g[o+(q*284|0)+40>>2]-+g[p+56>>2];m=+g[o+(q*284|0)+44>>2]-+g[p+60>>2];h=+g[p+332>>2];i=+g[p+336>>2];j=+g[p+328>>2];if(!(a[o+(q*284|0)+84>>0]|0)){e=o+(q*284|0)+240|0;h=+g[e>>2]}else{e=c[b+128>>2]|0;x=+g[p+4+(e<<2)>>2];v=+g[p+20+(e<<2)>>2];t=+g[p+36+(e<<2)>>2];w=+g[o+(q*284|0)>>2];u=+g[o+(q*284|0)+4>>2];s=+g[o+(q*284|0)+8>>2];h=((n*j-k*h+ +g[p+320>>2])*(t-s*(x*w+v*u+t*s))+((h*m-n*i+ +g[p+312>>2])*(x-w*(x*w+v*u+t*s))+(k*i-m*j+ +g[p+316>>2])*(v-u*(x*w+v*u+t*s))))*d/+g[o+(q*284|0)+212>>2];e=o+(q*284|0)+240|0;g[e>>2]=h}y=o+(q*284|0)+236|0;g[y>>2]=h+ +g[y>>2];g[e>>2]=h*.9900000095367432;q=q+1|0}while((q|0)!=(f|0));l=r;return}function oe(a,b,d){a=a|0;b=b|0;d=d|0;var f=0.0,i=0.0,j=0.0,k=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0;s=l;l=l+80|0;n=c[a+4>>2]|0;Fb[c[(c[n>>2]|0)+16>>2]&3](n,s+28|0,s+24|0,s+20|0,s+16|0,s+12|0,s+8|0,s+4|0,s,b);n=c[s+12>>2]|0;o=O(c[s+8>>2]|0,d)|0;r=c[a+4>>2]|0;p=(c[s+20>>2]|0)==0;q=c[s+28>>2]|0;do if((c[s>>2]|0)==3){m=c[s+16>>2]|0;k=O(m,e[n+o+4>>1]|0)|0;if(p){i=+g[q+(k+8)>>2];j=+g[q+(k+4)>>2]*+g[r+8>>2];f=+g[q+k>>2]*+g[r+4>>2]}else{i=+h[q+(k+16)>>3];j=+h[q+(k+8)>>3]*+g[r+8>>2];f=+h[q+k>>3]*+g[r+4>>2]}i=i*+g[r+12>>2];g[s+32+32>>2]=f;g[s+32+36>>2]=j;g[s+32+40>>2]=i;g[s+32+44>>2]=0.0;k=O(m,e[n+o+2>>1]|0)|0;if(p){i=+g[q+(k+8)>>2];j=+g[q+(k+4)>>2]*+g[r+8>>2];f=+g[q+k>>2]*+g[r+4>>2]}else{i=+h[q+(k+16)>>3];j=+h[q+(k+8)>>3]*+g[r+8>>2];f=+h[q+k>>3]*+g[r+4>>2]}i=i*+g[r+12>>2];g[s+32+16>>2]=f;g[s+32+20>>2]=j;g[s+32+24>>2]=i;g[s+32+28>>2]=0.0;k=O(m,e[n+o>>1]|0)|0;if(p){i=+g[q+(k+4)>>2]*+g[r+8>>2];j=+g[q+k>>2]*+g[r+4>>2];f=+g[q+(k+8)>>2];break}else{i=+h[q+(k+8)>>3]*+g[r+8>>2];j=+h[q+k>>3]*+g[r+4>>2];f=+h[q+(k+16)>>3];break}}else{k=c[s+16>>2]|0;m=O(k,c[n+(o+8)>>2]|0)|0;if(p){i=+g[q+(m+4)>>2]*+g[r+8>>2];j=+g[q+(m+8)>>2]*+g[r+12>>2];g[s+32+32>>2]=+g[q+m>>2]*+g[r+4>>2];g[s+32+36>>2]=i;g[s+32+40>>2]=j;g[s+32+44>>2]=0.0;p=O(k,c[n+(o+4)>>2]|0)|0;j=+g[q+(p+4)>>2]*+g[r+8>>2];i=+g[q+(p+8)>>2]*+g[r+12>>2];g[s+32+16>>2]=+g[q+p>>2]*+g[r+4>>2];g[s+32+20>>2]=j;g[s+32+24>>2]=i;g[s+32+28>>2]=0.0;p=O(k,c[n+o>>2]|0)|0;i=+g[q+(p+4)>>2]*+g[r+8>>2];j=+g[q+p>>2]*+g[r+4>>2];f=+g[q+(p+8)>>2];break}else{i=+h[q+(m+8)>>3]*+g[r+8>>2];j=+h[q+(m+16)>>3]*+g[r+12>>2];g[s+32+32>>2]=+h[q+m>>3]*+g[r+4>>2];g[s+32+36>>2]=i;g[s+32+40>>2]=j;g[s+32+44>>2]=0.0;p=O(k,c[n+(o+4)>>2]|0)|0;j=+h[q+(p+8)>>3]*+g[r+8>>2];i=+h[q+(p+16)>>3]*+g[r+12>>2];g[s+32+16>>2]=+h[q+p>>3]*+g[r+4>>2];g[s+32+20>>2]=j;g[s+32+24>>2]=i;g[s+32+28>>2]=0.0;p=O(k,c[n+o>>2]|0)|0;i=+h[q+(p+8)>>3]*+g[r+8>>2];j=+h[q+p>>3]*+g[r+4>>2];f=+h[q+(p+16)>>3];break}}while(0);f=f*+g[r+12>>2];g[s+32>>2]=j;g[s+32+4>>2]=i;g[s+32+8>>2]=f;g[s+32+12>>2]=0.0;r=c[a+8>>2]|0;Vb[c[(c[r>>2]|0)+8>>2]&127](r,s+32|0,b,d);a=c[a+4>>2]|0;jb[c[(c[a>>2]|0)+24>>2]&127](a,b);l=s;return}function pe(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0.0,i=0.0,j=0.0,k=0.0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0,J=0;J=l;l=l+32|0;if(!a){l=J;return}F=+g[d>>2]-+g[b>>2];G=+g[d+4>>2]-+g[b+4>>2];A=+g[d+8>>2]-+g[b+8>>2];z=1.0/+C(+(F*F+G*G+A*A));w=F*z==0.0?999999984306749440.0:1.0/(F*z);x=G*z==0.0?999999984306749440.0:1.0/(G*z);y=A*z==0.0?999999984306749440.0:1.0/(A*z);c[6432]=(c[6432]|0)+1;d=ec(531)|0;if(!d)d=0;else{c[(d+4+15&-16)+-4>>2]=d;d=d+4+15&-16}Hk(d+4|0,0,508)|0;c[d>>2]=a;n=d;p=d;r=d;v=1;a=128;u=d;o=128;m=126;while(1){q=v+-1|0;t=c[u+(q<<2)>>2]|0;c[J>>2]=c[t>>2];c[J+4>>2]=c[t+4>>2];c[J+8>>2]=c[t+8>>2];c[J+12>>2]=c[t+12>>2];c[J+16>>2]=c[t+16>>2];c[J+16+4>>2]=c[t+16+4>>2];c[J+16+8>>2]=c[t+16+8>>2];c[J+16+12>>2]=c[t+16+12>>2];i=+g[b>>2];h=w*(+g[J+((w<0.0&1)<<4)>>2]-i);i=w*(+g[J+((w<0.0^1)<<4)>>2]-i);k=+g[b+4>>2];j=x*(+g[J+((x<0.0&1)<<4)+4>>2]-k);k=x*(+g[J+((x<0.0^1)<<4)+4>>2]-k);do if((!(j>i|h>k)?(B=j>h?j:h,H=k<i?k:i,E=+g[b+8>>2],D=y*(+g[J+((y<0.0&1)<<4)+8>>2]-E),E=y*(+g[J+((y<0.0^1)<<4)+8>>2]-E),!(D>H|B>E)):0)?((E<H?E:H)>0.0?(D>B?D:B)<F*z*F+G*z*G+A*z*A:0):0){if(!(c[t+40>>2]|0)){jb[c[(c[e>>2]|0)+12>>2]&127](e,t);f=n;d=u;break}if((q|0)>(m|0)){s=o<<1;if((o|0)<(s|0)){do if((a|0)<(s|0)){if(o){c[6432]=(c[6432]|0)+1;d=ec((o<<3|3)+16|0)|0;if(!d)a=0;else{c[(d+4+15&-16)+-4>>2]=d;a=d+4+15&-16}if((o|0)>0){d=0;do{c[a+(d<<2)>>2]=c[u+(d<<2)>>2];d=d+1|0}while((d|0)!=(o|0));f=a;d=a}else{f=a;d=a;I=17}}else{f=0;d=0;I=17}if((I|0)==17){I=0;if(!u){p=d;m=d;n=d;a=s;d=f;break}}if(!n){p=d;m=d;n=d;a=s;d=f}else{c[6433]=(c[6433]|0)+1;Pc(c[n+-4>>2]|0);p=d;m=d;n=d;a=s;d=f}}else{m=r;d=u}while(0);Hk(d+(o<<2)|0,0,o<<2|0)|0;o=p;f=n}else{o=p;m=r;f=n;d=u}p=o;r=m;o=s;m=s+-2|0}else{f=n;d=u}c[d+(q<<2)>>2]=c[t+36>>2];c[d+(v<<2)>>2]=c[t+40>>2];q=v+1|0}else{f=n;d=u}while(0);if(!q)break;else{n=f;v=q;u=d}}if((d|0)==0|(p|0)==0){l=J;return}c[6433]=(c[6433]|0)+1;Pc(c[p+-4>>2]|0);l=J;return}function qe(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,D=0.0,E=0.0,F=0.0,G=0,H=0.0,I=0.0,J=0.0;d=l;l=l+96|0;k=+g[b>>2];m=+g[a+28>>2];x=+g[b+4>>2];y=+g[a+32>>2];z=+g[b+8>>2];A=+g[a+36>>2];B=+g[a+44>>2];D=+g[a+48>>2];E=+g[a+52>>2];F=+g[a+60>>2];n=+g[a+64>>2];o=+g[a+68>>2];p=+g[a+76>>2];q=+g[a+80>>2];r=+g[a+84>>2];g[d+80>>2]=k*m+x*y+z*A+p;g[d+80+4>>2]=k*B+x*D+z*E+q;g[d+80+8>>2]=k*F+x*n+z*o+r;g[d+80+12>>2]=0.0;s=+g[b+16>>2];t=+g[b+20>>2];u=+g[b+24>>2];g[d+64>>2]=s*m+t*y+u*A+p;g[d+64+4>>2]=s*B+t*D+u*E+q;g[d+64+8>>2]=s*F+t*n+u*o+r;g[d+64+12>>2]=0.0;v=+g[b+32>>2];w=+g[b+36>>2];f=+g[b+40>>2];g[d+48>>2]=v*m+w*y+f*A+p;g[d+48+4>>2]=v*B+w*D+f*E+q;g[d+48+8>>2]=v*F+w*n+f*o+r;g[d+48+12>>2]=0.0;h=(k*m+x*y+z*A+p+(s*m+t*y+u*A+p)+(v*m+w*y+f*A+p))*.3333333432674408;i=(k*B+x*D+z*E+q+(s*B+t*D+u*E+q)+(v*B+w*D+f*E+q))*.3333333432674408;j=(k*F+x*n+z*o+r+(s*F+t*n+u*o+r)+(v*F+w*n+f*o+r))*.3333333432674408;g[d+32>>2]=h;g[d+32+4>>2]=i;g[d+32+8>>2]=j;g[d+32+12>>2]=0.0;b=c[a+8>>2]|0;if(!((lb[c[(c[b>>2]|0)+48>>2]&127](b)|0)&16384)){e=c[a+8>>2]|0;G=c[e>>2]|0;G=G+8|0;G=c[G>>2]|0;b=a+12|0;Vb[G&127](e,d+80|0,d+64|0,b);e=c[a+8>>2]|0;G=c[e>>2]|0;G=G+8|0;G=c[G>>2]|0;Vb[G&127](e,d+64|0,d+48|0,b);a=c[a+8>>2]|0;e=c[a>>2]|0;e=e+8|0;e=c[e>>2]|0;Vb[e&127](a,d+48|0,d+80|0,b);l=d;return}J=+g[d+80>>2];I=s*B+t*D+u*E+q-(k*B+x*D+z*E+q);H=s*F+t*n+u*o+r-(k*F+x*n+z*o+r);B=v*B+w*D+f*E+q-(k*B+x*D+z*E+q);z=v*F+w*n+f*o+r-(k*F+x*n+z*o+r);D=H*(v*m+w*y+f*A+p-J)-(s*m+t*y+u*A+p-J)*z;F=(s*m+t*y+u*A+p-J)*B-I*(v*m+w*y+f*A+p-J);E=1.0/+C(+(F*F+((I*z-H*B)*(I*z-H*B)+D*D)));c[d+16>>2]=1065353216;c[d+16+4>>2]=1065353216;c[d+16+8>>2]=0;g[d+16+12>>2]=0.0;b=c[a+8>>2]|0;e=c[(c[b>>2]|0)+8>>2]|0;g[d>>2]=E*(I*z-H*B)+h;g[d+4>>2]=E*D+i;g[d+8>>2]=E*F+j;g[d+12>>2]=0.0;Vb[e&127](b,d+32|0,d,d+16|0);b=c[a+8>>2]|0;e=c[b>>2]|0;e=e+8|0;e=c[e>>2]|0;G=a+12|0;Vb[e&127](b,d+80|0,d+64|0,G);b=c[a+8>>2]|0;e=c[b>>2]|0;e=e+8|0;e=c[e>>2]|0;Vb[e&127](b,d+64|0,d+48|0,G);a=c[a+8>>2]|0;b=c[a>>2]|0;b=b+8|0;b=c[b>>2]|0;Vb[b&127](a,d+48|0,d+80|0,G);l=d;return}function re(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;if(!((a|0)!=0&(b|0)!=0))return;c[6432]=(c[6432]|0)+1;e=ec(1043)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}c[e>>2]=a;c[e+4>>2]=b;j=e;f=e;h=e;q=1;a=128;m=e;k=128;e=124;while(1){n=q+-1|0;o=c[m+(n<<3)>>2]|0;p=c[m+(n<<3)+4>>2]|0;if((n|0)>(e|0)){i=k<<1;do if((k|0)<(i|0)&(a|0)<(i|0)){if(k){c[6432]=(c[6432]|0)+1;e=ec((k<<4|3)+16|0)|0;if(!e)a=0;else{c[(e+4+15&-16)+-4>>2]=e;a=e+4+15&-16}if((k|0)>0){e=0;do{f=m+(e<<3)|0;h=c[f+4>>2]|0;l=a+(e<<3)|0;c[l>>2]=c[f>>2];c[l+4>>2]=h;e=e+1|0}while((e|0)!=(k|0));b=a;e=a}else{b=a;e=a;r=12}}else{b=0;e=0;r=12}if((r|0)==12){r=0;if(!m){f=e;h=e;a=i;break}}if(!j){f=e;h=e;a=i}else{c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0);f=e;h=e;a=i}}else{e=j;b=m}while(0);j=e;l=a;k=i;i=i+-4|0}else{l=a;b=m;i=e}do if((o|0)==(p|0))if(!(c[o+40>>2]|0))e=n;else{p=c[o+36>>2]|0;c[b+(n<<3)>>2]=p;c[b+(n<<3)+4>>2]=p;p=c[o+40>>2]|0;e=q+1|0;c[b+(q<<3)>>2]=p;c[b+(q<<3)+4>>2]=p;p=c[o+40>>2]|0;c[b+(e<<3)>>2]=c[o+36>>2];c[b+(e<<3)+4>>2]=p;e=q+2|0}else if(((((+g[o>>2]<=+g[p+16>>2]?+g[o+16>>2]>=+g[p>>2]:0)?+g[o+4>>2]<=+g[p+20>>2]:0)?+g[o+20>>2]>=+g[p+4>>2]:0)?+g[o+8>>2]<=+g[p+24>>2]:0)?+g[o+24>>2]>=+g[p+8>>2]:0){a=(c[p+40>>2]|0)!=0;if(!(c[o+40>>2]|0))if(a){e=c[p+36>>2]|0;c[b+(n<<3)>>2]=o;c[b+(n<<3)+4>>2]=e;e=c[p+40>>2]|0;c[b+(q<<3)>>2]=o;c[b+(q<<3)+4>>2]=e;e=q+1|0;break}else{Rb[c[(c[d>>2]|0)+8>>2]&127](d,o,p);e=n;break}else{e=c[o+36>>2]|0;if(a){m=c[p+36>>2]|0;c[b+(n<<3)>>2]=e;c[b+(n<<3)+4>>2]=m;m=c[p+36>>2]|0;n=q+1|0;c[b+(q<<3)>>2]=c[o+40>>2];c[b+(q<<3)+4>>2]=m;m=c[p+40>>2]|0;e=q+2|0;c[b+(n<<3)>>2]=c[o+36>>2];c[b+(n<<3)+4>>2]=m;p=c[p+40>>2]|0;c[b+(e<<3)>>2]=c[o+40>>2];c[b+(e<<3)+4>>2]=p;e=q+3|0;break}else{c[b+(n<<3)>>2]=e;c[b+(n<<3)+4>>2]=p;c[b+(q<<3)>>2]=c[o+40>>2];c[b+(q<<3)+4>>2]=p;e=q+1|0;break}}}else e=n;while(0);if(!e)break;else{q=e;a=l;m=b;e=i}}if((b|0)==0|(f|0)==0)return;c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0);return}function se(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0.0,h=0,i=0,j=0.0;a=l;l=l+144|0;switch(c[b+388>>2]&15){case 1:{c[a+112>>2]=3492;h=c[d+8>>2]|0;h=(c[h+236>>2]&2|0)==0?0:h;i=c[d+12>>2]|0;j=+g[i+48>>2];e=+g[i+52>>2];f=+g[i+56>>2];f=+C(+((j-j)*(j-j)+(e-e)*(e-e)+(f-f)*(f-f)));i=c[b+192>>2]|0;e=+zb[c[(c[i>>2]|0)+48>>2]&15](i);i=c[d+4>>2]|0;Vb[c[(c[i>>2]|0)+8>>2]&127](i,c[d+12>>2]|0,a+96|0,a+64|0);c[a>>2]=c[a+96>>2];c[a+4>>2]=c[a+96+4>>2];c[a+8>>2]=c[a+96+8>>2];c[a+12>>2]=c[a+96+12>>2];c[a+16>>2]=c[a+64>>2];c[a+16+4>>2]=c[a+64+4>>2];c[a+16+8>>2]=c[a+64+8>>2];c[a+16+12>>2]=c[a+64+12>>2];c[a+32>>2]=c[a>>2];c[a+32+4>>2]=c[a+4>>2];c[a+32+8>>2]=c[a+8>>2];c[a+32+12>>2]=c[a+12>>2];c[a+32+16>>2]=c[a+16>>2];c[a+32+20>>2]=c[a+20>>2];c[a+32+24>>2]=c[a+24>>2];c[a+32+28>>2]=c[a+28>>2];g[a+32>>2]=+g[a+32>>2]-e;g[a+32+4>>2]=+g[a+32+4>>2]-e;g[a+32+8>>2]=+g[a+32+8>>2]-e;g[a+32+16>>2]=e+ +g[a+32+16>>2];g[a+32+20>>2]=e+ +g[a+32+20>>2];g[a+32+24>>2]=e+ +g[a+32+24>>2];c[a+112+4>>2]=b;c[a+112+8>>2]=d;c[a+112+12>>2]=h;g[a+112+16>>2]=f+e;g[a+112+20>>2]=e;Qe(c[b+928>>2]|0,a+32|0,a+112|0);l=a;return}case 2:{g[a+4>>2]=1.0;c[a+8+4>>2]=0;c[a+8+4+4>>2]=0;c[a+8+4+8>>2]=0;c[a>>2]=3528;c[a+24>>2]=b;c[a+28>>2]=d;c[a+8>>2]=c[b+456>>2];i=c[d+4>>2]|0;j=+zb[c[(c[i>>2]|0)+48>>2]&15](i);i=c[b+192>>2]|0;j=j+ +zb[c[(c[i>>2]|0)+48>>2]&15](i);g[a+12>>2]=j;f=+g[(c[d+8>>2]|0)+224>>2];g[a+112>>2]=f;c[a+16>>2]=c[(+g[b+316>>2]<f?b+316|0:a+112|0)>>2];i=c[d+4>>2]|0;Vb[c[(c[i>>2]|0)+8>>2]&127](i,c[d+12>>2]|0,a+112|0,a+96|0);c[a+32>>2]=c[a+112>>2];c[a+32+4>>2]=c[a+112+4>>2];c[a+32+8>>2]=c[a+112+8>>2];c[a+32+12>>2]=c[a+112+12>>2];c[a+32+16>>2]=c[a+96>>2];c[a+32+16+4>>2]=c[a+96+4>>2];c[a+32+16+8>>2]=c[a+96+8>>2];c[a+32+16+12>>2]=c[a+96+12>>2];c[a+64>>2]=c[a+32>>2];c[a+64+4>>2]=c[a+32+4>>2];c[a+64+8>>2]=c[a+32+8>>2];c[a+64+12>>2]=c[a+32+12>>2];c[a+64+16>>2]=c[a+32+16>>2];c[a+64+20>>2]=c[a+32+20>>2];c[a+64+24>>2]=c[a+32+24>>2];c[a+64+28>>2]=c[a+32+28>>2];g[a+64>>2]=+g[a+64>>2]-j;g[a+64+4>>2]=+g[a+64+4>>2]-j;g[a+64+8>>2]=+g[a+64+8>>2]-j;g[a+64+16>>2]=j+ +g[a+64+16>>2];g[a+64+20>>2]=j+ +g[a+64+20>>2];g[a+64+24>>2]=j+ +g[a+64+24>>2];Qe(c[b+1048>>2]|0,a+64|0,a);l=a;return}default:{l=a;return}}}function te(b,d,e,f,h,i){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;c[b+4>>2]=6;c[b+8>>2]=-1;c[b+12>>2]=-1;g[b+16>>2]=3402823466385288598117041.0e14;a[b+20>>0]=1;a[b+21>>0]=0;c[b+24>>2]=-1;c[b+28>>2]=d;c[b+32>>2]=e;g[b+36>>2]=0.0;g[b+40>>2]=.30000001192092896;c[b+44>>2]=0;c[b>>2]=4504;c[b+48>>2]=c[f>>2];c[b+48+4>>2]=c[f+4>>2];c[b+48+8>>2]=c[f+8>>2];c[b+48+12>>2]=c[f+12>>2];c[b+64>>2]=c[f+16>>2];c[b+64+4>>2]=c[f+16+4>>2];c[b+64+8>>2]=c[f+16+8>>2];c[b+64+12>>2]=c[f+16+12>>2];c[b+80>>2]=c[f+32>>2];c[b+80+4>>2]=c[f+32+4>>2];c[b+80+8>>2]=c[f+32+8>>2];c[b+80+12>>2]=c[f+32+12>>2];c[b+96>>2]=c[f+48>>2];c[b+96+4>>2]=c[f+48+4>>2];c[b+96+8>>2]=c[f+48+8>>2];c[b+96+12>>2]=c[f+48+12>>2];c[b+112>>2]=c[h>>2];c[b+112+4>>2]=c[h+4>>2];c[b+112+8>>2]=c[h+8>>2];c[b+112+12>>2]=c[h+12>>2];c[b+128>>2]=c[h+16>>2];c[b+128+4>>2]=c[h+16+4>>2];c[b+128+8>>2]=c[h+16+8>>2];c[b+128+12>>2]=c[h+16+12>>2];c[b+144>>2]=c[h+32>>2];c[b+144+4>>2]=c[h+32+4>>2];c[b+144+8>>2]=c[h+32+8>>2];c[b+144+12>>2]=c[h+32+12>>2];c[b+160>>2]=c[h+48>>2];c[b+160+4>>2]=c[h+48+4>>2];c[b+160+8>>2]=c[h+48+8>>2];c[b+160+12>>2]=c[h+48+12>>2];f=b+680|0;h=f+48|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0));c[b+740>>2]=0;c[b+740+4>>2]=0;c[b+740+8>>2]=0;c[b+740+12>>2]=0;c[b+756>>2]=1045220557;c[b+760>>2]=1045220557;c[b+764>>2]=1045220557;c[b+768>>2]=0;c[b+768+4>>2]=0;c[b+768+8>>2]=0;c[b+768+12>>2]=0;c[b+768+16>>2]=0;g[b+728>>2]=.699999988079071;g[b+732>>2]=1.0;g[b+736>>2]=.5;a[b+788>>0]=0;g[b+792>>2]=0.0;g[b+808>>2]=0.0;a[b+789>>0]=0;g[b+796>>2]=0.0;g[b+812>>2]=0.0;a[b+790>>0]=0;g[b+800>>2]=0.0;g[b+816>>2]=0.0;g[b+928>>2]=0.0;g[b+876>>2]=0.0;g[b+880>>2]=.10000000149011612;g[b+884>>2]=300.0;g[b+868>>2]=1.0;g[b+872>>2]=-1.0;g[b+896>>2]=0.0;g[b+900>>2]=.20000000298023224;g[b+904>>2]=0.0;g[b+908>>2]=0.0;g[b+888>>2]=1.0;g[b+892>>2]=.5;c[b+924>>2]=0;g[b+916>>2]=0.0;a[b+912>>0]=0;g[b+992>>2]=0.0;g[b+940>>2]=0.0;g[b+944>>2]=.10000000149011612;g[b+948>>2]=300.0;g[b+932>>2]=1.0;g[b+936>>2]=-1.0;g[b+960>>2]=0.0;g[b+964>>2]=.20000000298023224;g[b+968>>2]=0.0;g[b+972>>2]=0.0;g[b+952>>2]=1.0;g[b+956>>2]=.5;c[b+988>>2]=0;g[b+980>>2]=0.0;a[b+976>>0]=0;g[b+1056>>2]=0.0;g[b+1004>>2]=0.0;g[b+1008>>2]=.10000000149011612;g[b+1012>>2]=300.0;g[b+996>>2]=1.0;g[b+1e3>>2]=-1.0;g[b+1024>>2]=0.0;g[b+1028>>2]=.20000000298023224;g[b+1032>>2]=0.0;g[b+1036>>2]=0.0;g[b+1016>>2]=1.0;g[b+1020>>2]=.5;c[b+1052>>2]=0;g[b+1044>>2]=0.0;a[b+1040>>0]=0;a[b+1300>>0]=i&1;a[b+1301>>0]=1;c[b+1304>>2]=0;a[b+1308>>0]=0;_c(b,(c[b+28>>2]|0)+4|0,(c[b+32>>2]|0)+4|0);return}function ue(a,b,d){a=a|0;b=b|0;d=+d;var e=0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0,m=0;if(!b)b=0;else b=(c[b+236>>2]&2|0)==0?0:b;c[a+64>>2]=0;c[a+64+4>>2]=0;c[a+64+8>>2]=0;c[a+64+12>>2]=0;c[a+64+16>>2]=0;c[a+64+20>>2]=0;c[a+64+24>>2]=0;c[a+64+28>>2]=0;c[a+144>>2]=0;c[a+144+4>>2]=0;c[a+144+8>>2]=0;c[a+144+12>>2]=0;c[a+144+16>>2]=0;c[a+144+20>>2]=0;c[a+144+24>>2]=0;c[a+144+28>>2]=0;if(!b){c[a>>2]=1065353216;c[a+4>>2]=0;c[a+4+4>>2]=0;c[a+4+8>>2]=0;c[a+4+12>>2]=0;c[a+20>>2]=1065353216;c[a+24>>2]=0;c[a+24+4>>2]=0;c[a+24+8>>2]=0;c[a+24+12>>2]=0;c[a+40>>2]=1065353216;c[a+44>>2]=0;c[a+44+4>>2]=0;c[a+44+8>>2]=0;c[a+44+12>>2]=0;c[a+44+16>>2]=0;c[a+240>>2]=0;c[a+128>>2]=0;c[a+128+4>>2]=0;c[a+128+8>>2]=0;c[a+128+12>>2]=0;c[a+96>>2]=1065353216;c[a+100>>2]=1065353216;c[a+104>>2]=1065353216;g[a+108>>2]=0.0;c[a+112>>2]=1065353216;c[a+116>>2]=1065353216;c[a+120>>2]=1065353216;g[a+124>>2]=0.0;b=a+176|0;e=b+60|0;do{c[b>>2]=0;b=b+4|0}while((b|0)<(e|0));a=a+236|0;g[a>>2]=0.0;return}else{e=b+4|0;c[a>>2]=c[e>>2];c[a+4>>2]=c[e+4>>2];c[a+8>>2]=c[e+8>>2];c[a+12>>2]=c[e+12>>2];e=b+20|0;c[a+16>>2]=c[e>>2];c[a+16+4>>2]=c[e+4>>2];c[a+16+8>>2]=c[e+8>>2];c[a+16+12>>2]=c[e+12>>2];e=b+36|0;c[a+32>>2]=c[e>>2];c[a+32+4>>2]=c[e+4>>2];c[a+32+8>>2]=c[e+8>>2];c[a+32+12>>2]=c[e+12>>2];e=b+52|0;c[a+48>>2]=c[e>>2];c[a+48+4>>2]=c[e+4>>2];c[a+48+8>>2]=c[e+8>>2];c[a+48+12>>2]=c[e+12>>2];e=b+344|0;k=+g[e>>2];l=b+348|0;j=k*+g[b+352>>2];i=k*+g[b+356>>2];g[a+128>>2]=k*+g[l>>2];g[a+132>>2]=j;g[a+136>>2]=i;g[a+140>>2]=0.0;c[a+240>>2]=b;m=b+544|0;c[a+96>>2]=c[m>>2];c[a+96+4>>2]=c[m+4>>2];c[a+96+8>>2]=c[m+8>>2];c[a+96+12>>2]=c[m+12>>2];c[a+112>>2]=c[l>>2];c[a+112+4>>2]=c[l+4>>2];c[a+112+8>>2]=c[l+8>>2];c[a+112+12>>2]=c[l+12>>2];l=b+312|0;c[a+176>>2]=c[l>>2];c[a+176+4>>2]=c[l+4>>2];c[a+176+8>>2]=c[l+8>>2];c[a+176+12>>2]=c[l+12>>2];l=b+328|0;c[a+192>>2]=c[l>>2];c[a+192+4>>2]=c[l+4>>2];c[a+192+8>>2]=c[l+8>>2];c[a+192+12>>2]=c[l+12>>2];i=+g[e>>2];j=i*+g[b+416>>2]*d;k=i*+g[b+420>>2]*d;g[a+208>>2]=i*+g[b+412>>2]*d;g[a+212>>2]=j;g[a+216>>2]=k;g[a+220>>2]=0.0;k=+g[b+428>>2];j=+g[b+432>>2];i=+g[b+436>>2];h=(k*+g[b+268>>2]+j*+g[b+284>>2]+i*+g[b+300>>2])*d;f=(k*+g[b+272>>2]+j*+g[b+288>>2]+i*+g[b+304>>2])*d;g[a+224>>2]=(+g[b+264>>2]*k+ +g[b+280>>2]*j+ +g[b+296>>2]*i)*d;g[a+228>>2]=h;g[a+232>>2]=f;a=a+236|0;g[a>>2]=0.0;return}}function ve(a,e,f){a=a|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0;c[e+16>>2]=c[a+20>>2];c[e+20>>2]=c[a+24>>2];c[e+24>>2]=c[a+28>>2];c[e+28>>2]=c[a+32>>2];c[e>>2]=c[a+4>>2];c[e+4>>2]=c[a+8>>2];c[e+8>>2]=c[a+12>>2];c[e+12>>2]=c[a+16>>2];c[e+32>>2]=c[a+36>>2];c[e+36>>2]=c[a+40>>2];c[e+40>>2]=c[a+44>>2];c[e+44>>2]=c[a+48>>2];c[e+48>>2]=c[a+56>>2];c[e+52>>2]=d[a+60>>0];k=c[a+88>>2]|0;c[e+56>>2]=k;if(k){k=Gb[c[(c[f>>2]|0)+28>>2]&31](f,c[a+96>>2]|0)|0;c[e+64>>2]=k;if(k|0){h=c[a+88>>2]|0;k=vb[c[(c[f>>2]|0)+16>>2]&63](f,48,h)|0;if((h|0)>0){g=c[a+96>>2]|0;i=0;j=c[k+8>>2]|0;while(1){c[j+16>>2]=c[g+(i<<6)+16>>2];c[j+20>>2]=c[g+(i<<6)+20>>2];c[j+24>>2]=c[g+(i<<6)+24>>2];c[j+28>>2]=c[g+(i<<6)+28>>2];c[j>>2]=c[g+(i<<6)>>2];c[j+4>>2]=c[g+(i<<6)+4>>2];c[j+8>>2]=c[g+(i<<6)+8>>2];c[j+12>>2]=c[g+(i<<6)+12>>2];c[j+32>>2]=c[g+(i<<6)+32>>2];c[j+36>>2]=c[g+(i<<6)+36>>2];c[j+40>>2]=c[g+(i<<6)+40>>2];i=i+1|0;if((i|0)==(h|0))break;else j=j+48|0}}else g=c[a+96>>2]|0;fb[c[(c[f>>2]|0)+20>>2]&31](f,k,18588,1497453121,g)}}else c[e+64>>2]=0;k=c[a+128>>2]|0;c[e+60>>2]=k;if(k){k=Gb[c[(c[f>>2]|0)+28>>2]&31](f,c[a+136>>2]|0)|0;c[e+68>>2]=k;if(k|0){h=c[a+128>>2]|0;k=vb[c[(c[f>>2]|0)+16>>2]&63](f,16,h)|0;if((h|0)>0){g=c[a+136>>2]|0;i=0;j=c[k+8>>2]|0;while(1){c[j+12>>2]=c[g+(i<<4)+12>>2];b[j+6>>1]=b[g+(i<<4)+6>>1]|0;b[j+8>>1]=b[g+(i<<4)+8>>1]|0;b[j+10>>1]=b[g+(i<<4)+10>>1]|0;b[j>>1]=b[g+(i<<4)>>1]|0;b[j+2>>1]=b[g+(i<<4)+2>>1]|0;b[j+4>>1]=b[g+(i<<4)+4>>1]|0;i=i+1|0;if((i|0)==(h|0))break;else j=j+16|0}}else g=c[a+136>>2]|0;fb[c[(c[f>>2]|0)+20>>2]&31](f,k,18611,1497453121,g)}}else c[e+68>>2]=0;c[e+76>>2]=c[a+144>>2];k=c[a+152>>2]|0;c[e+80>>2]=k;if(!k){c[e+72>>2]=0;return 18655}k=Gb[c[(c[f>>2]|0)+28>>2]&31](f,c[a+160>>2]|0)|0;c[e+72>>2]=k;if(!k)return 18655;j=c[a+152>>2]|0;k=vb[c[(c[f>>2]|0)+16>>2]&63](f,20,j)|0;if((j|0)>0){g=c[a+160>>2]|0;h=0;i=c[k+8>>2]|0;while(1){b[i+14>>1]=b[g+(h<<5)+6>>1]|0;b[i+16>>1]=b[g+(h<<5)+8>>1]|0;b[i+18>>1]=b[g+(h<<5)+10>>1]|0;b[i+8>>1]=b[g+(h<<5)>>1]|0;b[i+10>>1]=b[g+(h<<5)+2>>1]|0;b[i+12>>1]=b[g+(h<<5)+4>>1]|0;c[i>>2]=c[g+(h<<5)+12>>2];c[i+4>>2]=c[g+(h<<5)+16>>2];h=h+1|0;if((h|0)==(j|0))break;else i=i+20|0}}else g=c[a+160>>2]|0;fb[c[(c[f>>2]|0)+20>>2]&31](f,k,18634,1497453121,g);return 18655}function we(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var h=0,i=0,k=0,m=0.0,n=0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0,N=0;M=l;l=l+64|0;c[M+48>>2]=a;c[M+48+4>>2]=b;c[M+48+8>>2]=d;z=+g[a>>2];A=+g[b>>2];B=+g[a+4>>2];D=+g[b+4>>2];E=+g[a+8>>2];F=+g[b+8>>2];g[M>>2]=z-A;g[M+4>>2]=B-D;g[M+8>>2]=E-F;g[M+12>>2]=0.0;G=+g[d>>2];H=+g[d+4>>2];I=+g[d+8>>2];g[M+16>>2]=A-G;g[M+20>>2]=D-H;g[M+24>>2]=F-I;g[M+28>>2]=0.0;g[M+32>>2]=G-z;g[M+36>>2]=H-B;g[M+40>>2]=I-E;g[M+44>>2]=0.0;J=(B-D)*(F-I)-(E-F)*(D-H);K=(E-F)*(A-G)-(F-I)*(z-A);L=(D-H)*(z-A)-(B-D)*(A-G);if(L*L+(J*J+K*K)>0.0){o=B-D;p=E-F;q=z-A;v=z;w=B;x=E;k=0;y=-1.0;n=0;h=0;i=0}else{L=-1.0;l=M;return +L}while(1){if(v*(L*o-K*p)+w*(J*p-L*q)+(K*q-J*o)*x>0.0){u=c[5100+(k<<2)>>2]|0;N=c[M+48+(u<<2)>>2]|0;m=+g[N>>2];r=m-v;p=+g[N+4>>2];t=p-w;q=+g[N+8>>2];s=q-x;do if(r*r+t*t+s*s>0.0){o=-(v*r+w*t+x*s)/(r*r+t*t+s*s);if(o>=1.0){m=m*m+p*p+q*q;n=2;h=0;i=1065353216;break}if(!(o<=0.0)){i=(g[j>>2]=o,c[j>>2]|0);v=v+r*o;m=w+t*o;x=x+s*o;m=x*x+(v*v+m*m);n=3;h=(g[j>>2]=1.0-o,c[j>>2]|0);break}else{m=v*v+w*w+x*x;n=1;h=1065353216;i=0;break}}else m=-1.0;while(0);if(y<0.0|m<y){c[f>>2]=(n&1|0?1<<k:0)+(n&2|0?1<<u:0);c[e+(k<<2)>>2]=h;c[e+(u<<2)>>2]=i;g[e+(c[5100+(u<<2)>>2]<<2)>>2]=0.0}else m=y}else m=y;k=k+1|0;if((k|0)==3)break;N=c[M+48+(k<<2)>>2]|0;o=+g[M+(k<<4)+4>>2];p=+g[M+(k<<4)+8>>2];q=+g[M+(k<<4)>>2];v=+g[N>>2];w=+g[N+4>>2];x=+g[N+8>>2];y=m}if(!(m<0.0)){L=m;l=M;return +L}x=+C(+(L*L+(J*J+K*K)));y=(J*+g[a>>2]+K*+g[a+4>>2]+L*+g[a+8>>2])/(L*L+(J*J+K*K));c[f>>2]=7;v=+g[b>>2]-J*y;t=+g[b+4>>2]-K*y;w=+g[b+8>>2]-L*y;F=+C(+((t*(A-G)-v*(D-H))*(t*(A-G)-v*(D-H))+(((D-H)*w-t*(F-I))*((D-H)*w-t*(F-I))+(v*(F-I)-w*(A-G))*(v*(F-I)-w*(A-G)))))/x;g[e>>2]=F;A=+g[d>>2]-J*y;w=+g[d+4>>2]-K*y;D=+g[d+8>>2]-L*y;I=+C(+((w*(G-z)-A*(H-B))*(w*(G-z)-A*(H-B))+(((H-B)*D-w*(I-E))*((H-B)*D-w*(I-E))+(A*(I-E)-D*(G-z))*(A*(I-E)-D*(G-z)))))/x;g[e+4>>2]=I;g[e+8>>2]=1.0-(I+F);L=L*y*L*y+(J*y*J*y+K*y*K*y);l=M;return +L}function xe(a){a=a|0;var b=0,d=0,e=0,f=0,h=0,i=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0;d=l;l=l+144|0;g[a+36>>2]=0.0;c[d+128>>2]=0;c[d+128+4>>2]=0;c[d+128+8>>2]=0;c[d+128+12>>2]=0;b=0;do{e=d+128+(b<<2)|0;g[e>>2]=1.0;A=c[a+28>>2]|0;I=c[A+4>>2]|0;c[d+80>>2]=I;F=c[A+20>>2]|0;c[d+80+4>>2]=F;C=c[A+36>>2]|0;c[d+80+8>>2]=C;g[d+80+12>>2]=0.0;H=c[A+8>>2]|0;c[d+80+16>>2]=H;E=c[A+24>>2]|0;c[d+80+20>>2]=E;B=c[A+40>>2]|0;c[d+80+24>>2]=B;g[d+80+28>>2]=0.0;G=c[A+12>>2]|0;c[d+80+32>>2]=G;D=c[A+28>>2]|0;c[d+80+36>>2]=D;z=c[A+44>>2]|0;c[d+80+40>>2]=z;g[d+80+44>>2]=0.0;f=c[a+32>>2]|0;y=c[f+4>>2]|0;c[d+32>>2]=y;v=c[f+20>>2]|0;c[d+32+4>>2]=v;s=c[f+36>>2]|0;c[d+32+8>>2]=s;g[d+32+12>>2]=0.0;x=c[f+8>>2]|0;c[d+32+16>>2]=x;u=c[f+24>>2]|0;c[d+32+20>>2]=u;r=c[f+40>>2]|0;c[d+32+24>>2]=r;g[d+32+28>>2]=0.0;w=c[f+12>>2]|0;c[d+32+32>>2]=w;t=c[f+28>>2]|0;c[d+32+36>>2]=t;h=c[f+44>>2]|0;c[d+32+40>>2]=h;g[d+32+44>>2]=0.0;p=+g[a+300>>2];m=p*(c[j>>2]=I,+g[j>>2]);i=+g[a+304>>2];m=m+i*(c[j>>2]=H,+g[j>>2]);k=+g[a+308>>2];m=m+k*(c[j>>2]=G,+g[j>>2]);q=p*(c[j>>2]=F,+g[j>>2]);q=q+i*(c[j>>2]=E,+g[j>>2]);q=q+k*(c[j>>2]=D,+g[j>>2]);p=p*(c[j>>2]=C,+g[j>>2]);i=p+i*(c[j>>2]=B,+g[j>>2]);p=+g[A+52>>2];o=+g[A+56>>2];n=+g[A+60>>2];n=i+k*(c[j>>2]=z,+g[j>>2])+n-n;g[d+16>>2]=m+p-p;g[d+16+4>>2]=q+o-o;g[d+16+8>>2]=n;g[d+16+12>>2]=0.0;n=+g[a+316>>2];o=n*(c[j>>2]=y,+g[j>>2]);q=+g[a+320>>2];o=o+q*(c[j>>2]=x,+g[j>>2]);p=+g[a+324>>2];o=o+p*(c[j>>2]=w,+g[j>>2]);m=n*(c[j>>2]=v,+g[j>>2]);m=m+q*(c[j>>2]=u,+g[j>>2]);m=m+p*(c[j>>2]=t,+g[j>>2]);n=n*(c[j>>2]=s,+g[j>>2]);q=n+q*(c[j>>2]=r,+g[j>>2]);n=+g[f+52>>2];k=+g[f+56>>2];i=+g[f+60>>2];i=q+p*(c[j>>2]=h,+g[j>>2])+i-i;g[d>>2]=o+n-n;g[d+4>>2]=m+k-k;g[d+8>>2]=i;g[d+12>>2]=0.0;h=c[a+28>>2]|0;f=c[a+32>>2]|0;ug(a+48+(b*84|0)|0,d+80|0,d+32|0,d+16|0,d,d+128|0,h+396|0,+g[h+344>>2],f+396|0,+g[f+344>>2]);g[e>>2]=0.0;b=b+1|0}while((b|0)!=3);l=d;return}function ye(b,d,e,f,h,i,j,k,l,m){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;j=j|0;k=k|0;l=l|0;m=m|0;var n=0,o=0,p=0,q=0,r=0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0;if((j|0)<2|(k|0)<2){m=0;return m|0}r=O(k,j)|0;c[6432]=(c[6432]|0)+1;b=ec(r>>>0>268435455?18:(r<<4|3)+16|0)|0;if(!b)q=0;else{c[(b+4+15&-16)+-4>>2]=b;q=b+4+15&-16}p=UG(r>>>0>1073741823?-1:r<<2)|0;if((k|0)>0?(j|0)>0:0){n=0;do{y=+(n|0)/+(k+-1|0);s=+g[e>>2];s=s+y*(+g[h>>2]-s);t=+g[e+4>>2];t=t+y*(+g[h+4>>2]-t);u=+g[e+8>>2];u=u+y*(+g[h+8>>2]-u);v=+g[f>>2];w=+g[f+4>>2];x=+g[f+8>>2];v=v+y*(+g[i>>2]-v)-s;w=w+y*(+g[i+4>>2]-w)-t;x=x+y*(+g[i+8>>2]-x)-u;o=O(n,j)|0;b=0;do{y=+(b|0)/+(j+-1|0);z=b+o|0;g[q+(z<<4)>>2]=s+v*y;g[q+(z<<4)+4>>2]=t+w*y;g[q+(z<<4)+8>>2]=u+x*y;g[q+(z<<4)+12>>2]=0.0;g[p+(z<<2)>>2]=1.0;b=b+1|0}while((b|0)!=(j|0));n=n+1|0}while((n|0)!=(k|0))}c[6432]=(c[6432]|0)+1;b=ec(1271)|0;if(!b)b=0;else{c[(b+4+15&-16)+-4>>2]=b;b=b+4+15&-16}oc(b,d,r,q,p);if(l&1|0){g[(c[b+720>>2]|0)+88>>2]=0.0;a[b+924>>0]=1}if(l&2|0){g[(c[b+720>>2]|0)+((j+-1|0)*104|0)+88>>2]=0.0;a[b+924>>0]=1}if(l&4|0){z=O(k+-1|0,j)|0;g[(c[b+720>>2]|0)+(z*104|0)+88>>2]=0.0;a[b+924>>0]=1}if(l&8|0){z=j+-1+(O(k+-1|0,j)|0)|0;g[(c[b+720>>2]|0)+(z*104|0)+88>>2]=0.0;a[b+924>>0]=1}if(q|0){c[6433]=(c[6433]|0)+1;Pc(c[q+-4>>2]|0)}VG(p);if((k|0)<=0){z=b;return z|0}q=0;do{i=q;q=q+1|0;a:do if((j|0)>0){r=O(i,j)|0;p=O(q,j)|0;if((q|0)<(k|0))f=0;else{n=0;while(1){o=n;n=n+1|0;if((n|0)<(j|0))Df(b,o+r|0,n+r|0,0,0);if((n|0)==(j|0))break a}}do{n=f+r|0;h=f;f=f+1|0;do if((f|0)<(j|0)){o=f+r|0;Df(b,n,o,0,0);Df(b,n,h+p|0,0,0);if(!(h+i&1)){Mf(b,h+p|0,n,o,0);Mf(b,h+p|0,o,f+p|0,0);if(!m)break;Df(b,o,h+p|0,0,0);break}else{e=f+p|0;Mf(b,n,o,e,0);Mf(b,n,e,h+p|0,0);if(!m)break;Df(b,n,e,0,0);break}}else Df(b,n,h+p|0,0,0);while(0)}while((f|0)!=(j|0))}while(0)}while((q|0)!=(k|0));return b|0}function ze(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,h=0,i=0,j=0,k=0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0;if(!(c[a+204>>2]&2)){c[a+68>>2]=c[b>>2];c[a+68+4>>2]=c[b+4>>2];c[a+68+8>>2]=c[b+8>>2];c[a+68+12>>2]=c[b+12>>2];c[a+84>>2]=c[b+16>>2];c[a+84+4>>2]=c[b+16+4>>2];c[a+84+8>>2]=c[b+16+8>>2];c[a+84+12>>2]=c[b+16+12>>2];c[a+100>>2]=c[b+32>>2];c[a+100+4>>2]=c[b+32+4>>2];c[a+100+8>>2]=c[b+32+8>>2];c[a+100+12>>2]=c[b+32+12>>2];c[a+116>>2]=c[b+48>>2];c[a+116+4>>2]=c[b+48+4>>2];c[a+116+8>>2]=c[b+48+8>>2];c[a+116+12>>2]=c[b+48+12>>2];e=b;f=a+20|0;h=b+16|0;i=a+36|0;j=b+32|0;k=a+52|0;b=b+48|0;d=a+4|0}else{c[a+68>>2]=c[a+4>>2];c[a+68+4>>2]=c[a+4+4>>2];c[a+68+8>>2]=c[a+4+8>>2];c[a+68+12>>2]=c[a+4+12>>2];c[a+84>>2]=c[a+20>>2];c[a+84+4>>2]=c[a+20+4>>2];c[a+84+8>>2]=c[a+20+8>>2];c[a+84+12>>2]=c[a+20+12>>2];c[a+100>>2]=c[a+36>>2];c[a+100+4>>2]=c[a+36+4>>2];c[a+100+8>>2]=c[a+36+8>>2];c[a+100+12>>2]=c[a+36+12>>2];c[a+116>>2]=c[a+52>>2];c[a+116+4>>2]=c[a+52+4>>2];c[a+116+8>>2]=c[a+52+8>>2];c[a+116+12>>2]=c[a+52+12>>2];e=b;f=a+20|0;h=b+16|0;i=a+36|0;j=b+32|0;k=a+52|0;b=b+48|0;d=a+4|0}c[a+132>>2]=c[a+312>>2];c[a+132+4>>2]=c[a+312+4>>2];c[a+132+8>>2]=c[a+312+8>>2];c[a+132+12>>2]=c[a+312+12>>2];c[a+148>>2]=c[a+328>>2];c[a+148+4>>2]=c[a+328+4>>2];c[a+148+8>>2]=c[a+328+8>>2];c[a+148+12>>2]=c[a+328+12>>2];c[d>>2]=c[e>>2];c[d+4>>2]=c[e+4>>2];c[d+8>>2]=c[e+8>>2];c[d+12>>2]=c[e+12>>2];c[f>>2]=c[h>>2];c[f+4>>2]=c[h+4>>2];c[f+8>>2]=c[h+8>>2];c[f+12>>2]=c[h+12>>2];c[i>>2]=c[j>>2];c[i+4>>2]=c[j+4>>2];c[i+8>>2]=c[j+8>>2];c[i+12>>2]=c[j+12>>2];c[k>>2]=c[b>>2];c[k+4>>2]=c[b+4>>2];c[k+8>>2]=c[b+8>>2];c[k+12>>2]=c[b+12>>2];w=+g[a+4>>2];q=+g[a+396>>2];v=+g[a+8>>2];o=+g[a+400>>2];u=+g[a+12>>2];m=+g[a+404>>2];t=+g[a+20>>2];s=+g[a+24>>2];r=+g[a+28>>2];p=+g[a+36>>2];n=+g[a+40>>2];l=+g[a+44>>2];g[a+264>>2]=w*w*q+v*v*o+u*u*m;g[a+268>>2]=w*q*t+v*o*s+u*m*r;g[a+272>>2]=w*q*p+v*o*n+u*m*l;g[a+276>>2]=0.0;g[a+280>>2]=w*q*t+v*o*s+u*m*r;g[a+284>>2]=t*q*t+s*o*s+r*m*r;g[a+288>>2]=q*t*p+o*s*n+m*r*l;g[a+292>>2]=0.0;g[a+296>>2]=w*q*p+v*o*n+u*m*l;g[a+300>>2]=t*q*p+s*o*n+r*m*l;g[a+304>>2]=p*q*p+n*o*n+l*m*l;g[a+308>>2]=0.0;return}function Ae(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0;h=l;l=l+160|0;e=c[a+4>>2]|0;f=c[e+12>>2]|0;D=+g[f>>2];C=+g[f+4>>2];B=+g[f+8>>2];A=+g[f+16>>2];z=+g[f+20>>2];y=+g[f+24>>2];r=+g[f+32>>2];p=+g[f+36>>2];n=+g[f+40>>2];e=c[(c[e+4>>2]|0)+24>>2]|0;x=+g[e+(d*80|0)>>2];w=+g[e+(d*80|0)+16>>2];v=+g[e+(d*80|0)+32>>2];u=+g[e+(d*80|0)+4>>2];t=+g[e+(d*80|0)+20>>2];s=+g[e+(d*80|0)+36>>2];q=+g[e+(d*80|0)+8>>2];o=+g[e+(d*80|0)+24>>2];m=+g[e+(d*80|0)+40>>2];F=+g[e+(d*80|0)+48>>2];E=+g[e+(d*80|0)+52>>2];i=+g[e+(d*80|0)+56>>2];k=+g[f+48>>2]+(D*F+C*E+B*i);j=+g[f+52>>2]+(A*F+z*E+y*i);i=+g[f+56>>2]+(r*F+p*E+n*i);g[h+88>>2]=D*x+C*w+B*v;g[h+88+4>>2]=D*u+C*t+B*s;g[h+88+8>>2]=D*q+C*o+B*m;g[h+88+12>>2]=0.0;g[h+88+16>>2]=A*x+z*w+y*v;g[h+88+20>>2]=A*u+z*t+y*s;g[h+88+24>>2]=A*q+z*o+y*m;g[h+88+28>>2]=0.0;g[h+88+32>>2]=r*x+p*w+n*v;g[h+88+36>>2]=r*u+p*t+n*s;g[h+88+40>>2]=r*q+p*o+n*m;g[h+88+44>>2]=0.0;g[h+88+48>>2]=k;g[h+88+52>>2]=j;g[h+88+56>>2]=i;g[h+88+60>>2]=0.0;Vb[c[(c[b>>2]|0)+8>>2]&127](b,h+88|0,h+72|0,h+56|0);f=c[a+8>>2]|0;e=c[f+4>>2]|0;Vb[c[(c[e>>2]|0)+8>>2]&127](e,c[f+12>>2]|0,h+40|0,h+24|0);if(!(+g[h+72>>2]>+g[h+24>>2])?!(+g[h+56>>2]<+g[h+40>>2]):0)e=1;else e=0;if(!(!(+g[h+72+8>>2]>+g[h+24+8>>2])?!(+g[h+56+8>>2]<+g[h+40+8>>2]):0))e=0;if(+g[h+72+4>>2]>+g[h+24+4>>2]){l=h;return}if(+g[h+56+4>>2]<+g[h+40+4>>2]|e^1){l=h;return}e=c[a+4>>2]|0;f=c[e+8>>2]|0;c[h>>2]=e;c[h+4>>2]=b;c[h+8>>2]=f;c[h+12>>2]=h+88;c[h+16>>2]=-1;c[h+20>>2]=d;if(!(c[(c[a+24>>2]|0)+(d<<2)>>2]|0)){f=c[a+12>>2]|0;f=pb[c[(c[f>>2]|0)+8>>2]&31](f,h,c[a+8>>2]|0,c[a+28>>2]|0)|0;c[(c[a+24>>2]|0)+(d<<2)>>2]=f;f=c[a+4>>2]|0}else f=e;b=c[a+20>>2]|0;e=c[b+8>>2]|0;if((c[e+8>>2]|0)==(c[f+8>>2]|0)){c[b+8>>2]=h;Rb[c[(c[b>>2]|0)+8>>2]&127](b,-1,d)}else{e=c[b+12>>2]|0;c[b+12>>2]=h;Rb[c[(c[b>>2]|0)+12>>2]&127](b,-1,d)}d=c[(c[a+24>>2]|0)+(d<<2)>>2]|0;fb[c[(c[d>>2]|0)+8>>2]&31](d,h,c[a+8>>2]|0,c[a+16>>2]|0,c[a+20>>2]|0);d=c[a+20>>2]|0;c[((c[(c[d+8>>2]|0)+8>>2]|0)==(c[(c[a+4>>2]|0)+8>>2]|0)?d+8|0:d+12|0)>>2]=e;l=h;return}function Be(a,b,d,e,f,h,i,j){a=a|0;b=b|0;d=d|0;e=+e;f=+f;h=+h;i=i|0;j=j|0;var k=0,m=0,n=0.0,o=0,p=0.0,q=0,r=0.0,s=0,t=0.0,u=0.0,v=0.0,w=0,x=0,y=0,z=0.0,A=0.0,B=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0.0,O=0.0,P=0.0,Q=0.0,R=0.0,S=0.0,T=0.0,U=0.0,V=0,W=0;W=l;l=l+32|0;R=+g[d>>2];T=+g[d+4>>2];S=+g[d+8>>2];r=+g[i>>2];t=+g[i+4>>2];u=+g[i+8>>2];v=+g[j>>2];n=+g[j+4>>2];p=+g[j+8>>2];K=1.0/+C(+((e-R)*(e-R)+(f-T)*(f-T)+(h-S)*(h-S)));H=(e-R)*K==0.0?999999984306749440.0:1.0/((e-R)*K);I=(f-T)*K==0.0?999999984306749440.0:1.0/((f-T)*K);J=(h-S)*K==0.0?999999984306749440.0:1.0/((h-S)*K);B=(R>e?e:R)+r;G=(T>f?f:T)+t;E=(S>h?h:S)+u;A=(R<e?e:R)+v;F=(T<f?f:T)+n;D=(S<h?h:S)+p;k=c[a+56>>2]|0;a:do if((k|0)>0){x=k;w=0;y=c[a+96>>2]|0;k=0;while(1){k=k+1|0;c[W>>2]=c[y>>2];c[W+4>>2]=c[y+4>>2];c[W+8>>2]=c[y+8>>2];c[W+12>>2]=c[y+12>>2];s=y+16|0;c[W+16>>2]=c[s>>2];c[W+16+4>>2]=c[s+4>>2];c[W+16+8>>2]=c[s+8>>2];c[W+16+12>>2]=c[s+12>>2];g[W>>2]=+g[W>>2]-v;g[W+4>>2]=+g[W+4>>2]-n;g[W+8>>2]=+g[W+8>>2]-p;g[W+16>>2]=+g[W+16>>2]-r;g[W+20>>2]=+g[W+20>>2]-t;g[W+24>>2]=+g[W+24>>2]-u;if(!(B>+g[s>>2])?!(A<+g[y>>2]):0)m=1;else m=0;if(!(!(E>+g[y+24>>2])?!(D<+g[y+8>>2]):0))m=0;if(((!(G>+g[y+20>>2])?!(F<+g[y+4>>2]|m^1):0)?(M=+g[d>>2],L=H*(+g[W+((H<0.0&1)<<4)>>2]-M),M=H*(+g[W+((H<0.0^1)<<4)>>2]-M),O=+g[d+4>>2],N=I*(+g[W+((I<0.0&1)<<4)+4>>2]-O),O=I*(+g[W+((I<0.0^1)<<4)+4>>2]-O),!(N>M|L>O)):0)?(z=N>L?N:L,U=O<M?O:M,Q=+g[d+8>>2],P=J*(+g[W+((J<0.0&1)<<4)+8>>2]-Q),Q=J*(+g[W+((J<0.0^1)<<4)+8>>2]-Q),!(P>U|z>Q)):0){o=(Q<U?Q:U)>0.0?(P>z?P:z)<(h-S)*(h-S)*K+((e-R)*(e-R)*K+(f-T)*(f-T)*K):0;m=c[y+32>>2]|0;if(o&(m|0)==-1){Rb[c[(c[b>>2]|0)+8>>2]&127](b,c[y+36>>2]|0,c[y+40>>2]|0);q=1;m=c[a+56>>2]|0}else{s=m;q=(m|0)==-1;m=o;V=16}}else{q=c[y+32>>2]|0;s=q;q=(q|0)==-1;m=0;V=16}if((V|0)==16){V=0;q=q|m?1:s;m=x}o=q+w|0;if((o|0)>=(m|0))break a;n=+g[j+4>>2];p=+g[j+8>>2];r=+g[i>>2];t=+g[i+4>>2];u=+g[i+8>>2];x=m;v=+g[j>>2];w=o;y=y+(q<<6)|0}}else k=0;while(0);if((c[6164]|0)>=(k|0)){l=W;return}c[6164]=k;l=W;return}function Ce(){if(a[22720]|0)return;if(!(jy(22720)|0))return;c[6165]=0;c[6166]=-2147483648;c[6167]=-1082130432;g[6168]=0.0;c[6169]=1060716128;c[6170]=-1090087446;c[6171]=-1092290076;g[6172]=0.0;c[6173]=-1098022214;c[6174]=-1084636126;c[6175]=-1092290076;g[6176]=0.0;c[6177]=-1083901670;c[6178]=-2147483648;c[6179]=-1092290177;g[6180]=0.0;c[6181]=-1098022214;c[6182]=1062847522;c[6183]=-1092290043;g[6184]=0.0;c[6185]=1060716128;c[6186]=1057396202;c[6187]=-1092290076;g[6188]=0.0;c[6189]=1049461434;c[6190]=-1084636126;c[6191]=1055193605;g[6192]=0.0;c[6193]=-1086767520;c[6194]=-1090087446;c[6195]=1055193572;g[6196]=0.0;c[6197]=-1086767520;c[6198]=1057396202;c[6199]=1055193572;g[6200]=0.0;c[6201]=1049461434;c[6202]=1062847522;c[6203]=1055193572;g[6204]=0.0;c[6205]=1063581978;c[6206]=0;c[6207]=1055193471;g[6208]=0.0;c[6209]=-2147483648;c[6210]=0;c[6211]=1065353216;g[6212]=0.0;c[6213]=1054458864;c[6214]=-1096927567;c[6215]=-1084636042;g[6216]=0.0;c[6217]=-1104782626;c[6218]=-1090519208;c[6219]=-1084636042;g[6220]=0.0;c[6221]=1049007812;c[6222]=-1085334679;c[6223]=-1090087228;g[6224]=0.0;c[6225]=1054458864;c[6226]=1050556081;c[6227]=-1084636042;g[6228]=0.0;c[6229]=1062847505;c[6230]=-2147483648;c[6231]=-1090087262;g[6232]=0.0;c[6233]=-1090087362;c[6234]=-2147483648;c[6235]=-1084636076;g[6236]=0.0;c[6237]=-1087361736;c[6238]=-1090519141;c[6239]=-1090087262;g[6240]=0.0;c[6241]=-1104782626;c[6242]=1056964440;c[6243]=-1084636042;g[6244]=0.0;c[6245]=-1087361736;c[6246]=1056964507;c[6247]=-1090087262;g[6248]=0.0;c[6249]=1049007812;c[6250]=1062148969;c[6251]=-1090087228;g[6252]=0.0;c[6253]=1064532105;c[6254]=1050556148;c[6255]=0;g[6256]=0.0;c[6257]=1064532105;c[6258]=-1096927500;c[6259]=0;g[6260]=0.0;c[6261]=1058437413;c[6262]=-1085334595;c[6263]=0;g[6264]=0.0;c[6265]=0;c[6266]=-1082130432;c[6267]=0;g[6268]=0.0;c[6269]=-1089046235;c[6270]=-1085334595;c[6271]=0;g[6272]=0.0;c[6273]=-1082951543;c[6274]=-1096927500;c[6275]=-2147483648;g[6276]=0.0;c[6277]=-1082951543;c[6278]=1050556148;c[6279]=-2147483648;g[6280]=0.0;c[6281]=-1089046235;c[6282]=1062149053;c[6283]=-2147483648;g[6284]=0.0;c[6285]=-2147483648;c[6286]=1065353216;c[6287]=-2147483648;g[6288]=0.0;c[6289]=1058437413;c[6290]=1062149053;c[6291]=-2147483648;g[6292]=0.0;c[6293]=1060121912;c[6294]=-1090519141;c[6295]=1057396386;g[6296]=0.0;c[6297]=-1098475836;c[6298]=-1085334679;c[6299]=1057396420;g[6300]=0.0;c[6301]=-1084636143;c[6302]=0;c[6303]=1057396386;g[6304]=0.0;c[6305]=-1098475836;c[6306]=1062148969;c[6307]=1057396420;g[6308]=0.0;c[6309]=1060121912;c[6310]=1056964507;c[6311]=1057396386;g[6312]=0.0;c[6313]=1057396286;c[6314]=0;c[6315]=1062847572;g[6316]=0.0;c[6317]=1042701022;c[6318]=-1090519208;c[6319]=1062847606;g[6320]=0.0;c[6321]=-1093024784;c[6322]=-1096927567;c[6323]=1062847606;g[6324]=0.0;c[6325]=-1093024784;c[6326]=1050556081;c[6327]=1062847606;g[6328]=0.0;c[6329]=1042701022;c[6330]=1056964440;c[6331]=1062847606;g[6332]=0.0;return}function De(a,b,d,e,f,h){a=a|0;b=b|0;d=+d;e=+e;f=+f;h=h|0;var i=0,j=0,k=0.0,l=0.0,m=0,n=0.0,o=0,p=0,q=0.0,r=0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0,y=0,z=0.0,A=0.0,B=0,D=0.0;a:while(1){if((b|0)>0){j=0;i=-1;do{do if(c[h+(j<<2)>>2]|0){if((i|0)!=-1?!(+g[a+(j<<4)>>2]*d+ +g[a+(j<<4)+4>>2]*e+ +g[a+(j<<4)+8>>2]*f>+g[a+(i<<4)>>2]*d+ +g[a+(i<<4)+4>>2]*e+ +g[a+(i<<4)+8>>2]*f):0)break;i=j}while(0);j=j+1|0}while((j|0)!=(b|0))}else i=-1;y=h+(i<<2)|0;if((c[y>>2]|0)==3){B=36;break}l=+C(+((e-f*0.0)*(e-f*0.0)+(f*0.0-d)*(f*0.0-d)+(d*0.0-e*0.0)*(d*0.0-e*0.0)));k=+C(+((d-e*0.0)*(d-e*0.0)+((e*0.0-f)*(e*0.0-f)+(f*0.0-d*0.0)*(f*0.0-d*0.0))));if(l>k){z=(e-f*0.0)*(1.0/l);A=(f*0.0-d)*(1.0/l);t=(d*0.0-e*0.0)*(1.0/l)}else{z=(e*0.0-f)*(1.0/k);A=(f*0.0-d*0.0)*(1.0/k);t=(d-e*0.0)*(1.0/k)}u=A*f-t*e;v=t*d-z*f;w=z*e-A*d;r=(i|0)==-1;j=-1;x=0;while(1){s=+(x|0);q=+F(+(s*.01745329238474369));l=+E(+(s*.01745329238474369));k=(z*q+u*l)*.02500000037252903+d;n=(A*q+v*l)*.02500000037252903+e;l=(t*q+w*l)*.02500000037252903+f;if((b|0)>0){o=0;m=-1;do{do if(c[h+(o<<2)>>2]|0){if((m|0)!=-1?!(k*+g[a+(o<<4)>>2]+n*+g[a+(o<<4)+4>>2]+l*+g[a+(o<<4)+8>>2]>k*+g[a+(m<<4)>>2]+n*+g[a+(m<<4)+4>>2]+l*+g[a+(m<<4)+8>>2]):0)break;m=o}while(0);o=o+1|0}while((o|0)!=(b|0))}else m=-1;if((j|0)==(i|0)&(m|0)==(i|0))break a;b:do if(!((j|0)==-1|(j|0)==(m|0))?s+-40.0<=s:0){if((b|0)>0)q=s+-40.0;else{k=s+-40.0;while(1){if((j|0)==(i|0)&r){i=-1;break a}k=k+5.0;if(!(k<=s))break b;else j=-1}}while(1){l=q*.01745329238474369;D=+F(+l);l=+E(+l);k=(z*D+u*l)*.02500000037252903+d;n=(A*D+v*l)*.02500000037252903+e;l=(t*D+w*l)*.02500000037252903+f;p=0;o=-1;do{do if(c[h+(p<<2)>>2]|0){if((o|0)!=-1?!(k*+g[a+(p<<4)>>2]+n*+g[a+(p<<4)+4>>2]+l*+g[a+(p<<4)+8>>2]>k*+g[a+(o<<4)>>2]+n*+g[a+(o<<4)+4>>2]+l*+g[a+(o<<4)+8>>2]):0)break;o=p}while(0);p=p+1|0}while((p|0)!=(b|0));if((j|0)==(i|0)&(o|0)==(i|0))break a;q=q+5.0;if(!(q<=s))break;else j=o}}while(0);x=x+45|0;if((x|0)>360)break;else j=m}c[y>>2]=0}if((B|0)==36)return i|0;c[h+(i<<2)>>2]=3;B=i;return B|0}function Ee(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;while(1){p=(b+d|0)/2|0;m=c[a+12>>2]|0;n=c[m+(p<<4)>>2]|0;o=c[m+(p<<4)+4>>2]|0;p=c[m+(p<<4)+8>>2]|0;e=b;f=d;while(1){a:do if(!n)while(1){j=c[m+(e<<4)>>2]|0;if(!j)g=-1;else g=c[j+12>>2]|0;k=c[m+(e<<4)+4>>2]|0;if(!k)h=-1;else h=c[k+12>>2]|0;if(!o)i=-1;else i=c[o+12>>2]|0;do if((g|0)<=-1){g=(h|0)>(i|0);if(g|(j|0)==(n|0)^1)if((j|0)==(n|0)&g)break;else break a;if((k|0)!=(o|0))break a;if((c[m+(e<<4)+8>>2]|0)>>>0<=p>>>0)break a}while(0);e=e+1|0}else{l=c[n+12>>2]|0;while(1){j=c[m+(e<<4)>>2]|0;if(!j)g=-1;else g=c[j+12>>2]|0;k=c[m+(e<<4)+4>>2]|0;if(!k)h=-1;else h=c[k+12>>2]|0;if(!o)i=-1;else i=c[o+12>>2]|0;do if((g|0)<=(l|0)){g=(h|0)>(i|0);if(g|(j|0)==(n|0)^1)if((j|0)==(n|0)&g)break;else break a;if((k|0)!=(o|0))break a;if((c[m+(e<<4)+8>>2]|0)>>>0<=p>>>0)break a}while(0);e=e+1|0}}while(0);b:while(1){if(!n)g=-1;else g=c[n+12>>2]|0;k=c[m+(f<<4)>>2]|0;if(!k)h=-1;else h=c[k+12>>2]|0;if(!o)i=-1;else i=c[o+12>>2]|0;l=c[m+(f<<4)+4>>2]|0;if(!l)j=-1;else j=c[l+12>>2]|0;do if((g|0)<=(h|0)){g=(i|0)>(j|0);if(g|(n|0)==(k|0)^1)if((n|0)==(k|0)&g)break;else break b;if((o|0)!=(l|0))break b;if(p>>>0<=(c[m+(f<<4)+8>>2]|0)>>>0)break b}while(0);f=f+-1|0}if((e|0)<=(f|0)){h=m+(e<<4)|0;i=c[h>>2]|0;j=c[m+(e<<4)+4>>2]|0;k=c[m+(e<<4)+8>>2]|0;l=c[m+(e<<4)+12>>2]|0;m=m+(f<<4)|0;c[h>>2]=c[m>>2];c[h+4>>2]=c[m+4>>2];c[h+8>>2]=c[m+8>>2];c[h+12>>2]=c[m+12>>2];m=c[a+12>>2]|0;c[m+(f<<4)>>2]=i;c[m+(f<<4)+4>>2]=j;c[m+(f<<4)+8>>2]=k;c[m+(f<<4)+12>>2]=l;e=e+1|0;f=f+-1|0}if((e|0)>(f|0))break;m=c[a+12>>2]|0}if((f|0)>(b|0))Ee(a,b,f);if((e|0)<(d|0))b=e;else break}return}function Fe(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,h=0,i=0,j=0,k=0.0,l=0,m=0.0,n=0.0,o=0.0;i=c[a+192>>2]|0;k=+zb[c[(c[i>>2]|0)+48>>2]&15](i);i=c[a+712>>2]|0;if((i|0)>0){l=0;do{j=c[a+720>>2]|0;d=j+(l*104|0)+8|0;m=+g[b>>2]*+g[d>>2];g[d>>2]=m;d=j+(l*104|0)+12|0;o=+g[b+4>>2]*+g[d>>2];g[d>>2]=o;d=j+(l*104|0)+16|0;n=+g[b+8>>2]*+g[d>>2];g[d>>2]=n;d=j+(l*104|0)+24|0;g[d>>2]=+g[b>>2]*+g[d>>2];d=j+(l*104|0)+28|0;g[d>>2]=+g[b+4>>2]*+g[d>>2];d=j+(l*104|0)+32|0;g[d>>2]=+g[b+8>>2]*+g[d>>2];j=c[j+(l*104|0)+96>>2]|0;d=Kg(a+928|0,j)|0;a:do if(d){f=c[a+936>>2]|0;if((f|0)<=-1){d=c[a+928>>2]|0;break}if(f){h=0;while(1){e=c[d+32>>2]|0;h=h+1|0;if(!e)break a;if((h|0)>=(f|0)){d=e;break}else d=e}}}else d=0;while(0);g[j>>2]=m-k;g[j+4>>2]=o-k;g[j+8>>2]=n-k;g[j+12>>2]=0.0;g[j+16>>2]=k+m;g[j+20>>2]=k+o;g[j+24>>2]=k+n;g[j+28>>2]=0.0;We(a+928|0,d,j);l=l+1|0}while((l|0)!=(i|0))}gg(a);d=c[a+928>>2]|0;if(d){l=c[a+192>>2]|0;m=+zb[c[(c[l>>2]|0)+48>>2]&15](l);o=+g[d+4>>2]-m;n=+g[d+8>>2]-m;g[a+892>>2]=+g[d>>2]-m;g[a+896>>2]=o;g[a+900>>2]=n;g[a+904>>2]=0.0;n=m+ +g[d+20>>2];o=m+ +g[d+24>>2];g[a+908>>2]=m+ +g[d+16>>2];g[a+912>>2]=n;g[a+916>>2]=o;g[a+920>>2]=0.0;d=c[a+188>>2]|0;if(d|0){l=c[a+684>>2]|0;b=c[l+32>>2]|0;fb[c[(c[b>>2]|0)+16>>2]&31](b,d,a+892|0,a+908|0,c[l+36>>2]|0)}}else{c[a+892>>2]=0;c[a+892+4>>2]=0;c[a+892+8>>2]=0;c[a+892+12>>2]=0;c[a+892+16>>2]=0;c[a+892+20>>2]=0;c[a+892+24>>2]=0;c[a+892+28>>2]=0}e=c[a+732>>2]|0;if((e|0)<=0){Hf(a);return}f=c[a+740>>2]|0;d=0;do{b=c[f+(d*52|0)+8>>2]|0;l=c[f+(d*52|0)+12>>2]|0;m=+g[b+8>>2]-+g[l+8>>2];n=+g[b+12>>2]-+g[l+12>>2];o=+g[b+16>>2]-+g[l+16>>2];o=+C(+(m*m+n*n+o*o));g[f+(d*52|0)+16>>2]=o;g[f+(d*52|0)+28>>2]=o*o;d=d+1|0}while((d|0)!=(e|0));d=0;do{g[f+(d*52|0)+24>>2]=(+g[(c[f+(d*52|0)+8>>2]|0)+88>>2]+ +g[(c[f+(d*52|0)+12>>2]|0)+88>>2])/+g[(c[f+(d*52|0)+4>>2]|0)+4>>2];d=d+1|0}while((d|0)!=(e|0));Hf(a);return}function Ge(b,d,e,f){b=b|0;d=d|0;e=e|0;f=+f;var h=0,i=0,j=0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0,u=0.0,v=0.0,w=0.0,x=0,y=0.0,z=0.0,A=0,B=0;j=l;l=l+192|0;h=c[(c[b+4>>2]|0)+740>>2]|0;i=c[(c[b+8>>2]|0)+8>>2]|0;z=+g[e>>2];n=+g[d>>2]*f+z;y=+g[e+4>>2];m=+g[d+4>>2]*f+y;o=+g[e+8>>2];k=+g[d+8>>2]*f+o;x=c[(c[b+12>>2]|0)+8>>2]|0;t=(h|0)!=(i|0)?x:h;x=(h|0)!=(i|0)?i:x;w=n-+g[t+52>>2];v=m-+g[t+56>>2];u=k-+g[t+60>>2];s=w*+g[t+8>>2]+v*+g[t+24>>2]+u*+g[t+40>>2];r=w*+g[t+12>>2]+v*+g[t+28>>2]+u*+g[t+44>>2];z=z-+g[x+52>>2];y=y-+g[x+56>>2];o=o-+g[x+60>>2];q=z*+g[x+4>>2]+y*+g[x+20>>2]+o*+g[x+36>>2];p=z*+g[x+8>>2]+y*+g[x+24>>2]+o*+g[x+40>>2];o=z*+g[x+12>>2]+y*+g[x+28>>2]+o*+g[x+44>>2];g[j>>2]=w*+g[t+4>>2]+v*+g[t+20>>2]+u*+g[t+36>>2];g[j+4>>2]=s;g[j+8>>2]=r;g[j+12>>2]=0.0;g[j+16>>2]=q;g[j+20>>2]=p;g[j+24>>2]=o;g[j+28>>2]=0.0;c[j+64>>2]=c[d>>2];c[j+64+4>>2]=c[d+4>>2];c[j+64+8>>2]=c[d+8>>2];c[j+64+12>>2]=c[d+12>>2];g[j+80>>2]=f;g[j+84>>2]=0.0;g[j+88>>2]=0.0;g[j+92>>2]=0.0;c[j+112>>2]=0;a[j+116>>0]=0;c[j+120>>2]=0;c[j+120+4>>2]=0;c[j+120+8>>2]=0;c[j+120+12>>2]=0;c[j+120+16>>2]=0;c[j+120+20>>2]=0;c[j+120+24>>2]=0;c[j+120+28>>2]=0;g[j+48>>2]=n;g[j+52>>2]=m;g[j+56>>2]=k;g[j+60>>2]=0.0;c[j+32>>2]=c[e>>2];c[j+32+4>>2]=c[e+4>>2];c[j+32+8>>2]=c[e+8>>2];c[j+32+12>>2]=c[e+12>>2];d=c[b+16>>2]|0;e=c[b+20>>2]|0;if((h|0)!=(i|0)){c[j+96>>2]=e;A=b+28|0;t=d;d=e;x=b+24|0;e=c[A>>2]|0;A=j+100|0;c[A>>2]=t;A=j+104|0;c[A>>2]=e;x=c[x>>2]|0;A=j+108|0;c[A>>2]=x;A=(h|0)!=(i|0)?b+12|0:b+8|0;A=c[A>>2]|0;i=(h|0)!=(i|0)?b+8|0:b+12|0;i=c[i>>2]|0;b=b+32|0;b=c[b>>2]|0;h=c[b>>2]|0;h=h+12|0;h=c[h>>2]|0;+rb[h&1](b,j,A,d,e,i,t,x);l=j;return}else{c[j+96>>2]=d;B=b+24|0;x=e;A=b+28|0;e=c[B>>2]|0;B=j+100|0;c[B>>2]=x;B=j+104|0;c[B>>2]=e;A=c[A>>2]|0;B=j+108|0;c[B>>2]=A;B=(h|0)!=(i|0)?b+12|0:b+8|0;B=c[B>>2]|0;t=(h|0)!=(i|0)?b+8|0:b+12|0;t=c[t>>2]|0;b=b+32|0;b=c[b>>2]|0;i=c[b>>2]|0;i=i+12|0;i=c[i>>2]|0;+rb[i&1](b,j,B,d,e,t,x,A);l=j;return}}function He(a,b){a=a|0;b=b|0;var d=0.0,e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0;c[a+556>>2]=c[b>>2];c[a+556+4>>2]=c[b+4>>2];c[a+556+8>>2]=c[b+8>>2];c[a+556+12>>2]=c[b+12>>2];i=+g[a+568>>2];j=+g[a+560>>2];k=+g[a+564>>2];l=+g[a+556>>2];d=-l-j*0.0-k*0.0;e=(k+i*0.0-l*0.0)*-k+(i*(i+j*0.0-k*0.0)+d*-l)-(i*0.0+l*0.0-j)*-j;f=(i*0.0+l*0.0-j)*-l+(i*(k+i*0.0-l*0.0)+d*-j)-(i+j*0.0-k*0.0)*-k;d=(i+j*0.0-k*0.0)*-j+(d*-k+i*(i*0.0+l*0.0-j))-(k+i*0.0-l*0.0)*-l;if(d*0.0+(f*0.0+e)<-.9999998807907104){h=1.0;d=-0.0;e=0.0;f=0.0}else{r=+C(+((d*0.0+(f*0.0+e)+1.0)*2.0));h=(e*0.0-d)*(1.0/r);d=(d*0.0-f*0.0)*(1.0/r);e=(f-e*0.0)*(1.0/r);f=r*.5}m=1.0/+C(+(d*d+h*h+e*e+f*f));q=d*m;n=h*m;o=e*m;m=f*m;r=1.0/+C(+((m*i-l*-q-j*-n-k*-o)*(m*i-l*-q-j*-n-k*-o)+((i*-o+m*k+j*-q-l*-n)*(i*-o+m*k+j*-q-l*-n)+((l*m+i*-q+k*-n-j*-o)*(l*m+i*-q+k*-n-j*-o)+(l*-o+(i*-n+m*j)-k*-q)*(l*-o+(i*-n+m*j)-k*-q)))));h=(l*m+i*-q+k*-n-j*-o)*r;d=r*(l*-o+(i*-n+m*j)-k*-q);f=r*(i*-o+m*k+j*-q-l*-n);r=r*(m*i-l*-q-j*-n-k*-o);e=+g[a+444>>2];if(e>=.05000000074505806?(p=+g[a+448>>2],p>=.05000000074505806):0){j=m<-1.0?-1.0:m;j=+H(+(j>1.0?1.0:j))*2.0;if(j>1.1920928955078125e-07){i=1.0/+C(+(o*o+(q*q+n*n)));if(+B(+(n*i))>1.1920928955078125e-07){e=+C(+((o*i*o*i/(n*i*n*i)+1.0)/(1.0/(p*p)+o*i*o*i/(n*i*n*i)/(e*e))));k=q*i;l=n*i;i=o*i}else{k=q*i;l=n*i;i=o*i}}else{e=0.0;k=0.0;l=0.0;i=0.0}if(+B(+j)>1.1920928955078125e-07){if(!(j>e)){e=-e;if(!(j<e))e=j}m=e*.5;n=+F(+m)/+C(+(k*k+l*l+i*i));m=+E(+m);q=k*n;o=i*n;n=l*n}}l=+g[a+452>>2];if(l>=.05000000074505806){e=r<-1.0?-1.0:r;e=+H(+(e>1.0?1.0:e))*2.0;if(e>3.1415927410125732){e=-r<-1.0?-1.0:-r;i=-h;j=-d;k=-f;e=+H(+(e>1.0?1.0:e))*2.0}else{i=h;j=d;k=f}if(e>1.1920928955078125e-07){p=1.0/+C(+(i*i+j*j+k*k));i=i*p;j=j*p;k=k*p}if(+B(+e)>1.1920928955078125e-07){if(!(e>l))if(e<-l)d=-l;else d=e;else d=l;e=d*.5;d=+F(+e)/+C(+(k*k+(j*j+i*i)));h=i*d;f=k*d;e=+E(+e);d=j*d}else e=r}else e=r;g[a+556>>2]=n*f+(m*h+q*e)-o*d;g[a+560>>2]=o*h+(m*d+n*e)-q*f;g[a+564>>2]=q*d+(m*f+o*e)-n*h;g[a+568>>2]=m*e-q*h-n*d-o*f;return}function Ie(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0;h=l;l=l+48|0;c[b+8>>2]=0;g[b+12>>2]=0.0;c[b>>2]=7048;c[b+48>>2]=d;c[b+4>>2]=21;if(lb[c[(c[d>>2]|0)+40>>2]&127](d)|0)Rb[c[(c[d>>2]|0)+48>>2]&127](d,b+16|0,b+32|0);else{d=h+32+4|0;c[d>>2]=0;c[d+4>>2]=0;c[d+8>>2]=0;g[h+32>>2]=1.0;Rb[c[(c[b>>2]|0)+68>>2]&127](h+16|0,b,h+32|0);g[b+32>>2]=+g[h+16>>2]+ +g[b+12>>2];g[h+32>>2]=-1.0;Rb[c[(c[b>>2]|0)+68>>2]&127](h,b,h+32|0);c[h+16>>2]=c[h>>2];c[h+16+4>>2]=c[h+4>>2];c[h+16+8>>2]=c[h+8>>2];c[h+16+12>>2]=c[h+12>>2];g[b+16>>2]=+g[h+16>>2]-+g[b+12>>2];c[h+32>>2]=0;c[h+32+4>>2]=0;c[h+32+8>>2]=0;c[h+32+12>>2]=0;g[d>>2]=1.0;Rb[c[(c[b>>2]|0)+68>>2]&127](h+16|0,b,h+32|0);g[b+36>>2]=+g[h+16+4>>2]+ +g[b+12>>2];g[d>>2]=-1.0;Rb[c[(c[b>>2]|0)+68>>2]&127](h,b,h+32|0);c[h+16>>2]=c[h>>2];c[h+16+4>>2]=c[h+4>>2];c[h+16+8>>2]=c[h+8>>2];c[h+16+12>>2]=c[h+12>>2];g[b+20>>2]=+g[h+16+4>>2]-+g[b+12>>2];c[h+32>>2]=0;c[h+32+4>>2]=0;c[h+32+8>>2]=0;c[h+32+12>>2]=0;g[h+32+8>>2]=1.0;Rb[c[(c[b>>2]|0)+68>>2]&127](h+16|0,b,h+32|0);g[b+40>>2]=+g[h+16+8>>2]+ +g[b+12>>2];g[h+32+8>>2]=-1.0;Rb[c[(c[b>>2]|0)+68>>2]&127](h,b,h+32|0);c[h+16>>2]=c[h>>2];c[h+16+4>>2]=c[h+4>>2];c[h+16+8>>2]=c[h+8>>2];c[h+16+12>>2]=c[h+12>>2];g[b+24>>2]=+g[h+16+8>>2]-+g[b+12>>2]}c[b>>2]=6896;c[b+52>>2]=0;c[b+56>>2]=0;a[b+60>>0]=e&1;a[b+61>>0]=0;c[b+4>>2]=21;if(!f){l=h;return}c[6432]=(c[6432]|0)+1;f=ec(191)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}c[f+52>>2]=282;a[f+60>>0]=0;a[f+80>>0]=1;c[f+76>>2]=0;c[f+68>>2]=0;c[f+72>>2]=0;a[f+100>>0]=1;c[f+96>>2]=0;c[f+88>>2]=0;c[f+92>>2]=0;a[f+120>>0]=1;c[f+116>>2]=0;c[f+108>>2]=0;c[f+112>>2]=0;a[f+140>>0]=1;c[f+136>>2]=0;c[f+128>>2]=0;c[f+132>>2]=0;c[f+144>>2]=0;a[f+164>>0]=1;c[f+160>>2]=0;c[f+152>>2]=0;c[f+156>>2]=0;c[f+168>>2]=0;c[f+4>>2]=-8388609;c[f+8>>2]=-8388609;c[f+12>>2]=-8388609;g[f+16>>2]=0.0;c[f+20>>2]=2139095039;c[f+24>>2]=2139095039;c[f+28>>2]=2139095039;g[f+32>>2]=0.0;c[f>>2]=8104;c[b+52>>2]=f;Xc(f,c[b+48>>2]|0,(a[b+60>>0]|0)!=0,b+16|0,b+32|0);a[b+61>>0]=1;l=h;return}function Je(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;if(!b)if(!e){if(f|0){c[f>>2]=(a>>>0)%(d>>>0);c[f+4>>2]=0}e=0;f=(a>>>0)/(d>>>0)>>>0;return (z=e,f)|0}else{if(!f){e=0;f=0;return (z=e,f)|0}c[f>>2]=a|0;c[f+4>>2]=b&0;e=0;f=0;return (z=e,f)|0}do if(d){if(e|0){h=(R(e|0)|0)-(R(b|0)|0)|0;if(h>>>0<=31){n=h+1|0;i=a>>>((h+1|0)>>>0)&h-31>>31|b<<31-h;m=b>>>((h+1|0)>>>0)&h-31>>31;g=0;h=a<<31-h;break}if(!f){e=0;f=0;return (z=e,f)|0}c[f>>2]=a|0;c[f+4>>2]=b|b&0;e=0;f=0;return (z=e,f)|0}if(d-1&d|0){h=(R(d|0)|0)+33-(R(b|0)|0)|0;n=h;i=32-h-1>>31&b>>>((h-32|0)>>>0)|(b<<32-h|a>>>(h>>>0))&h-32>>31;m=h-32>>31&b>>>(h>>>0);g=a<<64-h&32-h>>31;h=(b<<64-h|a>>>((h-32|0)>>>0))&32-h>>31|a<<32-h&h-33>>31;break}if(f|0){c[f>>2]=d-1&a;c[f+4>>2]=0}if((d|0)==1){e=b|b&0;f=a|0|0;return (z=e,f)|0}else{f=yp(d|0)|0;e=b>>>(f>>>0)|0;f=b<<32-f|a>>>(f>>>0)|0;return (z=e,f)|0}}else{if(!e){if(f|0){c[f>>2]=(b>>>0)%(d>>>0);c[f+4>>2]=0}e=0;f=(b>>>0)/(d>>>0)>>>0;return (z=e,f)|0}if(!a){if(f|0){c[f>>2]=0;c[f+4>>2]=(b>>>0)%(e>>>0)}d=0;f=(b>>>0)/(e>>>0)>>>0;return (z=d,f)|0}if(!(e-1&e)){if(f|0){c[f>>2]=a|0;c[f+4>>2]=e-1&b|b&0}d=0;f=b>>>((yp(e|0)|0)>>>0);return (z=d,f)|0}h=(R(e|0)|0)-(R(b|0)|0)|0;if(h>>>0<=30){n=h+1|0;i=b<<31-h|a>>>((h+1|0)>>>0);m=b>>>((h+1|0)>>>0);g=0;h=a<<31-h;break}if(!f){e=0;f=0;return (z=e,f)|0}c[f>>2]=a|0;c[f+4>>2]=b|b&0;e=0;f=0;return (z=e,f)|0}while(0);if(!n){j=h;b=m;a=0;h=0}else{k=xv(d|0|0,e|e&0|0,-1,-1)|0;l=z;j=h;b=m;a=n;h=0;do{p=j;j=g>>>31|j<<1;g=h|g<<1;p=i<<1|p>>>31|0;o=i>>>31|b<<1|0;St(k|0,l|0,p|0,o|0)|0;n=z;m=n>>31|((n|0)<0?-1:0)<<1;h=m&1;i=St(p|0,o|0,m&(d|0)|0,(((n|0)<0?-1:0)>>31|((n|0)<0?-1:0)<<1)&(e|e&0)|0)|0;b=z;a=a-1|0}while((a|0)!=0);a=0}if(f|0){c[f>>2]=i;c[f+4>>2]=b}o=(g|0)>>>31|j<<1|(0<<1|g>>>31)&0|a;p=(g<<1|0>>>31)&-2|h;return (z=o,p)|0}function Ke(a,b,f){a=a|0;b=b|0;f=f|0;var i=0,j=0,k=0.0,m=0.0,n=0.0,o=0,p=0,q=0,r=0,s=0,t=0.0;s=l;l=l+32|0;p=c[a+4>>2]|0;Fb[c[(c[p>>2]|0)+16>>2]&3](p,s+28|0,s+24|0,s+20|0,s+16|0,s+12|0,s+8|0,s+4|0,s,b);p=c[s+12>>2]|0;q=O(c[s+8>>2]|0,f)|0;r=c[a+4>>2]|0;o=c[s>>2]|0;switch(o|0){case 3:{i=e[p+q+4>>1]|0;break}case 2:{i=c[p+q+8>>2]|0;break}default:i=d[p+(q+2)>>0]|0}j=c[s+28>>2]|0;i=O(c[s+16>>2]|0,i)|0;if(!(c[s+20>>2]|0)){m=+g[j+(i+8)>>2];n=+g[j+(i+4)>>2]*+g[r+8>>2];k=+g[j+i>>2]*+g[r+4>>2]}else{m=+h[j+(i+16)>>3];n=+h[j+(i+8)>>3]*+g[r+8>>2];k=+h[j+i>>3]*+g[r+4>>2]}m=m*+g[r+12>>2];g[a+44>>2]=k;g[a+48>>2]=n;g[a+52>>2]=m;g[a+56>>2]=0.0;switch(o|0){case 3:{i=e[p+q+2>>1]|0;break}case 2:{i=c[p+q+4>>2]|0;break}default:i=d[p+(q+1)>>0]|0}j=c[s+28>>2]|0;i=O(c[s+16>>2]|0,i)|0;if(!(c[s+20>>2]|0)){m=+g[j+(i+8)>>2];n=+g[j+(i+4)>>2]*+g[r+8>>2];k=+g[j+i>>2]*+g[r+4>>2]}else{m=+h[j+(i+16)>>3];n=+h[j+(i+8)>>3]*+g[r+8>>2];k=+h[j+i>>3]*+g[r+4>>2]}m=m*+g[r+12>>2];g[a+28>>2]=k;g[a+32>>2]=n;g[a+36>>2]=m;g[a+40>>2]=0.0;switch(o|0){case 3:{i=e[p+q>>1]|0;break}case 2:{i=c[p+q>>2]|0;break}default:i=d[p+q>>0]|0}j=c[s+28>>2]|0;i=O(c[s+16>>2]|0,i)|0;if(!(c[s+20>>2]|0)){m=+g[j+(i+4)>>2]*+g[r+8>>2];k=+g[j+i>>2]*+g[r+4>>2];t=+g[j+(i+8)>>2];n=+g[r+12>>2];n=t*n;q=a+12|0;g[q>>2]=k;q=a+16|0;g[q>>2]=m;q=a+20|0;g[q>>2]=n;q=a+24|0;g[q>>2]=0.0;q=a+8|0;q=c[q>>2]|0;p=c[q>>2]|0;p=p+8|0;p=c[p>>2]|0;r=a+12|0;Vb[p&127](q,r,b,f);a=c[a+4>>2]|0;f=c[a>>2]|0;f=f+24|0;f=c[f>>2]|0;jb[f&127](a,b);l=s;return}else{n=+h[j+(i+8)>>3]*+g[r+8>>2];m=+h[j+i>>3]*+g[r+4>>2];k=+h[j+(i+16)>>3];t=+g[r+12>>2];t=k*t;q=a+12|0;g[q>>2]=m;q=a+16|0;g[q>>2]=n;q=a+20|0;g[q>>2]=t;q=a+24|0;g[q>>2]=0.0;q=a+8|0;q=c[q>>2]|0;p=c[q>>2]|0;p=p+8|0;p=c[p>>2]|0;r=a+12|0;Vb[p&127](q,r,b,f);a=c[a+4>>2]|0;f=c[a>>2]|0;f=f+24|0;f=c[f>>2]|0;jb[f&127](a,b);l=s;return}}function Le(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,h=0.0,i=0.0,j=0,k=0,l=0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0;f=c[b+748>>2]|0;if((f|0)<=0)return;do{k=f;f=f+-1|0;q=+g[b+4+(f*184|0)>>2];r=+g[b+4+(f*184|0)+4>>2];h=+g[b+4+(f*184|0)+8>>2];p=q*+g[d>>2]+r*+g[d+4>>2]+h*+g[d+8>>2]+ +g[d+48>>2];n=q*+g[d+16>>2]+r*+g[d+20>>2]+h*+g[d+24>>2]+ +g[d+52>>2];h=q*+g[d+32>>2]+r*+g[d+36>>2]+h*+g[d+40>>2]+ +g[d+56>>2];g[b+4+(f*184|0)+48>>2]=p;g[b+4+(f*184|0)+52>>2]=n;g[b+4+(f*184|0)+56>>2]=h;g[b+4+(f*184|0)+60>>2]=0.0;r=+g[b+4+(f*184|0)+16>>2];q=+g[b+4+(f*184|0)+20>>2];i=+g[b+4+(f*184|0)+24>>2];o=r*+g[e>>2]+q*+g[e+4>>2]+i*+g[e+8>>2]+ +g[e+48>>2];m=r*+g[e+16>>2]+q*+g[e+20>>2]+i*+g[e+24>>2]+ +g[e+52>>2];i=r*+g[e+32>>2]+q*+g[e+36>>2]+i*+g[e+40>>2]+ +g[e+56>>2];g[b+4+(f*184|0)+32>>2]=o;g[b+4+(f*184|0)+36>>2]=m;g[b+4+(f*184|0)+40>>2]=i;g[b+4+(f*184|0)+44>>2]=0.0;g[b+4+(f*184|0)+80>>2]=(p-o)*+g[b+4+(f*184|0)+64>>2]+(n-m)*+g[b+4+(f*184|0)+68>>2]+(h-i)*+g[b+4+(f*184|0)+72>>2];j=b+4+(f*184|0)+148|0;c[j>>2]=(c[j>>2]|0)+1}while((k|0)>1);f=c[b+748>>2]|0;if((f|0)<=0)return;e=f;j=f;while(1){k=j;j=j+-1|0;d=b+4+(j*184|0)|0;h=+g[b+4+(j*184|0)+80>>2];i=+g[b+752>>2];if(!(h<=i)){f=e+-1|0;if((f|0)==(j|0)){f=e;l=12}else{Th(d|0,b+4+(f*184|0)|0,184)|0;c[b+4+(f*184|0)+112>>2]=0;g[b+4+(f*184|0)+120>>2]=0.0;a[b+4+(f*184|0)+116>>0]=0;g[b+4+(f*184|0)+124>>2]=0.0;g[b+4+(f*184|0)+128>>2]=0.0;c[b+4+(f*184|0)+148>>2]=0;f=c[b+748>>2]|0;l=12}}else{p=+g[b+4+(j*184|0)+32>>2]-(+g[b+4+(j*184|0)+48>>2]-+g[b+4+(j*184|0)+64>>2]*h);q=+g[b+4+(j*184|0)+36>>2]-(+g[b+4+(j*184|0)+52>>2]-h*+g[b+4+(j*184|0)+68>>2]);r=+g[b+4+(j*184|0)+40>>2]-(+g[b+4+(j*184|0)+56>>2]-h*+g[b+4+(j*184|0)+72>>2]);if(p*p+q*q+r*r>i*i){f=e+-1|0;if((f|0)==(j|0)){f=e;l=12}else{Th(d|0,b+4+(f*184|0)|0,184)|0;c[b+4+(f*184|0)+112>>2]=0;g[b+4+(f*184|0)+120>>2]=0.0;a[b+4+(f*184|0)+116>>0]=0;g[b+4+(f*184|0)+124>>2]=0.0;g[b+4+(f*184|0)+128>>2]=0.0;c[b+4+(f*184|0)+148>>2]=0;f=c[b+748>>2]|0;l=12}}else f=e}if((l|0)==12){l=0;f=f+-1|0;c[b+748>>2]=f}if((k|0)<=1)break;else e=f}return}function Me(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0.0,j=0.0,k=0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0;k=l;l=l+128|0;a=c[a+16>>2]|0;n=+g[a+892>>2];x=+g[a+896>>2];v=+g[a+900>>2];w=+g[a+908>>2];f=+g[a+912>>2];i=+g[a+916>>2];z=+g[b>>2];m=+g[b+4>>2];p=v*+g[b+8>>2];q=+g[b+16>>2];r=+g[b+20>>2];t=v*+g[b+24>>2];u=+g[b+32>>2];o=+g[b+36>>2];s=+g[b+40>>2];y=+g[b+48>>2];j=+g[b+52>>2];h=+g[b+56>>2];g[k>>2]=n*z+x*m+p+y;g[k+4>>2]=n*q+x*r+t+j;g[k+8>>2]=n*u+x*o+v*s+h;g[k+12>>2]=0.0;g[k+16>>2]=w*z+x*m+p+y;g[k+20>>2]=w*q+x*r+t+j;g[k+24>>2]=w*u+x*o+v*s+h;g[k+28>>2]=0.0;g[k+32>>2]=w*z+f*m+p+y;g[k+36>>2]=w*q+f*r+t+j;g[k+40>>2]=w*u+f*o+v*s+h;g[k+44>>2]=0.0;g[k+48>>2]=n*z+f*m+p+y;g[k+52>>2]=n*q+f*r+t+j;g[k+56>>2]=n*u+f*o+v*s+h;g[k+60>>2]=0.0;v=+g[b>>2];u=+g[b+4>>2];t=i*+g[b+8>>2];r=+g[b+16>>2];q=+g[b+20>>2];p=i*+g[b+24>>2];m=+g[b+32>>2];g[k+64>>2]=n*v+x*u+t+y;g[k+68>>2]=n*r+x*q+p+j;g[k+72>>2]=n*m+x*o+i*s+h;g[k+76>>2]=0.0;h=+g[b+36>>2];i=i*+g[b+40>>2];s=+g[b+48>>2];o=+g[b+52>>2];j=+g[b+56>>2];g[k+80>>2]=w*v+x*u+t+s;g[k+84>>2]=w*r+x*q+p+o;g[k+88>>2]=w*m+x*h+i+j;g[k+92>>2]=0.0;g[k+96>>2]=w*v+f*u+t+s;g[k+100>>2]=w*r+f*q+p+o;g[k+104>>2]=w*m+f*h+i+j;g[k+108>>2]=0.0;g[k+112>>2]=n*v+f*u+t+s;g[k+116>>2]=n*r+f*q+p+o;g[k+120>>2]=n*m+f*h+i+j;g[k+124>>2]=0.0;c[e>>2]=c[k>>2];c[e+4>>2]=c[k+4>>2];c[e+8>>2]=c[k+8>>2];c[e+12>>2]=c[k+12>>2];c[d>>2]=c[k>>2];c[d+4>>2]=c[k+4>>2];c[d+8>>2]=c[k+8>>2];c[d+12>>2]=c[k+12>>2];b=1;do{f=+g[k+(b<<4)>>2];if(f<+g[d>>2])g[d>>2]=f;h=+g[k+(b<<4)+4>>2];if(h<+g[d+4>>2])g[d+4>>2]=h;i=+g[k+(b<<4)+8>>2];if(i<+g[d+8>>2])g[d+8>>2]=i;j=+g[k+(b<<4)+12>>2];if(j<+g[d+12>>2])g[d+12>>2]=j;if(+g[e>>2]<f)g[e>>2]=f;if(+g[e+4>>2]<h)g[e+4>>2]=h;if(+g[e+8>>2]<i)g[e+8>>2]=i;if(+g[e+12>>2]<j)g[e+12>>2]=j;b=b+1|0}while((b|0)!=8);l=k;return}function Ne(b){b=b|0;var d=0,e=0,f=0,h=0,i=0,j=0,k=0,m=0,n=0,o=0,p=0;p=l;l=l+16|0;Yi(12231);j=c[b+204>>2]|0;Rb[c[(c[j>>2]|0)+8>>2]&127](j,b,c[b+24>>2]|0);j=c[b+308>>2]|0;if((j|0)>0){k=c[b+316>>2]|0;m=0;do{e=c[k+(m<<2)>>2]|0;d=c[e+740>>2]|0;e=c[e+744>>2]|0;if((d|0?(e|0?(c[d+204>>2]&3|0)==0:0):0)?(c[e+204>>2]&3|0)==0:0){f=c[d+208>>2]|0;d=c[e+208>>2]|0;i=c[(c[b+204>>2]|0)+16>>2]|0;e=c[i+(f<<3)>>2]|0;if((e|0)!=(f|0)){h=i+(f<<3)|0;do{f=i+(e<<3)|0;c[h>>2]=c[f>>2];f=c[f>>2]|0;h=i+(f<<3)|0;e=c[h>>2]|0}while((f|0)!=(e|0))}e=c[i+(d<<3)>>2]|0;if((e|0)!=(d|0)){h=i+(d<<3)|0;do{d=i+(e<<3)|0;c[h>>2]=c[d>>2];d=c[d>>2]|0;h=i+(d<<3)|0;e=c[h>>2]|0}while((d|0)!=(e|0))}if((f|0)!=(d|0)){c[i+(f<<3)>>2]=d;h=i+(d<<3)+4|0;c[h>>2]=(c[h>>2]|0)+(c[i+(f<<3)+4>>2]|0)}}m=m+1|0}while((m|0)!=(j|0))}k=c[b+212>>2]|0;if((k|0)>0){j=c[b+220>>2]|0;m=0;do{d=c[j+(m<<2)>>2]|0;if((a[d+20>>0]|0?(o=c[d+28>>2]|0,(c[o+204>>2]&3|0)==0):0)?(n=c[d+32>>2]|0,(c[n+204>>2]&3|0)==0):0){f=c[o+208>>2]|0;d=c[n+208>>2]|0;i=c[(c[b+204>>2]|0)+16>>2]|0;e=c[i+(f<<3)>>2]|0;if((e|0)!=(f|0)){h=i+(f<<3)|0;do{f=i+(e<<3)|0;c[h>>2]=c[f>>2];f=c[f>>2]|0;h=i+(f<<3)|0;e=c[h>>2]|0}while((f|0)!=(e|0))}e=c[i+(d<<3)>>2]|0;if((e|0)!=(d|0)){h=i+(d<<3)|0;do{d=i+(e<<3)|0;c[h>>2]=c[d>>2];d=c[d>>2]|0;h=i+(d<<3)|0;e=c[h>>2]|0}while((d|0)!=(e|0))}if((f|0)!=(d|0)){c[i+(f<<3)>>2]=d;h=i+(d<<3)+4|0;c[h>>2]=(c[h>>2]|0)+(c[i+(f<<3)+4>>2]|0)}}m=m+1|0}while((m|0)!=(k|0))}d=c[b+204>>2]|0;jb[c[(c[d>>2]|0)+12>>2]&127](d,b);d=c[2395]|0;b=(c[d+16>>2]|0)+-1|0;c[d+16>>2]=b;if(b|0){l=p;return}do if(c[d+4>>2]|0){Va(p|0,0)|0;b=c[6431]|0;g[d+8>>2]=+g[d+8>>2]+ +(((c[p+4>>2]|0)-(c[b+4>>2]|0)+(((c[p>>2]|0)-(c[b>>2]|0)|0)*1e6|0)-(c[d+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[d+16>>2]|0)){d=c[2395]|0;break}else{l=p;return}}while(0);c[2395]=c[d+20>>2];l=p;return}function Oe(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0,j=0,k=0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0;j=l;l=l+64|0;k=(a[b+8>>0]|0)!=0;i=k?e:d;e=k?d:e;d=c[e+4>>2]|0;if(((c[d+4>>2]|0)+-21|0)>>>0>=9){l=j;return}if((c[(c[i+4>>2]|0)+4>>2]|0)>=20){l=j;return}m=+zb[c[(c[d>>2]|0)+48>>2]&15](d);c[h+4>>2]=c[b+76>>2];c[b+16>>2]=i;c[b+20>>2]=e;c[b+64>>2]=f;g[b+68>>2]=m;c[b+56>>2]=h;k=c[e+12>>2]|0;B=+g[k>>2];A=+g[k+16>>2];z=+g[k+32>>2];y=+g[k+4>>2];x=+g[k+20>>2];w=+g[k+36>>2];s=+g[k+8>>2];q=+g[k+24>>2];o=+g[k+40>>2];v=-+g[k+48>>2];u=-+g[k+52>>2];t=-+g[k+56>>2];k=c[i+12>>2]|0;K=+g[k>>2];J=+g[k+16>>2];I=+g[k+32>>2];H=+g[k+4>>2];G=+g[k+20>>2];F=+g[k+36>>2];E=+g[k+8>>2];D=+g[k+24>>2];C=+g[k+40>>2];r=+g[k+48>>2];p=+g[k+52>>2];n=+g[k+56>>2];g[j>>2]=B*K+A*J+z*I;g[j+4>>2]=B*H+A*G+z*F;g[j+8>>2]=B*E+A*D+z*C;g[j+12>>2]=0.0;g[j+16>>2]=y*K+x*J+w*I;g[j+20>>2]=y*H+x*G+w*F;g[j+24>>2]=y*E+x*D+w*C;g[j+28>>2]=0.0;g[j+32>>2]=s*K+q*J+o*I;g[j+36>>2]=s*H+q*G+o*F;g[j+40>>2]=s*E+q*D+o*C;g[j+44>>2]=0.0;g[j+48>>2]=B*v+A*u+z*t+(B*r+A*p+z*n);g[j+52>>2]=y*v+x*u+w*t+(y*r+x*p+w*n);g[j+56>>2]=s*v+q*u+o*t+(s*r+q*p+o*n);g[j+60>>2]=0.0;k=c[(c[b+16>>2]|0)+4>>2]|0;Vb[c[(c[k>>2]|0)+8>>2]&127](k,j,b+24|0,b+40|0);g[b+40>>2]=+g[b+40>>2]+m;g[b+44>>2]=+g[b+44>>2]+m;g[b+48>>2]=+g[b+48>>2]+m;g[b+24>>2]=+g[b+24>>2]-m;g[b+28>>2]=+g[b+28>>2]-m;g[b+32>>2]=+g[b+32>>2]-m;k=c[b+76>>2]|0;e=c[e+8>>2]|0;c[k+740>>2]=c[i+8>>2];c[k+744>>2]=e;Vb[c[(c[d>>2]|0)+64>>2]&127](d,b+12|0,b+24|0,b+40|0);e=c[h+4>>2]|0;do if(c[e+748>>2]|0){i=c[e+740>>2]|0;f=c[(c[h+8>>2]|0)+8>>2]|0;d=c[(c[h+12>>2]|0)+8>>2]|0;if((i|0)==(f|0)){Le(e,i+4|0,d+4|0);break}else{Le(e,d+4|0,f+4|0);break}}while(0);c[b+16>>2]=0;c[b+20>>2]=0;l=j;return}function Pe(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0.0,i=0.0,j=0.0,k=0,m=0,n=0,o=0,p=0.0,q=0;o=l;l=l+128|0;h=+g[b>>2];i=+g[b+16>>2];p=h<i?h:i;j=+g[b+32>>2];if((p<j?p:j)>+g[a+28>>2]){l=o;return}m=h>i?b:b+16|0;if(+g[(+g[m>>2]>j?m:b+32|0)>>2]<+g[a+12>>2]){l=o;return}j=+g[b+8>>2];h=+g[b+24>>2];p=j<h?j:h;i=+g[b+40>>2];if((p<i?p:i)>+g[a+36>>2]){l=o;return}m=j>h?b+8|0:b+24|0;if(+g[(+g[m>>2]>i?m:b+40|0)>>2]<+g[a+20>>2]){l=o;return}h=+g[b+4>>2];i=+g[b+20>>2];p=h<i?h:i;j=+g[b+36>>2];if((p<j?p:j)>+g[a+32>>2]){l=o;return}m=h>i?b+4|0:b+20|0;if(+g[(+g[m>>2]>j?m:b+36|0)>>2]<+g[a+16>>2]){l=o;return}f=c[a+4>>2]|0;if((c[(c[f+4>>2]|0)+4>>2]|0)>=20){l=o;return}m=c[a+48>>2]|0;c[o+24+8>>2]=0;c[o+24+12>>2]=1065353216;c[o+24+16>>2]=1065353216;c[o+24+20>>2]=1065353216;g[o+24+24>>2]=0.0;c[o+24+52>>2]=0;c[o+24>>2]=3844;c[o+24+4>>2]=1;c[o+24+56>>2]=c[b>>2];c[o+24+56+4>>2]=c[b+4>>2];c[o+24+56+8>>2]=c[b+8>>2];c[o+24+56+12>>2]=c[b+12>>2];c[o+24+72>>2]=c[b+16>>2];c[o+24+72+4>>2]=c[b+16+4>>2];c[o+24+72+8>>2]=c[b+16+8>>2];c[o+24+72+12>>2]=c[b+16+12>>2];c[o+24+88>>2]=c[b+32>>2];c[o+24+88+4>>2]=c[b+32+4>>2];c[o+24+88+8>>2]=c[b+32+8>>2];c[o+24+88+12>>2]=c[b+32+12>>2];c[o+24+44>>2]=c[a+56>>2];q=c[a+8>>2]|0;b=c[q+8>>2]|0;k=c[q+12>>2]|0;c[o>>2]=q;c[o+4>>2]=o+24;c[o+8>>2]=b;c[o+12>>2]=k;c[o+16>>2]=d;c[o+20>>2]=e;k=pb[c[(c[m>>2]|0)+8>>2]&31](m,f,o,c[a+64>>2]|0)|0;b=c[a+44>>2]|0;f=c[b+8>>2]|0;if((c[f+8>>2]|0)==(c[(c[a+8>>2]|0)+8>>2]|0)){c[b+8>>2]=o;Rb[c[(c[b>>2]|0)+8>>2]&127](b,d,e)}else{f=c[b+12>>2]|0;c[b+12>>2]=o;Rb[c[(c[b>>2]|0)+12>>2]&127](b,d,e)}fb[c[(c[k>>2]|0)+8>>2]&31](k,c[a+4>>2]|0,o,c[a+52>>2]|0,c[a+44>>2]|0);q=c[a+44>>2]|0;c[((c[(c[q+8>>2]|0)+8>>2]|0)==(c[(c[a+8>>2]|0)+8>>2]|0)?q+8|0:q+12|0)>>2]=f;hb[c[c[k>>2]>>2]&511](k);jb[c[(c[m>>2]|0)+60>>2]&127](m,k);c[o+24>>2]=7248;f=c[o+24+52>>2]|0;if(f|0?(hb[c[c[f>>2]>>2]&511](f),n=c[o+24+52>>2]|0,n|0):0){c[6433]=(c[6433]|0)+1;Pc(c[n+-4>>2]|0)}l=o;return}function Qe(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0.0,r=0,s=0,t=0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0;if(!a)return;u=+g[b>>2];v=+g[b+4>>2];w=+g[b+8>>2];x=+g[b+16>>2];y=+g[b+20>>2];q=+g[b+24>>2];c[6432]=(c[6432]|0)+1;b=ec(275)|0;if(!b)b=0;else{c[(b+4+15&-16)+-4>>2]=b;b=b+4+15&-16}c[b>>2]=a;n=b;j=b;h=b;i=b;e=64;p=1;a=b;while(1){o=p+-1|0;m=c[a+(o<<2)>>2]|0;do if(((((+g[m>>2]<=x?+g[m+16>>2]>=u:0)?+g[m+4>>2]<=y:0)?+g[m+20>>2]>=v:0)?+g[m+8>>2]<=q:0)?+g[m+24>>2]>=w:0){if(!(c[m+40>>2]|0)){jb[c[(c[d>>2]|0)+12>>2]&127](d,m);b=n;f=o;break}l=c[m+36>>2]|0;do if((o|0)==(e|0)?(t=e|0?e<<1:1,(p|0)<=(t|0)):0){if((t|0)!=0?(c[6432]=(c[6432]|0)+1,s=ec((t<<2|3)+16|0)|0,(s|0)!=0):0){c[(s+4+15&-16)+-4>>2]=s;f=s+4+15&-16}else f=0;if((p|0)>1){b=0;do{c[f+(b<<2)>>2]=c[a+(b<<2)>>2];b=b+1|0}while((b|0)!=(e|0));if(!n){i=f;k=f;h=f;b=f;e=t;n=f;break}}else if((a|0)==0|(n|0)==0){i=f;k=f;h=f;b=f;e=t;n=f;break}c[6433]=(c[6433]|0)+1;Pc(c[n+-4>>2]|0);i=f;k=f;h=f;b=f;e=t;n=f}else{k=j;b=n;n=a}while(0);c[n+(o<<2)>>2]=l;j=c[m+40>>2]|0;do if((p|0)==(e|0)){e=p|0?p<<1:1;if((p|0)<(e|0)){if((e|0)!=0?(c[6432]=(c[6432]|0)+1,r=ec((e<<2|3)+16|0)|0,(r|0)!=0):0){c[(r+4+15&-16)+-4>>2]=r;a=r+4+15&-16}else a=0;if((p|0)>0){b=0;do{c[a+(b<<2)>>2]=c[n+(b<<2)>>2];b=b+1|0}while((b|0)!=(p|0));if(!i){f=a;h=a;i=a;b=a;break}}else if((n|0)==0|(i|0)==0){f=a;h=a;i=a;b=a;break}c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0);f=a;h=a;i=a;b=a}else{f=k;e=p;a=n}}else{f=k;a=n}while(0);c[a+(p<<2)>>2]=j;j=f;f=p+1|0}else{b=n;f=o}while(0);if((f|0)>0){n=b;p=f}else break}if((a|0)==0|(j|0)==0)return;c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0);return}function Re(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0.0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0;r=a[h+16>>0]&-16;a[h+16>>0]=r;t=+g[e>>2];u=+g[d>>2];w=+g[e+4>>2];x=+g[d+4>>2];n=+g[e+8>>2];o=+g[d+8>>2];p=+g[f>>2];q=+g[f+4>>2];s=+g[f+8>>2];l=+g[b>>2];m=+g[b+4>>2];i=+g[b+8>>2];y=(t-u)*(l-u)+(w-x)*(m-x)+(n-o)*(i-o);z=(p-u)*(l-u)+(q-x)*(m-x)+(s-o)*(i-o);do if(y<=0.0&z<=0.0){c[h>>2]=c[d>>2];c[h+4>>2]=c[d+4>>2];c[h+8>>2]=c[d+8>>2];c[h+12>>2]=c[d+12>>2];a[h+16>>0]=r|1;j=0.0;k=0.0;i=1.0}else{v=(t-u)*(l-t)+(w-x)*(m-w)+(n-o)*(i-n);k=(p-u)*(l-t)+(q-x)*(m-w)+(s-o)*(i-n);if(!(!(v>=0.0)|!(k<=v))){c[h>>2]=c[e>>2];c[h+4>>2]=c[e+4>>2];c[h+8>>2]=c[e+8>>2];c[h+12>>2]=c[e+12>>2];a[h+16>>0]=r|2;j=0.0;k=1.0;i=0.0;break}if(v<=0.0&(y>=0.0?y*k-v*z<=0.0:0)){g[h>>2]=u+(t-u)*(y/(y-v));g[h+4>>2]=x+(w-x)*(y/(y-v));g[h+8>>2]=o+(n-o)*(y/(y-v));g[h+12>>2]=0.0;a[h+16>>0]=r|3;j=0.0;k=y/(y-v);i=1.0-y/(y-v);break}j=(t-u)*(l-p)+(w-x)*(m-q)+(n-o)*(i-s);i=(p-u)*(l-p)+(q-x)*(m-q)+(s-o)*(i-s);if(!(!(i>=0.0)|!(j<=i))){c[h>>2]=c[f>>2];c[h+4>>2]=c[f+4>>2];c[h+8>>2]=c[f+8>>2];c[h+12>>2]=c[f+12>>2];a[h+16>>0]=r|4;j=1.0;k=0.0;i=0.0;break}if(i<=0.0&(z>=0.0?j*z-y*i<=0.0:0)){g[h>>2]=u+(p-u)*(z/(z-i));g[h+4>>2]=x+(q-x)*(z/(z-i));g[h+8>>2]=o+(s-o)*(z/(z-i));g[h+12>>2]=0.0;a[h+16>>0]=r|5;j=z/(z-i);k=0.0;i=1.0-z/(z-i);break}if((v*i-j*k<=0.0?k-v>=0.0:0)?j-i>=0.0:0){k=(k-v)/(k-v+(j-i));g[h>>2]=t+(p-t)*k;g[h+4>>2]=w+(q-w)*k;g[h+8>>2]=n+(s-n)*k;g[h+12>>2]=0.0;a[h+16>>0]=r|6;j=k;k=1.0-k;i=0.0;break}l=1.0/(y*k-v*z+(v*i-j*k+(j*z-y*i)));m=(j*z-y*i)*l;i=(y*k-v*z)*l;g[h>>2]=(p-u)*i+(u+(t-u)*m);g[h+4>>2]=(q-x)*i+(x+(w-x)*m);g[h+8>>2]=(s-o)*i+((n-o)*m+o);g[h+12>>2]=0.0;a[h+16>>0]=r|7;j=i;k=m;i=1.0-m-i}while(0);g[h+20>>2]=i;g[h+24>>2]=k;g[h+28>>2]=j;g[h+32>>2]=0.0;return}function Se(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0.0,i=0.0,j=0.0,k=0,m=0,n=0.0,o=0.0,p=0.0,q=0.0;f=l;l=l+256|0;Yi(11843);c[f+32>>2]=4188;k=f+32+36|0;c[k>>2]=c[b>>2];c[k+4>>2]=c[b+4>>2];c[k+8>>2]=c[b+8>>2];c[k+12>>2]=c[b+12>>2];m=f+32+52|0;c[m>>2]=c[d>>2];c[m+4>>2]=c[d+4>>2];c[m+8>>2]=c[d+8>>2];c[m+12>>2]=c[d+12>>2];c[f+32+212>>2]=a;c[f+32+216>>2]=e;c[f+32+68>>2]=1065353216;c[f+32+72>>2]=0;c[f+32+72+4>>2]=0;c[f+32+72+8>>2]=0;c[f+32+72+12>>2]=0;c[f+32+88>>2]=1065353216;c[f+32+92>>2]=0;c[f+32+92+4>>2]=0;c[f+32+92+8>>2]=0;c[f+32+92+12>>2]=0;c[f+32+108>>2]=1065353216;c[f+32+112>>2]=0;c[f+32+116>>2]=c[k>>2];c[f+32+116+4>>2]=c[k+4>>2];c[f+32+116+8>>2]=c[k+8>>2];c[f+32+116+12>>2]=c[k+12>>2];c[f+32+132>>2]=1065353216;c[f+32+136>>2]=0;c[f+32+136+4>>2]=0;c[f+32+136+8>>2]=0;c[f+32+136+12>>2]=0;c[f+32+152>>2]=1065353216;c[f+32+156>>2]=0;c[f+32+156+4>>2]=0;c[f+32+156+8>>2]=0;c[f+32+156+12>>2]=0;c[f+32+172>>2]=1065353216;c[f+32+176>>2]=0;c[f+32+180>>2]=c[d>>2];c[f+32+180+4>>2]=c[d+4>>2];c[f+32+180+8>>2]=c[d+8>>2];c[f+32+180+12>>2]=c[d+12>>2];n=+g[d>>2]-+g[b>>2];j=+g[d+4>>2]-+g[b+4>>2];i=+g[d+8>>2]-+g[b+8>>2];h=1.0/+C(+(n*n+j*j+i*i));q=n*h==0.0?1000000015047466219876688.0e6:1.0/(n*h);g[f+32+4>>2]=q;p=j*h==0.0?1000000015047466219876688.0e6:1.0/(j*h);g[f+32+8>>2]=p;o=i*h==0.0?1000000015047466219876688.0e6:1.0/(i*h);g[f+32+12>>2]=o;c[f+32+20>>2]=q<0.0&1;c[f+32+24>>2]=p<0.0&1;c[f+32+28>>2]=o<0.0&1;g[f+32+32>>2]=n*h*(+g[m>>2]-+g[k>>2])+j*h*(+g[f+32+56>>2]-+g[f+32+40>>2])+i*h*(+g[f+32+60>>2]-+g[f+32+44>>2]);a=c[a+68>>2]|0;e=c[(c[a>>2]|0)+24>>2]|0;c[f+16>>2]=0;c[f+16+4>>2]=0;c[f+16+8>>2]=0;c[f+16+12>>2]=0;c[f>>2]=0;c[f+4>>2]=0;c[f+8>>2]=0;c[f+12>>2]=0;xb[e&7](a,b,d,f+32|0,f+16|0,f);b=c[2395]|0;a=(c[b+16>>2]|0)+-1|0;c[b+16>>2]=a;if(a|0){l=f;return}do if(c[b+4>>2]|0){Va(f+32|0,0)|0;m=c[6431]|0;g[b+8>>2]=+g[b+8>>2]+ +(((c[f+32+4>>2]|0)-(c[m+4>>2]|0)+(((c[f+32>>2]|0)-(c[m>>2]|0)|0)*1e6|0)-(c[b+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[b+16>>2]|0)){b=c[2395]|0;break}else{l=f;return}}while(0);c[2395]=c[b+20>>2];l=f;return}function Te(b,d){b=b|0;d=+d;var e=0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0,r=0,s=0,t=0.0;s=l;l=l+16|0;Yi(12336);e=c[b+232>>2]|0;if((e|0)>0){r=0;do{q=c[(c[b+240>>2]|0)+(r<<2)>>2]|0;if(!(c[q+204>>2]&3)){n=+g[q+444>>2];f=+D(+(1.0-n),+d);i=f*+g[q+312>>2];g[q+312>>2]=i;h=f*+g[q+316>>2];g[q+316>>2]=h;f=f*+g[q+320>>2];g[q+320>>2]=f;p=+g[q+448>>2];m=+D(+(1.0-p),+d);j=m*+g[q+328>>2];g[q+328>>2]=j;k=m*+g[q+332>>2];g[q+332>>2]=k;m=m*+g[q+336>>2];g[q+336>>2]=m;do if(a[q+452>>0]|0){if(m*m+(j*j+k*k)<+g[q+464>>2]?i*i+h*h+f*f<+g[q+460>>2]:0){t=+g[q+456>>2];g[q+328>>2]=j*t;g[q+332>>2]=t*k;g[q+336>>2]=t*m;g[q+312>>2]=t*i;g[q+316>>2]=t*h;g[q+320>>2]=t*f;i=t*i;h=t*h;f=t*f;o=j*t;k=t*k;m=t*m}else o=j;j=+C(+(i*i+h*h+f*f));do if(j<n)if(j>.004999999888241291){i=i-i*(1.0/j)*.004999999888241291;g[q+312>>2]=i;h=h-h*(1.0/j)*.004999999888241291;g[q+316>>2]=h;f=f-f*(1.0/j)*.004999999888241291;g[q+320>>2]=f;break}else{c[q+312>>2]=0;c[q+312+4>>2]=0;c[q+312+8>>2]=0;c[q+312+12>>2]=0;i=0.0;h=0.0;f=0.0;break}while(0);j=+C(+(o*o+k*k+m*m));if(j<p)if(j>.004999999888241291){g[q+328>>2]=o-o*(1.0/j)*.004999999888241291;g[q+332>>2]=k-k*(1.0/j)*.004999999888241291;g[q+336>>2]=m-m*(1.0/j)*.004999999888241291;break}else{c[q+328>>2]=0;c[q+328+4>>2]=0;c[q+328+8>>2]=0;c[q+328+12>>2]=0;break}}while(0);Cg(q+4|0,i,h,f,q+328|0,d,q+68|0);e=c[b+232>>2]|0}r=r+1|0}while((r|0)<(e|0))}e=c[2395]|0;b=(c[e+16>>2]|0)+-1|0;c[e+16>>2]=b;if(b|0){l=s;return}do if(c[e+4>>2]|0){Va(s|0,0)|0;b=c[6431]|0;g[e+8>>2]=+g[e+8>>2]+ +(((c[s+4>>2]|0)-(c[b+4>>2]|0)+(((c[s>>2]|0)-(c[b>>2]|0)|0)*1e6|0)-(c[e+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[e+16>>2]|0)){e=c[2395]|0;break}else{l=s;return}}while(0);c[2395]=c[e+20>>2];l=s;return}function Ue(b,d){b=b|0;d=d|0;var e=0,f=0;e=c[b>>2]|0;do if((e|0)>3)if(!(a[d>>0]&8)){c[b>>2]=e+-1;f=b+4+(e+-1<<4)|0;c[b+52>>2]=c[f>>2];c[b+52+4>>2]=c[f+4>>2];c[b+52+8>>2]=c[f+8>>2];c[b+52+12>>2]=c[f+12>>2];f=b+84+(e+-1<<4)|0;c[b+132>>2]=c[f>>2];c[b+132+4>>2]=c[f+4>>2];c[b+132+8>>2]=c[f+8>>2];c[b+132+12>>2]=c[f+12>>2];f=b+164+(e+-1<<4)|0;c[b+212>>2]=c[f>>2];c[b+212+4>>2]=c[f+4>>2];c[b+212+8>>2]=c[f+8>>2];c[b+212+12>>2]=c[f+12>>2];e=e+-1|0;f=6}else f=6;else{if((e|0)==3){e=3;f=6;break}if((e|0)>1){e=2;f=10;break}if((e|0)==1){e=1;break}else return}while(0);if((f|0)==6)if(!(a[d>>0]&4)){e=e+-1|0;c[b>>2]=e;c[b+36>>2]=c[b+4+(e<<4)>>2];c[b+36+4>>2]=c[b+4+(e<<4)+4>>2];c[b+36+8>>2]=c[b+4+(e<<4)+8>>2];c[b+36+12>>2]=c[b+4+(e<<4)+12>>2];c[b+116>>2]=c[b+84+(e<<4)>>2];c[b+116+4>>2]=c[b+84+(e<<4)+4>>2];c[b+116+8>>2]=c[b+84+(e<<4)+8>>2];c[b+116+12>>2]=c[b+84+(e<<4)+12>>2];c[b+196>>2]=c[b+164+(e<<4)>>2];c[b+196+4>>2]=c[b+164+(e<<4)+4>>2];c[b+196+8>>2]=c[b+164+(e<<4)+8>>2];c[b+196+12>>2]=c[b+164+(e<<4)+12>>2];f=10}else f=10;if((f|0)==10)if(!(a[d>>0]&2)){e=e+-1|0;c[b>>2]=e;c[b+20>>2]=c[b+4+(e<<4)>>2];c[b+20+4>>2]=c[b+4+(e<<4)+4>>2];c[b+20+8>>2]=c[b+4+(e<<4)+8>>2];c[b+20+12>>2]=c[b+4+(e<<4)+12>>2];c[b+100>>2]=c[b+84+(e<<4)>>2];c[b+100+4>>2]=c[b+84+(e<<4)+4>>2];c[b+100+8>>2]=c[b+84+(e<<4)+8>>2];c[b+100+12>>2]=c[b+84+(e<<4)+12>>2];c[b+180>>2]=c[b+164+(e<<4)>>2];c[b+180+4>>2]=c[b+164+(e<<4)+4>>2];c[b+180+8>>2]=c[b+164+(e<<4)+8>>2];c[b+180+12>>2]=c[b+164+(e<<4)+12>>2]}if(a[d>>0]&1)return;f=e+-1|0;c[b>>2]=f;c[b+4>>2]=c[b+4+(f<<4)>>2];c[b+4+4>>2]=c[b+4+(f<<4)+4>>2];c[b+4+8>>2]=c[b+4+(f<<4)+8>>2];c[b+4+12>>2]=c[b+4+(f<<4)+12>>2];c[b+84>>2]=c[b+84+(f<<4)>>2];c[b+84+4>>2]=c[b+84+(f<<4)+4>>2];c[b+84+8>>2]=c[b+84+(f<<4)+8>>2];c[b+84+12>>2]=c[b+84+(f<<4)+12>>2];c[b+164>>2]=c[b+164+(f<<4)>>2];c[b+164+4>>2]=c[b+164+(f<<4)+4>>2];c[b+164+8>>2]=c[b+164+(f<<4)+8>>2];c[b+164+12>>2]=c[b+164+(f<<4)+12>>2];return}function Ve(b){b=b|0;var d=0,e=0;c[b>>2]=5348;if(a[b+20>>0]|0){d=c[b+16>>2]|0;e=c[d+16>>2]|0;if(e){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0);d=c[b+16>>2]|0}if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}}if(a[b+12>>0]|0){d=c[b+8>>2]|0;e=c[d+16>>2]|0;if(e){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0);d=c[b+8>>2]|0}if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}}d=c[b+32>>2]|0;hb[c[c[d>>2]>>2]&511](d);d=c[b+32>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+36>>2]|0;hb[c[c[d>>2]>>2]&511](d);d=c[b+36>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+40>>2]|0;hb[c[c[d>>2]>>2]&511](d);d=c[b+40>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+44>>2]|0;hb[c[c[d>>2]>>2]&511](d);d=c[b+44>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+48>>2]|0;hb[c[c[d>>2]>>2]&511](d);d=c[b+48>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+52>>2]|0;hb[c[c[d>>2]>>2]&511](d);d=c[b+52>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+56>>2]|0;hb[c[c[d>>2]>>2]&511](d);d=c[b+56>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+60>>2]|0;hb[c[c[d>>2]>>2]&511](d);d=c[b+60>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+76>>2]|0;hb[c[c[d>>2]>>2]&511](d);d=c[b+76>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+80>>2]|0;hb[c[c[d>>2]>>2]&511](d);d=c[b+80>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+72>>2]|0;hb[c[c[d>>2]>>2]&511](d);d=c[b+72>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+88>>2]|0;hb[c[c[d>>2]>>2]&511](d);d=c[b+88>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+84>>2]|0;hb[c[c[d>>2]>>2]&511](d);d=c[b+84>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+24>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}d=c[b+28>>2]|0;hb[c[c[d>>2]>>2]&511](d);d=c[b+28>>2]|0;if(!d)return;c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0);return}function We(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0,p=0,q=0.0;if(!(c[a>>2]|0)){c[a>>2]=d;c[d+32>>2]=0;return}e=c[b+40>>2]|0;if(!e)o=b;else{k=+g[d>>2]+ +g[d+16>>2];i=+g[d+4>>2]+ +g[d+20>>2];j=+g[d+8>>2]+ +g[d+24>>2];do{p=c[b+36>>2]|0;n=+B(+(k-(+g[p>>2]+ +g[p+16>>2])))+ +B(+(i-(+g[p+4>>2]+ +g[p+20>>2])))+ +B(+(j-(+g[p+8>>2]+ +g[p+24>>2])));b=c[b+36+((!(n<+B(+(k-(+g[e>>2]+ +g[e+16>>2])))+ +B(+(i-(+g[e+4>>2]+ +g[e+20>>2])))+ +B(+(j-(+g[e+8>>2]+ +g[e+24>>2]))))&1)<<2)>>2]|0;e=c[b+40>>2]|0}while((e|0)!=0);o=b}p=o+32|0;e=c[p>>2]|0;b=c[a+4>>2]|0;if(!b){c[6432]=(c[6432]|0)+1;b=ec(63)|0;if(!b)b=0;else{c[(b+4+15&-16)+-4>>2]=b;b=b+4+15&-16}f=b;h=f+44|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0))}else c[a+4>>2]=0;c[b+32>>2]=e;c[b+36>>2]=0;f=b+40|0;c[f>>2]=0;q=+g[d>>2];n=+g[o>>2];n=q<n?q:n;g[b>>2]=n;q=+g[d+16>>2];k=+g[o+16>>2];k=q>k?q:k;g[b+16>>2]=k;q=+g[d+4>>2];m=+g[o+4>>2];m=q<m?q:m;g[b+4>>2]=m;q=+g[d+20>>2];j=+g[o+20>>2];j=q>j?q:j;g[b+20>>2]=j;q=+g[d+8>>2];l=+g[o+8>>2];l=q<l?q:l;g[b+8>>2]=l;q=+g[d+24>>2];i=+g[o+24>>2];i=q>i?q:i;g[b+24>>2]=i;if(!e){c[b+36>>2]=o;c[p>>2]=b;c[f>>2]=d;c[d+32>>2]=b;c[a>>2]=b;return}c[e+36+(((c[(c[p>>2]|0)+40>>2]|0)==(o|0)&1)<<2)>>2]=b;c[b+36>>2]=o;c[p>>2]=b;c[f>>2]=d;c[d+32>>2]=b;while(1){b=e+4|0;if(((((+g[e>>2]<=n?+g[b>>2]<=m:0)?+g[e+8>>2]<=l:0)?+g[e+16>>2]>=k:0)?+g[e+20>>2]>=j:0)?+g[e+24>>2]>=i:0){b=21;break}d=c[e+36>>2]|0;a=c[e+40>>2]|0;q=+g[d>>2];n=+g[a>>2];n=q<n?q:n;g[e>>2]=n;q=+g[d+16>>2];k=+g[a+16>>2];k=q>k?q:k;g[e+16>>2]=k;q=+g[d+4>>2];m=+g[a+4>>2];m=q<m?q:m;g[b>>2]=m;q=+g[d+20>>2];j=+g[a+20>>2];j=q>j?q:j;g[e+20>>2]=j;q=+g[d+8>>2];l=+g[a+8>>2];l=q<l?q:l;g[e+8>>2]=l;q=+g[d+24>>2];i=+g[a+24>>2];i=q>i?q:i;g[e+24>>2]=i;e=c[e+32>>2]|0;if(!e){b=21;break}}if((b|0)==21)return}function Xe(b,d,e,f,g){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0,i=0,j=0,k=0;a:do if(!(HB(b,c[d+8>>2]|0)|0)){if(!(HB(b,c[d>>2]|0)|0)){i=c[b+12>>2]|0;En(b+16|0,d,e,f,g);if((i|0)<=1)break;h=c[b+8>>2]|0;if((h&2|0)==0?(c[d+36>>2]|0)!=1:0){if(!(h&1)){h=b+24|0;while(1){if(a[d+54>>0]|0)break a;if((c[d+36>>2]|0)==1)break a;En(h,d,e,f,g);h=h+8|0;if(h>>>0>=(b+16+(i<<3)|0)>>>0)break a}}else h=b+24|0;while(1){if(a[d+54>>0]|0)break a;if((c[d+36>>2]|0)==1?(c[d+24>>2]|0)==1:0)break a;En(h,d,e,f,g);h=h+8|0;if(h>>>0>=(b+16+(i<<3)|0)>>>0)break a}}else h=b+24|0;while(1){if(a[d+54>>0]|0)break a;En(h,d,e,f,g);h=h+8|0;if(h>>>0>=(b+16+(i<<3)|0)>>>0)break a}}if((c[d+16>>2]|0)!=(e|0)?(c[d+20>>2]|0)!=(e|0):0){c[d+32>>2]=f;if((c[d+44>>2]|0)==4)break;f=b+16+(c[b+12>>2]<<3)|0;k=0;h=0;j=b+16|0;b:while(1){if(j>>>0>=f>>>0){i=18;break}a[d+52>>0]=0;a[d+53>>0]=0;nn(j,d,e,e,1,g);if(a[d+54>>0]|0){i=18;break}do if(a[d+53>>0]|0){if(!(a[d+52>>0]|0))if(!(c[b+8>>2]&1)){h=1;i=18;break b}else{i=k;h=1;break}if((c[d+24>>2]|0)==1){i=23;break b}if(!(c[b+8>>2]&2)){i=23;break b}else{i=1;h=1}}else i=k;while(0);k=i;j=j+8|0}do if((i|0)==18){if((!k?(c[d+20>>2]=e,c[d+40>>2]=(c[d+40>>2]|0)+1,(c[d+36>>2]|0)==1):0)?(c[d+24>>2]|0)==2:0){a[d+54>>0]=1;if(h){i=23;break}else{h=4;break}}if(h)i=23;else h=4}while(0);if((i|0)==23)h=3;c[d+44>>2]=h;break}if((f|0)==1)c[d+32>>2]=1}else rr(d,e,f);while(0);return}function Ye(a,b){a=a|0;b=b|0;var d=0,e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0,x=0,y=0.0,z=0.0,A=0.0,C=0.0,D=0.0;d=c[a+748>>2]|0;if((d|0)!=4){c[a+748>>2]=d+1;x=d;w=(x|0)>0;x=w?x:0;a=a+4+(x*184|0)|0;Th(a|0,b|0,184)|0;return x|0}y=+g[b+80>>2];v=+g[a+84>>2];u=v<y?v:y;t=+g[a+268>>2];s=t<u?t:u;r=+g[a+452>>2];w=+g[a+636>>2]<(r<s?r:s);d=w?3:r<s?2:t<u?1:(v<y^1)<<31>>31;y=+g[b>>2];if(d){e=+g[a+188>>2];f=+g[b+4>>2];h=+g[a+192>>2];m=+g[b+8>>2];l=+g[a+196>>2];p=+g[a+556>>2];q=+g[a+372>>2];r=+g[a+560>>2];o=+g[a+376>>2];s=+g[a+564>>2];k=+g[a+380>>2];i=((y-e)*(r-o)-(f-h)*(p-q))*((y-e)*(r-o)-(f-h)*(p-q))+(((f-h)*(s-k)-(m-l)*(r-o))*((f-h)*(s-k)-(m-l)*(r-o))+((m-l)*(p-q)-(y-e)*(s-k))*((m-l)*(p-q)-(y-e)*(s-k)));if((d|0)==1){v=+g[a+4>>2];j=+g[a+8>>2];n=+g[a+12>>2];t=e;u=h;e=s;h=0.0;x=7}else{t=e;u=h;x=6}}else{t=+g[a+188>>2];u=+g[a+192>>2];l=+g[a+196>>2];f=+g[b+4>>2];m=+g[b+8>>2];q=+g[a+372>>2];p=+g[a+556>>2];o=+g[a+376>>2];r=+g[a+560>>2];k=+g[a+380>>2];s=+g[a+564>>2];i=0.0;x=6}if((x|0)==6){e=+g[a+4>>2];j=+g[a+8>>2];C=f-j;n=+g[a+12>>2];z=m-n;v=p-q;A=r-o;h=s-k;h=((y-e)*A-C*v)*((y-e)*A-C*v)+((C*h-z*A)*(C*h-z*A)+(z*v-(y-e)*h)*(z*v-(y-e)*h));if((d|0)==2){s=e;r=t;p=u;e=0.0;x=8}else{v=e;e=s;x=7}}if((x|0)==7){C=y-v;D=f-j;z=m-n;A=p-t;s=r-u;e=e-l;e=(C*s-D*A)*(C*s-D*A)+((D*e-z*s)*(D*e-z*s)+(z*A-C*e)*(z*A-C*e));if(w)f=0.0;else{s=v;r=t;p=u;x=8}}if((x|0)==8){D=y-s;y=f-j;A=m-n;C=q-r;z=o-p;f=k-l;f=(D*z-y*C)*(D*z-y*C)+((y*f-A*z)*(y*f-A*z)+(A*C-D*f)*(A*C-D*f))}D=+B(+i);A=+B(+h);y=+B(+e);v=+B(+f);C=D>-999999984306749440.0?D:-999999984306749440.0;z=A>C?A:C;x=v>(y>z?y:z)?3:y>z?2:A>C?1:(D>-999999984306749440.0^1)<<31>>31;w=(x|0)>0;x=w?x:0;a=a+4+(x*184|0)|0;Th(a|0,b|0,184)|0;return x|0}function Ze(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;c[b+16>>2]=c[a+4>>2];c[b+20>>2]=c[a+8>>2];c[b+24>>2]=c[a+12>>2];c[b+28>>2]=c[a+16>>2];c[b+32>>2]=c[a+20>>2];c[b+36>>2]=c[a+24>>2];c[b+40>>2]=c[a+28>>2];c[b+44>>2]=c[a+32>>2];c[b+48>>2]=c[a+36>>2];c[b+52>>2]=c[a+40>>2];c[b+56>>2]=c[a+44>>2];c[b+60>>2]=c[a+48>>2];c[b+64>>2]=c[a+52>>2];c[b+68>>2]=c[a+56>>2];c[b+72>>2]=c[a+60>>2];c[b+76>>2]=c[a+64>>2];c[b+80>>2]=c[a+68>>2];c[b+84>>2]=c[a+72>>2];c[b+88>>2]=c[a+76>>2];c[b+92>>2]=c[a+80>>2];c[b+96>>2]=c[a+84>>2];c[b+100>>2]=c[a+88>>2];c[b+104>>2]=c[a+92>>2];c[b+108>>2]=c[a+96>>2];c[b+112>>2]=c[a+100>>2];c[b+116>>2]=c[a+104>>2];c[b+120>>2]=c[a+108>>2];c[b+124>>2]=c[a+112>>2];c[b+128>>2]=c[a+116>>2];c[b+132>>2]=c[a+120>>2];c[b+136>>2]=c[a+124>>2];c[b+140>>2]=c[a+128>>2];c[b+144>>2]=c[a+132>>2];c[b+148>>2]=c[a+136>>2];c[b+152>>2]=c[a+140>>2];c[b+156>>2]=c[a+144>>2];c[b+160>>2]=c[a+148>>2];c[b+164>>2]=c[a+152>>2];c[b+168>>2]=c[a+156>>2];c[b+172>>2]=c[a+160>>2];c[b+176>>2]=c[a+164>>2];c[b+180>>2]=c[a+168>>2];c[b+184>>2]=c[a+172>>2];c[b+188>>2]=c[a+176>>2];c[b+224>>2]=c[a+180>>2];c[b+192>>2]=c[a+184>>2];c[b>>2]=0;c[b+4>>2]=Gb[c[(c[d>>2]|0)+28>>2]&31](d,c[a+192>>2]|0)|0;c[b+8>>2]=0;c[b+228>>2]=c[a+204>>2];c[b+232>>2]=c[a+208>>2];c[b+236>>2]=c[a+212>>2];c[b+240>>2]=c[a+216>>2];c[b+196>>2]=c[a+220>>2];c[b+200>>2]=c[a+224>>2];c[b+204>>2]=c[a+232>>2];c[b+208>>2]=c[a+228>>2];c[b+244>>2]=c[a+236>>2];e=Gb[c[(c[d>>2]|0)+40>>2]&31](d,a)|0;f=Gb[c[(c[d>>2]|0)+28>>2]&31](d,e)|0;c[b+12>>2]=f;if(!f){d=a+244|0;d=c[d>>2]|0;f=b+212|0;c[f>>2]=d;f=a+248|0;f=c[f>>2]|0;d=b+216|0;c[d>>2]=f;d=a+252|0;d=c[d>>2]|0;f=b+220|0;c[f>>2]=d;a=a+256|0;a=c[a>>2]|0;f=b+248|0;c[f>>2]=a;return 13296}jb[c[(c[d>>2]|0)+48>>2]&127](d,e);d=a+244|0;d=c[d>>2]|0;f=b+212|0;c[f>>2]=d;f=a+248|0;f=c[f>>2]|0;d=b+216|0;c[d>>2]=f;d=a+252|0;d=c[d>>2]|0;f=b+220|0;c[f>>2]=d;a=a+256|0;a=c[a>>2]|0;f=b+248|0;c[f>>2]=a;return 13296}function _e(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0;q=c[b+9288>>2]|0;if(!q){c[b>>2]=5;b=0;return b|0}i=c[q+48>>2]|0;if(i|0)c[i+44>>2]=c[q+44>>2];i=c[q+44>>2]|0;if(i|0)c[i+48>>2]=c[q+48>>2];if((c[b+9288>>2]|0)==(q|0))c[b+9288>>2]=c[q+48>>2];c[b+9292>>2]=(c[b+9292>>2]|0)+-1;c[q+44>>2]=0;c[q+48>>2]=c[b+9280>>2];i=c[b+9280>>2]|0;if(i|0)c[i+44>>2]=q;c[b+9280>>2]=q;c[b+9284>>2]=(c[b+9284>>2]|0)+1;a[q+55>>0]=0;c[q+20>>2]=d;c[q+24>>2]=e;c[q+28>>2]=f;l=+g[d+16>>2];k=+g[e+16>>2]-l;p=+g[d+20>>2];o=+g[e+20>>2]-p;n=+g[d+24>>2];m=+g[e+24>>2]-n;l=+g[f+16>>2]-l;p=+g[f+20>>2]-p;n=+g[f+24>>2]-n;g[q>>2]=o*n-m*p;g[q+4>>2]=m*l-k*n;g[q+8>>2]=k*p-o*l;g[q+12>>2]=0.0;j=+C(+((o*n-m*p)*(o*n-m*p)+(m*l-k*n)*(m*l-k*n)+(k*p-o*l)*(k*p-o*l)));if(j>9.999999747378752e-05){if((!(Ik(o*n-m*p,m*l-k*n,k*p-o*l,+g[d+16>>2],+g[d+20>>2],+g[d+24>>2],+g[e+16>>2],+g[e+20>>2],+g[e+24>>2],q+16|0)|0)?!(Ik(+g[q>>2],+g[q+4>>2],+g[q+8>>2],+g[e+16>>2],+g[e+20>>2],+g[e+24>>2],+g[f+16>>2],+g[f+20>>2],+g[f+24>>2],q+16|0)|0):0)?!(Ik(+g[q>>2],+g[q+4>>2],+g[q+8>>2],+g[f+16>>2],+g[f+20>>2],+g[f+24>>2],+g[d+16>>2],+g[d+20>>2],+g[d+24>>2],q+16|0)|0):0)g[q+16>>2]=(+g[d+16>>2]*+g[q>>2]+ +g[d+20>>2]*+g[q+4>>2]+ +g[d+24>>2]*+g[q+8>>2])/j;g[q>>2]=1.0/j*+g[q>>2];g[q+4>>2]=1.0/j*+g[q+4>>2];g[q+8>>2]=1.0/j*+g[q+8>>2];if(h){b=q;return b|0}if(!(+g[q+16>>2]>=-9.999999747378752e-06))i=3;else{b=q;return b|0}}else i=2;c[b>>2]=i;i=c[q+48>>2]|0;if(i|0)c[i+44>>2]=c[q+44>>2];i=c[q+44>>2]|0;if(i|0)c[i+48>>2]=c[q+48>>2];if((c[b+9280>>2]|0)==(q|0))c[b+9280>>2]=c[q+48>>2];c[b+9284>>2]=(c[b+9284>>2]|0)+-1;c[q+44>>2]=0;c[q+48>>2]=c[b+9288>>2];i=c[b+9288>>2]|0;if(i|0)c[i+44>>2]=q;c[b+9288>>2]=q;c[b+9292>>2]=(c[b+9292>>2]|0)+1;b=0;return b|0}function $e(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,h=0,i=0,j=0,k=0,l=0,m=0;f=c[d+8>>2]|0;if((f|0)>0){h=c[d+16>>2]|0;j=0;e=0;do{i=c[h+(j<<2)>>2]|0;if(!(c[i+204>>2]&3)){c[i+208>>2]=e;e=e+1|0}c[i+212>>2]=-1;g[i+244>>2]=1.0;j=j+1|0}while((j|0)!=(f|0));j=e}else j=0;i=c[b+8>>2]|0;if((i|0)<(j|0)){if((c[b+12>>2]|0)<(j|0)){if(!j){f=i;h=0}else{c[6432]=(c[6432]|0)+1;e=ec((j<<3|3)+16|0)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}f=c[b+8>>2]|0;h=e}if((f|0)>0){e=0;do{m=(c[b+16>>2]|0)+(e<<3)|0;k=c[m+4>>2]|0;l=h+(e<<3)|0;c[l>>2]=c[m>>2];c[l+4>>2]=k;e=e+1|0}while((e|0)!=(f|0))}e=c[b+16>>2]|0;if(e|0){if(a[b+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}c[b+16>>2]=0}a[b+20>>0]=1;c[b+16>>2]=h;c[b+12>>2]=j;f=b+16|0}else f=b+16|0;e=i;do{m=(c[f>>2]|0)+(e<<3)|0;c[m>>2]=0;c[m+4>>2]=0;e=e+1|0}while((e|0)!=(j|0))}c[b+8>>2]=j;if((j|0)>0){e=c[b+16>>2]|0;f=0;do{c[e+(f<<3)>>2]=f;c[e+(f<<3)+4>>2]=1;f=f+1|0}while((f|0)!=(j|0))}e=c[d+68>>2]|0;e=lb[c[(c[e>>2]|0)+36>>2]&127](e)|0;l=lb[c[(c[e>>2]|0)+36>>2]&127](e)|0;if(!l)return;d=lb[c[(c[e>>2]|0)+20>>2]&127](e)|0;if((l|0)<=0)return;k=0;do{e=c[c[d+(k<<4)>>2]>>2]|0;f=c[c[d+(k<<4)+4>>2]>>2]|0;if((e|0?(f|0?(c[e+204>>2]&7|0)==0:0):0)?(c[f+204>>2]&7|0)==0:0){h=c[e+208>>2]|0;e=c[f+208>>2]|0;j=c[b+16>>2]|0;f=c[j+(h<<3)>>2]|0;if((f|0)!=(h|0)){i=j+(h<<3)|0;do{h=j+(f<<3)|0;c[i>>2]=c[h>>2];h=c[h>>2]|0;i=j+(h<<3)|0;f=c[i>>2]|0}while((h|0)!=(f|0))}f=c[j+(e<<3)>>2]|0;if((f|0)!=(e|0)){i=j+(e<<3)|0;do{e=j+(f<<3)|0;c[i>>2]=c[e>>2];e=c[e>>2]|0;i=j+(e<<3)|0;f=c[i>>2]|0}while((e|0)!=(f|0))}if((h|0)!=(e|0)){c[j+(h<<3)>>2]=e;m=j+(e<<3)+4|0;c[m>>2]=(c[m>>2]|0)+(c[j+(h<<3)+4>>2]|0)}}k=k+1|0}while((k|0)!=(l|0));return}function af(a,d,f){a=a|0;d=d|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;g=c[a+108>>2]|0;if(g|0)Rb[c[(c[g>>2]|0)+12>>2]&127](g,c[d+60>>2]|0,f);o=c[d+12>>2]|0;n=c[a+60>>2]|0;m=c[a+92>>2]|0;if(!(lb[c[(c[m>>2]|0)+56>>2]&127](m)|0)){m=c[a+92>>2]|0;Rb[c[(c[m>>2]|0)+16>>2]&127](m,n+((o&65535)<<6)|0,f)}k=e[a+56>>1]|0;g=c[a+60>>2]|0;b[g+54>>1]=(e[g+54>>1]|0)+65534;b[g+56>>1]=(e[g+56>>1]|0)+65534;b[g+58>>1]=(e[g+58>>1]|0)+65534;g=b[a+6>>1]|0;m=0;do{j=a+68+(m<<2)|0;l=c[j>>2]|0;f=e[n+((o&65535)<<6)+54+(m<<1)>>1]|0;b[l+(f<<2)>>1]=g;d=b[l+(f+1<<2)+2>>1]|0;if(!(d<<16>>16))h=l;else{i=(c[a+60>>2]|0)+((e[l+(f<<2)+2>>1]|0)<<6)+54+(m<<1)|0;h=l+(f<<2)|0;f=l+(f+1<<2)|0;while(1){g=b[f>>1]|0;if((e[h>>1]|0)<(g&65535))break;q=c[a+60>>2]|0;p=d&65535;g=(g&1)==0?q+(p<<6)+48+(m<<1)|0:q+(p<<6)+54+(m<<1)|0;b[g>>1]=(b[g>>1]|0)+-1<<16>>16;b[i>>1]=(b[i>>1]|0)+1<<16>>16;g=e[h>>1]|e[h+2>>1]<<16;p=e[f>>1]|e[f+2>>1]<<16;b[h>>1]=p;b[h+2>>1]=p>>>16;b[f>>1]=g;b[f+2>>1]=g>>>16;d=b[f+6>>1]|0;if(!(d<<16>>16))break;else{h=h+4|0;f=f+4|0}}g=b[a+6>>1]|0;h=c[j>>2]|0}f=e[n+((o&65535)<<6)+48+(m<<1)>>1]|0;b[l+(f<<2)>>1]=g;d=b[h+(f+1<<2)+2>>1]|0;if(d<<16>>16){j=(c[a+60>>2]|0)+((e[h+(f<<2)+2>>1]|0)<<6)+48+(m<<1)|0;i=h+(f<<2)|0;f=h+(f+1<<2)|0;while(1){g=b[f>>1]|0;if((e[i>>1]|0)<(g&65535))break;p=c[a+60>>2]|0;q=d&65535;q=(g&1)==0?p+(q<<6)+48+(m<<1)|0:p+(q<<6)+54+(m<<1)|0;b[q>>1]=(b[q>>1]|0)+-1<<16>>16;b[j>>1]=(b[j>>1]|0)+1<<16>>16;q=e[i>>1]|e[i+2>>1]<<16;p=e[f>>1]|e[f+2>>1]<<16;b[i>>1]=p;b[i+2>>1]=p>>>16;b[f>>1]=q;b[f+2>>1]=q>>>16;d=b[f+6>>1]|0;if(!(d<<16>>16))break;else{i=i+4|0;f=f+4|0}}g=b[a+6>>1]|0}b[l+((k<<1)+-1<<2)+2>>1]=0;b[l+((k<<1)+-1<<2)>>1]=g;m=m+1|0}while((m|0)!=3);b[(c[a+60>>2]|0)+((o&65535)<<6)+48>>1]=b[a+64>>1]|0;b[a+64>>1]=o;b[a+56>>1]=(b[a+56>>1]|0)+-1<<16>>16;return}function bf(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0;u=+g[b>>2];t=+g[b+4>>2];s=+g[b+8>>2];r=1.0/+C(+(u*u+t*t+s*s));y=+g[d>>2];x=+g[d+4>>2];w=+g[d+8>>2];v=1.0/+C(+(y*y+x*x+w*w));B=s*r*x*v-t*r*w*v;A=u*r*w*v-s*r*y*v;z=t*r*y*v-u*r*x*v;d=c[a+28>>2]|0;e=+g[d+4>>2];h=+g[d+20>>2];j=+g[d+36>>2];f=+g[d+8>>2];i=+g[d+24>>2];k=+g[d+40>>2];l=+g[d+12>>2];n=+g[d+28>>2];p=+g[d+44>>2];m=-+g[d+52>>2];o=-+g[d+56>>2];q=-+g[d+60>>2];g[a+48>>2]=z*j+(e*B+h*A);g[a+52>>2]=e*y*v+x*v*h+w*v*j;g[a+56>>2]=u*r*e+t*r*h+s*r*j;g[a+60>>2]=0.0;g[a+64>>2]=B*f+A*i+z*k;g[a+68>>2]=y*v*f+x*v*i+w*v*k;g[a+72>>2]=u*r*f+t*r*i+s*r*k;g[a+76>>2]=0.0;g[a+80>>2]=B*l+A*n+z*p;g[a+84>>2]=y*v*l+x*v*n+w*v*p;g[a+88>>2]=u*r*l+t*r*n+s*r*p;g[a+92>>2]=0.0;g[a+96>>2]=e*0.0+h*0.0+j*0.0+(e*m+h*o+j*q);g[a+100>>2]=f*0.0+i*0.0+k*0.0+(f*m+i*o+k*q);g[a+104>>2]=l*0.0+n*0.0+p*0.0+(l*m+n*o+p*q);g[a+108>>2]=0.0;d=c[a+32>>2]|0;q=+g[d+4>>2];p=+g[d+20>>2];o=+g[d+36>>2];n=+g[d+8>>2];m=+g[d+24>>2];l=+g[d+40>>2];k=+g[d+12>>2];i=+g[d+28>>2];f=+g[d+44>>2];j=-+g[d+52>>2];h=-+g[d+56>>2];e=-+g[d+60>>2];g[a+112>>2]=B*q+A*p+z*o;g[a+116>>2]=y*v*q+x*v*p+w*v*o;g[a+120>>2]=u*r*q+t*r*p+s*r*o;g[a+124>>2]=0.0;g[a+128>>2]=B*n+A*m+z*l;g[a+132>>2]=y*v*n+x*v*m+w*v*l;g[a+136>>2]=u*r*n+t*r*m+s*r*l;g[a+140>>2]=0.0;g[a+144>>2]=B*k+A*i+z*f;g[a+148>>2]=y*v*k+x*v*i+w*v*f;g[a+152>>2]=u*r*k+t*r*i+s*r*f;g[a+156>>2]=0.0;g[a+160>>2]=q*0.0+p*0.0+o*0.0+(q*j+p*h+o*e);g[a+164>>2]=n*0.0+m*0.0+l*0.0+(n*j+m*h+l*e);g[a+168>>2]=k*0.0+i*0.0+f*0.0+(k*j+i*h+f*e);g[a+172>>2]=0.0;_c(a,(c[a+28>>2]|0)+4|0,(c[a+32>>2]|0)+4|0);return}function cf(d,e,f){d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;c[6162]=(c[6162]|0)+1;g=c[d+24>>2]|0;if(!g){if(!((b[f+6>>1]&b[e+4>>1])<<16>>16)){d=0;return d|0}if(!((b[e+6>>1]&b[f+4>>1])<<16>>16)){d=0;return d|0}}else if(!(vb[c[(c[g>>2]|0)+8>>2]&63](g,e,f)|0)){d=0;return d|0}l=(c[e+12>>2]|0)>(c[f+12>>2]|0);m=l?f:e;h=c[m+12>>2]|0;l=l?e:f;e=c[l+12>>2]|0;k=((e<<16|h)+~((e<<16|h)<<15)>>10^(e<<16|h)+~((e<<16|h)<<15))*9|0;k=(k>>6^k)+~((k>>6^k)<<11)>>16^(k>>6^k)+~((k>>6^k)<<11);j=c[d+12>>2]|0;g=c[(c[d+44>>2]|0)+((k&j+-1)<<2)>>2]|0;a:do if((g|0)!=-1){f=c[d+16>>2]|0;while(1){if((c[(c[f+(g<<4)>>2]|0)+12>>2]|0)==(h|0)?(c[(c[f+(g<<4)+4>>2]|0)+12>>2]|0)==(e|0):0)break;g=c[(c[d+64>>2]|0)+(g<<2)>>2]|0;if((g|0)==-1)break a}g=f+(g<<4)|0;if(g|0){d=g;return d|0}}while(0);i=c[d+8>>2]|0;if((i|0)==(j|0)){g=j|0?j<<1:1;if((j|0)<(g|0)){if(!g){e=j;f=0}else{c[6432]=(c[6432]|0)+1;e=ec((g<<4|3)+16|0)|0;if(!e)f=0;else{c[(e+4+15&-16)+-4>>2]=e;f=e+4+15&-16}e=c[d+8>>2]|0}if((e|0)>0){h=0;do{n=c[d+16>>2]|0;c[f+(h<<4)>>2]=c[n+(h<<4)>>2];c[f+(h<<4)+4>>2]=c[n+(h<<4)+4>>2];c[f+(h<<4)+8>>2]=c[n+(h<<4)+8>>2];c[f+(h<<4)+12>>2]=c[n+(h<<4)+12>>2];h=h+1|0}while((h|0)!=(e|0))}h=c[d+16>>2]|0;if(h){if(a[d+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0);e=c[d+8>>2]|0}c[d+16>>2]=0}a[d+20>>0]=1;c[d+16>>2]=f;c[d+12>>2]=g}else{e=j;g=j}}else{e=i;g=j}c[d+8>>2]=e+1;f=c[d+16>>2]|0;e=c[d+72>>2]|0;if(e){vb[c[(c[e>>2]|0)+8>>2]&63](e,m,l)|0;g=c[d+12>>2]|0}if((j|0)<(g|0)){sf(d);g=(c[d+12>>2]|0)+-1&k}else g=k&j+-1;n=(c[m+12>>2]|0)<(c[l+12>>2]|0);c[f+(i<<4)>>2]=n?m:l;c[f+(i<<4)+4>>2]=n?l:m;c[f+(i<<4)+8>>2]=0;c[f+(i<<4)+8+4>>2]=0;n=(c[d+44>>2]|0)+(g<<2)|0;c[(c[d+64>>2]|0)+(i<<2)>>2]=c[n>>2];c[n>>2]=i;n=f+(i<<4)|0;return n|0}function df(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0,r=0.0,s=0,t=0.0,u=0.0,v=0.0,w=0,x=0;w=l;l=l+32|0;q=c[a+12>>2]|0;r=+g[q+(((e+d|0)/2|0)*24|0)>>2];t=+g[q+(((e+d|0)/2|0)*24|0)+4>>2];u=+g[q+(((e+d|0)/2|0)*24|0)+8>>2];v=+g[q+(((e+d|0)/2|0)*24|0)+16>>2];s=c[q+(((e+d|0)/2|0)*24|0)+20>>2]|0;f=d;h=e;while(1){m=+g[b>>2];n=+g[b+4>>2];o=+g[b+8>>2];p=(r-m)*(r-m)+(t-n)*(t-n)+(u-o)*(u-o);a:while(1){i=+g[q+(f*24|0)+16>>2];do if(i!=v){if(!(i<v))break a}else{i=+g[q+(f*24|0)>>2]-m;k=+g[q+(f*24|0)+4>>2]-n;j=+g[q+(f*24|0)+8>>2]-o;if(i*i+k*k+j*j!=p)if(i*i+k*k+j*j<p)break;else break a;else if((c[q+(f*24|0)+20>>2]|0)<(s|0))break;else break a}while(0);f=f+1|0}b:while(1){i=+g[q+(h*24|0)+16>>2];do if(v!=i){if(!(v<i))break b}else{i=+g[q+(h*24|0)>>2]-m;k=+g[q+(h*24|0)+4>>2]-n;j=+g[q+(h*24|0)+8>>2]-o;if(p!=i*i+k*k+j*j)if(p<i*i+k*k+j*j)break;else break b;else if((s|0)<(c[q+(h*24|0)+20>>2]|0))break;else break b}while(0);h=h+-1|0}if((f|0)<=(h|0)){x=q+(f*24|0)|0;c[w>>2]=c[x>>2];c[w+4>>2]=c[x+4>>2];c[w+8>>2]=c[x+8>>2];c[w+12>>2]=c[x+12>>2];c[w+16>>2]=c[x+16>>2];c[w+20>>2]=c[x+20>>2];q=q+(h*24|0)|0;c[x>>2]=c[q>>2];c[x+4>>2]=c[q+4>>2];c[x+8>>2]=c[q+8>>2];c[x+12>>2]=c[q+12>>2];c[x+16>>2]=c[q+16>>2];c[x+20>>2]=c[q+20>>2];q=(c[a+12>>2]|0)+(h*24|0)|0;c[q>>2]=c[w>>2];c[q+4>>2]=c[w+4>>2];c[q+8>>2]=c[w+8>>2];c[q+12>>2]=c[w+12>>2];c[q+16>>2]=c[w+16>>2];c[q+20>>2]=c[w+20>>2];f=f+1|0;h=h+-1|0}if((f|0)>(h|0))break;q=c[a+12>>2]|0}if((h|0)>(d|0))df(a,b,d,h);if((f|0)>=(e|0)){l=w;return}df(a,b,f,e);l=w;return}function ef(a,b){a=a|0;b=b|0;var d=0.0,e=0,f=0.0,h=0,i=0,j=0,k=0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0;j=c[a+28>>2]|0;k=c[a+32>>2]|0;e=c[b+8>>2]|0;g[e>>2]=1.0;h=c[b+24>>2]|0;g[e+(h+1<<2)>>2]=1.0;g[e+((h<<1)+2<<2)>>2]=1.0;l=+g[a+300>>2];q=+g[a+304>>2];f=+g[a+308>>2];o=+g[j+4>>2]*l+ +g[j+8>>2]*q+ +g[j+12>>2]*f;m=l*+g[j+20>>2]+q*+g[j+24>>2]+f*+g[j+28>>2];f=l*+g[j+36>>2]+q*+g[j+40>>2]+f*+g[j+44>>2];e=c[b+12>>2]|0;c[e>>2]=0;g[e+4>>2]=f;g[e+8>>2]=-m;g[e+12>>2]=0.0;g[e+(h<<2)>>2]=-f;c[e+(h<<2)+4>>2]=0;g[e+(h<<2)+8>>2]=o;g[e+(h<<2)+12>>2]=0.0;g[e+(h<<1<<2)>>2]=m;g[e+(h<<1<<2)+4>>2]=-o;c[e+(h<<1<<2)+8>>2]=0;g[e+(h<<1<<2)+12>>2]=0.0;e=c[b+16>>2]|0;g[e>>2]=-1.0;g[e+(h+1<<2)>>2]=-1.0;g[e+((h<<1)+2<<2)>>2]=-1.0;q=+g[a+316>>2];l=+g[a+320>>2];d=+g[a+324>>2];p=+g[k+4>>2]*q+ +g[k+8>>2]*l+ +g[k+12>>2]*d;n=q*+g[k+20>>2]+l*+g[k+24>>2]+d*+g[k+28>>2];d=q*+g[k+36>>2]+l*+g[k+40>>2]+d*+g[k+44>>2];h=c[b+20>>2]|0;e=c[b+24>>2]|0;c[h>>2]=0;g[h+4>>2]=-d;g[h+8>>2]=n;g[h+12>>2]=0.0;g[h+(e<<2)>>2]=d;c[h+(e<<2)+4>>2]=0;g[h+(e<<2)+8>>2]=-p;g[h+(e<<2)+12>>2]=0.0;g[h+(e<<1<<2)>>2]=-n;g[h+(e<<1<<2)+4>>2]=p;c[h+(e<<1<<2)+8>>2]=0;g[h+(e<<1<<2)+12>>2]=0.0;h=c[a+332>>2]|0;l=+g[(h&1|0?a+336|0:b+4|0)>>2]*+g[b>>2];i=c[b+28>>2]|0;g[i>>2]=l*(p+ +g[k+52>>2]-o-+g[j+52>>2]);g[i+(e<<2)>>2]=l*(n+ +g[k+56>>2]-m-+g[j+56>>2]);g[i+(e<<1<<2)>>2]=l*(d+ +g[k+60>>2]-f-+g[j+60>>2]);if(h&2|0){k=c[b+32>>2]|0;c[k>>2]=c[a+340>>2];c[k+(e<<2)>>2]=c[a+340>>2];c[k+(e<<1<<2)>>2]=c[a+340>>2]}f=+g[a+356>>2];if(f>0.0){g[c[b+36>>2]>>2]=-f;g[c[b+40>>2]>>2]=f;d=+g[a+356>>2]}else d=f;if(d>0.0){g[(c[b+36>>2]|0)+(e<<2)>>2]=-f;g[(c[b+40>>2]|0)+(e<<2)>>2]=f;d=+g[a+356>>2]}if(!(d>0.0)){j=a+352|0;j=c[j>>2]|0;k=b+52|0;c[k>>2]=j;return}g[(c[b+36>>2]|0)+(e<<1<<2)>>2]=-f;g[(c[b+40>>2]|0)+(e<<1<<2)>>2]=f;j=a+352|0;j=c[j>>2]|0;k=b+52|0;c[k>>2]=j;return}function ff(a,b,d){a=a|0;b=b|0;d=d|0;var f=0,i=0.0,j=0.0,k=0.0,m=0,n=0,o=0,p=0,q=0,r=0,s=0.0;r=l;l=l+80|0;n=c[a+4>>2]|0;Fb[c[(c[n>>2]|0)+16>>2]&3](n,r+28|0,r+24|0,r+20|0,r+16|0,r+12|0,r+8|0,r+4|0,r,b);n=(c[r+12>>2]|0)+(O(c[r+8>>2]|0,d)|0)|0;q=c[a+4>>2]|0;m=(c[r>>2]|0)==3;o=(c[r+20>>2]|0)==0;p=c[r+28>>2]|0;if(m)f=e[n+4>>1]|0;else f=c[n+8>>2]|0;f=O(c[r+16>>2]|0,f)|0;if(o){j=+g[p+(f+8)>>2];k=+g[p+(f+4)>>2]*+g[q+8>>2];i=+g[p+f>>2]*+g[q+4>>2]}else{j=+h[p+(f+16)>>3];k=+h[p+(f+8)>>3]*+g[q+8>>2];i=+h[p+f>>3]*+g[q+4>>2]}j=j*+g[q+12>>2];g[r+32+32>>2]=i;g[r+32+36>>2]=k;g[r+32+40>>2]=j;g[r+32+44>>2]=0.0;if(m)f=e[n+2>>1]|0;else f=c[n+4>>2]|0;f=O(c[r+16>>2]|0,f)|0;if(o){j=+g[p+(f+8)>>2];k=+g[p+(f+4)>>2]*+g[q+8>>2];i=+g[p+f>>2]*+g[q+4>>2]}else{j=+h[p+(f+16)>>3];k=+h[p+(f+8)>>3]*+g[q+8>>2];i=+h[p+f>>3]*+g[q+4>>2]}j=j*+g[q+12>>2];g[r+32+16>>2]=i;g[r+32+20>>2]=k;g[r+32+24>>2]=j;g[r+32+28>>2]=0.0;if(m)f=e[n>>1]|0;else f=c[n>>2]|0;f=O(c[r+16>>2]|0,f)|0;if(o){j=+g[p+(f+4)>>2]*+g[q+8>>2];i=+g[p+f>>2]*+g[q+4>>2];s=+g[p+(f+8)>>2];k=+g[q+12>>2];k=s*k;g[r+32>>2]=i;q=r+32+4|0;g[q>>2]=j;q=r+32+8|0;g[q>>2]=k;q=r+32+12|0;g[q>>2]=0.0;q=a+8|0;q=c[q>>2]|0;p=c[q>>2]|0;p=p+8|0;p=c[p>>2]|0;Vb[p&127](q,r+32|0,b,d);a=c[a+4>>2]|0;d=c[a>>2]|0;d=d+24|0;d=c[d>>2]|0;jb[d&127](a,b);l=r;return}else{k=+h[p+(f+8)>>3]*+g[q+8>>2];j=+h[p+f>>3]*+g[q+4>>2];i=+h[p+(f+16)>>3];s=+g[q+12>>2];s=i*s;g[r+32>>2]=j;q=r+32+4|0;g[q>>2]=k;q=r+32+8|0;g[q>>2]=s;q=r+32+12|0;g[q>>2]=0.0;q=a+8|0;q=c[q>>2]|0;p=c[q>>2]|0;p=p+8|0;p=c[p>>2]|0;Vb[p&127](q,r+32|0,b,d);a=c[a+4>>2]|0;d=c[a>>2]|0;d=d+24|0;d=c[d>>2]|0;jb[d&127](a,b);l=r;return}}function gf(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0.0,j=0,k=0,l=0,m=0.0,n=0.0,o=0.0,p=0,q=0.0,r=0.0,s=0.0,t=0,u=0.0,v=0.0,w=0.0,x=0,y=0.0,z=0.0,A=0,B=0.0,C=0,D=0.0,E=0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0.0,O=0.0,P=0.0;j=(a[b+28>>0]|0)!=0;C=j?e:d;j=j?d:e;d=c[b+12>>2]|0;if((d|0)<=0){B=1.0;return +B}l=(c[C+192>>2]|0)+24|0;m=+g[C+4>>2];y=+g[C+8>>2];z=+g[C+12>>2];A=c[C+16>>2]|0;B=+g[C+20>>2];n=+g[C+24>>2];o=+g[C+28>>2];p=c[C+32>>2]|0;q=+g[C+36>>2];r=+g[C+40>>2];s=+g[C+44>>2];t=c[C+48>>2]|0;u=+g[C+52>>2];v=+g[C+56>>2];w=+g[C+60>>2];x=c[C+64>>2]|0;e=c[C+260>>2]|0;i=1.0;k=0;do{E=c[l>>2]|0;P=+g[E+(k*80|0)>>2];O=+g[E+(k*80|0)+16>>2];N=+g[E+(k*80|0)+32>>2];M=+g[E+(k*80|0)+4>>2];L=+g[E+(k*80|0)+20>>2];K=+g[E+(k*80|0)+36>>2];J=+g[E+(k*80|0)+8>>2];I=+g[E+(k*80|0)+24>>2];H=+g[E+(k*80|0)+40>>2];G=+g[E+(k*80|0)+48>>2];F=+g[E+(k*80|0)+52>>2];D=+g[E+(k*80|0)+56>>2];c[C+260>>2]=e+1;g[C+4>>2]=m*P+y*O+z*N;g[C+8>>2]=m*M+y*L+z*K;g[C+12>>2]=m*J+y*I+z*H;g[C+16>>2]=0.0;g[C+20>>2]=B*P+n*O+o*N;g[C+24>>2]=B*M+n*L+o*K;g[C+28>>2]=B*J+n*I+o*H;g[C+32>>2]=0.0;g[C+36>>2]=q*P+r*O+s*N;g[C+40>>2]=q*M+r*L+s*K;g[C+44>>2]=q*J+r*I+s*H;g[C+48>>2]=0.0;g[C+52>>2]=u+(m*G+y*F+z*D);g[C+56>>2]=v+(B*G+n*F+o*D);g[C+60>>2]=w+(q*G+r*F+s*D);g[C+64>>2]=0.0;E=c[(c[b+20>>2]|0)+(k<<2)>>2]|0;D=+tb[c[(c[E>>2]|0)+12>>2]&15](E,C,j,f,h);i=D<i?D:i;e=(c[C+260>>2]|0)+1|0;c[C+260>>2]=e;g[C+4>>2]=m;g[C+8>>2]=y;g[C+12>>2]=z;c[C+16>>2]=A;g[C+20>>2]=B;g[C+24>>2]=n;g[C+28>>2]=o;c[C+32>>2]=p;g[C+36>>2]=q;g[C+40>>2]=r;g[C+44>>2]=s;c[C+48>>2]=t;g[C+52>>2]=u;g[C+56>>2]=v;g[C+60>>2]=w;c[C+64>>2]=x;k=k+1|0}while((k|0)!=(d|0));return +i}function hf(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0;i=gs()|0;c[i+4>>2]=7;c[i+8>>2]=-1;c[i+12>>2]=-1;g[i+16>>2]=3402823466385288598117041.0e14;a[i+20>>0]=1;a[i+21>>0]=0;c[i+24>>2]=-1;c[i+28>>2]=b;c[i+32>>2]=d;g[i+36>>2]=0.0;g[i+40>>2]=.30000001192092896;c[i+44>>2]=0;c[i>>2]=4724;a[i+48>>0]=0;c[i+52>>2]=c[e>>2];c[i+52+4>>2]=c[e+4>>2];c[i+52+8>>2]=c[e+8>>2];c[i+52+12>>2]=c[e+12>>2];c[i+68>>2]=c[e+16>>2];c[i+68+4>>2]=c[e+16+4>>2];c[i+68+8>>2]=c[e+16+8>>2];c[i+68+12>>2]=c[e+16+12>>2];c[i+84>>2]=c[e+32>>2];c[i+84+4>>2]=c[e+32+4>>2];c[i+84+8>>2]=c[e+32+8>>2];c[i+84+12>>2]=c[e+32+12>>2];c[i+100>>2]=c[e+48>>2];c[i+100+4>>2]=c[e+48+4>>2];c[i+100+8>>2]=c[e+48+8>>2];c[i+100+12>>2]=c[e+48+12>>2];c[i+116>>2]=c[f>>2];c[i+116+4>>2]=c[f+4>>2];c[i+116+8>>2]=c[f+8>>2];c[i+116+12>>2]=c[f+12>>2];c[i+132>>2]=c[f+16>>2];c[i+132+4>>2]=c[f+16+4>>2];c[i+132+8>>2]=c[f+16+8>>2];c[i+132+12>>2]=c[f+16+12>>2];c[i+148>>2]=c[f+32>>2];c[i+148+4>>2]=c[f+32+4>>2];c[i+148+8>>2]=c[f+32+8>>2];c[i+148+12>>2]=c[f+32+12>>2];c[i+164>>2]=c[f+48>>2];c[i+164+4>>2]=c[f+48+4>>2];c[i+164+8>>2]=c[f+48+8>>2];c[i+164+12>>2]=c[f+48+12>>2];a[i+180>>0]=h&1;g[i+184>>2]=1.0;g[i+188>>2]=-1.0;g[i+192>>2]=0.0;g[i+196>>2]=0.0;g[i+200>>2]=1.0;g[i+204>>2]=.699999988079071;g[i+208>>2]=0.0;g[i+212>>2]=0.0;g[i+216>>2]=1.0;g[i+220>>2]=.699999988079071;g[i+224>>2]=0.0;g[i+228>>2]=0.0;g[i+264>>2]=1.0;g[i+268>>2]=.699999988079071;g[i+272>>2]=1.0;g[i+276>>2]=0.0;g[i+280>>2]=1.0;g[i+284>>2]=.699999988079071;g[i+288>>2]=1.0;g[i+292>>2]=0.0;g[i+232>>2]=1.0;g[i+236>>2]=.699999988079071;g[i+240>>2]=1.0;g[i+244>>2]=0.0;g[i+248>>2]=1.0;g[i+252>>2]=.699999988079071;g[i+256>>2]=1.0;g[i+260>>2]=0.0;a[i+1096>>0]=0;g[i+1116>>2]=0.0;g[i+1120>>2]=0.0;g[i+1124>>2]=0.0;c[i+300>>2]=0;c[i+1100>>2]=0;c[i+1100+4>>2]=0;c[i+1100+8>>2]=0;a[i+1100+12>>0]=0;a[i+49>>0]=1;Qc(i,(c[i+28>>2]|0)+4|0,(c[i+32>>2]|0)+4|0);return i|0}function jf(b,d){b=b|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0.0,j=0,k=0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0;j=l;l=l+64|0;xg(c[b+116>>2]|0,d,0);e=+g[d+204>>2]+ +g[d+212>>2];h=e*+g[d+56>>2]+ +g[d+40>>2];i=e*+g[d+60>>2]+ +g[d+44>>2];g[d+16>>2]=+g[d+52>>2]*e+ +g[d+36>>2];g[d+20>>2]=h;g[d+24>>2]=i;g[d+28>>2]=0.0;g[j+32>>2]=-1.0;k=c[b+100>>2]|0;k=pb[c[(c[k>>2]|0)+8>>2]&31](k,d+36|0,d+16|0,j)|0;c[d+88>>2]=0;if(!k){c[d+32>>2]=c[d+204>>2];g[d+272>>2]=0.0;i=-+g[d+56>>2];h=-+g[d+60>>2];g[d>>2]=-+g[d+52>>2];g[d+4>>2]=i;g[d+8>>2]=h;g[d+12>>2]=0.0;h=1.0;i=-1.0;k=d+268|0;g[k>>2]=h;l=j;return +i}h=e*+g[j+32>>2];c[d>>2]=c[j+16>>2];c[d+4>>2]=c[j+16+4>>2];c[d+8>>2]=c[j+16+8>>2];c[d+12>>2]=c[j+16+12>>2];a[d+84>>0]=1;if((a[22696]|0)==0?jy(22696)|0:0){c[j+40>>2]=0;c[j+40+4>>2]=0;c[j+40+8>>2]=0;c[j+40+12>>2]=0;_f(23876,0.0,0,0,j+40|0)}c[6020]=c[6020]|1;g[6055]=0.0;e=+g[6065]*0.0;f=+g[6066]*0.0;g[6060]=+g[6064]*0.0;g[6061]=e;g[6062]=f;g[6063]=0.0;c[6068]=0;c[6069]=0;c[6070]=0;c[6071]=0;f=+g[6057]*0.0;e=+g[6058]*0.0;g[6109]=+g[6056]*0.0;g[6110]=f;g[6111]=e;g[6112]=0.0;c[d+88>>2]=23876;e=h-+g[d+212>>2];g[d+32>>2]=e;f=+g[d+204>>2];i=+g[d+208>>2]*.009999999776482582;if(e<f-i){g[d+32>>2]=f-i;e=f-i}if(e>f+i)g[d+32>>2]=f+i;c[d+16>>2]=c[j>>2];c[d+16+4>>2]=c[j+4>>2];c[d+16+8>>2]=c[j+8>>2];c[d+16+12>>2]=c[j+12>>2];s=+g[d>>2];r=+g[d+4>>2];o=+g[d+8>>2];f=s*+g[d+52>>2]+r*+g[d+56>>2]+o*+g[d+60>>2];k=c[b+116>>2]|0;e=+g[d+16>>2]-+g[k+52>>2];n=+g[d+20>>2]-+g[k+56>>2];p=+g[d+24>>2]-+g[k+60>>2];i=+g[k+332>>2];q=+g[k+336>>2];m=+g[k+328>>2];g[d+272>>2]=!(f>=-.10000000149011612)?-1.0/f*(s*(i*p-n*q+ +g[k+312>>2])+r*(+g[k+316>>2]+(e*q-p*m))+o*(n*m-e*i+ +g[k+320>>2])):0.0;f=!(f>=-.10000000149011612)?-1.0/f:10.0;i=h;k=d+268|0;g[k>>2]=f;l=j;return +i}function kf(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,m=0,n=0,o=0,p=0,q=0;q=l;l=l+32|0;a[q+16>>0]=1;c[q+12>>2]=0;c[q+4>>2]=0;c[q+8>>2]=0;e=c[b+8>>2]|0;if((e|0)>0){h=0;f=0;i=0;o=0;g=0;do{m=c[b+16>>2]|0;n=m+(o<<4)|0;if((g|0)==(f|0)){k=f|0?f<<1:1;if((f|0)<(k|0)){if(k){c[6432]=(c[6432]|0)+1;e=ec((k<<4|3)+16|0)|0;if(!e){f=g;h=0}else{c[(e+4+15&-16)+-4>>2]=e;f=g;h=e+4+15&-16}}else h=0;if((f|0)>0){e=0;do{j=c[q+12>>2]|0;c[h+(e<<4)>>2]=c[j+(e<<4)>>2];c[h+(e<<4)+4>>2]=c[j+(e<<4)+4>>2];c[h+(e<<4)+8>>2]=c[j+(e<<4)+8>>2];c[h+(e<<4)+12>>2]=c[j+(e<<4)+12>>2];e=e+1|0}while((e|0)!=(f|0))}e=c[q+12>>2]|0;if(!e)g=f;else{c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0);c[q+12>>2]=0}c[q+12>>2]=h;j=g;e=c[b+8>>2]|0;f=k;i=k}else j=f}else j=g;c[h+(j<<4)>>2]=c[n>>2];c[h+(j<<4)+4>>2]=c[m+(o<<4)+4>>2];c[h+(j<<4)+8>>2]=c[m+(o<<4)+8>>2];c[h+(j<<4)+12>>2]=c[m+(o<<4)+12>>2];g=j+1|0;o=o+1|0}while((o|0)<(e|0));c[q+4>>2]=g;a[q+16>>0]=1;c[q+8>>2]=i;if((j|0)>-1){e=c[q+12>>2]|0;f=0;while(1){pb[c[(c[b>>2]|0)+12>>2]&31](b,c[e+(f<<4)>>2]|0,c[e+(f<<4)+4>>2]|0,d)|0;if((f|0)<(j|0))f=f+1|0;else break}}}else g=0;if((c[b+56>>2]|0)>0){e=c[b+64>>2]|0;f=0;do{c[e+(f<<2)>>2]=-1;f=f+1|0}while((f|0)<(c[b+56>>2]|0))}if((g|0)<=1)if((g|0)<=0){e=c[q+12>>2]|0;if(!e){l=q;return}}else p=23;else{Ee(q,0,g+-1|0);p=23}if((p|0)==23){e=c[q+12>>2]|0;f=0;do{vb[c[(c[b>>2]|0)+8>>2]&63](b,c[e+(f<<4)>>2]|0,c[e+(f<<4)+4>>2]|0)|0;f=f+1|0}while((f|0)<(g|0))}c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0);c[q+12>>2]=0;l=q;return}function lf(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,h=0,i=0.0,j=0.0,k=0,l=0,m=0.0;c[6135]=(c[6135]|0)+1;if(!(c[b+4>>2]&2))j=.019999999552965164;else{k=c[d+192>>2]|0;i=+Lb[c[(c[k>>2]|0)+20>>2]&1](k,.019999999552965164);k=c[e+192>>2]|0;j=+Lb[c[(c[k>>2]|0)+20>>2]&1](k,.019999999552965164);j=i<j?i:j}m=+g[d+184>>2];i=+g[e+184>>2];i=m<i?m:i;h=c[b+68>>2]|0;f=c[h+8>>2]|0;if(!f){if(c[b+4>>2]&4|0){b=0;return b|0}c[6432]=(c[6432]|0)+1;f=ec(791)|0;if(!f)k=0;else{c[(f+4+15&-16)+-4>>2]=f;k=f+4+15&-16}}else{k=c[h+12>>2]|0;c[h+12>>2]=c[k>>2];c[h+8>>2]=f+-1}c[k>>2]=1025;c[k+116>>2]=0;a[k+120>>0]=0;f=k+124|0;c[f>>2]=0;c[f+4>>2]=0;c[f+8>>2]=0;c[f+12>>2]=0;c[f+16>>2]=0;c[f+20>>2]=0;c[f+24>>2]=0;c[f+28>>2]=0;c[k+300>>2]=0;a[k+304>>0]=0;f=k+308|0;c[f>>2]=0;c[f+4>>2]=0;c[f+8>>2]=0;c[f+12>>2]=0;c[f+16>>2]=0;c[f+20>>2]=0;c[f+24>>2]=0;c[f+28>>2]=0;c[k+484>>2]=0;a[k+488>>0]=0;f=k+492|0;c[f>>2]=0;c[f+4>>2]=0;c[f+8>>2]=0;c[f+12>>2]=0;c[f+16>>2]=0;c[f+20>>2]=0;c[f+24>>2]=0;c[f+28>>2]=0;c[k+668>>2]=0;a[k+672>>0]=0;f=k+676|0;c[f>>2]=0;c[f+4>>2]=0;c[f+8>>2]=0;c[f+12>>2]=0;c[f+16>>2]=0;c[f+20>>2]=0;c[f+24>>2]=0;c[f+28>>2]=0;c[k+740>>2]=d;c[k+744>>2]=e;c[k+748>>2]=0;g[k+752>>2]=j;g[k+756>>2]=i;e=k;f=c[b+12>>2]|0;c[k+768>>2]=f;if((f|0)==(c[b+16>>2]|0)?(l=f|0?f<<1:1,(f|0)<(l|0)):0){if(!l)h=0;else{c[6432]=(c[6432]|0)+1;f=ec((l<<2|3)+16|0)|0;if(!f)h=0;else{c[(f+4+15&-16)+-4>>2]=f;h=f+4+15&-16}f=c[b+12>>2]|0}if((f|0)>0){d=0;do{c[h+(d<<2)>>2]=c[(c[b+20>>2]|0)+(d<<2)>>2];d=d+1|0}while((d|0)!=(f|0))}d=c[b+20>>2]|0;if(d){if(a[b+24>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0);f=c[b+12>>2]|0}c[b+20>>2]=0}a[b+24>>0]=1;c[b+20>>2]=h;c[b+16>>2]=l}c[(c[b+20>>2]|0)+(f<<2)>>2]=e;c[b+12>>2]=f+1;b=k;return b|0}function mf(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0;i=Or(460)|0;Ld(i,b,d,e);c[i>>2]=4e3;a[i+340>>0]=1;c[i+336>>2]=0;c[i+328>>2]=0;c[i+332>>2]=0;g[i+352>>2]=1.2000000476837158;g[i+356>>2]=0.0;g[i+360>>2]=0.0;g[i+364>>2]=1.0e3;c[i+368>>2]=0;c[i+368+4>>2]=0;c[i+368+8>>2]=0;c[i+368+12>>2]=0;c[i+368+16>>2]=0;c[i+368+20>>2]=0;c[i+368+24>>2]=0;c[i+396>>2]=-1054867456;c[i+400>>2]=0;g[i+404>>2]=0.0;a[i+424>>0]=1;c[i+420>>2]=0;c[i+412>>2]=0;c[i+416>>2]=0;c[i+452>>2]=h;a[i+456>>0]=0;if(!h){c[6432]=(c[6432]|0)+1;f=ec(59)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}g[f+12>>2]=1.0;c[f+8>>2]=0;c[f+4>>2]=5;c[f>>2]=3124;a[f+36>>0]=1;c[f+32>>2]=0;c[f+24>>2]=0;c[f+28>>2]=0;a[f+16>>0]=1;c[i+452>>2]=f;a[i+456>>0]=1}c[i+344>>2]=4302;a[i+348>>0]=1;a[i+349>>0]=0;a[i+350>>0]=0;c[i+384>>2]=d;c[i+388>>2]=b;ei(i+408|0);e=c[i+412>>2]|0;if((e|0)>0)h=0;else{d=i+428|0;g[d>>2]=.25;d=i+432|0;c[d>>2]=0;d=i+436|0;c[d>>2]=0;d=i+444|0;c[d>>2]=1;d=i+448|0;c[d>>2]=1;g[i+352>>2]=1.2000000476837158;g[i+356>>2]=0.0;g[i+360>>2]=0.0;d=i+392|0;c[d>>2]=0;c[i+368>>2]=0;c[i+368+4>>2]=0;c[i+368+8>>2]=0;c[i+368+12>>2]=0;c[i+396>>2]=-1054867456;c[i+400>>2]=0;g[i+404>>2]=0.0;ei(i+408|0);return i|0}do{d=(c[i+420>>2]|0)+(h<<2)|0;f=c[d>>2]|0;c[d>>2]=0;if(f|0)do{d=f;f=c[f+280>>2]|0;YG(d)}while((f|0)!=0);h=h+1|0}while((h|0)!=(e|0));d=i+428|0;g[d>>2]=.25;d=i+432|0;c[d>>2]=0;d=i+436|0;c[d>>2]=0;d=i+444|0;c[d>>2]=1;d=i+448|0;c[d>>2]=1;g[i+352>>2]=1.2000000476837158;g[i+356>>2]=0.0;g[i+360>>2]=0.0;d=i+392|0;c[d>>2]=0;c[i+368>>2]=0;c[i+368+4>>2]=0;c[i+368+8>>2]=0;c[i+368+12>>2]=0;c[i+396>>2]=-1054867456;c[i+400>>2]=0;g[i+404>>2]=0.0;ei(i+408|0);return i|0}function nf(a,b,e){a=a|0;b=b|0;e=e|0;Sh(a,b,e)|0;c[b+52>>2]=c[a+48>>2];c[b+56>>2]=c[a+52>>2];c[b+60>>2]=c[a+56>>2];c[b+64>>2]=c[a+60>>2];c[b+68>>2]=c[a+64>>2];c[b+72>>2]=c[a+68>>2];c[b+76>>2]=c[a+72>>2];c[b+80>>2]=c[a+76>>2];c[b+84>>2]=c[a+80>>2];c[b+88>>2]=c[a+84>>2];c[b+92>>2]=c[a+88>>2];c[b+96>>2]=c[a+92>>2];c[b+100>>2]=c[a+96>>2];c[b+104>>2]=c[a+100>>2];c[b+108>>2]=c[a+104>>2];c[b+112>>2]=c[a+108>>2];c[b+116>>2]=c[a+112>>2];c[b+120>>2]=c[a+116>>2];c[b+124>>2]=c[a+120>>2];c[b+128>>2]=c[a+124>>2];c[b+132>>2]=c[a+128>>2];c[b+136>>2]=c[a+132>>2];c[b+140>>2]=c[a+136>>2];c[b+144>>2]=c[a+140>>2];c[b+148>>2]=c[a+144>>2];c[b+152>>2]=c[a+148>>2];c[b+156>>2]=c[a+152>>2];c[b+160>>2]=c[a+156>>2];c[b+164>>2]=c[a+160>>2];c[b+168>>2]=c[a+164>>2];c[b+172>>2]=c[a+168>>2];c[b+176>>2]=c[a+172>>2];c[b+228>>2]=c[a+868>>2];c[b+212>>2]=c[a+872>>2];c[b+196>>2]=c[a+680>>2];c[b+180>>2]=c[a+696>>2];c[b+232>>2]=c[a+932>>2];c[b+216>>2]=c[a+936>>2];c[b+200>>2]=c[a+684>>2];c[b+184>>2]=c[a+700>>2];c[b+236>>2]=c[a+996>>2];c[b+220>>2]=c[a+1e3>>2];c[b+204>>2]=c[a+688>>2];c[b+188>>2]=c[a+704>>2];c[b+244>>2]=d[a+1300>>0];c[b+248>>2]=d[a+1301>>0];c[b+276>>2]=c[a+1316>>2];c[b+324>>2]=c[a+1364>>2];c[b+252>>2]=d[a+1309>>0];c[b+300>>2]=c[a+1340>>2];c[b+280>>2]=c[a+1320>>2];c[b+328>>2]=c[a+1368>>2];c[b+256>>2]=d[a+1310>>0];c[b+304>>2]=c[a+1344>>2];c[b+284>>2]=c[a+1324>>2];c[b+332>>2]=c[a+1372>>2];c[b+260>>2]=d[a+1311>>0];c[b+308>>2]=c[a+1348>>2];c[b+288>>2]=c[a+1328>>2];c[b+336>>2]=c[a+1376>>2];c[b+264>>2]=d[a+1312>>0];c[b+312>>2]=c[a+1352>>2];c[b+292>>2]=c[a+1332>>2];c[b+340>>2]=c[a+1380>>2];c[b+268>>2]=d[a+1313>>0];c[b+316>>2]=c[a+1356>>2];c[b+296>>2]=c[a+1336>>2];c[b+344>>2]=c[a+1384>>2];c[b+272>>2]=d[a+1314>>0];c[b+320>>2]=c[a+1360>>2];return 12651}function of(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;i=c[b+4>>2]|0;if((i|0)==(c[b+8>>2]|0)?(h=i|0?i<<1:1,(i|0)<(h|0)):0){if(!h){f=i;g=0}else{c[6432]=(c[6432]|0)+1;e=ec((h*244|3)+16|0)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}f=c[b+4>>2]|0;g=e}if((f|0)>0){e=0;do{k=g+(e*244|0)|0;j=c[b+12>>2]|0;l=j+(e*244|0)|0;c[k>>2]=c[l>>2];c[k+4>>2]=c[l+4>>2];c[k+8>>2]=c[l+8>>2];c[k+12>>2]=c[l+12>>2];k=j+(e*244|0)+16|0;l=g+(e*244|0)+16|0;c[l>>2]=c[k>>2];c[l+4>>2]=c[k+4>>2];c[l+8>>2]=c[k+8>>2];c[l+12>>2]=c[k+12>>2];l=j+(e*244|0)+32|0;k=g+(e*244|0)+32|0;c[k>>2]=c[l>>2];c[k+4>>2]=c[l+4>>2];c[k+8>>2]=c[l+8>>2];c[k+12>>2]=c[l+12>>2];k=g+(e*244|0)+48|0;l=j+(e*244|0)+48|0;c[k>>2]=c[l>>2];c[k+4>>2]=c[l+4>>2];c[k+8>>2]=c[l+8>>2];c[k+12>>2]=c[l+12>>2];Th(g+(e*244|0)+64|0,j+(e*244|0)+64|0,180)|0;e=e+1|0}while((e|0)!=(f|0))}e=c[b+12>>2]|0;if(e|0){if(a[b+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}c[b+12>>2]=0}a[b+16>>0]=1;c[b+12>>2]=g;c[b+8>>2]=h;e=c[b+4>>2]|0}else e=i;c[b+4>>2]=e+1;l=c[b+12>>2]|0;c[l+(i*244|0)>>2]=c[d>>2];c[l+(i*244|0)+4>>2]=c[d+4>>2];c[l+(i*244|0)+8>>2]=c[d+8>>2];c[l+(i*244|0)+12>>2]=c[d+12>>2];c[l+(i*244|0)+16>>2]=c[d+16>>2];c[l+(i*244|0)+16+4>>2]=c[d+16+4>>2];c[l+(i*244|0)+16+8>>2]=c[d+16+8>>2];c[l+(i*244|0)+16+12>>2]=c[d+16+12>>2];c[l+(i*244|0)+32>>2]=c[d+32>>2];c[l+(i*244|0)+32+4>>2]=c[d+32+4>>2];c[l+(i*244|0)+32+8>>2]=c[d+32+8>>2];c[l+(i*244|0)+32+12>>2]=c[d+32+12>>2];c[l+(i*244|0)+48>>2]=c[d+48>>2];c[l+(i*244|0)+48+4>>2]=c[d+48+4>>2];c[l+(i*244|0)+48+8>>2]=c[d+48+8>>2];c[l+(i*244|0)+48+12>>2]=c[d+48+12>>2];Th(l+(i*244|0)+64|0,d+64|0,180)|0;return (c[b+12>>2]|0)+(i*244|0)|0}function pf(a,b,e){a=a|0;b=b|0;e=e|0;var f=0.0,h=0.0,i=0.0,j=0;Sh(a,b,e)|0;c[b+52>>2]=c[a+552>>2];c[b+56>>2]=c[a+556>>2];c[b+60>>2]=c[a+560>>2];c[b+64>>2]=c[a+564>>2];c[b+68>>2]=c[a+568>>2];c[b+72>>2]=c[a+572>>2];c[b+76>>2]=c[a+576>>2];c[b+80>>2]=c[a+580>>2];c[b+84>>2]=c[a+584>>2];c[b+88>>2]=c[a+588>>2];c[b+92>>2]=c[a+592>>2];c[b+96>>2]=c[a+596>>2];c[b+100>>2]=c[a+600>>2];c[b+104>>2]=c[a+604>>2];c[b+108>>2]=c[a+608>>2];c[b+112>>2]=c[a+612>>2];c[b+116>>2]=c[a+616>>2];c[b+120>>2]=c[a+620>>2];c[b+124>>2]=c[a+624>>2];c[b+128>>2]=c[a+628>>2];c[b+132>>2]=c[a+632>>2];c[b+136>>2]=c[a+636>>2];c[b+140>>2]=c[a+640>>2];c[b+144>>2]=c[a+644>>2];c[b+148>>2]=c[a+648>>2];c[b+152>>2]=c[a+652>>2];c[b+156>>2]=c[a+656>>2];c[b+160>>2]=c[a+660>>2];c[b+164>>2]=c[a+664>>2];c[b+168>>2]=c[a+668>>2];c[b+172>>2]=c[a+672>>2];c[b+176>>2]=c[a+676>>2];c[b+184>>2]=d[a+736>>0];c[b+188>>2]=d[a+737>>0];c[b+196>>2]=c[a+684>>2];c[b+192>>2]=c[a+680>>2];c[b+180>>2]=d[a+740>>0];h=+g[a+688>>2];i=+g[a+692>>2];f=+Vg(h-i,6.2831854820251465);if(!(f<-3.1415927410125732)){if(f>3.1415927410125732)f=f+-6.2831854820251465}else f=f+6.2831854820251465;g[b+200>>2]=f;f=+Vg(h+i,6.2831854820251465);if(f<-3.1415927410125732){i=f+6.2831854820251465;e=b+204|0;g[e>>2]=i;e=a+696|0;e=c[e>>2]|0;j=b+208|0;c[j>>2]=e;j=a+700|0;j=c[j>>2]|0;e=b+212|0;c[e>>2]=j;e=a+704|0;e=c[e>>2]|0;a=b+216|0;c[a>>2]=e;return 12897}if(!(f>3.1415927410125732)){i=f;j=b+204|0;g[j>>2]=i;j=a+696|0;j=c[j>>2]|0;e=b+208|0;c[e>>2]=j;e=a+700|0;e=c[e>>2]|0;j=b+212|0;c[j>>2]=e;a=a+704|0;a=c[a>>2]|0;j=b+216|0;c[j>>2]=a;return 12897}i=f+-6.2831854820251465;j=b+204|0;g[j>>2]=i;j=a+696|0;j=c[j>>2]|0;e=b+208|0;c[e>>2]=j;e=a+700|0;e=c[e>>2]|0;j=b+212|0;c[j>>2]=e;a=a+704|0;a=c[a>>2]|0;j=b+216|0;c[j>>2]=a;return 12897}function qf(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;c[6161]=(c[6161]|0)+1;k=(c[b+12>>2]|0)>(c[d+12>>2]|0);n=k?d:b;h=c[n+12>>2]|0;k=k?b:d;f=c[k+12>>2]|0;j=((f<<16|h)+~((f<<16|h)<<15)>>10^(f<<16|h)+~((f<<16|h)<<15))*9|0;j=((j>>6^j)+~((j>>6^j)<<11)>>16^(j>>6^j)+~((j>>6^j)<<11))&(c[a+12>>2]|0)+-1;b=c[(c[a+44>>2]|0)+(j<<2)>>2]|0;if((b|0)==-1){a=0;return a|0}g=c[a+16>>2]|0;d=b;while(1){if((c[(c[g+(d<<4)>>2]|0)+12>>2]|0)==(h|0)?(c[(c[g+(d<<4)+4>>2]|0)+12>>2]|0)==(f|0):0)break;b=c[(c[a+64>>2]|0)+(d<<2)>>2]|0;if((b|0)==-1){b=0;i=22;break}else d=b}if((i|0)==22)return b|0;b=g+(d<<4)|0;if(!b){a=0;return a|0}Rb[c[(c[a>>2]|0)+32>>2]&127](a,b,e);m=c[g+(d<<4)+12>>2]|0;l=b-(c[a+16>>2]|0)>>4;d=j;f=a+44|0;g=-1;while(1){b=c[(c[f>>2]|0)+(d<<2)>>2]|0;if((b|0)==(l|0))break;else{d=b;f=a+64|0;g=b}}d=c[a+64>>2]|0;if((g|0)==-1)b=(c[a+44>>2]|0)+(j<<2)|0;else b=d+(g<<2)|0;c[b>>2]=c[d+(l<<2)>>2];j=(c[a+8>>2]|0)+-1|0;b=c[a+72>>2]|0;if(b|0)pb[c[(c[b>>2]|0)+12>>2]&31](b,n,k,e)|0;if((j|0)==(l|0)){c[a+8>>2]=(c[a+8>>2]|0)+-1;a=m;return a|0}h=c[a+16>>2]|0;i=c[(c[h+(j<<4)+4>>2]|0)+12>>2]<<16|c[(c[h+(j<<4)>>2]|0)+12>>2];i=(i+~(i<<15)>>10^i+~(i<<15))*9|0;i=((i>>6^i)+~((i>>6^i)<<11)>>16^(i>>6^i)+~((i>>6^i)<<11))&(c[a+12>>2]|0)+-1;d=i;f=a+44|0;g=-1;while(1){b=c[(c[f>>2]|0)+(d<<2)>>2]|0;if((b|0)==(j|0))break;else{d=b;f=a+64|0;g=b}}d=c[a+64>>2]|0;if((g|0)==-1)b=(c[a+44>>2]|0)+(i<<2)|0;else b=d+(g<<2)|0;c[b>>2]=c[d+(j<<2)>>2];c[h+(l<<4)>>2]=c[h+(j<<4)>>2];c[h+(l<<4)+4>>2]=c[h+(j<<4)+4>>2];c[h+(l<<4)+8>>2]=c[h+(j<<4)+8>>2];c[h+(l<<4)+12>>2]=c[h+(j<<4)+12>>2];e=(c[a+44>>2]|0)+(i<<2)|0;c[(c[a+64>>2]|0)+(l<<2)>>2]=c[e>>2];c[e>>2]=l;c[a+8>>2]=(c[a+8>>2]|0)+-1;a=m;return a|0}function rf(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0.0,j=0.0,k=0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0;k=l;l=l+64|0;n=+g[a+20>>2];u=+g[a+40>>2];p=+g[a+24>>2];s=+g[a+36>>2];t=+g[a+32>>2];m=+g[a+16>>2];j=+g[a>>2];i=+g[a+4>>2];q=+g[a+8>>2];h=1.0/((n*u-p*s)*j+i*(p*t-u*m)+(s*m-n*t)*q);z=+g[b>>2];y=+g[b+4>>2];A=+g[b+8>>2];x=+g[b+16>>2];w=+g[b+20>>2];v=+g[b+24>>2];r=+g[b+32>>2];o=+g[b+36>>2];f=+g[b+40>>2];g[k+16>>2]=A*(s*m-n*t)*h+(z*(n*u-p*s)*h+y*(p*t-u*m)*h);g[k+16+4>>2]=A*(t*i-s*j)*h+(z*(s*q-u*i)*h+y*(u*j-t*q)*h);g[k+16+8>>2]=A*(n*j-m*i)*h+(z*(p*i-n*q)*h+y*(m*q-p*j)*h);g[k+16+12>>2]=0.0;g[k+16+16>>2]=(n*u-p*s)*h*x+(p*t-u*m)*h*w+(s*m-n*t)*h*v;g[k+16+20>>2]=(s*q-u*i)*h*x+(u*j-t*q)*h*w+(t*i-s*j)*h*v;g[k+16+24>>2]=(p*i-n*q)*h*x+(m*q-p*j)*h*w+(n*j-m*i)*h*v;g[k+16+28>>2]=0.0;g[k+16+32>>2]=(n*u-p*s)*h*r+(p*t-u*m)*h*o+(s*m-n*t)*h*f;g[k+16+36>>2]=(s*q-u*i)*h*r+(u*j-t*q)*h*o+(t*i-s*j)*h*f;g[k+16+40>>2]=(p*i-n*q)*h*r+(m*q-p*j)*h*o+(n*j-m*i)*h*f;g[k+16+44>>2]=0.0;eh(k+16|0,k);f=+g[k>>2];h=+g[k+4>>2];i=+g[k+8>>2];m=+g[k+12>>2];j=1.0/+C(+(f*f+h*h+i*i+m*m));g[k>>2]=f*j;g[k+4>>2]=h*j;g[k+8>>2]=i*j;g[k+12>>2]=m*j;m=m*j<-1.0?-1.0:m*j;g[e>>2]=+H(+(m>1.0?1.0:m))*2.0;g[d>>2]=f*j;g[d+4>>2]=h*j;g[d+8>>2]=i*j;g[d+12>>2]=0.0;if(f*j*f*j+h*j*h*j+i*j*i*j<1.4210854715202004e-14){c[d>>2]=1065353216;c[d+4>>2]=0;c[d+8>>2]=0;g[d+12>>2]=0.0;l=k;return}else{A=1.0/+C(+(f*j*f*j+h*j*h*j+i*j*i*j));g[d>>2]=f*j*A;g[d+4>>2]=A*h*j;g[d+8>>2]=A*i*j;l=k;return}}\nfunction Ac(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0.0,j=0.0,k=0.0,m=0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0,y=0,z=0,A=0,B=0,D=0.0,E=0.0,F=0.0,G=0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0,O=0,P=0,Q=0.0,R=0.0,S=0.0,T=0;P=l;l=l+208|0;g[b+56>>2]=0.0;N=P+192+4|0;O=P+192+8|0;c[P+192>>2]=0;c[P+192+4>>2]=0;c[P+192+8>>2]=0;c[P+192+12>>2]=0;c[P+128>>2]=c[d>>2];c[P+128+4>>2]=c[d+4>>2];c[P+128+8>>2]=c[d+8>>2];c[P+128+12>>2]=c[d+12>>2];c[P+128+16>>2]=c[d+16>>2];c[P+128+16+4>>2]=c[d+16+4>>2];c[P+128+16+8>>2]=c[d+16+8>>2];c[P+128+16+12>>2]=c[d+16+12>>2];c[P+128+32>>2]=c[d+32>>2];c[P+128+32+4>>2]=c[d+32+4>>2];c[P+128+32+8>>2]=c[d+32+8>>2];c[P+128+32+12>>2]=c[d+32+12>>2];A=P+128+48|0;c[A>>2]=c[d+48>>2];c[A+4>>2]=c[d+48+4>>2];c[A+8>>2]=c[d+48+8>>2];c[A+12>>2]=c[d+48+12>>2];c[P+64>>2]=c[d+64>>2];c[P+64+4>>2]=c[d+64+4>>2];c[P+64+8>>2]=c[d+64+8>>2];c[P+64+12>>2]=c[d+64+12>>2];c[P+64+16>>2]=c[d+80>>2];c[P+64+16+4>>2]=c[d+80+4>>2];c[P+64+16+8>>2]=c[d+80+8>>2];c[P+64+16+12>>2]=c[d+80+12>>2];c[P+64+32>>2]=c[d+96>>2];c[P+64+32+4>>2]=c[d+96+4>>2];c[P+64+32+8>>2]=c[d+96+8>>2];c[P+64+32+12>>2]=c[d+96+12>>2];B=P+64+48|0;c[B>>2]=c[d+112>>2];c[B+4>>2]=c[d+112+4>>2];c[B+8>>2]=c[d+112+8>>2];c[B+12>>2]=c[d+112+12>>2];H=+g[A>>2];I=+g[B>>2];J=+g[P+128+52>>2];K=+g[P+64+52>>2];L=+g[P+128+56>>2];M=+g[P+64+56>>2];g[A>>2]=H-(H+I)*.5;g[P+128+52>>2]=J-(J+K)*.5;g[P+128+56>>2]=L-(L+M)*.5;g[B>>2]=I-(H+I)*.5;g[P+64+52>>2]=K-(J+K)*.5;g[P+64+56>>2]=M-(L+M)*.5;if(((c[(c[b+28>>2]|0)+4>>2]|0)+-17|0)>>>0<2)A=((c[(c[b+32>>2]|0)+4>>2]|0)+-17|0)>>>0<2;else A=0;v=+g[b+44>>2];u=+g[b+48>>2];c[6417]=(c[6417]|0)+1;B=a[b+52>>0]|0;c[b+64>>2]=0;c[b+4>>2]=0;c[b+8>>2]=1065353216;c[b+12>>2]=0;g[b+16>>2]=0.0;c[b+68>>2]=0;c[b+60>>2]=-1;m=c[b+24>>2]|0;a[m+312>>0]=0;c[m>>2]=0;a[m+356>>0]=1;c[m+292>>2]=1566444395;c[m+296>>2]=1566444395;c[m+300>>2]=1566444395;g[m+304>>2]=0.0;c[m+336>>2]=0;c[m+336+4>>2]=0;c[m+336+8>>2]=0;c[m+336+12>>2]=0;a[m+336+16>>0]=0;a[m+332>>0]=a[m+332>>0]&-16;m=0;p=999999984306749440.0;do{s=+g[b+4>>2];q=+g[b+8>>2];j=+g[b+12>>2];k=+g[d+4>>2]*-s+ +g[d+20>>2]*-q+ +g[d+36>>2]*-j;n=+g[d+8>>2]*-s+ +g[d+24>>2]*-q+ +g[d+40>>2]*-j;g[P+48>>2]=+g[d>>2]*-s+ +g[d+16>>2]*-q+ +g[d+32>>2]*-j;g[P+48+4>>2]=k;g[P+48+8>>2]=n;g[P+48+12>>2]=0.0;n=s*+g[d+68>>2]+q*+g[d+84>>2]+j*+g[d+100>>2];k=s*+g[d+72>>2]+q*+g[d+88>>2]+j*+g[d+104>>2];g[P+32>>2]=+g[d+64>>2]*s+ +g[d+80>>2]*q+ +g[d+96>>2]*j;g[P+32+4>>2]=n;g[P+32+8>>2]=k;g[P+32+12>>2]=0.0;md(P+16|0,c[b+28>>2]|0,P+48|0);md(P,c[b+32>>2]|0,P+32|0);k=+g[P+16>>2];n=+g[P+16+4>>2];j=+g[P+16+8>>2];q=k*+g[P+128>>2]+n*+g[P+128+4>>2]+j*+g[P+128+8>>2]+ +g[P+128+48>>2];s=k*+g[P+128+16>>2]+n*+g[P+128+20>>2]+j*+g[P+128+24>>2]+ +g[P+128+52>>2];j=k*+g[P+128+32>>2]+n*+g[P+128+36>>2]+j*+g[P+128+40>>2]+ +g[P+128+56>>2];n=+g[P>>2];k=+g[P+4>>2];t=+g[P+8>>2];o=n*+g[P+64>>2]+k*+g[P+64+4>>2]+t*+g[P+64+8>>2]+ +g[P+64+48>>2];r=n*+g[P+64+16>>2]+k*+g[P+64+20>>2]+t*+g[P+64+24>>2]+ +g[P+64+52>>2];t=n*+g[P+64+32>>2]+k*+g[P+64+36>>2]+t*+g[P+64+40>>2]+ +g[P+64+56>>2];k=A?0.0:t;n=A?0.0:j;t=(A?0.0:j)-(A?0.0:t);j=+g[b+4>>2]*(q-o)+ +g[b+8>>2]*(s-r)+ +g[b+12>>2]*t;if(j>0.0?j*j>p*+g[d+128>>2]:0){c[b+68>>2]=10;m=1;h=0}else T=7;do if((T|0)==7){T=0;y=c[b+24>>2]|0;z=c[y>>2]|0;if((z|0)>0){i=+g[y+308>>2];x=0;h=0;do{D=q-o-+g[y+4+(h<<4)>>2];E=s-r-+g[y+4+(h<<4)+4>>2];F=t-+g[y+4+(h<<4)+8>>2];x=x|D*D+E*E+F*F<=i;h=h+1|0}while((h|0)!=(z|0))}else x=0;if((+g[y+304>>2]==0.0?t==+g[y+300>>2]:0)?s-r==+g[y+296>>2]:0)h=q-o==+g[y+292>>2];else h=0;if(x|h){c[b+68>>2]=1;m=1;h=0;break}i=p-j;if(i<=p*9.999999974752427e-07){c[b+68>>2]=i<=0.0?2:11;m=1;h=0;break}g[y+292>>2]=q-o;g[y+296>>2]=s-r;g[y+300>>2]=t;g[y+304>>2]=0.0;a[y+356>>0]=1;g[y+4+(z<<4)>>2]=q-o;g[y+4+(z<<4)+4>>2]=s-r;g[y+4+(z<<4)+8>>2]=t;g[y+4+(z<<4)+12>>2]=0.0;h=c[y>>2]|0;g[y+84+(h<<4)>>2]=q;g[y+84+(h<<4)+4>>2]=s;g[y+84+(h<<4)+8>>2]=n;g[y+84+(h<<4)+12>>2]=0.0;h=c[y>>2]|0;g[y+164+(h<<4)>>2]=o;g[y+164+(h<<4)+4>>2]=r;g[y+164+(h<<4)+8>>2]=k;g[y+164+(h<<4)+12>>2]=0.0;c[y>>2]=(c[y>>2]|0)+1;h=c[b+24>>2]|0;z=Cc(h)|0;i=+g[h+276>>2];j=+g[h+280>>2];k=+g[h+284>>2];h=c[h+288>>2]|0;if(!z){c[b+68>>2]=3;m=1;h=0;break}if(i*i+j*j+k*k<9.999999974752427e-07){g[b+4>>2]=i;g[b+8>>2]=j;g[b+12>>2]=k;c[b+16>>2]=h;c[b+68>>2]=6;m=1;h=0;break}if(p-(i*i+j*j+k*k)<=p*1.1920928955078125e-07){c[b+68>>2]=12;m=1;h=0;p=i*i+j*j+k*k;break}g[b+4>>2]=i;g[b+8>>2]=j;g[b+12>>2]=k;c[b+16>>2]=h;z=c[b+64>>2]|0;c[b+64>>2]=z+1;if((z|0)<=1e3)if((c[c[b+24>>2]>>2]|0)==4){c[b+68>>2]=13;h=0;p=i*i+j*j+k*k}else{h=1;p=i*i+j*j+k*k}else{h=0;p=i*i+j*j+k*k}}while(0)}while(h);u=B<<24>>24==0?u:0.0;t=(B<<24>>24==0?v:0.0)+u;if(m){B=c[b+24>>2]|0;Cc(B)|0;j=+g[B+260>>2];n=+g[B+264>>2];q=+g[B+268>>2];c[P+192>>2]=c[b+4>>2];c[P+192+4>>2]=c[b+4+4>>2];c[P+192+8>>2]=c[b+4+8>>2];c[P+192+12>>2]=c[b+4+12>>2];i=+g[b+4>>2];k=+g[b+8>>2];o=+g[b+12>>2];if(i*i+k*k+o*o<.0001)c[b+68>>2]=5;if(i*i+k*k+o*o>1.4210854715202004e-14){E=1.0/+C(+(i*i+k*k+o*o));g[P+192>>2]=E*+g[P+192>>2];g[N>>2]=E*+g[N>>2];g[O>>2]=E*+g[O>>2];F=u/+C(+p);h=1;p=1.0/E-t;m=1;j=F*i+j;k=F*k+n;i=F*o+q}else{h=2;p=0.0;m=0;k=n;i=q}c[b+60>>2]=h;D=j;E=k;F=i}else{p=0.0;m=0;D=0.0;E=0.0;F=0.0}if((c[b+72>>2]|0)!=0?(c[b+20>>2]|0)!=0:0)h=t+p<.01&(c[b+68>>2]|0)!=0;else h=0;x=m^1;do if(h|x?(G=c[b+20>>2]|0,(G|0)!=0):0){c[6416]=(c[6416]|0)+1;c[b+4>>2]=0;c[b+4+4>>2]=0;c[b+4+8>>2]=0;c[b+4+12>>2]=0;if(kb[c[(c[G>>2]|0)+8>>2]&3](G,c[b+24>>2]|0,c[b+28>>2]|0,c[b+32>>2]|0,P+128|0,P+64|0,b+4|0,P+48|0,P+32|0,f)|0){k=+g[P+32>>2];o=+g[P+48>>2];j=+g[P+32+4>>2];q=+g[P+48+4>>2];i=+g[P+32+8>>2];r=+g[P+48+8>>2];if(!((k-o)*(k-o)+(j-q)*(j-q)+(i-r)*(i-r)<=1.4210854715202004e-14)){n=(k-o)*(k-o)+(j-q)*(j-q)+(i-r)*(i-r);t=k-o;u=i-r;v=0.0;w=j-q}else{t=+g[b+4>>2];w=+g[b+8>>2];u=+g[b+12>>2];n=t*t+w*w+u*u;v=+g[b+16>>2]}if(n>1.4210854715202004e-14){s=1.0/+C(+n);n=-+C(+((o-k)*(o-k)+(q-j)*(q-j)+(r-i)*(r-i)));if(p>n|x){g[P+192>>2]=t*s;g[N>>2]=w*s;g[O>>2]=u*s;g[P+192+12>>2]=v;c[b+60>>2]=3;break}else h=8}else h=9;c[b+60>>2]=h;if(m){n=p;k=D;j=E;i=F;break}l=P;return}else{j=+g[b+4>>2];o=+g[b+8>>2];r=+g[b+12>>2];if(!(j*j+o*o+r*r>0.0)){if(m){n=p;k=D;j=E;i=F;break}l=P;return}k=+g[P+32>>2];v=+g[P+48>>2]-k;q=+g[P+32+4>>2];w=+g[P+48+4>>2]-q;s=+g[P+32+8>>2];i=+g[P+48+8>>2]-s;i=+C(+(v*v+w*w+i*i))-t;if(i<p|x){c[P+192>>2]=c[b+4>>2];c[P+192+4>>2]=c[b+4+4>>2];c[P+192+8>>2]=c[b+4+8>>2];c[P+192+12>>2]=c[b+4+12>>2];D=+g[P+192>>2];E=+g[N>>2];F=+g[O>>2];n=1.0/+C(+(D*D+E*E+F*F));g[P+192>>2]=D*n;g[N>>2]=E*n;g[O>>2]=F*n;c[b+60>>2]=6;n=i;k=u*j+k;j=u*o+q;i=u*r+s;break}c[b+60>>2]=5;if(m){n=p;k=D;j=E;i=F;break}l=P;return}}else T=51;while(0);if((T|0)==51)if(m){n=p;k=D;j=E;i=F}else{l=P;return}if(!(n<0.0)?!(n*n<+g[d+128>>2]):0){l=P;return}if(c[b+76>>2]|0?(T=c[b+28>>2]|0,Vb[c[(c[T>>2]|0)+8>>2]&127](T,P+128|0,P+48|0,P+32|0),D=(+g[P+32>>2]+ +g[P+48>>2])*.5,E=(+g[P+32+4>>2]+ +g[P+48+4>>2])*.5,F=(+g[P+32+8>>2]+ +g[P+48+8>>2])*.5,T=c[b+32>>2]|0,Vb[c[(c[T>>2]|0)+8>>2]&127](T,P+64|0,P+48|0,P+32|0),Q=+g[P+192>>2],R=+g[N>>2],S=+g[O>>2],(D-(+g[P+48>>2]+ +g[P+32>>2])*.5)*Q+(E-(+g[P+48+4>>2]+ +g[P+32+4>>2])*.5)*R+(F-(+g[P+48+8>>2]+ +g[P+32+8>>2])*.5)*S<0.0):0){g[P+192>>2]=-Q;g[N>>2]=-R;g[O>>2]=-S}c[b+4>>2]=c[P+192>>2];c[b+4+4>>2]=c[P+192+4>>2];c[b+4+8>>2]=c[P+192+8>>2];c[b+4+12>>2]=c[P+192+12>>2];g[b+56>>2]=n;T=c[(c[e>>2]|0)+16>>2]|0;g[P+48>>2]=(H+I)*.5+k;g[P+48+4>>2]=(J+K)*.5+j;g[P+48+8>>2]=(L+M)*.5+i;g[P+48+12>>2]=0.0;Qb[T&15](e,P+192|0,P+48|0,n);l=P;return}function Bc(b,d,e,f,h,i,j){b=b|0;d=d|0;e=e|0;f=f|0;h=+h;i=+i;j=j|0;var k=0,m=0,n=0.0,o=0,p=0,q=0.0,r=0.0,s=0.0,t=0.0,u=0,v=0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0,I=0,J=0,K=0.0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0.0,Y=0.0,Z=0.0,_=0,$=0;W=l;l=l+48|0;a[W+16+16>>0]=1;V=W+16+12|0;c[V>>2]=0;c[W+16+4>>2]=0;c[W+16+8>>2]=0;p=c[f+4>>2]|0;if((p|0)>0){c[6432]=(c[6432]|0)+1;k=ec((p<<4|3)+16|0)|0;if(!k)o=0;else{c[(k+4+15&-16)+-4>>2]=k;o=k+4+15&-16}k=c[W+16+4>>2]|0;if((k|0)>0){m=0;do{U=o+(m<<4)|0;T=(c[V>>2]|0)+(m<<4)|0;c[U>>2]=c[T>>2];c[U+4>>2]=c[T+4>>2];c[U+8>>2]=c[T+8>>2];c[U+12>>2]=c[T+12>>2];m=m+1|0}while((m|0)!=(k|0))}k=c[V>>2]|0;if(k|0){if(a[W+16+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[k+-4>>2]|0)}c[V>>2]=0}a[W+16+16>>0]=1;c[V>>2]=o;c[W+16+8>>2]=p}k=c[d+28>>2]|0;if((k|0)>0){T=c[d+36>>2]|0;n=+g[e>>2];q=+g[e+4>>2];B=+g[e+8>>2];C=+g[e+16>>2];D=+g[e+20>>2];E=+g[e+24>>2];F=+g[e+32>>2];G=+g[e+36>>2];r=+g[e+40>>2];s=+g[b>>2];t=+g[b+4>>2];w=+g[b+8>>2];U=-1;A=3402823466385288598117041.0e14;o=0;while(1){x=+g[T+(o*36|0)+20>>2];y=+g[T+(o*36|0)+24>>2];z=+g[T+(o*36|0)+28>>2];m=(x*n+y*q+z*B)*s+(x*C+y*D+z*E)*t+(x*F+y*G+z*r)*w<A;U=m?o:U;o=o+1|0;if((o|0)==(k|0))break;else A=m?(x*n+y*q+z*B)*s+(x*C+y*D+z*E)*t+(x*F+y*G+z*r)*w:A}if((U|0)>=0){N=c[T+(U*36|0)+4>>2]|0;if((N|0)>0){O=T+(U*36|0)+12|0;o=T+(U*36|0)+20|0;P=T+(U*36|0)+24|0;Q=T+(U*36|0)+28|0;s=B;t=C;z=D;y=E;x=F;w=G;M=0;L=f;f=W+16|0;while(1){J=c[O>>2]|0;k=c[J+(M<<2)>>2]|0;I=c[d+16>>2]|0;M=M+1|0;J=c[J+(((M|0)==(N|0)?0:M)<<2)>>2]|0;X=+g[I+(k<<4)>>2];Y=X-+g[I+(J<<4)>>2];A=+g[I+(k<<4)+4>>2];Z=A-+g[I+(J<<4)+4>>2];B=+g[I+(k<<4)+8>>2];D=B-+g[I+(J<<4)+8>>2];K=Y*n+Z*q+D*s;F=Y*t+Z*z+D*y;D=Y*x+Z*w+D*r;Z=+g[o>>2];Y=+g[P>>2];C=+g[Q>>2];G=n*Z+q*Y+s*C;E=t*Z+z*Y+y*C;C=x*Z+w*Y+r*C;x=(X*n+A*q+B*s+ +g[e+48>>2])*-(F*C-D*E)+(X*t+A*z+B*y+ +g[e+52>>2])*-(D*G-K*C)+(X*x+A*w+B*r+ +g[e+56>>2])*-(K*E-F*G);J=L;I=f;k=c[J+4>>2]|0;if((k|0)>=2){p=c[J+12>>2]|0;r=+g[p+(k+-1<<4)>>2];t=+g[p+(k+-1<<4)+4>>2];w=+g[p+(k+-1<<4)+8>>2];q=r*-(F*C-D*E)+t*-(D*G-K*C)+w*-(K*E-F*G)-x;H=0;while(1){z=+g[p+(H<<4)>>2];A=+g[p+(H<<4)+4>>2];B=+g[p+(H<<4)+8>>2];n=+g[p+(H<<4)+12>>2];y=z*-(F*C-D*E)+A*-(D*G-K*C)+B*-(K*E-F*G)-x;do if(q<0.0)if(y<0.0){m=c[I+4>>2]|0;if((m|0)!=(c[I+8>>2]|0)){s=z;r=A;q=B;u=75;break}v=m|0?m<<1:1;if((m|0)>=(v|0)){s=z;r=A;q=B;u=75;break}if(!v)p=0;else{c[6432]=(c[6432]|0)+1;m=ec((v<<4|3)+16|0)|0;if(!m)p=0;else{c[(m+4+15&-16)+-4>>2]=m;p=m+4+15&-16}m=c[I+4>>2]|0}if((m|0)>0){u=0;do{_=p+(u<<4)|0;$=(c[I+12>>2]|0)+(u<<4)|0;c[_>>2]=c[$>>2];c[_+4>>2]=c[$+4>>2];c[_+8>>2]=c[$+8>>2];c[_+12>>2]=c[$+12>>2];u=u+1|0}while((u|0)!=(m|0))}m=c[I+12>>2]|0;if(m|0){if(a[I+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[m+-4>>2]|0)}c[I+12>>2]=0}a[I+16>>0]=1;c[I+12>>2]=p;c[I+8>>2]=v;m=c[I+4>>2]|0;s=z;r=A;q=B;u=75;break}else{q=q/(q-y);s=r+(z-r)*q;r=t+(A-t)*q;q=w+(B-w)*q;m=c[I+4>>2]|0;if((m|0)!=(c[I+8>>2]|0)){n=0.0;u=75;break}v=m|0?m<<1:1;if((m|0)>=(v|0)){n=0.0;u=75;break}if(!v)p=0;else{c[6432]=(c[6432]|0)+1;m=ec((v<<4|3)+16|0)|0;if(!m)p=0;else{c[(m+4+15&-16)+-4>>2]=m;p=m+4+15&-16}m=c[I+4>>2]|0}if((m|0)>0){u=0;do{$=p+(u<<4)|0;_=(c[I+12>>2]|0)+(u<<4)|0;c[$>>2]=c[_>>2];c[$+4>>2]=c[_+4>>2];c[$+8>>2]=c[_+8>>2];c[$+12>>2]=c[_+12>>2];u=u+1|0}while((u|0)!=(m|0))}m=c[I+12>>2]|0;if(m|0){if(a[I+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[m+-4>>2]|0)}c[I+12>>2]=0}a[I+16>>0]=1;c[I+12>>2]=p;c[I+8>>2]=v;m=c[I+4>>2]|0;n=0.0;u=75;break}else if(y<0.0){q=q/(q-y);s=r+(z-r)*q;r=t+(A-t)*q;q=w+(B-w)*q;m=c[I+4>>2]|0;if((m|0)==(c[I+8>>2]|0)?(S=m|0?m<<1:1,(m|0)<(S|0)):0){if(!S)p=0;else{c[6432]=(c[6432]|0)+1;m=ec((S<<4|3)+16|0)|0;if(!m)p=0;else{c[(m+4+15&-16)+-4>>2]=m;p=m+4+15&-16}m=c[I+4>>2]|0}if((m|0)>0){u=0;do{$=p+(u<<4)|0;_=(c[I+12>>2]|0)+(u<<4)|0;c[$>>2]=c[_>>2];c[$+4>>2]=c[_+4>>2];c[$+8>>2]=c[_+8>>2];c[$+12>>2]=c[_+12>>2];u=u+1|0}while((u|0)!=(m|0))}m=c[I+12>>2]|0;if(m|0){if(a[I+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[m+-4>>2]|0)}c[I+12>>2]=0}a[I+16>>0]=1;c[I+12>>2]=p;c[I+8>>2]=S;m=c[I+4>>2]|0}$=c[I+12>>2]|0;g[$+(m<<4)>>2]=s;g[$+(m<<4)+4>>2]=r;g[$+(m<<4)+8>>2]=q;g[$+(m<<4)+12>>2]=0.0;m=(c[I+4>>2]|0)+1|0;c[I+4>>2]=m;if((m|0)==(c[I+8>>2]|0)?(R=m|0?m<<1:1,(m|0)<(R|0)):0){if(!R)p=0;else{c[6432]=(c[6432]|0)+1;m=ec((R<<4|3)+16|0)|0;if(!m)p=0;else{c[(m+4+15&-16)+-4>>2]=m;p=m+4+15&-16}m=c[I+4>>2]|0}if((m|0)>0){u=0;do{$=p+(u<<4)|0;_=(c[I+12>>2]|0)+(u<<4)|0;c[$>>2]=c[_>>2];c[$+4>>2]=c[_+4>>2];c[$+8>>2]=c[_+8>>2];c[$+12>>2]=c[_+12>>2];u=u+1|0}while((u|0)!=(m|0))}m=c[I+12>>2]|0;if(m|0){if(a[I+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[m+-4>>2]|0)}c[I+12>>2]=0}a[I+16>>0]=1;c[I+12>>2]=p;c[I+8>>2]=R;m=c[I+4>>2]|0;s=z;r=A;q=B;u=75}else{s=z;r=A;q=B;u=75}}while(0);if((u|0)==75){u=0;$=c[I+12>>2]|0;g[$+(m<<4)>>2]=s;g[$+(m<<4)+4>>2]=r;g[$+(m<<4)+8>>2]=q;g[$+(m<<4)+12>>2]=n;c[I+4>>2]=(c[I+4>>2]|0)+1}m=H+1|0;if((m|0)==(k|0))break;p=c[J+12>>2]|0;q=y;r=z;w=B;t=A;H=m}k=c[J+4>>2]|0}if((k|0)<0){if((c[J+8>>2]|0)<0){m=c[J+12>>2]|0;if(m|0){if(a[J+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[m+-4>>2]|0)}c[J+12>>2]=0}a[J+16>>0]=1;c[J+12>>2]=0;c[J+8>>2]=0}do{$=(c[J+12>>2]|0)+(k<<4)|0;c[$>>2]=c[W>>2];c[$+4>>2]=c[W+4>>2];c[$+8>>2]=c[W+8>>2];c[$+12>>2]=c[W+12>>2];k=k+1|0}while((k|0)!=0)}c[J+4>>2]=0;n=+g[e>>2];q=+g[e+4>>2];s=+g[e+8>>2];t=+g[e+16>>2];z=+g[e+20>>2];y=+g[e+24>>2];x=+g[e+32>>2];w=+g[e+36>>2];r=+g[e+40>>2];if((M|0)>=(N|0)){A=t;m=P;k=Q;u=e+56|0;v=e+48|0;p=e+52|0;break}else{$=f;f=L;L=$}}}else{s=B;A=C;z=D;y=E;x=F;w=G;o=T+(U*36|0)+20|0;m=T+(U*36|0)+24|0;k=T+(U*36|0)+28|0;u=e+56|0;v=e+48|0;p=e+52|0}X=+g[o>>2];Y=+g[m>>2];Z=+g[k>>2];t=X*n+Y*q+Z*s;s=X*A+Y*z+Z*y;r=X*x+Y*w+Z*r;q=+g[T+(U*36|0)+32>>2]-(t*+g[v>>2]+s*+g[p>>2]+r*+g[u>>2]);k=c[f+4>>2]|0;if((k|0)>0){o=0;do{m=c[f+12>>2]|0;n=q+(t*+g[m+(o<<4)>>2]+s*+g[m+(o<<4)+4>>2]+r*+g[m+(o<<4)+8>>2]);n=n<=h?h:n;if(n<=i){k=m+(o<<4)|0;c[W>>2]=c[k>>2];c[W+4>>2]=c[k+4>>2];c[W+8>>2]=c[k+8>>2];c[W+12>>2]=c[k+12>>2];Qb[c[(c[j>>2]|0)+16>>2]&15](j,b,W,n);k=c[f+4>>2]|0}o=o+1|0}while((o|0)<(k|0))}}}k=c[V>>2]|0;if(!k){l=W;return}if(a[W+16+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[k+-4>>2]|0)}c[V>>2]=0;l=W;return}function Cc(b){b=b|0;var d=0,e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,m=0,n=0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0,C=0.0,D=0.0,E=0.0,F=0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0.0,O=0.0,P=0.0,Q=0.0,R=0.0,S=0.0,T=0;F=l;l=l+80|0;if(!(a[b+356>>0]|0)){b=a[b+312>>0]|0;b=b<<24>>24!=0;l=F;return b|0}c[b+336>>2]=0;c[b+336+4>>2]=0;c[b+336+8>>2]=0;c[b+336+12>>2]=0;a[b+336+16>>0]=0;m=a[b+332>>0]|0;a[b+332>>0]=m&-16;a[b+356>>0]=0;switch(c[b>>2]|0){case 0:{a[b+312>>0]=0;b=0;b=b<<24>>24!=0;l=F;return b|0}case 1:{c[b+244>>2]=c[b+84>>2];c[b+244+4>>2]=c[b+84+4>>2];c[b+244+8>>2]=c[b+84+8>>2];c[b+244+12>>2]=c[b+84+12>>2];c[b+260>>2]=c[b+164>>2];c[b+260+4>>2]=c[b+164+4>>2];c[b+260+8>>2]=c[b+164+8>>2];c[b+260+12>>2]=c[b+164+12>>2];D=+g[b+248>>2]-+g[b+264>>2];E=+g[b+252>>2]-+g[b+268>>2];g[b+276>>2]=+g[b+244>>2]-+g[b+260>>2];g[b+280>>2]=D;g[b+284>>2]=E;g[b+288>>2]=0.0;a[b+352>>0]=0;a[b+332>>0]=m&-16;g[b+336>>2]=1.0;g[b+340>>2]=0.0;g[b+344>>2]=0.0;g[b+348>>2]=0.0;a[b+312>>0]=1;b=1;b=b<<24>>24!=0;l=F;return b|0}case 2:{e=+g[b+4>>2];f=+g[b+8>>2];h=+g[b+12>>2];i=+g[b+20>>2]-e;j=+g[b+24>>2]-f;k=+g[b+28>>2]-h;if((0.0-e)*i+(0.0-f)*j+(0.0-h)*k>0.0)if((0.0-e)*i+(0.0-f)*j+(0.0-h)*k<i*i+j*j+k*k){d=3;e=((0.0-e)*i+(0.0-f)*j+(0.0-h)*k)/(i*i+j*j+k*k)}else{d=2;e=1.0}else{d=1;e=0.0}a[b+332>>0]=m&-16|d;g[b+336>>2]=1.0-e;g[b+340>>2]=e;g[b+344>>2]=0.0;g[b+348>>2]=0.0;y=+g[b+84>>2];A=+g[b+88>>2];D=+g[b+92>>2];y=y+e*(+g[b+100>>2]-y);A=A+e*(+g[b+104>>2]-A);D=D+e*(+g[b+108>>2]-D);g[b+244>>2]=y;g[b+248>>2]=A;g[b+252>>2]=D;g[b+256>>2]=0.0;z=+g[b+164>>2];C=+g[b+168>>2];E=+g[b+172>>2];z=z+e*(+g[b+180>>2]-z);C=C+e*(+g[b+184>>2]-C);E=E+e*(+g[b+188>>2]-E);g[b+260>>2]=z;g[b+264>>2]=C;g[b+268>>2]=E;g[b+272>>2]=0.0;g[b+276>>2]=y-z;g[b+280>>2]=A-C;g[b+284>>2]=D-E;g[b+288>>2]=0.0;Ue(b,b+332|0);if((+g[b+336>>2]>=0.0?+g[b+340>>2]>=0.0:0)?+g[b+344>>2]>=0.0:0)d=+g[b+348>>2]>=0.0&1;else d=0;a[b+312>>0]=d;b=d;b=b<<24>>24!=0;l=F;return b|0}case 3:{c[F+16>>2]=0;c[F+16+4>>2]=0;c[F+16+8>>2]=0;c[F+16+12>>2]=0;Re(F+16|0,b+4|0,b+20|0,b+36|0,b+316|0);w=+g[b+336>>2];x=+g[b+340>>2];E=+g[b+344>>2];y=+g[b+84>>2]*w+ +g[b+100>>2]*x+ +g[b+116>>2]*E;A=w*+g[b+88>>2]+x*+g[b+104>>2]+E*+g[b+120>>2];D=w*+g[b+92>>2]+x*+g[b+108>>2]+E*+g[b+124>>2];g[b+244>>2]=y;g[b+248>>2]=A;g[b+252>>2]=D;g[b+256>>2]=0.0;z=+g[b+164>>2]*w+ +g[b+180>>2]*x+ +g[b+196>>2]*E;C=w*+g[b+168>>2]+x*+g[b+184>>2]+E*+g[b+200>>2];E=w*+g[b+172>>2]+x*+g[b+188>>2]+E*+g[b+204>>2];g[b+260>>2]=z;g[b+264>>2]=C;g[b+268>>2]=E;g[b+272>>2]=0.0;g[b+276>>2]=y-z;g[b+280>>2]=A-C;g[b+284>>2]=D-E;g[b+288>>2]=0.0;Ue(b,b+332|0);if((+g[b+336>>2]>=0.0?+g[b+340>>2]>=0.0:0)?+g[b+344>>2]>=0.0:0)d=+g[b+348>>2]>=0.0&1;else d=0;a[b+312>>0]=d;b=d;b=b<<24>>24!=0;l=F;return b|0}case 4:{c[F>>2]=0;c[F+4>>2]=0;c[F+8>>2]=0;c[F+12>>2]=0;B=F+32+16|0;a[B>>0]=0;c[b+316>>2]=0;c[b+316+4>>2]=0;c[b+316+8>>2]=0;c[b+316+12>>2]=0;a[b+332>>0]=m|15;H=+g[b+20>>2];Q=+g[b+4>>2];N=+g[b+24>>2];G=+g[b+8>>2];J=+g[b+28>>2];R=+g[b+12>>2];M=+g[b+36>>2];O=+g[b+40>>2];K=+g[b+44>>2];I=+g[b+52>>2];P=+g[b+56>>2];L=+g[b+60>>2];S=((N-G)*(K-R)-(J-R)*(O-G))*(I-Q)+((J-R)*(M-Q)-(H-Q)*(K-R))*(P-G)+((H-Q)*(O-G)-(N-G)*(M-Q))*(L-R);d=S*S<9.99999905104687e-09?-1:((0.0-Q)*((N-G)*(K-R)-(J-R)*(O-G))+(0.0-G)*((J-R)*(M-Q)-(H-Q)*(K-R))+((H-Q)*(O-G)-(N-G)*(M-Q))*(0.0-R))*S<0.0&1;S=(J-R)*((M-Q)*(P-G)-(O-G)*(I-Q))+((H-Q)*((O-G)*(L-R)-(K-R)*(P-G))+(N-G)*((K-R)*(I-Q)-(M-Q)*(L-R)));m=S*S<9.99999905104687e-09?-1:((0.0-R)*((M-Q)*(P-G)-(O-G)*(I-Q))+((0.0-Q)*((O-G)*(L-R)-(K-R)*(P-G))+(0.0-G)*((K-R)*(I-Q)-(M-Q)*(L-R))))*S<0.0&1;S=(K-R)*((N-G)*(I-Q)-(H-Q)*(P-G))+((M-Q)*((J-R)*(P-G)-(N-G)*(L-R))+(O-G)*((H-Q)*(L-R)-(J-R)*(I-Q)));n=S*S<9.99999905104687e-09?-1:((0.0-R)*((N-G)*(I-Q)-(H-Q)*(P-G))+((0.0-Q)*((J-R)*(P-G)-(N-G)*(L-R))+(0.0-G)*((H-Q)*(L-R)-(J-R)*(I-Q))))*S<0.0&1;G=(R-J)*((O-N)*(I-H)-(M-H)*(P-N))+((Q-H)*((K-J)*(P-N)-(O-N)*(L-J))+(G-N)*((M-H)*(L-J)-(K-J)*(I-H)));u=G*G<9.99999905104687e-09?-1:((0.0-J)*((O-N)*(I-H)-(M-H)*(P-N))+((0.0-H)*((K-J)*(P-N)-(O-N)*(L-J))+(0.0-N)*((M-H)*(L-J)-(K-J)*(I-H))))*G<0.0&1;do if((m|d|n|u|0)<0){a[b+352>>0]=1;d=b+312|0}else{if(!(m|d|n|u)){if(a[b+352>>0]|0){d=b+312|0;break}a[b+312>>0]=1;c[b+276>>2]=0;c[b+276+4>>2]=0;c[b+276+8>>2]=0;c[b+276+12>>2]=0;b=1;b=b<<24>>24!=0;l=F;return b|0}if((d|0)!=0?(Re(F,b+4|0,b+20|0,b+36|0,F+32|0),e=+g[F+32>>2],f=+g[F+32+4>>2],h=+g[F+32+8>>2],i=e-+g[F>>2],j=f-+g[F+4>>2],k=h-+g[F+8>>2],i*i+j*j+k*k<3402823466385288598117041.0e14):0){T=c[F+32+12>>2]|0;g[b+316>>2]=e;g[b+320>>2]=f;g[b+324>>2]=h;c[b+328>>2]=T;T=a[B>>0]|0;a[b+332>>0]=T&1|a[b+332>>0]&-16|T&2|T&4;T=c[F+32+24>>2]|0;d=c[F+32+28>>2]|0;c[b+336>>2]=c[F+32+20>>2];c[b+340>>2]=T;c[b+344>>2]=d;g[b+348>>2]=0.0;e=i*i+j*j+k*k}else e=3402823466385288598117041.0e14;if((m|0)!=0?(Re(F,b+4|0,b+36|0,b+52|0,F+32|0),o=+g[F+32>>2],p=+g[F+32+4>>2],q=+g[F+32+8>>2],r=o-+g[F>>2],s=p-+g[F+4>>2],t=q-+g[F+8>>2],r*r+s*s+t*t<e):0){m=c[F+32+12>>2]|0;g[b+316>>2]=o;g[b+320>>2]=p;g[b+324>>2]=q;c[b+328>>2]=m;m=a[B>>0]|0;a[b+332>>0]=m<<1&4|(m&1|a[b+332>>0]&-16)|m<<1&8;m=c[F+32+24>>2]|0;T=c[F+32+28>>2]|0;c[b+336>>2]=c[F+32+20>>2];g[b+340>>2]=0.0;c[b+344>>2]=m;c[b+348>>2]=T;e=r*r+s*s+t*t}if((n|0)!=0?(Re(F,b+4|0,b+52|0,b+20|0,F+32|0),v=+g[F+32>>2],w=+g[F+32+4>>2],x=+g[F+32+8>>2],y=v-+g[F>>2],z=w-+g[F+4>>2],A=x-+g[F+8>>2],y*y+z*z+A*A<e):0){n=c[F+32+12>>2]|0;g[b+316>>2]=v;g[b+320>>2]=w;g[b+324>>2]=x;c[b+328>>2]=n;n=a[B>>0]|0;a[b+332>>0]=(n&255)>>>1&2|(n&1|a[b+332>>0]&-16)|n<<2&8;n=c[F+32+28>>2]|0;T=c[F+32+24>>2]|0;c[b+336>>2]=c[F+32+20>>2];c[b+340>>2]=n;g[b+344>>2]=0.0;c[b+348>>2]=T;e=y*y+z*z+A*A}if(u|0?(Re(F,b+20|0,b+52|0,b+36|0,F+32|0),C=+g[F+32>>2],D=+g[F+32+4>>2],E=+g[F+32+8>>2],Q=C-+g[F>>2],R=D-+g[F+4>>2],S=E-+g[F+8>>2],Q*Q+R*R+S*S<e):0){u=c[F+32+12>>2]|0;g[b+316>>2]=C;g[b+320>>2]=D;g[b+324>>2]=E;c[b+328>>2]=u;u=a[B>>0]|0;a[b+332>>0]=u<<1&2|a[b+332>>0]&-16|u&4|u<<2&8;u=c[F+32+20>>2]|0;B=c[F+32+28>>2]|0;T=c[F+32+24>>2]|0;g[b+336>>2]=0.0;c[b+340>>2]=u;c[b+344>>2]=B;c[b+348>>2]=T}K=+g[b+336>>2];L=+g[b+340>>2];M=+g[b+344>>2];S=+g[b+348>>2];N=+g[b+84>>2]*K+ +g[b+100>>2]*L+ +g[b+116>>2]*M+ +g[b+132>>2]*S;P=K*+g[b+88>>2]+L*+g[b+104>>2]+M*+g[b+120>>2]+S*+g[b+136>>2];R=K*+g[b+92>>2]+L*+g[b+108>>2]+M*+g[b+124>>2]+S*+g[b+140>>2];g[b+244>>2]=N;g[b+248>>2]=P;g[b+252>>2]=R;g[b+256>>2]=0.0;O=+g[b+164>>2]*K+ +g[b+180>>2]*L+ +g[b+196>>2]*M+ +g[b+212>>2]*S;Q=K*+g[b+168>>2]+L*+g[b+184>>2]+M*+g[b+200>>2]+S*+g[b+216>>2];S=K*+g[b+172>>2]+L*+g[b+188>>2]+M*+g[b+204>>2]+S*+g[b+220>>2];g[b+260>>2]=O;g[b+264>>2]=Q;g[b+268>>2]=S;g[b+272>>2]=0.0;g[b+276>>2]=N-O;g[b+280>>2]=P-Q;g[b+284>>2]=R-S;g[b+288>>2]=0.0;Ue(b,b+332|0);if((+g[b+336>>2]>=0.0?+g[b+340>>2]>=0.0:0)?+g[b+344>>2]>=0.0:0)d=+g[b+348>>2]>=0.0&1;else d=0;a[b+312>>0]=d;T=d;T=T<<24>>24!=0;l=F;return T|0}while(0);a[d>>0]=0;T=0;T=T<<24>>24!=0;l=F;return T|0}default:{a[b+312>>0]=0;T=0;T=T<<24>>24!=0;l=F;return T|0}}return 0}function Dc(b){b=b|0;var d=0.0,e=0.0,f=0.0,h=0,i=0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0,v=0.0,w=0.0,x=0,y=0.0,z=0.0,A=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0.0,O=0.0,P=0.0,Q=0.0,R=0.0,S=0.0,T=0.0,U=0.0,V=0.0,W=0.0,X=0.0;u=l;l=l+176|0;if(!(a[b+738>>0]|0)){l=u;return}g[b+36>>2]=0.0;g[b+744>>2]=0.0;if(!(a[b+736>>0]|0)){h=c[b+28>>2]|0;j=+g[b+600>>2];k=+g[b+604>>2];q=+g[b+608>>2];s=j*+g[h+20>>2]+k*+g[h+24>>2]+q*+g[h+28>>2]+ +g[h+56>>2];i=c[b+32>>2]|0;m=+g[b+664>>2];n=+g[b+668>>2];o=+g[b+672>>2];t=m*+g[i+20>>2]+n*+g[i+24>>2]+o*+g[i+28>>2]+ +g[i+56>>2];r=m*+g[i+36>>2]+n*+g[i+40>>2]+o*+g[i+44>>2]+ +g[i+60>>2];p=j*+g[h+4>>2]+k*+g[h+8>>2]+q*+g[h+12>>2]+ +g[h+52>>2];q=j*+g[h+36>>2]+k*+g[h+40>>2]+q*+g[h+44>>2]+ +g[h+60>>2];o=m*+g[i+4>>2]+n*+g[i+8>>2]+o*+g[i+12>>2]+ +g[i+52>>2];if((o-p)*(o-p)+(t-s)*(t-s)+(r-q)*(r-q)>1.1920928955078125e-07){j=1.0/+C(+((o-p)*(o-p)+(t-s)*(t-s)+(r-q)*(r-q)));g[u+128>>2]=(o-p)*j;g[u+128+4>>2]=(t-s)*j;g[u+128+8>>2]=(r-q)*j;c[u+128+12>>2]=0;e=(r-q)*j;d=(t-s)*j;j=(o-p)*j}else{c[u+128>>2]=1065353216;c[u+128+4>>2]=0;c[u+128+8>>2]=0;g[u+128+12>>2]=0.0;e=0.0;d=0.0;j=1.0}if(+B(+e)>.7071067690849304){w=e*e+d*d;n=1.0/+C(+w);v=-(n*e);e=n*d;f=e;k=0.0;m=v;n=w*n;e=-(e*j);d=j*v}else{v=j*j+d*d;w=1.0/+C(+v);d=-(d*w);n=w*j;f=0.0;k=d;m=n;n=-(n*e);e=e*d;d=v*w}g[u+128+16>>2]=k;g[u+128+20>>2]=m;g[u+128+24>>2]=f;g[u+128+32>>2]=n;g[u+128+36>>2]=e;g[u+128+40>>2]=d;h=0;while(1){x=c[b+28>>2]|0;c[u+80>>2]=c[x+4>>2];c[u+80+4>>2]=c[x+20>>2];c[u+80+8>>2]=c[x+36>>2];g[u+80+12>>2]=0.0;c[u+80+16>>2]=c[x+8>>2];c[u+80+20>>2]=c[x+24>>2];c[u+80+24>>2]=c[x+40>>2];g[u+80+28>>2]=0.0;c[u+80+32>>2]=c[x+12>>2];c[u+80+36>>2]=c[x+28>>2];c[u+80+40>>2]=c[x+44>>2];g[u+80+44>>2]=0.0;c[u+32>>2]=c[i+4>>2];c[u+32+4>>2]=c[i+20>>2];c[u+32+8>>2]=c[i+36>>2];g[u+32+12>>2]=0.0;c[u+32+16>>2]=c[i+8>>2];c[u+32+20>>2]=c[i+24>>2];c[u+32+24>>2]=c[i+40>>2];g[u+32+28>>2]=0.0;c[u+32+32>>2]=c[i+12>>2];c[u+32+36>>2]=c[i+28>>2];c[u+32+40>>2]=c[i+44>>2];g[u+32+44>>2]=0.0;w=s-+g[x+56>>2];v=q-+g[x+60>>2];g[u+16>>2]=p-+g[x+52>>2];g[u+16+4>>2]=w;g[u+16+8>>2]=v;g[u+16+12>>2]=0.0;v=t-+g[i+56>>2];w=r-+g[i+60>>2];g[u>>2]=o-+g[i+52>>2];g[u+4>>2]=v;g[u+8>>2]=w;g[u+12>>2]=0.0;x=c[b+28>>2]|0;i=c[b+32>>2]|0;ug(b+48+(h*84|0)|0,u+80|0,u+32|0,u+16|0,u,u+128+(h<<4)|0,x+396|0,+g[x+344>>2],i+396|0,+g[i+344>>2]);h=h+1|0;if((h|0)==3)break;i=c[b+32>>2]|0}}d=+g[b+560>>2];e=+g[b+576>>2];f=+g[b+592>>2];if(+B(+f)>.7071067690849304){p=1.0/+C(+(f*f+e*e));j=0.0;k=e*p;m=-(f*p);n=(f*f+e*e)*p;o=-(d*e*p);p=d*-(f*p)}else{p=1.0/+C(+(d*d+e*e));j=-(e*p);k=0.0;m=d*p;n=-(f*d*p);o=f*-(e*p);p=(d*d+e*e)*p}i=c[b+28>>2]|0;J=+g[i+4>>2];I=+g[i+8>>2];s=+g[i+12>>2];R=j*J+m*I+k*s;H=+g[i+20>>2];G=+g[i+24>>2];v=+g[i+28>>2];T=j*H+m*G+k*v;q=+g[i+36>>2];A=+g[i+40>>2];E=+g[i+44>>2];W=j*q+m*A+k*E;D=n*J+o*I+p*s;M=n*H+o*G+p*v;N=n*q+o*A+p*E;h=c[b+32>>2]|0;z=+g[h+4>>2];y=+g[h+20>>2];j=+g[h+36>>2];o=+g[h+8>>2];p=+g[h+24>>2];t=+g[h+40>>2];P=+g[h+12>>2];S=+g[h+28>>2];V=+g[h+44>>2];c[b+300>>2]=0;c[b+300+4>>2]=0;c[b+300+8>>2]=0;c[b+300+12>>2]=0;g[b+316>>2]=R*J+T*H+W*q;g[b+320>>2]=R*I+T*G+W*A;g[b+324>>2]=R*s+T*v+W*E;g[b+328>>2]=0.0;g[b+332>>2]=z*-R+y*-T+j*-W;g[b+336>>2]=o*-R+p*-T+t*-W;g[b+340>>2]=P*-R+S*-T+V*-W;g[b+344>>2]=0.0;F=(R*J+T*H+W*q)*+g[i+396>>2];L=(R*I+T*G+W*A)*+g[i+400>>2];K=(R*s+T*v+W*E)*+g[i+404>>2];g[b+348>>2]=F;g[b+352>>2]=L;g[b+356>>2]=K;g[b+360>>2]=0.0;n=(z*-R+y*-T+j*-W)*+g[h+396>>2];w=(o*-R+p*-T+t*-W)*+g[h+400>>2];X=(P*-R+S*-T+V*-W)*+g[h+404>>2];g[b+364>>2]=n;g[b+368>>2]=w;g[b+372>>2]=X;g[b+376>>2]=0.0;g[b+380>>2]=(R*J+T*H+W*q)*F+(R*I+T*G+W*A)*L+(R*s+T*v+W*E)*K+((z*-R+y*-T+j*-W)*n+(o*-R+p*-T+t*-W)*w+(P*-R+S*-T+V*-W)*X);h=c[b+28>>2]|0;X=+g[h+4>>2];W=+g[h+20>>2];V=+g[h+36>>2];T=+g[h+8>>2];S=+g[h+24>>2];R=+g[h+40>>2];P=+g[h+12>>2];w=+g[h+28>>2];t=+g[h+44>>2];i=c[b+32>>2]|0;p=+g[i+4>>2];o=+g[i+20>>2];n=+g[i+36>>2];j=+g[i+8>>2];y=+g[i+24>>2];z=+g[i+40>>2];K=+g[i+12>>2];L=+g[i+28>>2];F=+g[i+44>>2];c[b+384>>2]=0;c[b+384+4>>2]=0;c[b+384+8>>2]=0;c[b+384+12>>2]=0;g[b+400>>2]=D*X+M*W+N*V;g[b+404>>2]=D*T+M*S+N*R;g[b+408>>2]=D*P+M*w+N*t;g[b+412>>2]=0.0;g[b+416>>2]=p*-D+o*-M+n*-N;g[b+420>>2]=j*-D+y*-M+z*-N;g[b+424>>2]=K*-D+L*-M+F*-N;g[b+428>>2]=0.0;U=(D*X+M*W+N*V)*+g[h+396>>2];Q=(D*T+M*S+N*R)*+g[h+400>>2];r=(D*P+M*w+N*t)*+g[h+404>>2];g[b+432>>2]=U;g[b+436>>2]=Q;g[b+440>>2]=r;g[b+444>>2]=0.0;k=(p*-D+o*-M+n*-N)*+g[i+396>>2];m=(j*-D+y*-M+z*-N)*+g[i+400>>2];O=(K*-D+L*-M+F*-N)*+g[i+404>>2];g[b+448>>2]=k;g[b+452>>2]=m;g[b+456>>2]=O;g[b+460>>2]=0.0;g[b+464>>2]=(D*X+M*W+N*V)*U+(D*T+M*S+N*R)*Q+(D*P+M*w+N*t)*r+((p*-D+o*-M+n*-N)*k+(j*-D+y*-M+z*-N)*m+(K*-D+L*-M+F*-N)*O);i=c[b+28>>2]|0;O=+g[i+4>>2];N=+g[i+20>>2];F=+g[i+36>>2];M=+g[i+8>>2];L=+g[i+24>>2];D=+g[i+40>>2];K=+g[i+12>>2];m=+g[i+28>>2];z=+g[i+44>>2];h=c[b+32>>2]|0;y=+g[h+4>>2];j=+g[h+20>>2];k=+g[h+36>>2];n=+g[h+8>>2];o=+g[h+24>>2];p=+g[h+40>>2];r=+g[h+12>>2];t=+g[h+28>>2];w=+g[h+44>>2];c[b+468>>2]=0;c[b+468+4>>2]=0;c[b+468+8>>2]=0;c[b+468+12>>2]=0;F=(J*d+I*e+s*f)*O+(H*d+G*e+v*f)*N+(q*d+A*e+E*f)*F;D=(J*d+I*e+s*f)*M+(H*d+G*e+v*f)*L+(q*d+A*e+E*f)*D;z=(J*d+I*e+s*f)*K+(H*d+G*e+v*f)*m+(q*d+A*e+E*f)*z;g[b+484>>2]=F;g[b+488>>2]=D;g[b+492>>2]=z;g[b+496>>2]=0.0;s=-(J*d+I*e+s*f);v=-(H*d+G*e+v*f);f=-(q*d+A*e+E*f);g[b+500>>2]=y*s+j*v+k*f;g[b+504>>2]=n*s+o*v+p*f;g[b+508>>2]=r*s+t*v+w*f;g[b+512>>2]=0.0;E=F*+g[i+396>>2];A=D*+g[i+400>>2];e=z*+g[i+404>>2];g[b+516>>2]=E;g[b+520>>2]=A;g[b+524>>2]=e;g[b+528>>2]=0.0;m=(y*s+j*v+k*f)*+g[h+396>>2];q=(n*s+o*v+p*f)*+g[h+400>>2];d=(r*s+t*v+w*f)*+g[h+404>>2];g[b+532>>2]=m;g[b+536>>2]=q;g[b+540>>2]=d;g[b+544>>2]=0.0;g[b+548>>2]=F*E+D*A+z*e+((y*s+j*v+k*f)*m+(n*s+o*v+p*f)*q+(r*s+t*v+w*f)*d);g[b+724>>2]=0.0;h=c[b+28>>2]|0;i=c[b+32>>2]|0;d=+Mi(b,h+4|0,i+4|0);g[b+728>>2]=d;g[b+708>>2]=0.0;g[b+712>>2]=0.0;a[b+716>>0]=0;f=+g[b+692>>2];do if(f>=0.0){d=+Vg(d-+g[b+688>>2],6.2831854820251465);if(!(d<-3.1415927410125732)){if(d>3.1415927410125732)d=d+-6.2831854820251465}else d=d+6.2831854820251465;if(d<-f){a[b+716>>0]=1;e=1.0;d=-(d+f)}else{if(!(d>f))break;a[b+716>>0]=1;e=-1.0;d=f-d}g[b+708>>2]=d;g[b+712>>2]=e}while(0);T=+g[b+560>>2];U=+g[b+576>>2];X=+g[b+592>>2];V=T*+g[h+4>>2]+U*+g[h+8>>2]+X*+g[h+12>>2];W=T*+g[h+20>>2]+U*+g[h+24>>2]+X*+g[h+28>>2];X=T*+g[h+36>>2]+U*+g[h+40>>2]+X*+g[h+44>>2];g[b+720>>2]=1.0/(V*(V*+g[h+264>>2]+W*+g[h+280>>2]+X*+g[h+296>>2])+W*(V*+g[h+268>>2]+W*+g[h+284>>2]+X*+g[h+300>>2])+X*(V*+g[h+272>>2]+W*+g[h+288>>2]+X*+g[h+304>>2])+(V*(V*+g[i+264>>2]+W*+g[i+280>>2]+X*+g[i+296>>2])+W*(V*+g[i+268>>2]+W*+g[i+284>>2]+X*+g[i+300>>2])+X*(V*+g[i+272>>2]+W*+g[i+288>>2]+X*+g[i+304>>2])));l=u;return}function Ec(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0,j=0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,D=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0,N=0,O=0,P=0,Q=0.0,R=0.0,S=0.0,T=0.0,U=0.0,V=0.0,W=0.0,X=0.0,Y=0.0,Z=0.0,_=0.0,$=0.0,aa=0.0,ba=0,ca=0.0,da=0.0,ea=0.0,fa=0.0,ga=0.0,ha=0.0,ia=0.0,ja=0.0,ka=0.0,la=0.0,ma=0.0,na=0.0,oa=0.0;M=l;l=l+64|0;if(!(c[b+12>>2]|0)){l=M;return}f=(a[b+16>>0]|0)!=0;P=f?e:d;f=f?d:e;i=c[P+4>>2]|0;j=c[f+4>>2]|0;P=c[P+12>>2]|0;aa=+g[P>>2];$=+g[P+16>>2];_=+g[P+32>>2];Z=+g[P+4>>2];Y=+g[P+20>>2];A=+g[P+36>>2];k=+g[P+8>>2];G=+g[P+24>>2];u=+g[P+40>>2];T=+g[P+48>>2];S=+g[P+52>>2];R=+g[P+56>>2];O=c[f+12>>2]|0;X=+g[O>>2];W=+g[O+16>>2];D=+g[O+32>>2];V=+g[O+4>>2];U=+g[O+20>>2];H=+g[O+36>>2];t=+g[O+8>>2];r=+g[O+24>>2];p=+g[O+40>>2];Q=-+g[O+48>>2];I=-+g[O+52>>2];J=-+g[O+56>>2];K=+g[P>>2];L=+g[P+16>>2];z=+g[P+32>>2];x=+g[P+4>>2];w=+g[P+20>>2];v=+g[P+36>>2];s=+g[P+8>>2];q=+g[P+24>>2];o=+g[P+40>>2];P=c[(c[i>>2]|0)+64>>2]|0;n=-+g[j+48>>2];m=-+g[j+52>>2];y=-+g[j+56>>2];g[M+48>>2]=(aa*X+$*W+_*D)*n+(aa*V+$*U+_*H)*m+(aa*t+$*r+_*p)*y;g[M+48+4>>2]=(Z*X+Y*W+A*D)*n+(Z*V+Y*U+A*H)*m+(Z*t+Y*r+A*p)*y;g[M+48+8>>2]=(k*X+G*W+u*D)*n+(k*V+G*U+u*H)*m+(k*t+G*r+u*p)*y;g[M+48+12>>2]=0.0;Rb[P&127](M,i,M+48|0);y=+g[M>>2];u=+g[M+4>>2];G=+g[M+8>>2];k=+g[j+48>>2];m=+g[j+52>>2];n=+g[j+56>>2];A=n*(T*t+S*r+R*p+(t*Q+r*I+p*J)+((t*K+r*L+p*z)*y+(t*x+r*w+p*v)*u+(t*s+r*q+p*o)*G))+(k*(T*X+S*W+R*D+(X*Q+W*I+D*J)+((X*K+W*L+D*z)*y+(X*x+W*w+D*v)*u+(X*s+W*q+D*o)*G))+m*(T*V+S*U+R*H+(V*Q+U*I+H*J)+((V*K+U*L+H*z)*y+(V*x+U*w+H*v)*u+(V*s+U*q+H*o)*G)))-+g[j+64>>2];D=T*X+S*W+R*D+(X*Q+W*I+D*J)+((X*K+W*L+D*z)*y+(X*x+W*w+D*v)*u+(X*s+W*q+D*o)*G)-k*A;H=T*V+S*U+R*H+(V*Q+U*I+H*J)+((V*K+U*L+H*z)*y+(V*x+U*w+H*v)*u+(V*s+U*q+H*o)*G)-m*A;G=T*t+S*r+R*p+(t*Q+r*I+p*J)+((t*K+r*L+p*z)*y+(t*x+r*w+p*v)*u+(t*s+r*q+p*o)*G)-n*A;P=c[f+12>>2]|0;o=+g[P>>2];p=+g[P+4>>2];q=+g[P+8>>2];r=+g[P+16>>2];s=+g[P+20>>2];t=+g[P+24>>2];u=+g[P+32>>2];v=+g[P+36>>2];w=+g[P+40>>2];x=+g[P+48>>2];y=+g[P+52>>2];z=+g[P+56>>2];P=c[b+12>>2]|0;O=A<+g[P+752>>2];c[h+4>>2]=P;if(O){P=c[f+12>>2]|0;$=k*+g[P+16>>2]+m*+g[P+20>>2]+n*+g[P+24>>2];aa=k*+g[P+32>>2]+m*+g[P+36>>2]+n*+g[P+40>>2];g[M+48>>2]=+g[P>>2]*k+ +g[P+4>>2]*m+ +g[P+8>>2]*n;g[M+48+4>>2]=$;g[M+48+8>>2]=aa;g[M+48+12>>2]=0.0;g[M+32>>2]=q*G+(o*D+p*H)+x;g[M+32+4>>2]=D*r+H*s+G*t+y;g[M+32+8>>2]=D*u+H*v+G*w+z;g[M+32+12>>2]=0.0;Qb[c[(c[h>>2]|0)+16>>2]&15](h,M+48|0,M+32|0,A)}if((c[i+4>>2]|0)<7?(c[(c[h+4>>2]|0)+748>>2]|0)<(c[b+24>>2]|0):0){k=+g[j+56>>2];if(+B(+k)>.7071067690849304){n=+g[j+52>>2];aa=1.0/+C(+(k*k+n*n));m=0.0;n=n*aa;k=-(k*aa)}else{aa=+g[j+48>>2];m=+g[j+52>>2];k=1.0/+C(+(aa*aa+m*m));m=-(m*k);n=0.0;k=aa*k}I=.019999999552965164/+zb[c[(c[i>>2]|0)+16>>2]&15](i);I=(I>.39269909262657166?.39269909262657166:I)*.5;J=+F(+I)/+C(+(m*m+k*k+n*n));L=m*J;K=k*J;J=n*J;I=+E(+I);f=c[b+20>>2]|0;if((f|0)>0){i=0;do{r=+g[j+48>>2];aa=+g[j+52>>2];x=+g[j+56>>2];v=+(i|0)*(6.2831854820251465/+(f|0))*.5;$=+F(+v)/+C(+(r*r+aa*aa+x*x));v=+E(+v);w=J*-(aa*$)+(L*v+I*-(r*$))-K*-(x*$);t=L*-(x*$)+(K*v+I*-(aa*$))-J*-(r*$);da=K*-(r*$)+(J*v+I*-(x*$))-L*-(aa*$);z=I*v-L*-(r*$)-K*-(aa*$)-J*-(x*$);ia=x*$*t+(r*$*z+v*w)-aa*$*da;ha=r*$*da+(v*t+aa*$*z)-x*$*w;la=aa*$*w+(x*$*z+v*da)-r*$*t;da=v*z-r*$*w-aa*$*t-x*$*da;f=(a[b+16>>0]|0)!=0;ba=f?e:d;f=f?d:e;P=c[ba+4>>2]|0;O=c[f+4>>2]|0;ba=c[ba+12>>2]|0;$=+g[ba>>2];x=+g[ba+4>>2];t=+g[ba+8>>2];aa=+g[ba+16>>2];w=+g[ba+20>>2];r=+g[ba+24>>2];z=+g[ba+32>>2];v=+g[ba+36>>2];p=+g[ba+40>>2];V=+g[ba+48>>2];W=+g[ba+52>>2];X=+g[ba+56>>2];ba=c[f+12>>2]|0;R=+g[ba>>2];S=+g[ba+16>>2];A=+g[ba+32>>2];T=+g[ba+4>>2];U=+g[ba+20>>2];H=+g[ba+36>>2];s=+g[ba+8>>2];q=+g[ba+24>>2];o=+g[ba+40>>2];Y=-+g[ba+48>>2];Z=-+g[ba+52>>2];_=-+g[ba+56>>2];ga=ia*(2.0/(ia*ia+ha*ha+la*la+da*da));n=ha*(2.0/(ia*ia+ha*ha+la*la+da*da));ca=la*(2.0/(ia*ia+ha*ha+la*la+da*da));na=t*(ia*ca-da*n)+(x*(ia*n+da*ca)+$*(1.0-(ha*n+la*ca)));ka=t*(ha*ca+da*ga)+($*(ia*n-da*ca)+x*(1.0-(ia*ga+la*ca)));k=$*(ia*ca+da*n)+x*(ha*ca-da*ga)+t*(1.0-(ia*ga+ha*n));ma=r*(ia*ca-da*n)+(w*(ia*n+da*ca)+aa*(1.0-(ha*n+la*ca)));ja=r*(ha*ca+da*ga)+(aa*(ia*n-da*ca)+w*(1.0-(ia*ga+la*ca)));u=aa*(ia*ca+da*n)+w*(ha*ca-da*ga)+r*(1.0-(ia*ga+ha*n));oa=p*(ia*ca-da*n)+(v*(ia*n+da*ca)+z*(1.0-(ha*n+la*ca)));la=p*(ha*ca+da*ga)+(z*(ia*n-da*ca)+v*(1.0-(ia*ga+la*ca)));n=z*(ia*ca+da*n)+v*(ha*ca-da*ga)+p*(1.0-(ia*ga+ha*n));ha=+g[ba>>2];ga=+g[ba+16>>2];ia=+g[ba+32>>2];da=+g[ba+4>>2];ca=+g[ba+20>>2];ea=+g[ba+36>>2];m=+g[ba+8>>2];G=+g[ba+24>>2];D=+g[ba+40>>2];ba=c[(c[P>>2]|0)+64>>2]|0;fa=-+g[O+48>>2];Q=-+g[O+52>>2];y=-+g[O+56>>2];g[M+32>>2]=(ia*oa+(ha*na+ga*ma))*fa+(ea*oa+(da*na+ca*ma))*Q+(D*oa+(m*na+G*ma))*y;g[M+32+4>>2]=(ia*la+(ha*ka+ga*ja))*fa+(ea*la+(da*ka+ca*ja))*Q+(D*la+(m*ka+G*ja))*y;g[M+32+8>>2]=(ia*n+(ha*k+ga*u))*fa+(ea*n+(da*k+ca*u))*Q+(D*n+(m*k+G*u))*y;g[M+32+12>>2]=0.0;Rb[ba&127](M+48|0,P,M+32|0);y=+g[M+48>>2];u=+g[M+48+4>>2];G=+g[M+48+8>>2];k=+g[O+48>>2];m=+g[O+52>>2];n=+g[O+56>>2];D=n*(V*s+W*q+X*o+(s*Y+q*Z+o*_)+(($*s+aa*q+z*o)*y+(x*s+w*q+v*o)*u+(t*s+r*q+p*o)*G))+(k*(V*R+W*S+X*A+(R*Y+S*Z+A*_)+(($*R+aa*S+z*A)*y+(x*R+w*S+v*A)*u+(t*R+r*S+p*A)*G))+m*(V*T+W*U+X*H+(T*Y+U*Z+H*_)+(($*T+aa*U+z*H)*y+(x*T+w*U+v*H)*u+(t*T+r*U+p*H)*G)))-+g[O+64>>2];A=V*R+W*S+X*A+(R*Y+S*Z+A*_)+(($*R+aa*S+z*A)*y+(x*R+w*S+v*A)*u+(t*R+r*S+p*A)*G)-k*D;H=V*T+W*U+X*H+(T*Y+U*Z+H*_)+(($*T+aa*U+z*H)*y+(x*T+w*U+v*H)*u+(t*T+r*U+p*H)*G)-m*D;G=V*s+W*q+X*o+(s*Y+q*Z+o*_)+(($*s+aa*q+z*o)*y+(x*s+w*q+v*o)*u+(t*s+r*q+p*o)*G)-n*D;O=c[f+12>>2]|0;o=+g[O>>2];p=+g[O+4>>2];q=+g[O+8>>2];r=+g[O+16>>2];s=+g[O+20>>2];t=+g[O+24>>2];u=+g[O+32>>2];v=+g[O+36>>2];w=+g[O+40>>2];x=+g[O+48>>2];y=+g[O+52>>2];z=+g[O+56>>2];O=c[b+12>>2]|0;P=D<+g[O+752>>2];c[h+4>>2]=O;if(P){ba=c[f+12>>2]|0;na=k*+g[ba+16>>2]+m*+g[ba+20>>2]+n*+g[ba+24>>2];oa=k*+g[ba+32>>2]+m*+g[ba+36>>2]+n*+g[ba+40>>2];g[M+32>>2]=+g[ba>>2]*k+ +g[ba+4>>2]*m+ +g[ba+8>>2]*n;g[M+32+4>>2]=na;g[M+32+8>>2]=oa;g[M+32+12>>2]=0.0;g[M+16>>2]=q*G+(o*A+p*H)+x;g[M+16+4>>2]=A*r+H*s+G*t+y;g[M+16+8>>2]=A*u+H*v+G*w+z;g[M+16+12>>2]=0.0;Qb[c[(c[h>>2]|0)+16>>2]&15](h,M+32|0,M+16|0,D)}i=i+1|0;f=c[b+20>>2]|0}while((i|0)<(f|0))}}do if((a[b+8>>0]|0?c[(c[b+12>>2]|0)+748>>2]|0:0)?(N=c[h+4>>2]|0,c[N+748>>2]|0):0){i=c[N+740>>2]|0;j=c[(c[h+8>>2]|0)+8>>2]|0;f=c[(c[h+12>>2]|0)+8>>2]|0;if((i|0)==(j|0)){Le(N,i+4|0,f+4|0);break}else{Le(N,f+4|0,j+4|0);break}}while(0);l=M;return}function Fc(d,e,f,h){d=d|0;e=e|0;f=f|0;h=h|0;var i=0,j=0,k=0,l=0,m=0,n=0;c[d+168>>2]=c[d+152>>2];c[e>>2]=9136;c[e+52>>2]=282;a[e+60>>0]=0;a[e+80>>0]=1;c[e+76>>2]=0;c[e+68>>2]=0;c[e+72>>2]=0;a[e+100>>0]=1;c[e+96>>2]=0;c[e+88>>2]=0;c[e+92>>2]=0;a[e+120>>0]=1;c[e+116>>2]=0;c[e+108>>2]=0;c[e+112>>2]=0;a[e+140>>0]=1;c[e+136>>2]=0;c[e+128>>2]=0;c[e+132>>2]=0;c[e+144>>2]=0;a[e+164>>0]=1;c[e+160>>2]=0;c[e+152>>2]=0;c[e+156>>2]=0;c[e+168>>2]=0;c[e+4>>2]=-8388609;c[e+8>>2]=-8388609;c[e+12>>2]=-8388609;g[e+16>>2]=0.0;c[e+20>>2]=2139095039;c[e+24>>2]=2139095039;c[e+28>>2]=2139095039;g[e+32>>2]=0.0;f=c[d+56>>2]|0;if(h){c[e+56>>2]=fA(f|0)|0;a[e+4>>0]=a[d+4+3>>0]|0;a[e+5>>0]=a[d+4+2>>0]|0;a[e+6>>0]=a[d+4+1>>0]|0;a[e+7>>0]=a[d+4>>0]|0;a[e+8>>0]=a[d+8+3>>0]|0;a[e+9>>0]=a[d+8+2>>0]|0;a[e+10>>0]=a[d+8+1>>0]|0;a[e+11>>0]=a[d+8>>0]|0;a[e+12>>0]=a[d+12+3>>0]|0;a[e+13>>0]=a[d+12+2>>0]|0;a[e+14>>0]=a[d+12+1>>0]|0;a[e+15>>0]=a[d+12>>0]|0;a[e+16>>0]=a[d+16+3>>0]|0;a[e+17>>0]=a[d+16+2>>0]|0;a[e+18>>0]=a[d+16+1>>0]|0;a[e+19>>0]=a[d+16>>0]|0;a[e+20>>0]=a[d+20+3>>0]|0;a[e+21>>0]=a[d+20+2>>0]|0;a[e+22>>0]=a[d+20+1>>0]|0;a[e+23>>0]=a[d+20>>0]|0;a[e+24>>0]=a[d+24+3>>0]|0;a[e+25>>0]=a[d+24+2>>0]|0;a[e+26>>0]=a[d+24+1>>0]|0;a[e+27>>0]=a[d+24>>0]|0;a[e+28>>0]=a[d+28+3>>0]|0;a[e+29>>0]=a[d+28+2>>0]|0;a[e+30>>0]=a[d+28+1>>0]|0;a[e+31>>0]=a[d+28>>0]|0;a[e+32>>0]=a[d+32+3>>0]|0;a[e+33>>0]=a[d+32+2>>0]|0;a[e+34>>0]=a[d+32+1>>0]|0;a[e+35>>0]=a[d+32>>0]|0;a[e+36>>0]=a[d+36+3>>0]|0;a[e+37>>0]=a[d+36+2>>0]|0;a[e+38>>0]=a[d+36+1>>0]|0;a[e+39>>0]=a[d+36>>0]|0;a[e+40>>0]=a[d+40+3>>0]|0;a[e+41>>0]=a[d+40+2>>0]|0;a[e+42>>0]=a[d+40+1>>0]|0;a[e+43>>0]=a[d+40>>0]|0;a[e+44>>0]=a[d+44+3>>0]|0;a[e+45>>0]=a[d+44+2>>0]|0;a[e+46>>0]=a[d+44+1>>0]|0;a[e+47>>0]=a[d+44>>0]|0;a[e+48>>0]=a[d+48+3>>0]|0;a[e+49>>0]=a[d+48+2>>0]|0;a[e+50>>0]=a[d+48+1>>0]|0;a[e+51>>0]=a[d+48>>0]|0;c[e+144>>2]=fA(c[d+144>>2]|0)|0;f=fA(c[d+168>>2]|0)|0}else{c[e+56>>2]=f;c[e+4>>2]=c[d+4>>2];c[e+4+4>>2]=c[d+4+4>>2];c[e+4+8>>2]=c[d+4+8>>2];c[e+4+12>>2]=c[d+4+12>>2];c[e+20>>2]=c[d+20>>2];c[e+20+4>>2]=c[d+20+4>>2];c[e+20+8>>2]=c[d+20+8>>2];c[e+20+12>>2]=c[d+20+12>>2];c[e+36>>2]=c[d+36>>2];c[e+36+4>>2]=c[d+36+4>>2];c[e+36+8>>2]=c[d+36+8>>2];c[e+36+12>>2]=c[d+36+12>>2];c[e+144>>2]=c[d+144>>2];f=c[d+168>>2]|0}c[e+168>>2]=f;a[e+60>>0]=a[d+60>>0]|0;m=c[d+56>>2]|0;if(!(a[d+60>>0]|0)){f=c[e+96>>2]|0;if(f|0){if(a[e+100>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[e+96>>2]=0}a[e+100>>0]=0;c[e+96>>2]=e+172;c[e+88>>2]=m;c[e+92>>2]=m;if(h)if((m|0)>0){i=c[d+96>>2]|0;f=e+172|0;j=0;do{l=i+(j<<6)|0;n=f+(j<<6)|0;a[n>>0]=a[l+3>>0]|0;a[n+1>>0]=a[l+2>>0]|0;a[n+2>>0]=a[l+1>>0]|0;a[n+3>>0]=a[l>>0]|0;n=i+(j<<6)+4|0;l=f+(j<<6)+4|0;a[l>>0]=a[n+3>>0]|0;a[l+1>>0]=a[n+2>>0]|0;a[l+2>>0]=a[n+1>>0]|0;a[l+3>>0]=a[n>>0]|0;l=i+(j<<6)+8|0;n=f+(j<<6)+8|0;a[n>>0]=a[l+3>>0]|0;a[n+1>>0]=a[l+2>>0]|0;a[n+2>>0]=a[l+1>>0]|0;a[n+3>>0]=a[l>>0]|0;n=i+(j<<6)+12|0;f=f+(j<<6)+12|0;a[f>>0]=a[n+3>>0]|0;a[f+1>>0]=a[n+2>>0]|0;a[f+2>>0]=a[n+1>>0]|0;a[f+3>>0]=a[n>>0]|0;f=c[d+96>>2]|0;n=f+(j<<6)+16|0;l=c[e+96>>2]|0;k=l+(j<<6)+16|0;a[k>>0]=a[n+3>>0]|0;a[k+1>>0]=a[n+2>>0]|0;a[k+2>>0]=a[n+1>>0]|0;a[k+3>>0]=a[n>>0]|0;k=f+(j<<6)+20|0;n=l+(j<<6)+20|0;a[n>>0]=a[k+3>>0]|0;a[n+1>>0]=a[k+2>>0]|0;a[n+2>>0]=a[k+1>>0]|0;a[n+3>>0]=a[k>>0]|0;n=f+(j<<6)+24|0;k=l+(j<<6)+24|0;a[k>>0]=a[n+3>>0]|0;a[k+1>>0]=a[n+2>>0]|0;a[k+2>>0]=a[n+1>>0]|0;a[k+3>>0]=a[n>>0]|0;f=f+(j<<6)+28|0;l=l+(j<<6)+28|0;a[l>>0]=a[f+3>>0]|0;a[l+1>>0]=a[f+2>>0]|0;a[l+2>>0]=a[f+1>>0]|0;a[l+3>>0]=a[f>>0]|0;i=c[d+96>>2]|0;l=fA(c[i+(j<<6)+32>>2]|0)|0;f=c[e+96>>2]|0;c[f+(j<<6)+32>>2]=l;c[f+(j<<6)+36>>2]=fA(c[i+(j<<6)+36>>2]|0)|0;c[f+(j<<6)+40>>2]=fA(c[i+(j<<6)+40>>2]|0)|0;j=j+1|0}while((j|0)!=(m|0))}else f=e+172|0;else if((m|0)>0){i=c[d+96>>2]|0;f=e+172|0;j=0;do{l=i+(j<<6)|0;n=f+(j<<6)|0;c[n>>2]=c[l>>2];c[n+4>>2]=c[l+4>>2];c[n+8>>2]=c[l+8>>2];c[n+12>>2]=c[l+12>>2];n=(c[d+96>>2]|0)+(j<<6)+16|0;f=(c[e+96>>2]|0)+(j<<6)+16|0;c[f>>2]=c[n>>2];c[f+4>>2]=c[n+4>>2];c[f+8>>2]=c[n+8>>2];c[f+12>>2]=c[n+12>>2];i=c[d+96>>2]|0;f=c[e+96>>2]|0;c[f+(j<<6)+32>>2]=c[i+(j<<6)+32>>2];c[f+(j<<6)+36>>2]=c[i+(j<<6)+36>>2];c[f+(j<<6)+40>>2]=c[i+(j<<6)+40>>2];j=j+1|0}while((j|0)!=(m|0))}else f=e+172|0;if(!f){i=e+96|0;j=e+100|0;k=e+92|0;l=e+88|0;f=m<<6}else{if(a[e+100>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[e+96>>2]=0;i=e+96|0;j=e+100|0;k=e+92|0;l=e+88|0;f=m<<6}}else{f=c[e+136>>2]|0;if(f|0){if(a[e+140>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[e+136>>2]=0}a[e+140>>0]=0;c[e+136>>2]=e+172;c[e+128>>2]=m;c[e+132>>2]=m;if(h){if((m|0)>0){f=c[d+136>>2]|0;i=0;do{b[e+172+(i<<4)>>1]=KF(b[f+(i<<4)>>1]|0)|0;b[e+172+(i<<4)+2>>1]=KF(b[f+(i<<4)+2>>1]|0)|0;b[e+172+(i<<4)+4>>1]=KF(b[f+(i<<4)+4>>1]|0)|0;b[e+172+(i<<4)+6>>1]=KF(b[f+(i<<4)+6>>1]|0)|0;b[e+172+(i<<4)+8>>1]=KF(b[f+(i<<4)+8>>1]|0)|0;b[e+172+(i<<4)+10>>1]=KF(b[f+(i<<4)+10>>1]|0)|0;c[e+172+(i<<4)+12>>2]=fA(c[f+(i<<4)+12>>2]|0)|0;i=i+1|0}while((i|0)!=(m|0))}}else if((m|0)>0){f=c[d+136>>2]|0;i=0;do{b[e+172+(i<<4)>>1]=b[f+(i<<4)>>1]|0;b[e+172+(i<<4)+2>>1]=b[f+(i<<4)+2>>1]|0;b[e+172+(i<<4)+4>>1]=b[f+(i<<4)+4>>1]|0;b[e+172+(i<<4)+6>>1]=b[f+(i<<4)+6>>1]|0;b[e+172+(i<<4)+8>>1]=b[f+(i<<4)+8>>1]|0;b[e+172+(i<<4)+10>>1]=b[f+(i<<4)+10>>1]|0;c[e+172+(i<<4)+12>>2]=c[f+(i<<4)+12>>2];i=i+1|0}while((i|0)!=(m|0))}c[e+136>>2]=0;i=e+136|0;j=e+140|0;k=e+132|0;l=e+128|0;f=m<<4}a[j>>0]=0;c[i>>2]=0;c[l>>2]=0;c[k>>2]=0;k=e+172+f|0;f=c[d+168>>2]|0;i=c[e+160>>2]|0;if(i|0){if(a[e+164>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[e+160>>2]=0}a[e+164>>0]=0;c[e+160>>2]=k;c[e+152>>2]=f;c[e+156>>2]=f;j=c[d+168>>2]|0;if(h){if((j|0)<=0){c[e>>2]=0;c[e+152>>2]=0;c[e+152+4>>2]=0;c[e+152+8>>2]=0;a[e+152+12>>0]=0;return 1}f=c[d+160>>2]|0;i=0;do{b[k+(i<<5)>>1]=KF(b[f+(i<<5)>>1]|0)|0;b[k+(i<<5)+2>>1]=KF(b[f+(i<<5)+2>>1]|0)|0;b[k+(i<<5)+4>>1]=KF(b[f+(i<<5)+4>>1]|0)|0;b[k+(i<<5)+6>>1]=KF(b[f+(i<<5)+6>>1]|0)|0;b[k+(i<<5)+8>>1]=KF(b[f+(i<<5)+8>>1]|0)|0;b[k+(i<<5)+10>>1]=KF(b[f+(i<<5)+10>>1]|0)|0;c[k+(i<<5)+12>>2]=fA(c[f+(i<<5)+12>>2]|0)|0;c[k+(i<<5)+16>>2]=fA(c[f+(i<<5)+16>>2]|0)|0;i=i+1|0}while((i|0)!=(j|0));c[e>>2]=0;c[e+152>>2]=0;c[e+152+4>>2]=0;c[e+152+8>>2]=0;a[e+152+12>>0]=0;return 1}else{if((j|0)<=0){c[e>>2]=0;c[e+152>>2]=0;c[e+152+4>>2]=0;c[e+152+8>>2]=0;a[e+152+12>>0]=0;return 1}f=c[d+160>>2]|0;i=0;do{b[k+(i<<5)>>1]=b[f+(i<<5)>>1]|0;b[k+(i<<5)+2>>1]=b[f+(i<<5)+2>>1]|0;b[k+(i<<5)+4>>1]=b[f+(i<<5)+4>>1]|0;b[k+(i<<5)+6>>1]=b[f+(i<<5)+6>>1]|0;b[k+(i<<5)+8>>1]=b[f+(i<<5)+8>>1]|0;b[k+(i<<5)+10>>1]=b[f+(i<<5)+10>>1]|0;c[k+(i<<5)+12>>2]=c[f+(i<<5)+12>>2];c[k+(i<<5)+16>>2]=c[f+(i<<5)+16>>2];c[k+(i<<5)+20>>2]=0;c[k+(i<<5)+24>>2]=0;c[k+(i<<5)+28>>2]=0;i=i+1|0}while((i|0)<(c[d+168>>2]|0));c[e>>2]=0;c[e+152>>2]=0;c[e+152+4>>2]=0;c[e+152+8>>2]=0;a[e+152+12>>0]=0;return 1}return 0}function Gc(b,d,e,f,h,i,j,k,m,n){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;j=j|0;k=k|0;m=m|0;n=n|0;var o=0.0,p=0,q=0,r=0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0,B=0.0,C=0,D=0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0;C=l;l=l+4224|0;if(((c[e+4>>2]|0)+-17|0)>>>0<2)A=((c[f+4>>2]|0)+-17|0)>>>0<2;else A=0;b=0;do{Ce();v=+g[24660+(b<<4)>>2];w=+g[24660+(b<<4)+4>>2];x=+g[24660+(b<<4)+8>>2];z=+g[h+4>>2]*-v+ +g[h+20>>2]*-w+ +g[h+36>>2]*-x;y=+g[h+8>>2]*-v+ +g[h+24>>2]*-w+ +g[h+40>>2]*-x;g[C+1248+(b<<4)>>2]=+g[h>>2]*-v+ +g[h+16>>2]*-w+ +g[h+32>>2]*-x;g[C+1248+(b<<4)+4>>2]=z;g[C+1248+(b<<4)+8>>2]=y;g[C+1248+(b<<4)+12>>2]=0.0;y=v*+g[i+4>>2]+w*+g[i+20>>2]+x*+g[i+36>>2];z=v*+g[i+8>>2]+w*+g[i+24>>2]+x*+g[i+40>>2];g[C+256+(b<<4)>>2]=v*+g[i>>2]+w*+g[i+16>>2]+x*+g[i+32>>2];g[C+256+(b<<4)+4>>2]=y;g[C+256+(b<<4)+8>>2]=z;g[C+256+(b<<4)+12>>2]=0.0;b=b+1|0}while((b|0)!=42);b=lb[c[(c[e>>2]|0)+84>>2]&127](e)|0;if((b|0)>0){p=0;q=42;while(1){Rb[c[(c[e>>2]|0)+88>>2]&127](e,p,C+176|0);y=+g[C+176>>2];z=+g[C+176+4>>2];x=+g[C+176+8>>2];w=y*+g[h+16>>2]+z*+g[h+20>>2]+x*+g[h+24>>2];v=y*+g[h+32>>2]+z*+g[h+36>>2]+x*+g[h+40>>2];g[C+176>>2]=+g[h>>2]*y+ +g[h+4>>2]*z+ +g[h+8>>2]*x;g[C+176+4>>2]=w;g[C+176+8>>2]=v;g[C+176+12>>2]=0.0;Ce();r=24660+(q<<4)|0;c[r>>2]=c[C+176>>2];c[r+4>>2]=c[C+176+4>>2];c[r+8>>2]=c[C+176+8>>2];c[r+12>>2]=c[C+176+12>>2];v=+g[C+176>>2];w=+g[C+176+4>>2];x=+g[C+176+8>>2];z=+g[h+4>>2]*-v+ +g[h+20>>2]*-w+ +g[h+36>>2]*-x;y=+g[h+8>>2]*-v+ +g[h+24>>2]*-w+ +g[h+40>>2]*-x;g[C+1248+(q<<4)>>2]=+g[h>>2]*-v+ +g[h+16>>2]*-w+ +g[h+32>>2]*-x;g[C+1248+(q<<4)+4>>2]=z;g[C+1248+(q<<4)+8>>2]=y;g[C+1248+(q<<4)+12>>2]=0.0;y=v*+g[i+4>>2]+w*+g[i+20>>2]+x*+g[i+36>>2];z=v*+g[i+8>>2]+w*+g[i+24>>2]+x*+g[i+40>>2];g[C+256+(q<<4)>>2]=+g[i>>2]*v+ +g[i+16>>2]*w+ +g[i+32>>2]*x;g[C+256+(q<<4)+4>>2]=y;g[C+256+(q<<4)+8>>2]=z;g[C+256+(q<<4)+12>>2]=0.0;p=p+1|0;if((p|0)==(b|0))break;else q=q+1|0}q=b+42|0}else q=42;b=lb[c[(c[f>>2]|0)+84>>2]&127](f)|0;if((b|0)>0){p=0;r=q;while(1){Rb[c[(c[f>>2]|0)+88>>2]&127](f,p,C+176|0);y=+g[C+176>>2];z=+g[C+176+4>>2];x=+g[C+176+8>>2];w=y*+g[i+16>>2]+z*+g[i+20>>2]+x*+g[i+24>>2];v=y*+g[i+32>>2]+z*+g[i+36>>2]+x*+g[i+40>>2];g[C+176>>2]=+g[i>>2]*y+ +g[i+4>>2]*z+ +g[i+8>>2]*x;g[C+176+4>>2]=w;g[C+176+8>>2]=v;g[C+176+12>>2]=0.0;Ce();D=24660+(r<<4)|0;c[D>>2]=c[C+176>>2];c[D+4>>2]=c[C+176+4>>2];c[D+8>>2]=c[C+176+8>>2];c[D+12>>2]=c[C+176+12>>2];v=+g[C+176>>2];w=+g[C+176+4>>2];x=+g[C+176+8>>2];z=+g[h+4>>2]*-v+ +g[h+20>>2]*-w+ +g[h+36>>2]*-x;y=+g[h+8>>2]*-v+ +g[h+24>>2]*-w+ +g[h+40>>2]*-x;g[C+1248+(r<<4)>>2]=+g[h>>2]*-v+ +g[h+16>>2]*-w+ +g[h+32>>2]*-x;g[C+1248+(r<<4)+4>>2]=z;g[C+1248+(r<<4)+8>>2]=y;g[C+1248+(r<<4)+12>>2]=0.0;y=v*+g[i+4>>2]+w*+g[i+20>>2]+x*+g[i+36>>2];z=v*+g[i+8>>2]+w*+g[i+24>>2]+x*+g[i+40>>2];g[C+256+(r<<4)>>2]=+g[i>>2]*v+ +g[i+16>>2]*w+ +g[i+32>>2]*x;g[C+256+(r<<4)+4>>2]=y;g[C+256+(r<<4)+8>>2]=z;g[C+256+(r<<4)+12>>2]=0.0;p=p+1|0;if((p|0)==(b|0))break;else r=r+1|0}q=b+q|0}Vb[c[(c[e>>2]|0)+76>>2]&127](e,C+1248|0,C+3232|0,q);Vb[c[(c[f>>2]|0)+76>>2]&127](f,C+256|0,C+2240|0,q);if((q|0)>0){z=0.0;w=0.0;v=0.0;b=0;u=0.0;s=999999984306749440.0;while(1){Ce();t=+g[24660+(b<<4)>>2];x=+g[24660+(b<<4)+4>>2];y=+g[24660+(b<<4)+12>>2];o=A?0.0:+g[24660+(b<<4)+8>>2];if(t*t+x*x+o*o>.01?(F=+g[C+3232+(b<<4)>>2],E=+g[C+3232+(b<<4)+4>>2],B=+g[C+3232+(b<<4)+8>>2],I=+g[C+2240+(b<<4)>>2],H=+g[C+2240+(b<<4)+4>>2],G=+g[C+2240+(b<<4)+8>>2],B=t*(I*+g[i>>2]+H*+g[i+4>>2]+G*+g[i+8>>2]+ +g[i+48>>2]-(F*+g[h>>2]+E*+g[h+4>>2]+B*+g[h+8>>2]+ +g[h+48>>2]))+x*(I*+g[i+16>>2]+H*+g[i+20>>2]+G*+g[i+24>>2]+ +g[i+52>>2]-(F*+g[h+16>>2]+E*+g[h+20>>2]+B*+g[h+24>>2]+ +g[h+52>>2]))+o*((A?0.0:I*+g[i+32>>2]+H*+g[i+36>>2]+G*+g[i+40>>2]+ +g[i+56>>2])-(A?0.0:F*+g[h+32>>2]+E*+g[h+36>>2]+B*+g[h+40>>2]+ +g[h+56>>2])),B<s):0){v=t;w=x;u=y;s=B}else o=z;b=b+1|0;if((b|0)==(q|0)){x=o;break}else z=o}}else{x=0.0;w=0.0;v=0.0;u=0.0;s=999999984306749440.0}switch(c[e+4>>2]|0){case 4:case 5:case 10:case 11:case 13:case 1:case 0:case 8:break;default:+zb[c[(c[e>>2]|0)+48>>2]&15](e)}switch(c[f+4>>2]|0){case 4:case 5:case 10:case 11:case 13:case 1:case 0:case 8:break;default:+zb[c[(c[f>>2]|0)+48>>2]&15](f)}if(s<0.0){D=0;l=C;return D|0}switch(c[e+4>>2]|0){case 8:{t=+g[e+28>>2]*+g[e+12>>2];break}case 0:{t=+g[e+44>>2];break}case 1:{t=+g[e+44>>2];break}case 13:{t=+g[e+44>>2];break}case 11:{t=+g[e+44>>2];break}case 10:{t=+g[e+44>>2];break}case 4:case 5:{t=+g[e+44>>2];break}default:t=+zb[c[(c[e>>2]|0)+48>>2]&15](e)}b=c[f+4>>2]|0;switch(b|0){case 8:{b=8;o=+g[f+28>>2]*+g[f+12>>2];break}case 0:{b=0;o=+g[f+44>>2];break}case 1:{b=1;o=+g[f+44>>2];break}case 13:{b=13;o=+g[f+44>>2];break}case 11:{b=11;o=+g[f+44>>2];break}case 10:{b=10;o=+g[f+44>>2];break}case 4:case 5:{o=+g[f+44>>2];break}default:{o=+zb[c[(c[f>>2]|0)+48>>2]&15](f);b=c[f+4>>2]|0}}o=s+(t+o+.5);c[C+176>>2]=9360;c[C+176+4>>2]=0;c[C+176+8>>2]=1065353216;c[C+176+12>>2]=0;g[C+176+16>>2]=0.0;c[C+176+20>>2]=0;c[C+176+24>>2]=d;c[C+176+28>>2]=e;c[C+176+32>>2]=f;c[C+176+36>>2]=c[e+4>>2];c[C+176+40>>2]=b;g[C+176+44>>2]=+zb[c[(c[e>>2]|0)+48>>2]&15](e);g[C+176+48>>2]=+zb[c[(c[f>>2]|0)+48>>2]&15](f);a[C+176+52>>0]=0;c[C+176+60>>2]=-1;c[C+176+72>>2]=1;c[C+176+76>>2]=1;G=v*o+ +g[h+48>>2];H=w*o+ +g[h+52>>2];I=x*o+ +g[h+56>>2];c[C+44>>2]=c[h>>2];c[C+44+4>>2]=c[h+4>>2];c[C+44+8>>2]=c[h+8>>2];c[C+44+12>>2]=c[h+12>>2];c[C+44+16>>2]=c[h+16>>2];c[C+44+16+4>>2]=c[h+16+4>>2];c[C+44+16+8>>2]=c[h+16+8>>2];c[C+44+16+12>>2]=c[h+16+12>>2];c[C+44+32>>2]=c[h+32>>2];c[C+44+32+4>>2]=c[h+32+4>>2];c[C+44+32+8>>2]=c[h+32+8>>2];c[C+44+32+12>>2]=c[h+32+12>>2];g[C+44+48>>2]=G;g[C+44+52>>2]=H;g[C+44+56>>2]=I;g[C+44+60>>2]=0.0;c[C+44+64>>2]=c[i>>2];c[C+44+64+4>>2]=c[i+4>>2];c[C+44+64+8>>2]=c[i+8>>2];c[C+44+64+12>>2]=c[i+12>>2];c[C+44+80>>2]=c[i+16>>2];c[C+44+80+4>>2]=c[i+16+4>>2];c[C+44+80+8>>2]=c[i+16+8>>2];c[C+44+80+12>>2]=c[i+16+12>>2];c[C+44+96>>2]=c[i+32>>2];c[C+44+96+4>>2]=c[i+32+4>>2];c[C+44+96+8>>2]=c[i+32+8>>2];c[C+44+96+12>>2]=c[i+32+12>>2];c[C+44+112>>2]=c[i+48>>2];c[C+44+112+4>>2]=c[i+48+4>>2];c[C+44+112+8>>2]=c[i+48+8>>2];c[C+44+112+12>>2]=c[i+48+12>>2];g[C+44+128>>2]=999999984306749440.0;c[C>>2]=9244;a[C+40>>0]=0;g[C+176+4>>2]=-v;g[C+176+8>>2]=-w;g[C+176+12>>2]=-x;g[C+176+16>>2]=0.0;Ac(C+176|0,C+44|0,C,n,0);o=o-+g[C+36>>2];b=a[C+40>>0]|0;if(b<<24>>24){H=+g[C+24>>2]-w*o;I=+g[C+28>>2]-x*o;g[k>>2]=+g[C+20>>2]-v*o;g[k+4>>2]=H;g[k+8>>2]=I;g[k+12>>2]=0.0;c[m>>2]=c[C+20>>2];c[m+4>>2]=c[C+20+4>>2];c[m+8>>2]=c[C+20+8>>2];c[m+12>>2]=c[C+20+12>>2];g[j>>2]=v;g[j+4>>2]=w;g[j+8>>2]=x;g[j+12>>2]=u}D=b<<24>>24!=0;l=C;return D|0}function Hc(b){b=b|0;var d=0,e=0.0,f=0.0,h=0.0,i=0,j=0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0,E=0,F=0,G=0,H=0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0.0;H=l;l=l+192|0;Yi(11162);d=c[b+1112>>2]|0;if((d|0)>0){G=0;do{F=c[(c[b+1120>>2]|0)+(G<<2)>>2]|0;E=c[F+24>>2]|0;if(E){i=H+144+4|0;j=i+44|0;do{c[i>>2]=0;i=i+4|0}while((i|0)<(j|0));g[H+144>>2]=9.999999747378752e-05;g[H+144+20>>2]=1.9999999494757503e-04;g[H+144+40>>2]=2.9999998514540493e-04;if((E|0)>0){d=c[F+32>>2]|0;i=c[F+12>>2]|0;e=0.0;f=0.0;h=0.0;j=0;do{D=c[d+(j<<2)>>2]|0;C=+g[i+(j<<2)>>2];e=e+ +g[D+8>>2]*C;f=f+C*+g[D+12>>2];h=h+C*+g[D+16>>2];j=j+1|0}while((j|0)!=(E|0))}else{h=0.0;f=0.0;e=0.0}r=+g[F+128>>2];t=e*r;s=f*r;r=h*r;g[F+228>>2]=t;g[F+232>>2]=s;g[F+236>>2]=r;g[F+240>>2]=0.0;if((E|0)>0){d=c[F+32>>2]|0;i=c[F+52>>2]|0;e=9.999999747378752e-05;f=0.0;h=0.0;k=1.9999999494757503e-04;m=0.0;n=0.0;o=0.0;p=2.9999998514540493e-04;q=0.0;j=0;do{D=c[d+(j<<2)>>2]|0;x=+g[D+8>>2]-t;y=+g[D+12>>2]-s;B=+g[D+16>>2]-r;z=+g[i+(j<<4)>>2];A=+g[i+(j<<4)+4>>2];C=+g[i+(j<<4)+8>>2];e=x*z+e;f=x*A+f;h=x*C+h;q=y*z+q;k=y*A+k;m=y*C+m;n=B*z+n;o=B*A+o;p=B*C+p;j=j+1|0}while((j|0)!=(E|0));g[H+144>>2]=e;g[H+144+4>>2]=f;g[H+144+8>>2]=h;g[H+144+16>>2]=q;g[H+144+20>>2]=k;g[H+144+24>>2]=m;g[H+144+32>>2]=n;g[H+144+36>>2]=o;g[H+144+40>>2]=p}if((a[22664]|0)==0?jy(22664)|0:0){g[5784]=9.999999747378752e-05;c[5785]=16}Vc(H+144|0,H+96|0,H+48|0);c[F+108>>2]=c[F+228>>2];c[F+108+4>>2]=c[F+228+4>>2];c[F+108+8>>2]=c[F+228+8>>2];c[F+108+12>>2]=c[F+228+12>>2];c[F+60>>2]=c[H+96>>2];c[F+60+4>>2]=c[H+96+4>>2];c[F+60+8>>2]=c[H+96+8>>2];c[F+60+12>>2]=c[H+96+12>>2];c[F+76>>2]=c[H+96+16>>2];c[F+76+4>>2]=c[H+96+16+4>>2];c[F+76+8>>2]=c[H+96+16+8>>2];c[F+76+12>>2]=c[H+96+16+12>>2];c[F+92>>2]=c[H+96+32>>2];c[F+92+4>>2]=c[H+96+32+4>>2];c[F+92+8>>2]=c[H+96+32+8>>2];c[F+92+12>>2]=c[H+96+32+12>>2];m=+g[F+132>>2];K=+g[F+60>>2];n=+g[F+148>>2];J=+g[F+64>>2];o=+g[F+164>>2];y=+g[F+68>>2];p=+g[F+136>>2];q=+g[F+152>>2];r=+g[F+168>>2];s=+g[F+140>>2];t=+g[F+156>>2];u=+g[F+172>>2];I=+g[F+76>>2];e=+g[F+80>>2];x=+g[F+84>>2];k=+g[F+92>>2];h=+g[F+96>>2];f=+g[F+100>>2];w=(m*K+n*J+o*y)*K+(K*p+J*q+y*r)*J+(K*s+J*t+y*u)*y;v=(m*K+n*J+o*y)*I+(K*p+J*q+y*r)*e+(K*s+J*t+y*u)*x;C=(m*K+n*J+o*y)*k+(K*p+J*q+y*r)*h+(K*s+J*t+y*u)*f;B=(m*I+n*e+o*x)*K+(p*I+q*e+r*x)*J+(s*I+t*e+u*x)*y;A=(m*I+n*e+o*x)*I+(p*I+q*e+r*x)*e+(s*I+t*e+u*x)*x;z=(m*I+n*e+o*x)*k+(p*I+q*e+r*x)*h+(s*I+t*e+u*x)*f;y=K*(m*k+n*h+o*f)+(p*k+q*h+r*f)*J+(s*k+t*h+u*f)*y;x=I*(m*k+n*h+o*f)+(p*k+q*h+r*f)*e+(s*k+t*h+u*f)*x;u=(m*k+n*h+o*f)*k+(p*k+q*h+r*f)*h+(s*k+t*h+u*f)*f;g[F+180>>2]=w;g[F+184>>2]=v;g[F+188>>2]=C;g[F+192>>2]=0.0;g[F+196>>2]=B;g[F+200>>2]=A;g[F+204>>2]=z;g[F+208>>2]=0.0;g[F+212>>2]=y;g[F+216>>2]=x;g[F+220>>2]=u;g[F+224>>2]=0.0;c[F+316>>2]=0;c[F+316+4>>2]=0;c[F+316+8>>2]=0;c[F+316+12>>2]=0;c[F+316+16>>2]=0;c[F+316+20>>2]=0;c[F+316+24>>2]=0;c[F+316+28>>2]=0;if((E|0)>0){d=c[F+32>>2]|0;i=c[F+12>>2]|0;r=+g[F+228>>2];s=+g[F+232>>2];t=+g[F+236>>2];q=0.0;p=0.0;o=0.0;n=0.0;m=0.0;e=0.0;j=0;do{D=c[d+(j<<2)>>2]|0;M=+g[i+(j<<2)>>2];J=+g[D+40>>2]*M;L=M*+g[D+44>>2];M=M*+g[D+48>>2];q=J+q;g[F+316>>2]=q;p=L+p;g[F+320>>2]=p;o=M+o;g[F+324>>2]=o;I=+g[D+8>>2]-r;K=+g[D+12>>2]-s;N=+g[D+16>>2]-t;n=n+(M*K-L*N);g[F+332>>2]=n;m=J*N-M*I+m;g[F+336>>2]=m;e=L*I-J*K+e;g[F+340>>2]=e;j=j+1|0}while((j|0)!=(E|0));D=F+316|0;d=F+332|0}else{q=0.0;p=0.0;o=0.0;n=0.0;m=0.0;e=0.0;D=F+316|0;d=F+332|0}M=+g[F+128>>2];N=1.0-+g[F+356>>2];g[F+316>>2]=q*M*N;g[F+320>>2]=M*p*N;g[F+324>>2]=M*o*N;g[F+328>>2]=0.0;N=1.0-+g[F+360>>2];g[d>>2]=(w*n+v*m+C*e)*N;g[F+336>>2]=(n*B+m*A+e*z)*N;g[F+340>>2]=N*(n*y+m*x+e*u);g[F+344>>2]=0.0;i=F+244|0;j=i+72|0;do{c[i>>2]=0;i=i+4|0}while((i|0)<(j|0));e=+g[F+364>>2];a:do if(e>0.0?(c[F+24>>2]|0)>0:0){d=0;while(1){j=c[(c[F+32>>2]|0)+(d<<2)>>2]|0;i=c[F+52>>2]|0;I=+g[i+(d<<4)>>2];J=+g[i+(d<<4)+4>>2];K=+g[i+(d<<4)+8>>2];L=+g[j+8>>2];M=+g[j+12>>2];N=+g[j+16>>2];M=M+e*(I*+g[F+76>>2]+J*+g[F+80>>2]+K*+g[F+84>>2]+ +g[F+112>>2]-M);N=N+e*(I*k+J*h+K*f+ +g[F+116>>2]-N);g[j+8>>2]=L+e*(I*+g[F+60>>2]+J*+g[F+64>>2]+K*+g[F+68>>2]+ +g[F+108>>2]-L);g[j+12>>2]=M;g[j+16>>2]=N;g[j+20>>2]=0.0;d=d+1|0;if((d|0)>=(c[F+24>>2]|0))break a;k=+g[F+92>>2];h=+g[F+96>>2];f=+g[F+100>>2];e=+g[F+364>>2]}}while(0);if(a[F+377>>0]|0){d=c[F+32>>2]|0;j=c[d>>2]|0;e=+g[j+8>>2];q=+g[j+12>>2];r=+g[j+16>>2];f=+g[j+20>>2];if((E|0)>1){i=1;o=e;p=r;n=f;m=q;k=e;h=f;f=q;e=r;do{j=c[d+(i<<2)>>2]|0;K=+g[j+8>>2];o=K<o?K:o;L=+g[j+12>>2];m=L<m?L:m;M=+g[j+16>>2];p=M<p?M:p;N=+g[j+20>>2];n=N<n?N:n;k=k<K?K:k;f=f<L?L:f;e=e<M?M:e;h=h<N?N:h;i=i+1|0}while((i|0)!=(E|0))}else{o=e;p=r;n=f;m=q;k=e;h=f;f=q;e=r}g[H+16>>2]=o;g[H+16+4>>2]=m;g[H+16+8>>2]=p;g[H+16+12>>2]=n;g[H+16+16>>2]=k;g[H+16+20>>2]=f;g[H+16+24>>2]=e;g[H+16+28>>2]=h;d=c[F+348>>2]|0;if(!d){d=c[b+1052>>2]|0;if(!d){c[6432]=(c[6432]|0)+1;d=ec(63)|0;if(!d)d=0;else{c[(d+4+15&-16)+-4>>2]=d;d=d+4+15&-16}i=d;j=i+44|0;do{c[i>>2]=0;i=i+4|0}while((i|0)<(j|0))}else c[b+1052>>2]=0;c[d+32>>2]=0;c[d+36>>2]=F;c[d+40>>2]=0;c[d>>2]=c[H+16>>2];c[d+4>>2]=c[H+16+4>>2];c[d+8>>2]=c[H+16+8>>2];c[d+12>>2]=c[H+16+12>>2];c[d+16>>2]=c[H+16+16>>2];c[d+20>>2]=c[H+16+20>>2];c[d+24>>2]=c[H+16+24>>2];c[d+28>>2]=c[H+16+28>>2];We(b+1048|0,c[b+1048>>2]|0,d);c[b+1060>>2]=(c[b+1060>>2]|0)+1;c[F+348>>2]=d}else{L=+g[b+452>>2];M=L*+g[F+320>>2]*3.0;N=L*+g[F+324>>2]*3.0;g[H>>2]=+g[D>>2]*L*3.0;g[H+4>>2]=M;g[H+8>>2]=N;g[H+12>>2]=0.0;Ug(b+1048|0,d,H+16|0,H,+g[b+464>>2])|0}}d=c[b+1112>>2]|0}G=G+1|0}while((G|0)<(d|0))}d=c[2395]|0;b=(c[d+16>>2]|0)+-1|0;c[d+16>>2]=b;if(b|0){l=H;return}do if(c[d+4>>2]|0){Va(H+144|0,0)|0;b=c[6431]|0;g[d+8>>2]=+g[d+8>>2]+ +(((c[H+144+4>>2]|0)-(c[b+4>>2]|0)+(((c[H+144>>2]|0)-(c[b>>2]|0)|0)*1e6|0)-(c[d+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[d+16>>2]|0)){d=c[2395]|0;break}else{l=H;return}}while(0);c[2395]=c[d+20>>2];l=H;return}function Ic(d,e){d=d|0;e=+e;var f=0,h=0,i=0,j=0,k=0.0,m=0,n=0.0,o=0.0,p=0.0,q=0,r=0,s=0,t=0.0,u=0.0,v=0.0,w=0.0,x=0,y=0.0,z=0.0,A=0.0,B=0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0.0;B=l;l=l+464|0;Yi(12023);f=c[d+84>>2]|0;if(f|0)gb[f&31](d,e);gb[c[(c[d>>2]|0)+140>>2]&31](d,e);g[d+28>>2]=e;c[d+32>>2]=0;c[d+48>>2]=lb[c[(c[d>>2]|0)+20>>2]&127](d)|0;Yi(12066);Yi(12091);f=c[d+316>>2]|0;if((c[d+308>>2]|0)>0){h=0;do{s=c[d+24>>2]|0;jb[c[(c[s>>2]|0)+16>>2]&127](s,c[f+(h<<2)>>2]|0);h=h+1|0;f=c[d+316>>2]|0}while((h|0)<(c[d+308>>2]|0))}if(f|0){if(a[d+320>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[d+316>>2]=0}a[d+320>>0]=1;c[d+316>>2]=0;c[d+308>>2]=0;c[d+312>>2]=0;f=c[2395]|0;s=(c[f+16>>2]|0)+-1|0;c[f+16>>2]=s;do if(!s){if(c[f+4>>2]|0){Va(B+368|0,0)|0;s=c[6431]|0;g[f+8>>2]=+g[f+8>>2]+ +(((c[B+368+4>>2]|0)-(c[s+4>>2]|0)+(((c[B+368>>2]|0)-(c[s>>2]|0)|0)*1e6|0)-(c[f+12>>2]|0)|0)>>>0)/1.0e3;if(c[f+16>>2]|0)break;f=c[2395]|0}c[2395]=c[f+20>>2]}while(0);a:do if((c[d+232>>2]|0)>0){s=B+304+48|0;r=B+368+44|0;q=0;while(1){j=c[(c[d+240>>2]|0)+(q<<2)>>2]|0;g[j+244>>2]=1.0;b:do switch(c[j+216>>2]|0){case 2:case 5:break;default:if(((c[j+204>>2]&3|0)==0?(Cg(j+4|0,+g[j+312>>2],+g[j+316>>2],+g[j+320>>2],j+328|0,e,B+304|0),t=+g[s>>2],y=t-+g[j+52>>2],u=+g[B+304+52>>2],A=u-+g[j+56>>2],v=+g[B+304+56>>2],z=v-+g[j+60>>2],a[d+44>>0]|0):0)?(p=+g[j+252>>2],p*p!=0.0?p*p<y*y+A*A+z*z:0):0){Yi(12128);if((c[(c[j+192>>2]|0)+4>>2]|0)<20?(c[5813]=(c[5813]|0)+1,i=c[d+68>>2]|0,i=lb[c[(c[i>>2]|0)+36>>2]&127](i)|0,m=c[d+24>>2]|0,g[B+368+4>>2]=1.0,c[B+368+12>>2]=c[j+52>>2],c[B+368+12+4>>2]=c[j+52+4>>2],c[B+368+12+8>>2]=c[j+52+8>>2],c[B+368+12+12>>2]=c[j+52+12>>2],c[B+368+28>>2]=c[s>>2],c[B+368+28+4>>2]=c[s+4>>2],c[B+368+28+8>>2]=c[s+8>>2],c[B+368+28+12>>2]=c[s+12>>2],c[B+368+76>>2]=0,c[B+368>>2]=4460,c[B+368+80>>2]=j,c[B+368+88>>2]=i,c[B+368+92>>2]=m,m=c[j+248>>2]|0,c[B+248+8>>2]=0,c[B+248+12>>2]=1065353216,c[B+248+16>>2]=1065353216,c[B+248+20>>2]=1065353216,g[B+248+24>>2]=0.0,c[B+248>>2]=6796,c[B+248+4>>2]=8,c[B+248+28>>2]=m,c[B+248+44>>2]=m,c[B+368+84>>2]=c[d+56>>2],m=c[j+188>>2]|0,b[B+368+8>>1]=b[m+4>>1]|0,b[B+368+10>>1]=b[m+6>>1]|0,c[B+184+48>>2]=c[s>>2],c[B+184+48+4>>2]=c[s+4>>2],c[B+184+48+8>>2]=c[s+8>>2],c[B+184+48+12>>2]=c[s+12>>2],c[B+184>>2]=c[j+4>>2],c[B+184+4>>2]=c[j+4+4>>2],c[B+184+8>>2]=c[j+4+8>>2],c[B+184+12>>2]=c[j+4+12>>2],c[B+184+16>>2]=c[j+20>>2],c[B+184+16+4>>2]=c[j+20+4>>2],c[B+184+16+8>>2]=c[j+20+8>>2],c[B+184+16+12>>2]=c[j+20+12>>2],c[B+184+32>>2]=c[j+36>>2],c[B+184+32+4>>2]=c[j+36+4>>2],c[B+184+32+8>>2]=c[j+36+8>>2],c[B+184+32+12>>2]=c[j+36+12>>2],ud(d,B+248|0,j+4|0,B+184|0,B+368|0,0.0),w=+g[B+368+4>>2],w<1.0):0){n=w*(t-+g[j+52>>2]);o=w*(u-+g[j+56>>2]);p=w*(v-+g[j+60>>2]);k=-(o*+g[B+368+48>>2])-n*+g[r>>2]-p*+g[B+368+52>>2];m=c[d+24>>2]|0;m=vb[c[(c[m>>2]|0)+12>>2]&63](m,j,c[B+368+76>>2]|0)|0;f=c[d+308>>2]|0;if((f|0)==(c[d+312>>2]|0)?(x=f|0?f<<1:1,(f|0)<(x|0)):0){if(!x)h=0;else{c[6432]=(c[6432]|0)+1;f=ec((x<<2|3)+16|0)|0;if(!f)h=0;else{c[(f+4+15&-16)+-4>>2]=f;h=f+4+15&-16}f=c[d+308>>2]|0}if((f|0)>0){i=0;do{c[h+(i<<2)>>2]=c[(c[d+316>>2]|0)+(i<<2)>>2];i=i+1|0}while((i|0)!=(f|0))}i=c[d+316>>2]|0;if(i){if(a[d+320>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0);f=c[d+308>>2]|0}c[d+316>>2]=0}a[d+320>>0]=1;c[d+316>>2]=h;c[d+312>>2]=x}c[(c[d+316>>2]|0)+(f<<2)>>2]=m;c[d+308>>2]=f+1;n=n+ +g[j+52>>2];o=o+ +g[j+56>>2];p=p+ +g[j+60>>2];i=c[B+368+76>>2]|0;N=+g[i+4>>2];M=+g[i+20>>2];L=+g[i+36>>2];K=+g[i+8>>2];J=+g[i+24>>2];I=+g[i+40>>2];H=+g[i+12>>2];F=+g[i+28>>2];D=+g[i+44>>2];G=-+g[i+52>>2];E=-+g[i+56>>2];C=-+g[i+60>>2];c[B>>2]=0;c[B+4>>2]=0;c[B+8>>2]=0;c[B+12>>2]=0;g[B+16>>2]=n*N+o*M+p*L+(N*G+M*E+L*C);g[B+20>>2]=n*K+o*J+p*I+(K*G+J*E+I*C);g[B+24>>2]=n*H+o*F+p*D+(H*G+F*E+D*C);g[B+28>>2]=0.0;c[B+64>>2]=c[r>>2];c[B+64+4>>2]=c[r+4>>2];c[B+64+8>>2]=c[r+8>>2];c[B+64+12>>2]=c[r+12>>2];g[B+80>>2]=k;g[B+84>>2]=0.0;g[B+88>>2]=0.0;g[B+92>>2]=0.0;c[B+112>>2]=0;a[B+116>>0]=0;c[B+120>>2]=0;c[B+120+4>>2]=0;c[B+120+8>>2]=0;c[B+120+12>>2]=0;c[B+120+16>>2]=0;c[B+120+20>>2]=0;c[B+120+24>>2]=0;c[B+120+28>>2]=0;i=Ye(m,B)|0;g[m+4+(i*184|0)+92>>2]=0.0;k=+g[j+224>>2]*+g[(c[B+368+76>>2]|0)+224>>2];k=k<-10.0?-10.0:k;g[m+4+(i*184|0)+84>>2]=k>10.0?10.0:k;c[m+4+(i*184|0)+48>>2]=c[j+52>>2];c[m+4+(i*184|0)+48+4>>2]=c[j+52+4>>2];c[m+4+(i*184|0)+48+8>>2]=c[j+52+8>>2];c[m+4+(i*184|0)+48+12>>2]=c[j+52+12>>2];g[m+4+(i*184|0)+32>>2]=n;g[m+4+(i*184|0)+36>>2]=o;g[m+4+(i*184|0)+40>>2]=p;g[m+4+(i*184|0)+44>>2]=0.0}f=c[2395]|0;m=(c[f+16>>2]|0)+-1|0;c[f+16>>2]=m;if(!m){if(c[f+4>>2]|0){Va(B+368|0,0)|0;m=c[6431]|0;g[f+8>>2]=+g[f+8>>2]+ +(((c[B+368+4>>2]|0)-(c[m+4>>2]|0)+(((c[B+368>>2]|0)-(c[m>>2]|0)|0)*1e6|0)-(c[f+12>>2]|0)|0)>>>0)/1.0e3;if(c[f+16>>2]|0)break b;f=c[2395]|0}c[2395]=c[f+20>>2]}}}while(0);q=q+1|0;if((q|0)>=(c[d+232>>2]|0))break a}}while(0);f=c[2395]|0;x=(c[f+16>>2]|0)+-1|0;c[f+16>>2]=x;do if(!x){if(c[f+4>>2]|0){Va(B+368|0,0)|0;x=c[6431]|0;g[f+8>>2]=+g[f+8>>2]+ +(((c[B+368+4>>2]|0)-(c[x+4>>2]|0)+(((c[B+368>>2]|0)-(c[x>>2]|0)|0)*1e6|0)-(c[f+12>>2]|0)|0)>>>0)/1.0e3;if(c[f+16>>2]|0)break;f=c[2395]|0}c[2395]=c[f+20>>2]}while(0);hb[c[(c[d>>2]|0)+44>>2]&511](d);hb[c[(c[d>>2]|0)+148>>2]&511](d);g[d+104>>2]=e;jb[c[(c[d>>2]|0)+152>>2]&127](d,d+92|0);gb[c[(c[d>>2]|0)+144>>2]&31](d,e);Yi(12052);if((c[d+280>>2]|0)>0){f=0;do{x=c[(c[d+288>>2]|0)+(f<<2)>>2]|0;Tb[c[(c[x>>2]|0)+8>>2]&7](x,d,e);f=f+1|0}while((f|0)<(c[d+280>>2]|0))}f=c[2395]|0;x=(c[f+16>>2]|0)+-1|0;c[f+16>>2]=x;do if(!x){if(c[f+4>>2]|0){Va(B+368|0,0)|0;x=c[6431]|0;g[f+8>>2]=+g[f+8>>2]+ +(((c[B+368+4>>2]|0)-(c[x+4>>2]|0)+(((c[B+368>>2]|0)-(c[x>>2]|0)|0)*1e6|0)-(c[f+12>>2]|0)|0)>>>0)/1.0e3;if(c[f+16>>2]|0)break;f=c[2395]|0}c[2395]=c[f+20>>2]}while(0);gb[c[(c[d>>2]|0)+156>>2]&31](d,e);f=c[d+80>>2]|0;if(f|0)gb[f&31](d,e);f=c[2395]|0;d=(c[f+16>>2]|0)+-1|0;c[f+16>>2]=d;if(d|0){l=B;return}do if(c[f+4>>2]|0){Va(B+368|0,0)|0;d=c[6431]|0;g[f+8>>2]=+g[f+8>>2]+ +(((c[B+368+4>>2]|0)-(c[d+4>>2]|0)+(((c[B+368>>2]|0)-(c[d>>2]|0)|0)*1e6|0)-(c[f+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[f+16>>2]|0)){f=c[2395]|0;break}else{l=B;return}}while(0);c[2395]=c[f+20>>2];l=B;return}function Jc(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0,i=0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,D=0,E=0,F=0,G=0.0,H=0.0;F=l;l=l+784|0;c[F+168+8>>2]=0;c[F+168+12>>2]=1065353216;c[F+168+16>>2]=1065353216;c[F+168+20>>2]=1065353216;g[F+168+24>>2]=0.0;c[F+168>>2]=6796;c[F+168+4>>2]=8;g[F+168+28>>2]=0.0;g[F+168+44>>2]=0.0;D=c[e+4>>2]|0;E=c[e+12>>2]|0;h=c[D+4>>2]|0;if((h|0)<20){c[F+600>>2]=3816;c[F+600+168>>2]=0;g[F+600+172>>2]=0.0;c[F+600+164>>2]=c[f+4>>2];g[F+240+308>>2]=9.999999747378752e-05;a[F+240+332>>0]=0;c[F+224>>2]=5088;c[F+224+4>>2]=F+240;c[F+224+8>>2]=F+168;c[F+224+12>>2]=D;c[F+152>>2]=9292;c[F+152+4>>2]=F+240;c[F+152+8>>2]=F+168;c[F+152+12>>2]=D;D=(c[f+16>>2]&8|0)==0?F+224|0:F+152|0;if((Ab[c[(c[D>>2]|0)+8>>2]&3](D,b,d,E,E,F+600|0)|0?(i=F+600+132|0,j=+g[i>>2],k=+g[F+600+136>>2],m=+g[F+600+140>>2],j*j+k*k+m*m>9.999999747378752e-05):0)?(n=+g[F+600+164>>2],n<+g[f+4>>2]):0){B=1.0/+C(+(j*j+k*k+m*m));g[i>>2]=j*B;g[F+600+136>>2]=k*B;g[F+600+140>>2]=m*B;c[F+120>>2]=c[e+8>>2];c[F+120+4>>2]=0;c[F+120+8>>2]=c[i>>2];c[F+120+8+4>>2]=c[i+4>>2];c[F+120+8+8>>2]=c[i+8>>2];c[F+120+8+12>>2]=c[i+12>>2];g[F+120+24>>2]=n;+Hb[c[(c[f>>2]|0)+12>>2]&15](f,F+120|0,1)}l=F;return}if((h+-21|0)>>>0>=9){if((h|0)!=31){l=F;return}h=c[D+64>>2]|0;e=c[e+8>>2]|0;c[F+600>>2]=5884;c[F+600+4>>2]=e;c[F+600+8>>2]=D;c[F+600+12>>2]=E;c[F+600+16>>2]=b;c[F+600+20>>2]=d;c[F+600+24>>2]=f;if(!h){h=c[D+16>>2]|0;if((h|0)>0){i=0;do{Ef(F+600|0,i);i=i+1|0}while((i|0)<(h|0))}}else{w=+g[E+48>>2];n=+g[b+48>>2]-w;y=+g[E+52>>2];o=+g[b+52>>2]-y;A=+g[E+56>>2];p=+g[b+56>>2]-A;q=+g[E>>2];r=+g[E+16>>2];s=+g[E+32>>2];t=+g[E+4>>2];u=+g[E+20>>2];v=+g[E+36>>2];x=+g[E+8>>2];z=+g[E+24>>2];B=+g[E+40>>2];g[F+240>>2]=n*q+o*r+p*s;g[F+240+4>>2]=n*t+o*u+p*v;g[F+240+8>>2]=n*x+o*z+p*B;g[F+240+12>>2]=0.0;w=+g[d+48>>2]-w;y=+g[d+52>>2]-y;A=+g[d+56>>2]-A;g[F+224>>2]=w*q+y*r+A*s;g[F+224+4>>2]=w*t+y*u+A*v;g[F+224+8>>2]=w*x+y*z+A*B;g[F+224+12>>2]=0.0;pe(c[h>>2]|0,F+240|0,F+224|0,F+600|0)}l=F;return}o=+g[E>>2];p=+g[E+16>>2];j=+g[E+32>>2];m=+g[E+4>>2];t=+g[E+20>>2];u=+g[E+36>>2];k=+g[E+8>>2];x=+g[E+24>>2];y=+g[E+40>>2];z=-+g[E+48>>2];A=-+g[E+52>>2];B=-+g[E+56>>2];q=+g[b+48>>2];r=+g[b+52>>2];n=+g[b+56>>2];g[F+152>>2]=o*z+p*A+j*B+(o*q+p*r+j*n);g[F+152+4>>2]=m*z+t*A+u*B+(m*q+t*r+u*n);g[F+152+8>>2]=k*z+x*A+y*B+(k*q+x*r+y*n);g[F+152+12>>2]=0.0;v=+g[d+48>>2];w=+g[d+52>>2];s=+g[d+56>>2];j=o*z+p*A+j*B+(o*v+p*w+j*s);m=m*z+t*A+u*B+(m*v+t*w+u*s);k=k*z+x*A+y*B+(k*v+x*w+y*s);g[F+120>>2]=j;g[F+120+4>>2]=m;g[F+120+8>>2]=k;g[F+120+12>>2]=0.0;switch(c[D+4>>2]|0){case 21:{h=c[e+8>>2]|0;e=c[f+16>>2]|0;c[F+4>>2]=c[F+152>>2];c[F+4+4>>2]=c[F+152+4>>2];c[F+4+8>>2]=c[F+152+8>>2];c[F+4+12>>2]=c[F+152+12>>2];c[F+20>>2]=c[F+120>>2];c[F+20+4>>2]=c[F+120+4>>2];c[F+20+8>>2]=c[F+120+8>>2];c[F+20+12>>2]=c[F+120+12>>2];c[F+36>>2]=e;g[F+40>>2]=1.0;c[F>>2]=5836;c[F+44>>2]=f;c[F+48>>2]=h;c[F+52>>2]=D;c[F+56>>2]=c[E>>2];c[F+56+4>>2]=c[E+4>>2];c[F+56+8>>2]=c[E+8>>2];c[F+56+12>>2]=c[E+12>>2];c[F+72>>2]=c[E+16>>2];c[F+72+4>>2]=c[E+16+4>>2];c[F+72+8>>2]=c[E+16+8>>2];c[F+72+12>>2]=c[E+16+12>>2];c[F+88>>2]=c[E+32>>2];c[F+88+4>>2]=c[E+32+4>>2];c[F+88+8>>2]=c[E+32+8>>2];c[F+88+12>>2]=c[E+32+12>>2];c[F+104>>2]=c[E+48>>2];c[F+104+4>>2]=c[E+48+4>>2];c[F+104+8>>2]=c[E+48+8>>2];c[F+104+12>>2]=c[E+48+12>>2];c[F+40>>2]=c[f+4>>2];h=c[D+48>>2]|0;c[F+224>>2]=7008;c[F+224+4>>2]=h;c[F+224+8>>2]=F;h=c[D+52>>2]|0;c[F+600>>2]=0;c[F+600+4>>2]=0;c[F+600+8>>2]=0;c[F+600+12>>2]=0;c[F+240>>2]=0;c[F+240+4>>2]=0;c[F+240+8>>2]=0;c[F+240+12>>2]=0;if(!(a[h+60>>0]|0))Be(h,F+224|0,F+152|0,j,m,k,F+600|0,F+240|0);else fe(h,F+224|0,F+152|0,j,m,k,F+600|0,F+240|0,c[h+56>>2]|0);break}case 25:{e=c[e+8>>2]|0;d=c[f+16>>2]|0;c[F+600+4>>2]=c[F+152>>2];c[F+600+4+4>>2]=c[F+152+4>>2];c[F+600+4+8>>2]=c[F+152+8>>2];c[F+600+4+12>>2]=c[F+152+12>>2];c[F+600+20>>2]=c[F+120>>2];c[F+600+20+4>>2]=c[F+120+4>>2];c[F+600+20+8>>2]=c[F+120+8>>2];c[F+600+20+12>>2]=c[F+120+12>>2];c[F+600+36>>2]=d;g[F+600+40>>2]=1.0;c[F+600>>2]=5836;c[F+600+44>>2]=f;c[F+600+48>>2]=e;c[F+600+52>>2]=D;c[F+600+56>>2]=c[E>>2];c[F+600+56+4>>2]=c[E+4>>2];c[F+600+56+8>>2]=c[E+8>>2];c[F+600+56+12>>2]=c[E+12>>2];c[F+600+72>>2]=c[E+16>>2];c[F+600+72+4>>2]=c[E+16+4>>2];c[F+600+72+8>>2]=c[E+16+8>>2];c[F+600+72+12>>2]=c[E+16+12>>2];c[F+600+88>>2]=c[E+32>>2];c[F+600+88+4>>2]=c[E+32+4>>2];c[F+600+88+8>>2]=c[E+32+8>>2];c[F+600+88+12>>2]=c[E+32+12>>2];c[F+600+104>>2]=c[E+48>>2];c[F+600+104+4>>2]=c[E+48+4>>2];c[F+600+104+8>>2]=c[E+48+8>>2];c[F+600+104+12>>2]=c[E+48+12>>2];c[F+600+40>>2]=c[f+4>>2];Vb[c[(c[D>>2]|0)+144>>2]&127](D,F+600|0,F+152|0,F+120|0);break}default:{H=+g[E>>2];G=+g[E+16>>2];m=+g[E+32>>2];k=+g[E+4>>2];j=+g[E+8>>2];o=H*z+G*A+m*B+(H*q+G*r+m*n);p=k*z+t*A+u*B+(k*q+t*r+u*n);n=j*z+x*A+y*B+(j*q+x*r+y*n);m=H*z+G*A+m*B+(H*v+G*w+m*s);k=k*z+t*A+u*B+(k*v+t*w+u*s);j=j*z+x*A+y*B+(j*v+x*w+y*s);e=c[e+8>>2]|0;d=c[f+16>>2]|0;g[F+600+4>>2]=o;g[F+600+8>>2]=p;g[F+600+12>>2]=n;g[F+600+16>>2]=0.0;g[F+600+20>>2]=m;g[F+600+24>>2]=k;g[F+600+28>>2]=j;g[F+600+32>>2]=0.0;c[F+600+36>>2]=d;g[F+600+40>>2]=1.0;c[F+600>>2]=5860;c[F+600+44>>2]=f;c[F+600+48>>2]=e;c[F+600+52>>2]=D;c[F+600+56>>2]=c[E>>2];c[F+600+56+4>>2]=c[E+4>>2];c[F+600+56+8>>2]=c[E+8>>2];c[F+600+56+12>>2]=c[E+12>>2];c[F+600+72>>2]=c[E+16>>2];c[F+600+72+4>>2]=c[E+16+4>>2];c[F+600+72+8>>2]=c[E+16+8>>2];c[F+600+72+12>>2]=c[E+16+12>>2];c[F+600+88>>2]=c[E+32>>2];c[F+600+88+4>>2]=c[E+32+4>>2];c[F+600+88+8>>2]=c[E+32+8>>2];c[F+600+88+12>>2]=c[E+32+12>>2];c[F+600+104>>2]=c[E+48>>2];c[F+600+104+4>>2]=c[E+48+4>>2];c[F+600+104+8>>2]=c[E+48+8>>2];c[F+600+104+12>>2]=c[E+48+12>>2];c[F+600+40>>2]=c[f+4>>2];g[F+240>>2]=o;g[F+240+4>>2]=p;g[F+240+8>>2]=n;g[F+240+12>>2]=0.0;if(m<o)g[F+240>>2]=m;if(k<p)g[F+240+4>>2]=k;if(j<n)g[F+240+8>>2]=j;g[F+224>>2]=o;g[F+224+4>>2]=p;g[F+224+8>>2]=n;g[F+224+12>>2]=0.0;if(o<m)g[F+224>>2]=m;if(p<k)g[F+224+4>>2]=k;if(n<j)g[F+224+8>>2]=j;Vb[c[(c[D>>2]|0)+64>>2]&127](D,F+600|0,F+240|0,F+224|0)}}l=F;return}function Kc(b,d,e,f,h,i,j,k,l,m){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;j=j|0;k=k|0;l=l|0;m=m|0;var n=0.0,o=0,p=0,q=0,r=0,s=0,t=0,u=0.0;h=c[b+48>>2]|0;q=c[b+28>>2]|0;r=c[b+68>>2]|0;if(c[l+64>>2]&1|0){if((h|0)>0){i=c[b+136>>2]|0;m=c[b+192>>2]|0;p=0;do{o=i+(p<<2)|0;f=c[o>>2]|0;p=p+1|0;m=(O(m,1664525)|0)+1013904223|0;if(p>>>0<65537){e=m>>>16^m;if(p>>>0<257)if(p>>>0<17){e=(e>>>8^e)>>>4^(e>>>8^e);e=p>>>0<5?(p>>>0<3?(e>>>2^e)>>>1:0)^(e>>>2^e):e}else e=e>>>8^e}else e=m;e=i+(((e>>>0)%(p>>>0)|0)<<2)|0;c[o>>2]=c[e>>2];c[e>>2]=f}while((p|0)!=(h|0));c[b+192>>2]=m}if((c[l+20>>2]|0)>(d|0)){if((q|0)>0){f=c[b+116>>2]|0;i=c[b+192>>2]|0;o=0;do{m=f+(o<<2)|0;h=c[m>>2]|0;o=o+1|0;i=(O(i,1664525)|0)+1013904223|0;if(o>>>0<65537){e=i>>>16^i;if(o>>>0<257)if(o>>>0<17){e=(e>>>8^e)>>>4^(e>>>8^e);e=o>>>0<5?(o>>>0<3?(e>>>2^e)>>>1:0)^(e>>>2^e):e}else e=e>>>8^e}else e=i;p=f+(((e>>>0)%(o>>>0)|0)<<2)|0;c[m>>2]=c[p>>2];c[p>>2]=h}while((o|0)!=(q|0));c[b+192>>2]=i}if((r|0)>0){f=c[b+156>>2]|0;i=c[b+192>>2]|0;o=0;do{m=f+(o<<2)|0;h=c[m>>2]|0;o=o+1|0;i=(O(i,1664525)|0)+1013904223|0;if(o>>>0<65537){e=i>>>16^i;if(o>>>0<257)if(o>>>0<17){e=(e>>>8^e)>>>4^(e>>>8^e);e=o>>>0<5?(o>>>0<3?(e>>>2^e)>>>1:0)^(e>>>2^e):e}else e=e>>>8^e}else e=i;q=f+(((e>>>0)%(o>>>0)|0)<<2)|0;c[m>>2]=c[q>>2];c[q>>2]=h}while((o|0)!=(r|0));c[b+192>>2]=i}}}e=c[b+48>>2]|0;if(!(c[l+64>>2]&256)){if((e|0)>0){i=0;do{f=c[(c[b+136>>2]|0)+(i<<2)>>2]|0;h=c[b+56>>2]|0;if((c[h+(f*152|0)+136>>2]|0)>(d|0)){e=c[b+16>>2]|0;kg(e+((c[h+(f*152|0)+144>>2]|0)*244|0)|0,e+((c[h+(f*152|0)+148>>2]|0)*244|0)|0,h+(f*152|0)|0);e=c[b+48>>2]|0}i=i+1|0}while((i|0)<(e|0))}if((c[l+20>>2]|0)<=(d|0))return 0.0;if((k|0)>0){h=0;do{f=j+(h<<2)|0;e=c[f>>2]|0;if(a[e+20>>0]|0){d=Bj(b,c[e+28>>2]|0,+g[l+12>>2])|0;t=Bj(b,c[(c[f>>2]|0)+32>>2]|0,+g[l+12>>2])|0;s=c[b+16>>2]|0;r=c[f>>2]|0;Qb[c[(c[r>>2]|0)+24>>2]&15](r,s+(d*244|0)|0,s+(t*244|0)|0,+g[l+12>>2])}h=h+1|0}while((h|0)!=(k|0))}e=c[b+28>>2]|0;if((e|0)>0){f=0;do{l=c[(c[b+116>>2]|0)+(f<<2)>>2]|0;k=c[b+36>>2]|0;j=c[b+16>>2]|0;sg(j+((c[k+(l*152|0)+144>>2]|0)*244|0)|0,j+((c[k+(l*152|0)+148>>2]|0)*244|0)|0,k+(l*152|0)|0);f=f+1|0}while((f|0)!=(e|0))}e=c[b+68>>2]|0;if((e|0)>0){i=0;do{f=c[(c[b+156>>2]|0)+(i<<2)>>2]|0;h=c[b+76>>2]|0;n=+g[(c[b+36>>2]|0)+((c[h+(f*152|0)+140>>2]|0)*152|0)+100>>2];if(n>0.0){n=n*+g[h+(f*152|0)+104>>2];g[h+(f*152|0)+120>>2]=-n;g[h+(f*152|0)+124>>2]=n;l=c[b+16>>2]|0;kg(l+((c[h+(f*152|0)+144>>2]|0)*244|0)|0,l+((c[h+(f*152|0)+148>>2]|0)*244|0)|0,h+(f*152|0)|0)}i=i+1|0}while((i|0)!=(e|0))}e=c[b+88>>2]|0;if((e|0)<=0)return 0.0;h=0;do{f=c[b+96>>2]|0;n=+g[(c[b+36>>2]|0)+((c[f+(h*152|0)+140>>2]|0)*152|0)+100>>2];if(n>0.0){u=+g[f+(h*152|0)+104>>2];n=n*u>u?u:n*u;g[f+(h*152|0)+120>>2]=-n;g[f+(h*152|0)+124>>2]=n;l=c[b+16>>2]|0;kg(l+((c[f+(h*152|0)+144>>2]|0)*244|0)|0,l+((c[f+(h*152|0)+148>>2]|0)*244|0)|0,f+(h*152|0)|0)}h=h+1|0}while((h|0)!=(e|0));return 0.0}if((e|0)>0){i=0;do{f=c[(c[b+136>>2]|0)+(i<<2)>>2]|0;h=c[b+56>>2]|0;if((c[h+(f*152|0)+136>>2]|0)>(d|0)){e=c[b+16>>2]|0;kg(e+((c[h+(f*152|0)+144>>2]|0)*244|0)|0,e+((c[h+(f*152|0)+148>>2]|0)*244|0)|0,h+(f*152|0)|0);e=c[b+48>>2]|0}i=i+1|0}while((i|0)<(e|0))}if((c[l+20>>2]|0)<=(d|0))return 0.0;if((k|0)>0){h=0;do{f=j+(h<<2)|0;e=c[f>>2]|0;if(a[e+20>>0]|0){q=Bj(b,c[e+28>>2]|0,+g[l+12>>2])|0;d=Bj(b,c[(c[f>>2]|0)+32>>2]|0,+g[l+12>>2])|0;r=c[b+16>>2]|0;p=c[f>>2]|0;Qb[c[(c[p>>2]|0)+24>>2]&15](p,r+(q*244|0)|0,r+(d*244|0)|0,+g[l+12>>2])}h=h+1|0}while((h|0)!=(k|0))}e=c[l+64>>2]|0;o=c[b+28>>2]|0;if(e&512|0){if((o|0)<=0)return 0.0;i=0;do{m=c[(c[b+116>>2]|0)+(i<<2)>>2]|0;f=c[b+36>>2]|0;h=c[b+16>>2]|0;sg(h+((c[f+(m*152|0)+144>>2]|0)*244|0)|0,h+((c[f+(m*152|0)+148>>2]|0)*244|0)|0,f+(m*152|0)|0);n=+g[f+(m*152|0)+100>>2];m=O(i,(e>>>4&1)+1|0)|0;f=c[(c[b+156>>2]|0)+(m<<2)>>2]|0;h=c[b+76>>2]|0;if(n>0.0){u=n*+g[h+(f*152|0)+104>>2];g[h+(f*152|0)+120>>2]=-u;g[h+(f*152|0)+124>>2]=u;k=c[b+16>>2]|0;kg(k+((c[h+(f*152|0)+144>>2]|0)*244|0)|0,k+((c[h+(f*152|0)+148>>2]|0)*244|0)|0,h+(f*152|0)|0)}if(c[l+64>>2]&16|0?(s=c[(c[b+156>>2]|0)+(m+1<<2)>>2]|0,t=c[b+76>>2]|0,n>0.0):0){u=n*+g[t+(s*152|0)+104>>2];g[t+(s*152|0)+120>>2]=-u;g[t+(s*152|0)+124>>2]=u;k=c[b+16>>2]|0;kg(k+((c[t+(s*152|0)+144>>2]|0)*244|0)|0,k+((c[t+(s*152|0)+148>>2]|0)*244|0)|0,t+(s*152|0)|0)}i=i+1|0}while((i|0)!=(o|0));return 0.0}if((o|0)>0){e=0;do{l=c[(c[b+116>>2]|0)+(e<<2)>>2]|0;k=c[b+36>>2]|0;j=c[b+16>>2]|0;sg(j+((c[k+(l*152|0)+144>>2]|0)*244|0)|0,j+((c[k+(l*152|0)+148>>2]|0)*244|0)|0,k+(l*152|0)|0);e=e+1|0}while((e|0)!=(o|0))}e=c[b+68>>2]|0;if((e|0)>0){i=0;do{f=c[(c[b+156>>2]|0)+(i<<2)>>2]|0;h=c[b+76>>2]|0;n=+g[(c[b+36>>2]|0)+((c[h+(f*152|0)+140>>2]|0)*152|0)+100>>2];if(n>0.0){u=n*+g[h+(f*152|0)+104>>2];g[h+(f*152|0)+120>>2]=-u;g[h+(f*152|0)+124>>2]=u;l=c[b+16>>2]|0;kg(l+((c[h+(f*152|0)+144>>2]|0)*244|0)|0,l+((c[h+(f*152|0)+148>>2]|0)*244|0)|0,h+(f*152|0)|0)}i=i+1|0}while((i|0)!=(e|0))}e=c[b+88>>2]|0;if((e|0)<=0)return 0.0;h=0;do{f=c[b+96>>2]|0;n=+g[(c[b+36>>2]|0)+((c[f+(h*152|0)+140>>2]|0)*152|0)+100>>2];if(n>0.0){u=+g[f+(h*152|0)+104>>2];u=n*u>u?u:n*u;g[f+(h*152|0)+120>>2]=-u;g[f+(h*152|0)+124>>2]=u;l=c[b+16>>2]|0;kg(l+((c[f+(h*152|0)+144>>2]|0)*244|0)|0,l+((c[f+(h*152|0)+148>>2]|0)*244|0)|0,f+(h*152|0)|0)}h=h+1|0}while((h|0)!=(e|0));return 0.0}function Lc(a,b){a=a|0;b=+b;var d=0,e=0,f=0,h=0,i=0,j=0,k=0,m=0,n=0,o=0,p=0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0;o=l;l=l+48|0;d=c[a+24>>2]|0;if((d|0)<=0){l=o;return}n=0;a:while(1){m=c[(c[a+32>>2]|0)+(n<<2)>>2]|0;switch(c[m+216>>2]|0){case 2:case 5:break;default:{Cd(m,0);d=c[m+732>>2]|0;if((d|0)>0){e=0;do{k=c[m+740>>2]|0;i=c[k+(e*52|0)+12>>2]|0;j=c[k+(e*52|0)+8>>2]|0;y=+g[i+24>>2]-+g[j+24>>2];x=+g[i+28>>2]-+g[j+28>>2];b=+g[i+32>>2]-+g[j+32>>2];g[k+(e*52|0)+36>>2]=y;g[k+(e*52|0)+40>>2]=x;g[k+(e*52|0)+44>>2]=b;g[k+(e*52|0)+48>>2]=0.0;g[k+(e*52|0)+32>>2]=1.0/(+g[k+(e*52|0)+24>>2]*(y*y+x*x+b*b));e=e+1|0}while((e|0)!=(d|0))}d=c[m+792>>2]|0;if((d|0)>0){b=+g[m+452>>2];f=0;do{k=c[m+800>>2]|0;e=k+(f*96|0)+20|0;i=c[e>>2]|0;H=+g[k+(f*96|0)+4>>2];J=+g[k+(f*96|0)+8>>2];y=+g[k+(f*96|0)+12>>2];z=+g[i+4>>2]*H+ +g[i+8>>2]*J+ +g[i+12>>2]*y;x=H*+g[i+20>>2]+J*+g[i+24>>2]+y*+g[i+28>>2];y=H*+g[i+36>>2]+J*+g[i+40>>2]+y*+g[i+44>>2];j=k+(f*96|0)|0;J=+g[(c[j>>2]|0)+88>>2];H=1.0/b;Ch(o,+g[i+344>>2],i+264|0,z,x,y);C=J+ +g[o>>2];G=+g[o+4>>2]+0.0;E=+g[o+8>>2]+0.0;D=+g[o+16>>2]+0.0;F=J+ +g[o+20>>2];B=+g[o+24>>2]+0.0;I=+g[o+32>>2]+0.0;K=+g[o+36>>2]+0.0;J=J+ +g[o+40>>2];A=1.0/(E*(D*K-F*I)+(C*(F*J-B*K)+G*(B*I-D*J)));g[k+(f*96|0)+28>>2]=(D*K-F*I)*A*0.0+(H*(F*J-B*K)*A+(B*I-D*J)*A*0.0);g[k+(f*96|0)+32>>2]=(G*I-C*K)*A*0.0+(H*(E*K-G*J)*A+(C*J-E*I)*A*0.0);g[k+(f*96|0)+36>>2]=(C*F-G*D)*A*0.0+(H*(G*B-E*F)*A+(E*D-C*B)*A*0.0);g[k+(f*96|0)+40>>2]=0.0;g[k+(f*96|0)+44>>2]=(D*K-F*I)*A*0.0+((F*J-B*K)*A*0.0+H*(B*I-D*J)*A);g[k+(f*96|0)+48>>2]=(G*I-C*K)*A*0.0+((E*K-G*J)*A*0.0+H*(C*J-E*I)*A);g[k+(f*96|0)+52>>2]=(C*F-G*D)*A*0.0+((G*B-E*F)*A*0.0+H*(E*D-C*B)*A);g[k+(f*96|0)+56>>2]=0.0;g[k+(f*96|0)+60>>2]=H*(D*K-F*I)*A+((F*J-B*K)*A*0.0+(B*I-D*J)*A*0.0);g[k+(f*96|0)+64>>2]=H*(G*I-C*K)*A+((E*K-G*J)*A*0.0+(C*J-E*I)*A*0.0);g[k+(f*96|0)+68>>2]=H*(C*F-G*D)*A+((G*B-E*F)*A*0.0+(E*D-C*B)*A*0.0);g[k+(f*96|0)+72>>2]=0.0;g[k+(f*96|0)+76>>2]=z;g[k+(f*96|0)+80>>2]=x;g[k+(f*96|0)+84>>2]=y;g[k+(f*96|0)+88>>2]=0.0;b=+g[m+452>>2];g[k+(f*96|0)+92>>2]=b*+g[(c[j>>2]|0)+88>>2];e=c[e>>2]|0;if(!(c[e+204>>2]&3)){if((c[e+216>>2]&-2|0)!=4)c[e+216>>2]=1;g[e+220>>2]=0.0}f=f+1|0}while((f|0)!=(d|0))}d=c[m+372>>2]|0;if((d|0)>0){e=c[m+396>>2]|0;f=0;do{if((e|0)>0){d=0;do{gb[((c[(c[m+404>>2]|0)+(d<<2)>>2]|0)==0?23:0)&31](m,1.0);d=d+1|0;e=c[m+396>>2]|0}while((d|0)<(e|0));d=c[m+372>>2]|0}f=f+1|0}while((f|0)<(d|0));d=c[m+712>>2]|0;if((d|0)>0){e=0;do{k=c[m+720>>2]|0;I=+g[m+452>>2];J=I*+g[k+(e*104|0)+44>>2]+ +g[k+(e*104|0)+28>>2];K=I*+g[k+(e*104|0)+48>>2]+ +g[k+(e*104|0)+32>>2];g[k+(e*104|0)+8>>2]=+g[k+(e*104|0)+40>>2]*I+ +g[k+(e*104|0)+24>>2];g[k+(e*104|0)+12>>2]=J;g[k+(e*104|0)+16>>2]=K;g[k+(e*104|0)+20>>2]=0.0;e=e+1|0}while((e|0)!=(d|0))}}d=c[m+376>>2]|0;if((d|0)>0){e=c[m+416>>2]|0;h=0;do{b=+(h|0)/+(d|0);if((e|0)>0){f=0;do{switch(c[(c[m+424>>2]|0)+(f<<2)>>2]|0){case 1:{d=2;break}case 0:{d=3;break}case 2:{d=4;break}case 3:{d=5;break}default:{w=35;break a}}ub[d&7](m,1.0,b);f=f+1|0;e=c[m+416>>2]|0}while((f|0)<(e|0));d=c[m+376>>2]|0}h=h+1|0}while((h|0)<(d|0));b=+g[m+456>>2]*(1.0-+g[m+296>>2]);d=c[m+712>>2]|0;if((d|0)>0){e=0;do{k=c[m+720>>2]|0;J=b*(+g[k+(e*104|0)+12>>2]-+g[k+(e*104|0)+28>>2]);K=b*(+g[k+(e*104|0)+16>>2]-+g[k+(e*104|0)+32>>2]);g[k+(e*104|0)+40>>2]=b*(+g[k+(e*104|0)+8>>2]-+g[k+(e*104|0)+24>>2]);g[k+(e*104|0)+44>>2]=J;g[k+(e*104|0)+48>>2]=K;k=k+(e*104|0)+52|0;e=e+1|0;c[k>>2]=0;c[k+4>>2]=0;c[k+8>>2]=0;c[k+12>>2]=0;c[k+16>>2]=0}while((e|0)!=(d|0))}}d=c[m+380>>2]|0;if((d|0)>0){b=+g[m+292>>2]*+g[m+456>>2];e=c[m+712>>2]|0;if((e|0)>0){d=0;do{k=c[m+720>>2]|0;j=k+(d*104|0)+8|0;k=k+(d*104|0)+24|0;c[k>>2]=c[j>>2];c[k+4>>2]=c[j+4>>2];c[k+8>>2]=c[j+8>>2];c[k+12>>2]=c[j+12>>2];d=d+1|0}while((d|0)!=(e|0));d=c[m+380>>2]|0;if((d|0)>0)w=42}else w=42;if((w|0)==42){w=0;e=c[m+436>>2]|0;h=0;do{if((e|0)>0){f=0;do{switch(c[(c[m+444>>2]|0)+(f<<2)>>2]|0){case 1:{d=2;break}case 0:{d=3;break}case 2:{d=4;break}case 3:{d=5;break}default:{w=53;break a}}ub[d&7](m,1.0,0.0);f=f+1|0;e=c[m+436>>2]|0}while((f|0)<(e|0));d=c[m+380>>2]|0}h=h+1|0}while((h|0)<(d|0))}d=c[m+712>>2]|0;if((d|0)>0){e=c[m+720>>2]|0;f=0;do{J=b*(+g[e+(f*104|0)+12>>2]-+g[e+(f*104|0)+28>>2]);K=b*(+g[e+(f*104|0)+16>>2]-+g[e+(f*104|0)+32>>2]);k=e+(f*104|0)+40|0;g[k>>2]=b*(+g[e+(f*104|0)+8>>2]-+g[e+(f*104|0)+24>>2])+ +g[k>>2];k=e+(f*104|0)+44|0;g[k>>2]=J+ +g[k>>2];k=e+(f*104|0)+48|0;g[k>>2]=K+ +g[k>>2];f=f+1|0}while((f|0)!=(d|0))}}d=c[m+1112>>2]|0;if((d|0)>0){e=c[m+1120>>2]|0;j=0;do{f=c[e+(j<<2)>>2]|0;if(+g[f+352>>2]>0.0?(p=c[f+24>>2]|0,(p|0)>0):0){h=c[f+32>>2]|0;k=0;do{i=c[h+(k<<2)>>2]|0;if(+g[i+88>>2]>0.0?(q=+g[i+24>>2]-+g[f+228>>2],s=+g[i+28>>2]-+g[f+232>>2],v=+g[i+32>>2]-+g[f+236>>2],u=+g[f+336>>2],K=+g[f+340>>2],r=+g[f+332>>2],t=+g[f+316>>2]+(u*v-s*K),v=+g[f+320>>2]+(q*K-v*r),u=s*r-q*u+ +g[f+324>>2],q=+g[i+40>>2],r=+g[i+44>>2],s=+g[i+48>>2],t*t+v*v+u*u<=q*q+r*r+s*s):0){K=+g[f+352>>2];g[i+40>>2]=q+(t-q)*K;g[i+44>>2]=(v-r)*K+r;g[i+48>>2]=(u-s)*K+s}k=k+1|0}while((k|0)!=(p|0))}j=j+1|0}while((j|0)!=(d|0))}Cd(m,1);d=c[a+24>>2]|0}}n=n+1|0;if((n|0)>=(d|0)){w=3;break}}if((w|0)==3){l=o;return}}function Mc(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0,i=0,k=0,m=0,n=0.0,o=0.0,p=0.0,q=0,r=0.0,s=0,t=0.0;q=l;l=l+80|0;e=c[b+28>>2]|0;d=c[f+64>>2]|0;if((d&4|0)!=0&(e|0)>0){h=c[b+36>>2]|0;i=c[b+76>>2]|0;if(!(d&16)){d=0;do{m=c[h+(d*152|0)+132>>2]|0;c[m+120>>2]=c[h+(d*152|0)+100>>2];c[m+124>>2]=c[i+((c[h+(d*152|0)+140>>2]|0)*152|0)+100>>2];d=d+1|0}while((d|0)!=(e|0))}else{d=0;do{m=c[h+(d*152|0)+132>>2]|0;c[m+120>>2]=c[h+(d*152|0)+100>>2];k=c[h+(d*152|0)+140>>2]|0;c[m+124>>2]=c[i+(k*152|0)+100>>2];c[m+128>>2]=c[i+((k+1|0)*152|0)+100>>2];d=d+1|0}while((d|0)!=(e|0))}}e=c[b+48>>2]|0;if((e|0)>0){m=0;do{h=c[b+56>>2]|0;i=c[h+(m*152|0)+132>>2]|0;k=c[i+44>>2]|0;d=h+(m*152|0)+100|0;if(k|0){p=+g[d>>2];s=c[i+28>>2]|0;o=1.0/+g[f+12>>2];n=p*+g[h+(m*152|0)+20>>2]*+g[s+352>>2]*o;r=p*+g[h+(m*152|0)+24>>2]*+g[s+356>>2]*o;g[k>>2]=+g[k>>2]+ +g[h+(m*152|0)+16>>2]*p*+g[s+348>>2]*o;g[k+4>>2]=n+ +g[k+4>>2];g[k+8>>2]=r+ +g[k+8>>2];r=+g[d>>2];s=c[i+32>>2]|0;n=1.0/+g[f+12>>2];o=r*+g[h+(m*152|0)+52>>2]*+g[s+352>>2]*n;p=r*+g[h+(m*152|0)+56>>2]*+g[s+356>>2]*n;g[k+32>>2]=+g[k+32>>2]+ +g[h+(m*152|0)+48>>2]*r*+g[s+348>>2]*n;g[k+36>>2]=o+ +g[k+36>>2];g[k+40>>2]=p+ +g[k+40>>2];s=c[i+28>>2]|0;p=+g[d>>2];o=1.0/+g[f+12>>2];n=+g[h+(m*152|0)+4>>2]*+g[s+548>>2]*p*o;r=p*+g[h+(m*152|0)+8>>2]*+g[s+552>>2]*o;g[k+16>>2]=+g[k+16>>2]+ +g[h+(m*152|0)>>2]*+g[s+544>>2]*p*o;g[k+20>>2]=n+ +g[k+20>>2];g[k+24>>2]=r+ +g[k+24>>2];s=c[i+32>>2]|0;r=+g[d>>2];n=1.0/+g[f+12>>2];o=+g[h+(m*152|0)+36>>2]*+g[s+548>>2]*r*n;p=r*+g[h+(m*152|0)+40>>2]*+g[s+552>>2]*n;g[k+48>>2]=+g[k+48>>2]+ +g[h+(m*152|0)+32>>2]*+g[s+544>>2]*r*n;g[k+52>>2]=o+ +g[k+52>>2];g[k+56>>2]=p+ +g[k+56>>2]}s=c[d>>2]|0;c[i+36>>2]=s;r=+B(+(c[j>>2]=s,+g[j>>2]));if(r>=+g[i+16>>2])a[i+20>>0]=0;m=m+1|0}while((m|0)!=(e|0))}d=c[b+8>>2]|0;if((d|0)>0){e=c[b+16>>2]|0;k=0;do{h=e+(k*244|0)|0;i=c[e+(k*244|0)+240>>2]|0;if(i){if(!(c[f+44>>2]|0)){h=e+(k*244|0)+176|0;o=+g[e+(k*244|0)+64>>2]+ +g[h>>2];g[h>>2]=o;h=e+(k*244|0)+180|0;p=+g[e+(k*244|0)+68>>2]+ +g[h>>2];g[h>>2]=p;h=e+(k*244|0)+184|0;n=+g[e+(k*244|0)+72>>2]+ +g[h>>2];g[h>>2]=n;h=e+(k*244|0)+192|0;g[h>>2]=+g[e+(k*244|0)+80>>2]+ +g[h>>2];h=e+(k*244|0)+196|0;g[h>>2]=+g[e+(k*244|0)+84>>2]+ +g[h>>2];h=e+(k*244|0)+200|0;g[h>>2]=+g[e+(k*244|0)+88>>2]+ +g[h>>2];h=e;d=i}else{n=+g[f+12>>2];o=+g[f+52>>2];d=e+(k*244|0)+176|0;g[d>>2]=+g[e+(k*244|0)+64>>2]+ +g[d>>2];d=e+(k*244|0)+180|0;g[d>>2]=+g[e+(k*244|0)+68>>2]+ +g[d>>2];d=e+(k*244|0)+184|0;g[d>>2]=+g[e+(k*244|0)+72>>2]+ +g[d>>2];d=e+(k*244|0)+192|0;g[d>>2]=+g[e+(k*244|0)+80>>2]+ +g[d>>2];d=e+(k*244|0)+196|0;g[d>>2]=+g[e+(k*244|0)+84>>2]+ +g[d>>2];d=e+(k*244|0)+200|0;g[d>>2]=+g[e+(k*244|0)+88>>2]+ +g[d>>2];p=+g[e+(k*244|0)+144>>2];d=e+(k*244|0)+148|0;if(((((!(p!=0.0)?!(+g[d>>2]!=0.0):0)?!(+g[e+(k*244|0)+152>>2]!=0.0):0)?!(+g[e+(k*244|0)+160>>2]!=0.0):0)?!(+g[e+(k*244|0)+164>>2]!=0.0):0)?!(+g[e+(k*244|0)+168>>2]!=0.0):0)d=i;else{t=+g[e+(k*244|0)+164>>2]*o;r=+g[e+(k*244|0)+168>>2]*o;g[q>>2]=+g[e+(k*244|0)+160>>2]*o;g[q+4>>2]=t;g[q+8>>2]=r;g[q+12>>2]=0.0;Cg(h,p,+g[d>>2],+g[e+(k*244|0)+152>>2],q,n,q+16|0);c[h>>2]=c[q+16>>2];c[h+4>>2]=c[q+16+4>>2];c[h+8>>2]=c[q+16+8>>2];c[h+12>>2]=c[q+16+12>>2];d=e+(k*244|0)+16|0;c[d>>2]=c[q+16+16>>2];c[d+4>>2]=c[q+16+16+4>>2];c[d+8>>2]=c[q+16+16+8>>2];c[d+12>>2]=c[q+16+16+12>>2];d=e+(k*244|0)+32|0;c[d>>2]=c[q+16+32>>2];c[d+4>>2]=c[q+16+32+4>>2];c[d+8>>2]=c[q+16+32+8>>2];c[d+12>>2]=c[q+16+32+12>>2];d=e+(k*244|0)+48|0;c[d>>2]=c[q+16+48>>2];c[d+4>>2]=c[q+16+48+4>>2];c[d+8>>2]=c[q+16+48+8>>2];c[d+12>>2]=c[q+16+48+12>>2];d=c[b+16>>2]|0;e=d;d=c[d+(k*244|0)+240>>2]|0}h=e;o=+g[e+(k*244|0)+176>>2];p=+g[e+(k*244|0)+180>>2];n=+g[e+(k*244|0)+184>>2]}t=o+ +g[h+(k*244|0)+208>>2];r=p+ +g[h+(k*244|0)+212>>2];p=n+ +g[h+(k*244|0)+216>>2];m=d+260|0;c[m>>2]=(c[m>>2]|0)+1;g[d+312>>2]=t;g[d+316>>2]=r;g[d+320>>2]=p;g[d+324>>2]=0.0;m=c[b+16>>2]|0;s=c[m+(k*244|0)+240>>2]|0;p=+g[m+(k*244|0)+192>>2]+ +g[m+(k*244|0)+224>>2];r=+g[m+(k*244|0)+196>>2]+ +g[m+(k*244|0)+228>>2];t=+g[m+(k*244|0)+200>>2]+ +g[m+(k*244|0)+232>>2];c[s+260>>2]=(c[s+260>>2]|0)+1;g[s+328>>2]=p;g[s+332>>2]=r;g[s+336>>2]=t;g[s+340>>2]=0.0;if(c[f+44>>2]|0){m=c[b+16>>2]|0;s=c[m+(k*244|0)+240>>2]|0;i=m+(k*244|0)|0;c[s+260>>2]=(c[s+260>>2]|0)+1;c[s+4>>2]=c[i>>2];c[s+4+4>>2]=c[i+4>>2];c[s+4+8>>2]=c[i+8>>2];c[s+4+12>>2]=c[i+12>>2];i=m+(k*244|0)+16|0;c[s+20>>2]=c[i>>2];c[s+20+4>>2]=c[i+4>>2];c[s+20+8>>2]=c[i+8>>2];c[s+20+12>>2]=c[i+12>>2];i=m+(k*244|0)+32|0;c[s+36>>2]=c[i>>2];c[s+36+4>>2]=c[i+4>>2];c[s+36+8>>2]=c[i+8>>2];c[s+36+12>>2]=c[i+12>>2];m=m+(k*244|0)+48|0;c[s+52>>2]=c[m>>2];c[s+52+4>>2]=c[m+4>>2];c[s+52+8>>2]=c[m+8>>2];c[s+52+12>>2]=c[m+12>>2]}e=c[b+16>>2]|0;c[(c[e+(k*244|0)+240>>2]|0)+212>>2]=-1;d=c[b+8>>2]|0}k=k+1|0}while((k|0)<(d|0))}if((c[b+28>>2]|0)<0?(c[b+32>>2]|0)<0:0){d=c[b+36>>2]|0;if(d|0){if(a[b+40>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+36>>2]=0}a[b+40>>0]=1;c[b+36>>2]=0;c[b+32>>2]=0}c[b+28>>2]=0;if((c[b+48>>2]|0)<0?(c[b+52>>2]|0)<0:0){d=c[b+56>>2]|0;if(d|0){if(a[b+60>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+56>>2]=0}a[b+60>>0]=1;c[b+56>>2]=0;c[b+52>>2]=0}c[b+48>>2]=0;if((c[b+68>>2]|0)<0?(c[b+72>>2]|0)<0:0){d=c[b+76>>2]|0;if(d|0){if(a[b+80>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+76>>2]=0}a[b+80>>0]=1;c[b+76>>2]=0;c[b+72>>2]=0}c[b+68>>2]=0;if((c[b+88>>2]|0)<0?(c[b+92>>2]|0)<0:0){d=c[b+96>>2]|0;if(d|0){if(a[b+100>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+96>>2]=0}a[b+100>>0]=1;c[b+96>>2]=0;c[b+92>>2]=0}c[b+88>>2]=0;if((c[b+8>>2]|0)>=0){c[b+8>>2]=0;l=q;return 0.0}if((c[b+12>>2]|0)>=0){c[b+8>>2]=0;l=q;return 0.0}d=c[b+16>>2]|0;if(d|0){if(a[b+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+16>>2]=0}a[b+20>>0]=1;c[b+16>>2]=0;c[b+12>>2]=0;c[b+8>>2]=0;l=q;return 0.0}function Nc(b,e,f,g,h,i){b=b|0;e=+e;f=f|0;g=g|0;h=h|0;i=i|0;var j=0,k=0,m=0,n=0,o=0,p=0.0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,A=0,B=0,C=0,D=0;D=l;l=l+560|0;C=D+524|0;c[D>>2]=0;B=D+512+12|0;cv(e)|0;if((z|0)<0){y=1;x=20020;e=-e}else{y=(h&2049|0)!=0&1;x=(h&2048|0)==0?((h&1|0)==0?20021:20026):20023}cv(e)|0;A=z&2146435072;do if(A>>>0<2146435072|(A|0)==2146435072&0<0){p=+$F(e,D)*2.0;if(p!=0.0)c[D>>2]=(c[D>>2]|0)+-1;if((i|32|0)==97){o=(i&32|0)==0?x:x+9|0;n=y|2;do if(!(g>>>0>11|(12-g|0)==0)){j=12-g|0;e=8.0;do{j=j+-1|0;e=e*16.0}while((j|0)!=0);if((a[o>>0]|0)==45){e=-(e+(-p-e));break}else{e=p+e-e;break}}else e=p;while(0);k=c[D>>2]|0;j=(k|0)<0?0-k|0:k;j=rm(j,((j|0)<0)<<31>>31,B)|0;if((j|0)==(B|0)){a[D+512+11>>0]=48;j=D+512+11|0}a[j+-1>>0]=(k>>31&2)+43;m=j+-2|0;a[m>>0]=i+15;k=D+524|0;while(1){A=~~e;j=k+1|0;a[k>>0]=d[20055+A>>0]|i&32;e=(e-+(A|0))*16.0;if((j-C|0)==1?!((h&8|0)==0&((g|0)<1&e==0.0)):0){a[j>>0]=46;j=k+2|0}if(!(e!=0.0))break;else k=j}C=j-C|0;j=(g|0)!=0&(C+-2|0)<(g|0)?g+2|0:C;Nm(b,32,f,B-m+n+j|0,h);vy(b,o,n);Nm(b,48,f,B-m+n+j|0,h^65536);vy(b,D+524|0,C);Nm(b,48,j-C|0,0,0);vy(b,m,B-m|0);Nm(b,32,f,B-m+n+j|0,h^8192);j=B-m+n+j|0;break}k=(g|0)<0?6:g;if(p!=0.0){m=(c[D>>2]|0)+-28|0;c[D>>2]=m;e=p*268435456.0}else{m=c[D>>2]|0;e=p}A=(m|0)<0?D+8|0:D+8+288|0;n=A;do{v=~~e>>>0;c[n>>2]=v;n=n+4|0;e=(e-+(v>>>0))*1.0e9}while(e!=0.0);if((m|0)>0){j=A;do{g=(m|0)<29?m:29;m=n+-4|0;if(m>>>0>=j>>>0){o=0;do{u=mt(c[m>>2]|0,0,g|0)|0;u=xv(u|0,z|0,o|0,0)|0;v=z;t=yr(u|0,v|0,1e9,0)|0;c[m>>2]=t;o=Nz(u|0,v|0,1e9,0)|0;m=m+-4|0}while(m>>>0>=j>>>0);if(o){j=j+-4|0;c[j>>2]=o}}while(1){if(n>>>0<=j>>>0)break;m=n+-4|0;if(!(c[m>>2]|0))n=m;else break}m=(c[D>>2]|0)-g|0;c[D>>2]=m}while((m|0)>0)}else j=A;if((m|0)<0){do{g=0-m|0;g=(g|0)<9?g:9;if(j>>>0<n>>>0){o=0;m=j;do{v=c[m>>2]|0;c[m>>2]=(v>>>g)+o;o=O(v&(1<<g)+-1,1e9>>>g)|0;m=m+4|0}while(m>>>0<n>>>0);j=(c[j>>2]|0)==0?j+4|0:j;if(!o)m=n;else{c[n>>2]=o;m=n+4|0}}else{j=(c[j>>2]|0)==0?j+4|0:j;m=n}n=(i|32|0)==102?A:j;n=(m-n>>2|0)>(((k+25|0)/9|0)+1|0)?n+(((k+25|0)/9|0)+1<<2)|0:m;m=(c[D>>2]|0)+g|0;c[D>>2]=m}while((m|0)<0);s=n}else s=n;if(j>>>0<s>>>0){m=(A-j>>2)*9|0;o=c[j>>2]|0;if(o>>>0<10)n=m;else{n=10;do{n=n*10|0;m=m+1|0}while(o>>>0>=n>>>0);n=m}}else n=0;g=k-((i|32|0)!=102?n:0)+(((k|0)!=0&(i|32|0)==103)<<31>>31)|0;if((g|0)<(((s-A>>2)*9|0)+-9|0)){m=A+4+(((g+9216|0)/9|0)+-1024<<2)|0;if((((g+9216|0)%9|0)+1|0)<9){o=10;g=((g+9216|0)%9|0)+1|0;do{o=o*10|0;g=g+1|0}while((g|0)!=9)}else o=10;q=c[m>>2]|0;r=(q>>>0)%(o>>>0)|0;g=(m+4|0)==(s|0);if(!(g&(r|0)==0)){p=(((q>>>0)/(o>>>0)|0)&1|0)==0?9007199254740992.0:9007199254740994.0;v=(o|0)/2|0;e=r>>>0<v>>>0?.5:g&(r|0)==(v|0)?1.0:1.5;if(y){v=(a[x>>0]|0)==45;p=v?-p:p;e=v?-e:e}c[m>>2]=q-r;if(p+e!=p){v=q-r+o|0;c[m>>2]=v;if(v>>>0>999999999)while(1){n=m+-4|0;c[m>>2]=0;if(n>>>0<j>>>0){j=j+-4|0;c[j>>2]=0}v=(c[n>>2]|0)+1|0;c[n>>2]=v;if(v>>>0>999999999)m=n;else{m=n;break}}n=(A-j>>2)*9|0;g=c[j>>2]|0;if(g>>>0>=10){o=10;do{o=o*10|0;n=n+1|0}while(g>>>0>=o>>>0)}}}u=m+4|0;v=j;j=s>>>0>u>>>0?u:s}else{v=j;j=s}u=j;while(1){if(u>>>0<=v>>>0){t=0;break}j=u+-4|0;if(!(c[j>>2]|0))u=j;else{t=1;break}}g=0-n|0;do if((i|32|0)==103){if((n|0)>-5?((((k|0)!=0^1)&1)+k|0)>(n|0):0){k=(((k|0)!=0^1)&1)+k+-1-n|0;o=i+-1|0}else{k=(((k|0)!=0^1)&1)+k+-1|0;o=i+-2|0}if(!(h&8)){if(t?(w=c[u+-4>>2]|0,(w|0)!=0):0)if(!((w>>>0)%10|0)){m=10;j=0;do{m=m*10|0;j=j+1|0}while(!((w>>>0)%(m>>>0)|0|0))}else j=0;else j=9;m=((u-A>>2)*9|0)+-9|0;if((o|32|0)==102){m=m-j|0;m=(m|0)>0?m:0;r=0;k=(k|0)<(m|0)?k:m;m=o;break}else{m=m+n-j|0;m=(m|0)>0?m:0;r=0;k=(k|0)<(m|0)?k:m;m=o;break}}else{r=h&8;m=o}}else{r=h&8;m=i}while(0);q=k|r;o=(m|32|0)==102;if(o){s=0;j=(n|0)>0?n:0}else{j=(n|0)<0?g:n;j=rm(j,((j|0)<0)<<31>>31,B)|0;if((B-j|0)<2)do{j=j+-1|0;a[j>>0]=48}while((B-j|0)<2);a[j+-1>>0]=(n>>31&2)+43;j=j+-2|0;a[j>>0]=m;s=j;j=B-j|0}j=y+1+k+((q|0)!=0&1)+j|0;Nm(b,32,f,j,h);vy(b,x,y);Nm(b,48,f,j,h^65536);if(o){o=v>>>0>A>>>0?A:v;n=o;do{m=rm(c[n>>2]|0,0,D+524+9|0)|0;if((n|0)==(o|0)){if((m|0)==(D+524+9|0)){a[D+524+8>>0]=48;m=D+524+8|0}}else if(m>>>0>(D+524|0)>>>0){Hk(D+524|0,48,m-C|0)|0;do m=m+-1|0;while(m>>>0>(D+524|0)>>>0)}vy(b,m,D+524+9-m|0);n=n+4|0}while(n>>>0<=A>>>0);if(q|0)vy(b,20071,1);if(n>>>0<u>>>0&(k|0)>0)while(1){m=rm(c[n>>2]|0,0,D+524+9|0)|0;if(m>>>0>(D+524|0)>>>0){Hk(D+524|0,48,m-C|0)|0;do m=m+-1|0;while(m>>>0>(D+524|0)>>>0)}vy(b,m,(k|0)<9?k:9);n=n+4|0;m=k+-9|0;if(!(n>>>0<u>>>0&(k|0)>9)){k=m;break}else k=m}Nm(b,48,k+9|0,9,0)}else{q=t?u:v+4|0;if((k|0)>-1){g=(r|0)==0;o=v;do{m=rm(c[o>>2]|0,0,D+524+9|0)|0;if((m|0)==(D+524+9|0)){a[D+524+8>>0]=48;m=D+524+8|0}do if((o|0)==(v|0)){n=m+1|0;vy(b,m,1);if(g&(k|0)<1){m=n;break}vy(b,20071,1);m=n}else{if(m>>>0<=(D+524|0)>>>0)break;Hk(D+524|0,48,m+(0-C)|0)|0;do m=m+-1|0;while(m>>>0>(D+524|0)>>>0)}while(0);A=D+524+9-m|0;vy(b,m,(k|0)>(A|0)?A:k);k=k-A|0;o=o+4|0}while(o>>>0<q>>>0&(k|0)>-1)}Nm(b,48,k+18|0,18,0);vy(b,s,B-s|0)}Nm(b,32,f,j,h^8192)}else{j=y+3|0;Nm(b,32,f,j,h&-65537);vy(b,x,y);vy(b,e!=e|0.0!=0.0?(i&32|0?20047:20051):i&32|0?20039:20043,3);Nm(b,32,f,j,h^8192)}while(0);l=D;return ((j|0)<(f|0)?f:j)|0}function Oc(d,e,f,g,i){d=d|0;e=e|0;f=f|0;g=g|0;i=i|0;var j=0,k=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0;y=l;l=l+64|0;c[y+16>>2]=e;x=y+24+40|0;q=e;e=0;j=0;n=0;a:while(1){do if((e|0)>-1)if((j|0)>(2147483647-e|0)){c[6577]=75;e=-1;break}else{e=j+e|0;break}while(0);j=a[q>>0]|0;if(!(j<<24>>24)){w=87;break}else k=q;b:while(1){switch(j<<24>>24){case 37:{j=k;w=9;break b}case 0:{j=k;break b}default:{}}v=k+1|0;c[y+16>>2]=v;j=a[v>>0]|0;k=v}c:do if((w|0)==9)while(1){w=0;if((a[j+1>>0]|0)!=37)break c;k=k+1|0;j=j+2|0;c[y+16>>2]=j;if((a[j>>0]|0)==37)w=9;else break}while(0);k=k-q|0;if(d|0)vy(d,q,k);if(k|0){q=j;j=k;continue}m=j+1|0;k=(a[m>>0]|0)+-48|0;if(k>>>0<10){v=(a[j+2>>0]|0)==36;s=v?k:-1;p=v?1:n;m=v?j+3|0:m}else{s=-1;p=n}c[y+16>>2]=m;j=a[m>>0]|0;d:do if(((j<<24>>24)+-32|0)>>>0<32){o=j;n=0;k=(j<<24>>24)+-32|0;while(1){j=1<<k;if(!(j&75913)){j=o;o=n;break d}n=j|n;m=m+1|0;c[y+16>>2]=m;j=a[m>>0]|0;k=(j<<24>>24)+-32|0;if(k>>>0>=32){o=n;break}else o=j}}else o=0;while(0);if(j<<24>>24==42){k=m+1|0;j=(a[k>>0]|0)+-48|0;if(j>>>0<10?(a[m+2>>0]|0)==36:0){c[i+(j<<2)>>2]=10;n=1;j=m+3|0;k=c[g+((a[k>>0]|0)+-48<<3)>>2]|0}else{if(p|0){e=-1;break}if(d|0){n=(c[f>>2]|0)+(4-1)&~(4-1);v=c[n>>2]|0;c[f>>2]=n+4;n=0;j=k;k=v}else{n=0;j=k;k=0}}c[y+16>>2]=j;u=(k|0)<0;m=j;r=u?o|8192:o;v=n;u=u?0-k|0:k}else{j=cp(y+16|0)|0;if((j|0)<0){e=-1;break}m=c[y+16>>2]|0;r=o;v=p;u=j}do if((a[m>>0]|0)==46){j=m+1|0;if((a[j>>0]|0)!=42){c[y+16>>2]=j;o=cp(y+16|0)|0;j=c[y+16>>2]|0;break}j=m+2|0;k=(a[j>>0]|0)+-48|0;if(k>>>0<10?(a[m+3>>0]|0)==36:0){c[i+(k<<2)>>2]=10;o=c[g+((a[j>>0]|0)+-48<<3)>>2]|0;j=m+4|0;c[y+16>>2]=j;break}if(v|0){e=-1;break a}if(d|0){t=(c[f>>2]|0)+(4-1)&~(4-1);k=c[t>>2]|0;c[f>>2]=t+4}else k=0;c[y+16>>2]=j;o=k}else{j=m;o=-1}while(0);p=0;while(1){if(((a[j>>0]|0)+-65|0)>>>0>57){e=-1;break a}t=j+1|0;c[y+16>>2]=t;k=a[(a[j>>0]|0)+-65+(19539+(p*58|0))>>0]|0;if(((k&255)+-1|0)>>>0<8){j=t;p=k&255}else break}if(!(k<<24>>24)){e=-1;break}m=(s|0)>-1;do if(k<<24>>24==19)if(m){e=-1;break a}else w=49;else{if(m){c[i+(s<<2)>>2]=k&255;s=g+(s<<3)|0;w=c[s+4>>2]|0;c[y>>2]=c[s>>2];c[y+4>>2]=w;w=49;break}if(!d){e=0;break a}yg(y,k&255,f)}while(0);if((w|0)==49?(w=0,(d|0)==0):0){q=t;j=0;n=v;continue}n=a[j>>0]|0;n=(p|0)!=0&(n&15|0)==3?n&-33:n;k=r&-65537;s=(r&8192|0)==0?r:k;e:do switch(n|0){case 110:switch((p&255)<<24>>24){case 0:{c[c[y>>2]>>2]=e;q=t;j=0;n=v;continue a}case 1:{c[c[y>>2]>>2]=e;q=t;j=0;n=v;continue a}case 2:{q=c[y>>2]|0;c[q>>2]=e;c[q+4>>2]=((e|0)<0)<<31>>31;q=t;j=0;n=v;continue a}case 3:{b[c[y>>2]>>1]=e;q=t;j=0;n=v;continue a}case 4:{a[c[y>>2]>>0]=e;q=t;j=0;n=v;continue a}case 6:{c[c[y>>2]>>2]=e;q=t;j=0;n=v;continue a}case 7:{q=c[y>>2]|0;c[q>>2]=e;c[q+4>>2]=((e|0)<0)<<31>>31;q=t;j=0;n=v;continue a}default:{q=t;j=0;n=v;continue a}}case 112:{j=s|8;k=o>>>0>8?o:8;n=120;w=61;break}case 88:case 120:{j=s;k=o;w=61;break}case 111:{q=c[y>>2]|0;r=c[y+4>>2]|0;k=xq(q,r,x)|0;p=k;j=s;k=(s&8|0)==0|(o|0)>(x-k|0)?o:x-k+1|0;m=0;o=20003;w=67;break}case 105:case 100:{j=c[y>>2]|0;k=c[y+4>>2]|0;if((k|0)<0){j=St(0,0,j|0,k|0)|0;k=z;c[y>>2]=j;c[y+4>>2]=k;m=1;n=20003;w=66;break e}else{m=(s&2049|0)!=0&1;n=(s&2048|0)==0?((s&1|0)==0?20003:20005):20004;w=66;break e}}case 117:{j=c[y>>2]|0;k=c[y+4>>2]|0;m=0;n=20003;w=66;break}case 99:{a[y+24+39>>0]=c[y>>2];q=y+24+39|0;p=k;n=1;m=0;k=20003;j=x;break}case 109:{j=kG(c[6577]|0)|0;w=71;break}case 115:{j=c[y>>2]|0;j=j|0?j:20013;w=71;break}case 67:{c[y+8>>2]=c[y>>2];c[y+8+4>>2]=0;c[y>>2]=y+8;j=y+8|0;o=-1;w=75;break}case 83:{j=c[y>>2]|0;if(!o){Nm(d,32,u,0,s);j=0;w=84}else w=75;break}case 65:case 71:case 70:case 69:case 97:case 103:case 102:case 101:{q=t;j=Nc(d,+h[y>>3],u,o,s,n)|0;n=v;continue a}default:{p=s;n=o;m=0;k=20003;j=x}}while(0);f:do if((w|0)==61){q=c[y>>2]|0;r=c[y+4>>2]|0;p=vp(q,r,x,n&32)|0;o=(j&8|0)==0|(q|0)==0&(r|0)==0;m=o?0:2;o=o?20003:20003+(n>>4)|0;w=67}else if((w|0)==66){q=j;r=k;p=rm(j,k,x)|0;j=s;k=o;o=n;w=67}else if((w|0)==71){w=0;s=rj(j,o)|0;q=j;p=k;n=(s|0)==0?o:s-j|0;m=0;k=20003;j=(s|0)==0?j+o|0:s}else if((w|0)==75){w=0;m=0;k=0;p=j;while(1){n=c[p>>2]|0;if(!n)break;k=fz(y+20|0,n)|0;if((k|0)<0|k>>>0>(o-m|0)>>>0)break;m=k+m|0;if(o>>>0>m>>>0)p=p+4|0;else break}if((k|0)<0){e=-1;break a}Nm(d,32,u,m,s);if(!m){j=0;w=84}else{n=0;while(1){k=c[j>>2]|0;if(!k){j=m;w=84;break f}k=fz(y+20|0,k)|0;n=k+n|0;if((n|0)>(m|0)){j=m;w=84;break f}vy(d,y+20|0,k);if(n>>>0>=m>>>0){j=m;w=84;break}else j=j+4|0}}}while(0);if((w|0)==67){w=0;n=(q|0)!=0|(r|0)!=0;s=(k|0)!=0|n;n=((n^1)&1)+(x-p)|0;q=s?p:x;p=(k|0)>-1?j&-65537:j;n=s?((k|0)>(n|0)?k:n):k;k=o;j=x}else if((w|0)==84){w=0;Nm(d,32,u,j,s^8192);q=t;j=(u|0)>(j|0)?u:j;n=v;continue}s=j-q|0;r=(n|0)<(s|0)?s:n;n=r+m|0;j=(u|0)<(n|0)?n:u;Nm(d,32,j,n,p);vy(d,k,m);Nm(d,48,j,n,p^65536);Nm(d,48,r,s,0);vy(d,q,s);Nm(d,32,j,n,p^8192);q=t;n=v}g:do if((w|0)==87)if(!d)if(!n)e=0;else{e=1;while(1){j=c[i+(e<<2)>>2]|0;if(!j){j=0;break}yg(g+(e<<3)|0,j,f);e=e+1|0;if((e|0)>=10){e=1;break g}}while(1){e=e+1|0;if(j|0){e=-1;break g}if((e|0)>=10){e=1;break g}j=c[i+(e<<2)>>2]|0}}while(0);l=y;return e|0}function Pc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;if(!a)return;h=c[6454]|0;if((a+-8|0)>>>0<h>>>0)Qa();b=c[a+-4>>2]|0;if((b&3|0)==1)Qa();o=a+-8+(b&-8)|0;a:do if(!(b&1)){d=c[a+-8>>2]|0;if(!(b&3))return;k=a+-8+(0-d)|0;j=d+(b&-8)|0;if(k>>>0<h>>>0)Qa();if((k|0)==(c[6455]|0)){a=c[o+4>>2]|0;if((a&3|0)!=3){m=k;r=k;f=j;break}c[6452]=j;c[o+4>>2]=a&-2;c[k+4>>2]=j|1;c[k+j>>2]=j;return}if(d>>>0<256){a=c[k+8>>2]|0;b=c[k+12>>2]|0;if((a|0)!=(25840+(d>>>3<<1<<2)|0)){if(a>>>0<h>>>0)Qa();if((c[a+12>>2]|0)!=(k|0))Qa()}if((b|0)==(a|0)){c[6450]=c[6450]&~(1<<(d>>>3));m=k;r=k;f=j;break}if((b|0)!=(25840+(d>>>3<<1<<2)|0)){if(b>>>0<h>>>0)Qa();if((c[b+8>>2]|0)!=(k|0))Qa();else e=b+8|0}else e=b+8|0;c[a+12>>2]=b;c[e>>2]=a;m=k;r=k;f=j;break}g=c[k+24>>2]|0;a=c[k+12>>2]|0;do if((a|0)==(k|0)){a=c[k+16+4>>2]|0;if(!a){a=c[k+16>>2]|0;if(!a){i=0;break}else e=k+16|0}else e=k+16+4|0;while(1){d=a+20|0;b=c[d>>2]|0;if(b|0){a=b;e=d;continue}d=a+16|0;b=c[d>>2]|0;if(!b)break;else{a=b;e=d}}if(e>>>0<h>>>0)Qa();else{c[e>>2]=0;i=a;break}}else{b=c[k+8>>2]|0;if(b>>>0<h>>>0)Qa();if((c[b+12>>2]|0)!=(k|0))Qa();if((c[a+8>>2]|0)==(k|0)){c[b+12>>2]=a;c[a+8>>2]=b;i=a;break}else Qa()}while(0);if(g){a=c[k+28>>2]|0;do if((k|0)==(c[26104+(a<<2)>>2]|0)){c[26104+(a<<2)>>2]=i;if(!i){c[6451]=c[6451]&~(1<<a);m=k;r=k;f=j;break a}}else if(g>>>0>=(c[6454]|0)>>>0){c[g+16+(((c[g+16>>2]|0)!=(k|0)&1)<<2)>>2]=i;if(!i){m=k;r=k;f=j;break a}else break}else Qa();while(0);b=c[6454]|0;if(i>>>0<b>>>0)Qa();c[i+24>>2]=g;a=c[k+16>>2]|0;do if(a|0)if(a>>>0<b>>>0)Qa();else{c[i+16>>2]=a;c[a+24>>2]=i;break}while(0);a=c[k+16+4>>2]|0;if(a)if(a>>>0<(c[6454]|0)>>>0)Qa();else{c[i+20>>2]=a;c[a+24>>2]=i;m=k;r=k;f=j;break}else{m=k;r=k;f=j}}else{m=k;r=k;f=j}}else{m=a+-8|0;r=a+-8|0;f=b&-8}while(0);if(m>>>0>=o>>>0)Qa();d=c[o+4>>2]|0;if(!(d&1))Qa();if(!(d&2)){a=c[6455]|0;if((o|0)==(c[6456]|0)){q=(c[6453]|0)+f|0;c[6453]=q;c[6456]=r;c[r+4>>2]=q|1;if((r|0)!=(a|0))return;c[6455]=0;c[6452]=0;return}if((o|0)==(a|0)){q=(c[6452]|0)+f|0;c[6452]=q;c[6455]=m;c[r+4>>2]=q|1;c[m+q>>2]=q;return}f=(d&-8)+f|0;b:do if(d>>>0>=256){g=c[o+24>>2]|0;a=c[o+12>>2]|0;do if((a|0)==(o|0)){a=c[o+16+4>>2]|0;if(!a){a=c[o+16>>2]|0;if(!a){n=0;break}else e=o+16|0}else e=o+16+4|0;while(1){d=a+20|0;b=c[d>>2]|0;if(b|0){a=b;e=d;continue}d=a+16|0;b=c[d>>2]|0;if(!b)break;else{a=b;e=d}}if(e>>>0<(c[6454]|0)>>>0)Qa();else{c[e>>2]=0;n=a;break}}else{b=c[o+8>>2]|0;if(b>>>0<(c[6454]|0)>>>0)Qa();if((c[b+12>>2]|0)!=(o|0))Qa();if((c[a+8>>2]|0)==(o|0)){c[b+12>>2]=a;c[a+8>>2]=b;n=a;break}else Qa()}while(0);if(g|0){a=c[o+28>>2]|0;do if((o|0)==(c[26104+(a<<2)>>2]|0)){c[26104+(a<<2)>>2]=n;if(!n){c[6451]=c[6451]&~(1<<a);break b}}else if(g>>>0>=(c[6454]|0)>>>0){c[g+16+(((c[g+16>>2]|0)!=(o|0)&1)<<2)>>2]=n;if(!n)break b;else break}else Qa();while(0);b=c[6454]|0;if(n>>>0<b>>>0)Qa();c[n+24>>2]=g;a=c[o+16>>2]|0;do if(a|0)if(a>>>0<b>>>0)Qa();else{c[n+16>>2]=a;c[a+24>>2]=n;break}while(0);a=c[o+16+4>>2]|0;if(a|0)if(a>>>0<(c[6454]|0)>>>0)Qa();else{c[n+20>>2]=a;c[a+24>>2]=n;break}}}else{a=c[o+8>>2]|0;b=c[o+12>>2]|0;if((a|0)!=(25840+(d>>>3<<1<<2)|0)){if(a>>>0<(c[6454]|0)>>>0)Qa();if((c[a+12>>2]|0)!=(o|0))Qa()}if((b|0)==(a|0)){c[6450]=c[6450]&~(1<<(d>>>3));break}if((b|0)!=(25840+(d>>>3<<1<<2)|0)){if(b>>>0<(c[6454]|0)>>>0)Qa();if((c[b+8>>2]|0)!=(o|0))Qa();else l=b+8|0}else l=b+8|0;c[a+12>>2]=b;c[l>>2]=a}while(0);c[r+4>>2]=f|1;c[m+f>>2]=f;if((r|0)==(c[6455]|0)){c[6452]=f;return}}else{c[o+4>>2]=d&-2;c[r+4>>2]=f|1;c[m+f>>2]=f}b=f>>>3;if(f>>>0<256){a=c[6450]|0;if(a&1<<b){a=c[25840+(b<<1<<2)+8>>2]|0;if(a>>>0<(c[6454]|0)>>>0)Qa();else{p=25840+(b<<1<<2)+8|0;q=a}}else{c[6450]=a|1<<b;p=25840+(b<<1<<2)+8|0;q=25840+(b<<1<<2)|0}c[p>>2]=r;c[q+12>>2]=r;c[r+8>>2]=q;c[r+12>>2]=25840+(b<<1<<2);return}a=f>>>8;if(a)if(f>>>0>16777215)b=31;else{b=a<<((a+1048320|0)>>>16&8)<<(((a<<((a+1048320|0)>>>16&8))+520192|0)>>>16&4);b=14-(((a<<((a+1048320|0)>>>16&8))+520192|0)>>>16&4|(a+1048320|0)>>>16&8|(b+245760|0)>>>16&2)+(b<<((b+245760|0)>>>16&2)>>>15)|0;b=f>>>(b+7|0)&1|b<<1}else b=0;e=26104+(b<<2)|0;c[r+28>>2]=b;c[r+20>>2]=0;c[r+16>>2]=0;a=c[6451]|0;d=1<<b;do if(a&d){b=f<<((b|0)==31?0:25-(b>>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(f|0)){a=124;break}d=e+16+(b>>>31<<2)|0;a=c[d>>2]|0;if(!a){a=121;break}else{b=b<<1;e=a}}if((a|0)==121)if(d>>>0<(c[6454]|0)>>>0)Qa();else{c[d>>2]=r;c[r+24>>2]=e;c[r+12>>2]=r;c[r+8>>2]=r;break}else if((a|0)==124){b=e+8|0;a=c[b>>2]|0;q=c[6454]|0;if(a>>>0>=q>>>0&e>>>0>=q>>>0){c[a+12>>2]=r;c[b>>2]=r;c[r+8>>2]=a;c[r+12>>2]=e;c[r+24>>2]=0;break}else Qa()}}else{c[6451]=a|d;c[e>>2]=r;c[r+24>>2]=e;c[r+12>>2]=r;c[r+8>>2]=r}while(0);r=(c[6458]|0)+-1|0;c[6458]=r;if(!r)a=26256;else return;while(1){a=c[a>>2]|0;if(!a)break;else a=a+8|0}c[6458]=-1;return}function Qc(b,d,e){b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0,u=0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0;if((a[b+180>>0]|0)==0?(a[b+48>>0]|0)!=0:0){s=+g[b+116>>2];v=+g[e>>2];y=+g[b+132>>2];x=+g[e+4>>2];A=+g[b+148>>2];z=+g[e+8>>2];q=+g[b+120>>2];D=+g[b+136>>2];E=+g[b+152>>2];o=+g[b+124>>2];I=+g[b+140>>2];p=+g[b+156>>2];w=+g[e+16>>2];m=+g[e+20>>2];n=+g[e+24>>2];H=+g[e+32>>2];r=+g[e+36>>2];B=+g[e+40>>2];h=+g[b+164>>2];f=+g[b+168>>2];G=+g[b+172>>2];F=+g[e+48>>2]+(v*h+x*f+z*G);C=w*h+m*f+n*G+ +g[e+52>>2];G=H*h+r*f+B*G+ +g[e+56>>2];g[b+824>>2]=s*v+y*x+A*z;g[b+828>>2]=v*q+x*D+z*E;g[b+832>>2]=v*o+x*I+z*p;g[b+836>>2]=0.0;g[b+840>>2]=s*w+y*m+A*n;g[b+844>>2]=q*w+D*m+E*n;g[b+848>>2]=o*w+I*m+p*n;g[b+852>>2]=0.0;g[b+856>>2]=s*H+y*r+A*B;g[b+860>>2]=q*H+D*r+E*B;g[b+864>>2]=o*H+I*r+p*B;g[b+868>>2]=0.0;g[b+872>>2]=F;g[b+876>>2]=C;g[b+880>>2]=G;g[b+884>>2]=0.0;G=+g[b+52>>2];C=+g[d>>2];F=+g[b+68>>2];B=+g[d+4>>2];p=+g[b+84>>2];r=+g[d+8>>2];I=+g[b+56>>2];H=+g[b+72>>2];o=+g[b+88>>2];E=+g[b+60>>2];D=+g[b+76>>2];q=+g[b+92>>2];A=+g[d+16>>2];y=+g[d+20>>2];s=+g[d+24>>2];n=+g[d+32>>2];m=+g[d+36>>2];w=+g[d+40>>2];z=+g[b+100>>2];x=+g[b+104>>2];v=+g[b+108>>2];f=n*z+m*x;h=E*n+D*m+q*w;i=C*I+B*H+r*o;k=G*C+F*B+p*r;l=I*n+H*m+o*w;m=G*n+F*m+p*w;n=E*A+D*y+q*s;o=I*A+H*y+o*s;p=G*A+F*y+p*s;q=C*E+B*D+r*q;r=C*z+B*x+r*v;s=A*z+y*x+s*v;t=b+856|0;u=b+840|0;v=w*v}else{s=+g[b+52>>2];v=+g[d>>2];G=+g[b+68>>2];H=+g[d+4>>2];E=+g[b+84>>2];F=+g[d+8>>2];q=+g[b+56>>2];B=+g[b+72>>2];A=+g[b+88>>2];o=+g[b+60>>2];w=+g[b+76>>2];p=+g[b+92>>2];I=+g[d+16>>2];m=+g[d+20>>2];n=+g[d+24>>2];x=+g[d+32>>2];r=+g[d+36>>2];D=+g[d+40>>2];h=+g[b+100>>2];f=+g[b+104>>2];y=+g[b+108>>2];z=+g[d+48>>2]+(v*h+H*f+F*y);C=I*h+m*f+n*y+ +g[d+52>>2];y=x*h+r*f+D*y+ +g[d+56>>2];g[b+824>>2]=s*v+G*H+E*F;g[b+828>>2]=v*q+H*B+F*A;g[b+832>>2]=v*o+H*w+F*p;g[b+836>>2]=0.0;g[b+840>>2]=s*I+G*m+E*n;g[b+844>>2]=q*I+B*m+A*n;g[b+848>>2]=o*I+w*m+p*n;g[b+852>>2]=0.0;g[b+856>>2]=s*x+G*r+E*D;g[b+860>>2]=q*x+B*r+A*D;g[b+864>>2]=o*x+w*r+p*D;g[b+868>>2]=0.0;g[b+872>>2]=z;g[b+876>>2]=C;g[b+880>>2]=y;g[b+884>>2]=0.0;y=+g[b+116>>2];C=+g[e>>2];z=+g[b+132>>2];D=+g[e+4>>2];p=+g[b+148>>2];r=+g[e+8>>2];w=+g[b+120>>2];x=+g[b+136>>2];o=+g[b+152>>2];A=+g[b+124>>2];B=+g[b+140>>2];q=+g[b+156>>2];E=+g[e+16>>2];G=+g[e+20>>2];s=+g[e+24>>2];n=+g[e+32>>2];m=+g[e+36>>2];I=+g[e+40>>2];F=+g[b+164>>2];H=+g[b+168>>2];v=+g[b+172>>2];f=n*F+m*H;h=A*n+B*m+q*I;i=C*w+D*x+r*o;k=y*C+z*D+p*r;l=w*n+x*m+o*I;m=y*n+z*m+p*I;n=A*E+B*G+q*s;o=w*E+x*G+o*s;p=y*E+z*G+p*s;q=C*A+D*B+r*q;r=C*F+D*H+r*v;s=E*F+G*H+s*v;t=b+856|0;u=b+840|0;v=I*v;d=e}H=r+ +g[d+48>>2];I=s+ +g[d+52>>2];f=v+f+ +g[d+56>>2];g[b+888>>2]=k;g[b+892>>2]=i;g[b+896>>2]=q;g[b+900>>2]=0.0;g[b+904>>2]=p;g[b+908>>2]=o;g[b+912>>2]=n;g[b+916>>2]=0.0;g[b+920>>2]=m;g[b+924>>2]=l;g[b+928>>2]=h;g[b+932>>2]=0.0;g[b+936>>2]=H;g[b+940>>2]=I;g[b+944>>2]=f;g[b+948>>2]=0.0;c[b+968>>2]=c[b+872>>2];c[b+968+4>>2]=c[b+872+4>>2];c[b+968+8>>2]=c[b+872+8>>2];c[b+968+12>>2]=c[b+872+12>>2];c[b+984>>2]=c[b+936>>2];c[b+984+4>>2]=c[b+936+4>>2];c[b+984+8>>2]=c[b+936+8>>2];c[b+984+12>>2]=c[b+936+12>>2];d=c[b+824>>2]|0;e=c[u>>2]|0;u=c[t>>2]|0;c[b+952>>2]=d;c[b+956>>2]=e;c[b+960>>2]=u;g[b+964>>2]=0.0;i=(c[j>>2]=d,+g[j>>2]);f=(c[j>>2]=e,+g[j>>2]);h=(c[j>>2]=u,+g[j>>2]);if((a[b+180>>0]|0)==0?(a[b+48>>0]|0)==0:0){t=b+968|0;u=b+984|0;G=+g[t>>2];F=+g[u>>2];F=G-F;e=t+4|0;G=+g[e>>2];e=u+4|0;H=+g[e>>2];H=G-H;t=t+8|0;G=+g[t>>2];u=u+8|0;I=+g[u>>2];I=G-I;u=b+1016|0;g[u>>2]=F;u=b+1020|0;g[u>>2]=H;u=b+1024|0;g[u>>2]=I;u=b+1028|0;g[u>>2]=0.0;G=i*F;C=f*H;C=G+C;G=h*I;G=C+G;C=i*G;D=f*G;E=h*G;B=+g[b+968>>2];C=B+C;u=b+972|0;B=+g[u>>2];D=B+D;u=b+976|0;B=+g[u>>2];E=B+E;u=b+1e3|0;g[u>>2]=C;u=b+1004|0;g[u>>2]=D;u=b+1008|0;g[u>>2]=E;u=b+1012|0;g[u>>2]=0.0;u=b+1032|0;g[u>>2]=G;u=b+828|0;t=b+844|0;e=b+860|0;G=+g[u>>2];E=+g[t>>2];D=+g[e>>2];G=G*F;E=E*H;E=G+E;D=D*I;D=E+D;e=b+1036|0;g[e>>2]=D;e=b+832|0;t=b+848|0;u=b+864|0;D=+g[e>>2];E=+g[t>>2];G=+g[u>>2];F=D*F;H=E*H;H=F+H;I=G*I;I=H+I;b=b+1040|0;g[b>>2]=I;return}t=b+984|0;u=b+968|0;G=+g[t>>2];F=+g[u>>2];F=G-F;e=t+4|0;G=+g[e>>2];e=u+4|0;H=+g[e>>2];H=G-H;t=t+8|0;G=+g[t>>2];u=u+8|0;I=+g[u>>2];I=G-I;u=b+1016|0;g[u>>2]=F;u=b+1020|0;g[u>>2]=H;u=b+1024|0;g[u>>2]=I;u=b+1028|0;g[u>>2]=0.0;G=i*F;C=f*H;C=G+C;G=h*I;G=C+G;C=i*G;D=f*G;E=h*G;B=+g[b+968>>2];C=B+C;u=b+972|0;B=+g[u>>2];D=B+D;u=b+976|0;B=+g[u>>2];E=B+E;u=b+1e3|0;g[u>>2]=C;u=b+1004|0;g[u>>2]=D;u=b+1008|0;g[u>>2]=E;u=b+1012|0;g[u>>2]=0.0;u=b+1032|0;g[u>>2]=G;u=b+828|0;t=b+844|0;e=b+860|0;G=+g[u>>2];E=+g[t>>2];D=+g[e>>2];G=G*F;E=E*H;E=G+E;D=D*I;D=E+D;e=b+1036|0;g[e>>2]=D;e=b+832|0;t=b+848|0;u=b+864|0;D=+g[e>>2];E=+g[t>>2];G=+g[u>>2];F=D*F;H=E*H;H=F+H;I=G*I;I=H+I;b=b+1040|0;g[b>>2]=I;return}function Rc(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0.0,j=0.0,k=0,m=0,n=0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0;u=l;l=l+672|0;c[u+448+8>>2]=0;c[u+448+12>>2]=1065353216;c[u+448+16>>2]=1065353216;c[u+448+20>>2]=1065353216;g[u+448+24>>2]=0.0;c[u+448>>2]=6796;c[u+448+4>>2]=8;g[u+448+28>>2]=0.0;g[u+448+44>>2]=0.0;g[u+384>>2]=1.0;m=u+384+4|0;c[m>>2]=0;c[m+4>>2]=0;c[m+8>>2]=0;c[m+12>>2]=0;g[u+384+20>>2]=1.0;n=u+384+24|0;c[n>>2]=0;c[n+4>>2]=0;c[n+8>>2]=0;c[n+12>>2]=0;g[u+384+40>>2]=1.0;g[u+384+44>>2]=0.0;c[u+384+48>>2]=c[a>>2];c[u+384+48+4>>2]=c[a+4>>2];c[u+384+48+8>>2]=c[a+8>>2];c[u+384+48+12>>2]=c[a+12>>2];a=e;k=a+36|0;do{c[a>>2]=0;a=a+4|0}while((a|0)<(k|0));c[u+504>>2]=b;c[u+504+4>>2]=u+448;w=+g[d>>2];v=+g[d+16>>2];f=+g[d+32>>2];h=+g[d+4>>2];i=+g[d+20>>2];j=+g[d+36>>2];s=+g[d+8>>2];q=+g[d+24>>2];o=+g[d+40>>2];g[u+504+8>>2]=w+v*0.0+f*0.0;g[u+504+12>>2]=h+i*0.0+j*0.0;g[u+504+16>>2]=s+q*0.0+o*0.0;g[u+504+20>>2]=0.0;g[u+504+24>>2]=w*0.0+v+f*0.0;g[u+504+28>>2]=h*0.0+i+j*0.0;g[u+504+32>>2]=s*0.0+q+o*0.0;g[u+504+36>>2]=0.0;g[u+504+40>>2]=w*0.0+v*0.0+f;g[u+504+44>>2]=h*0.0+i*0.0+j;g[u+504+48>>2]=s*0.0+q*0.0+o;g[u+504+52>>2]=0.0;o=+g[u+384+48>>2]-+g[d+48>>2];q=+g[u+384+52>>2]-+g[d+52>>2];s=+g[u+384+56>>2]-+g[d+56>>2];G=+g[u+384>>2];F=+g[u+384+16>>2];E=+g[u+384+32>>2];D=+g[m>>2];B=+g[u+384+20>>2];A=+g[u+384+36>>2];z=+g[u+384+8>>2];y=+g[n>>2];x=+g[u+384+40>>2];p=+g[d+8>>2];r=+g[d+24>>2];t=+g[d+40>>2];g[u+504+56>>2]=w*G+v*F+f*E;g[u+504+60>>2]=w*D+v*B+f*A;g[u+504+64>>2]=w*z+v*y+f*x;g[u+504+68>>2]=0.0;g[u+504+72>>2]=G*h+F*i+E*j;g[u+504+76>>2]=D*h+B*i+A*j;g[u+504+80>>2]=z*h+y*i+x*j;g[u+504+84>>2]=0.0;g[u+504+88>>2]=G*p+F*r+E*t;g[u+504+92>>2]=D*p+B*r+A*t;g[u+504+96>>2]=z*p+y*r+x*t;g[u+504+100>>2]=0.0;g[u+504+104>>2]=o*w+q*v+s*f;g[u+504+108>>2]=o*h+q*i+s*j;g[u+504+112>>2]=o*p+q*r+s*t;g[u+504+116>>2]=0.0;c[u+504+120>>2]=80;c[u+504+124>>2]=0;c[u+364>>2]=0;c[u+128>>2]=0;c[u+128+4>>2]=0;c[u+128+8>>2]=0;c[u+128+12>>2]=0;c[u+376>>2]=2;c[u+368>>2]=0;g[u+144>>2]=0.0;c[u+648>>2]=1065353216;c[u+648+4>>2]=1065353216;c[u+648+8>>2]=1065353216;g[u+648+12>>2]=0.0;switch(wc(u,u+504|0,u+648|0)|0){case 0:{a=c[u+372>>2]|0;if(!(c[a+32>>2]|0)){j=0.0;i=0.0;f=0.0;r=0.0;q=0.0;h=0.0}else{f=0.0;i=0.0;j=0.0;h=0.0;q=0.0;r=0.0;n=0;do{t=+g[a+16+(n<<2)>>2];k=c[u+504+120>>2]|0;H=c[u+504+124>>2]|0;m=(c[u+504>>2]|0)+(H>>1)|0;if(H&1)k=c[(c[m>>2]|0)+k>>2]|0;Rb[k&127](u+648|0,m,c[a+(n<<2)>>2]|0);f=f+t*+g[u+648>>2];i=i+t*+g[u+648+4>>2];j=j+t*+g[u+648+8>>2];a=c[(c[u+372>>2]|0)+(n<<2)>>2]|0;o=-+g[a>>2];p=-+g[a+4>>2];s=-+g[a+8>>2];a=c[u+504+120>>2]|0;H=c[u+504+124>>2]|0;k=(c[u+504+4>>2]|0)+(H>>1)|0;if(H&1)a=c[(c[k>>2]|0)+a>>2]|0;F=+g[u+504+24>>2]*o+ +g[u+504+28>>2]*p+ +g[u+504+32>>2]*s;E=+g[u+504+40>>2]*o+ +g[u+504+44>>2]*p+ +g[u+504+48>>2]*s;g[u+632>>2]=+g[u+504+8>>2]*o+ +g[u+504+12>>2]*p+ +g[u+504+16>>2]*s;g[u+632+4>>2]=F;g[u+632+8>>2]=E;g[u+632+12>>2]=0.0;Rb[a&127](u+648|0,k,u+632|0);E=+g[u+648>>2];F=+g[u+648+4>>2];G=+g[u+648+8>>2];h=h+t*(E*+g[u+504+56>>2]+F*+g[u+504+60>>2]+G*+g[u+504+64>>2]+ +g[u+504+104>>2]);q=q+t*(E*+g[u+504+72>>2]+F*+g[u+504+76>>2]+G*+g[u+504+80>>2]+ +g[u+504+108>>2]);r=r+t*(E*+g[u+504+88>>2]+F*+g[u+504+92>>2]+G*+g[u+504+96>>2]+ +g[u+504+112>>2]);n=n+1|0;a=c[u+372>>2]|0}while(n>>>0<(c[a+32>>2]|0)>>>0)}s=f*+g[d>>2]+i*+g[d+4>>2]+j*+g[d+8>>2]+ +g[d+48>>2];t=f*+g[d+16>>2]+i*+g[d+20>>2]+j*+g[d+24>>2]+ +g[d+52>>2];o=f*+g[d+32>>2]+i*+g[d+36>>2]+j*+g[d+40>>2]+ +g[d+56>>2];g[e+4>>2]=s;g[e+8>>2]=t;g[e+12>>2]=o;g[e+16>>2]=0.0;j=h*+g[d>>2]+q*+g[d+4>>2]+r*+g[d+8>>2]+ +g[d+48>>2];p=h*+g[d+16>>2]+q*+g[d+20>>2]+r*+g[d+24>>2]+ +g[d+52>>2];i=h*+g[d+32>>2]+q*+g[d+36>>2]+r*+g[d+40>>2]+ +g[d+56>>2];g[e+20>>2]=j;g[e+24>>2]=p;g[e+28>>2]=i;g[e+32>>2]=0.0;switch(c[b+4>>2]|0){case 8:{f=+g[b+28>>2]*+g[b+12>>2];break}case 0:{f=+g[b+44>>2];break}case 1:{f=+g[b+44>>2];break}case 13:{f=+g[b+44>>2];break}case 11:{f=+g[b+44>>2];break}case 10:{f=+g[b+44>>2];break}case 4:case 5:{f=+g[b+44>>2];break}default:f=+zb[c[(c[b>>2]|0)+48>>2]&15](b)}switch(c[u+448+4>>2]|0){case 8:{h=+g[u+448+28>>2]*+g[u+448+12>>2];break}case 0:{h=+g[u+448+44>>2];break}case 1:{h=+g[u+448+44>>2];break}case 13:{h=+g[u+448+44>>2];break}case 11:{h=+g[u+448+44>>2];break}case 10:{h=+g[u+448+44>>2];break}case 4:case 5:{h=+g[u+448+44>>2];break}default:h=+zb[c[(c[u+448>>2]|0)+48>>2]&15](u+448|0)}G=f+h;F=+C(+((j-s)*(j-s)+(p-t)*(p-t)+(i-o)*(i-o)));g[e+36>>2]=(j-s)*(1.0/F);g[e+40>>2]=(p-t)*(1.0/F);g[e+44>>2]=(i-o)*(1.0/F);g[e+48>>2]=0.0;g[e+4>>2]=G*(j-s)*(1.0/F)+ +g[e+4>>2];g[e+8>>2]=G*(p-t)*(1.0/F)+ +g[e+8>>2];g[e+12>>2]=G*(i-o)*(1.0/F)+ +g[e+12>>2];G=F-G;l=u;return +G}case 1:{if(!(vc(b,d,u+448|0,u+384|0,u+128|0,e,1)|0)){G=3402823466385288598117041.0e14;l=u;return +G}h=+g[e+4>>2]-+g[e+20>>2];j=+g[e+8>>2]-+g[e+24>>2];i=+g[e+12>>2]-+g[e+28>>2];f=+C(+(h*h+j*j+i*i));if(f>=1.1920928955078125e-07){g[e+36>>2]=h*(1.0/f);g[e+40>>2]=j*(1.0/f);g[e+44>>2]=i*(1.0/f);g[e+48>>2]=0.0}G=-f;l=u;return +G}default:{G=3402823466385288598117041.0e14;l=u;return +G}}return 0.0}function Sc(d,e){d=d|0;e=+e;var f=0,h=0.0,i=0,j=0.0,k=0.0,m=0,n=0,o=0,p=0,q=0.0,r=0.0,s=0,t=0.0,u=0;s=l;l=l+304|0;Yi(12258);a:do if((c[d+232>>2]|0)>0){o=s+136+48|0;n=0;while(1){m=c[(c[d+240>>2]|0)+(n<<2)>>2]|0;g[m+244>>2]=1.0;b:do switch(c[m+216>>2]|0){case 2:case 5:break;default:if(!(c[m+204>>2]&3)){Cg(m+4|0,+g[m+312>>2],+g[m+316>>2],+g[m+320>>2],m+328|0,e,s+136|0);h=+g[o>>2]-+g[m+52>>2];k=+g[s+136+52>>2]-+g[m+56>>2];j=+g[s+136+56>>2]-+g[m+60>>2];if(a[d+44>>0]|0?(t=+g[m+252>>2],t*t!=0.0?t*t<h*h+k*k+j*j:0):0){Yi(12278);if((c[(c[m+192>>2]|0)+4>>2]|0)<20){c[5813]=(c[5813]|0)+1;f=c[d+68>>2]|0;f=lb[c[(c[f>>2]|0)+36>>2]&127](f)|0;i=c[d+24>>2]|0;g[s+200+4>>2]=1.0;c[s+200+12>>2]=c[m+52>>2];c[s+200+12+4>>2]=c[m+52+4>>2];c[s+200+12+8>>2]=c[m+52+8>>2];c[s+200+12+12>>2]=c[m+52+12>>2];c[s+200+28>>2]=c[o>>2];c[s+200+28+4>>2]=c[o+4>>2];c[s+200+28+8>>2]=c[o+8>>2];c[s+200+28+12>>2]=c[o+12>>2];c[s+200+76>>2]=0;c[s+200>>2]=4460;c[s+200+80>>2]=m;c[s+200+88>>2]=f;c[s+200+92>>2]=i;i=c[m+248>>2]|0;c[s+80+8>>2]=0;c[s+80+12>>2]=1065353216;c[s+80+16>>2]=1065353216;c[s+80+20>>2]=1065353216;g[s+80+24>>2]=0.0;c[s+80>>2]=6796;c[s+80+4>>2]=8;c[s+80+28>>2]=i;c[s+80+44>>2]=i;c[s+200+84>>2]=c[d+56>>2];i=c[m+188>>2]|0;b[s+200+8>>1]=b[i+4>>1]|0;b[s+200+10>>1]=b[i+6>>1]|0;c[s+16+48>>2]=c[o>>2];c[s+16+48+4>>2]=c[o+4>>2];c[s+16+48+8>>2]=c[o+8>>2];c[s+16+48+12>>2]=c[o+12>>2];c[s+16>>2]=c[m+4>>2];c[s+16+4>>2]=c[m+4+4>>2];c[s+16+8>>2]=c[m+4+8>>2];c[s+16+12>>2]=c[m+4+12>>2];c[s+16+16>>2]=c[m+20>>2];c[s+16+16+4>>2]=c[m+20+4>>2];c[s+16+16+8>>2]=c[m+20+8>>2];c[s+16+16+12>>2]=c[m+20+12>>2];c[s+16+32>>2]=c[m+36>>2];c[s+16+32+4>>2]=c[m+36+4>>2];c[s+16+32+8>>2]=c[m+36+8>>2];c[s+16+32+12>>2]=c[m+36+12>>2];ud(d,s+80|0,m+4|0,s+16|0,s+200|0,0.0);h=+g[s+200+4>>2];if(h<1.0){g[m+244>>2]=h;Cg(m+4|0,+g[m+312>>2],+g[m+316>>2],+g[m+320>>2],m+328|0,h*e,s+136|0);g[m+244>>2]=0.0;ze(m,s+136|0);f=4}else f=0;if(!f)p=12}else p=12;if((p|0)==12){p=0;f=0}i=c[2395]|0;u=(c[i+16>>2]|0)+-1|0;c[i+16>>2]=u;do if(!u){if(c[i+4>>2]|0){Va(s+200|0,0)|0;u=c[6431]|0;g[i+8>>2]=+g[i+8>>2]+ +(((c[s+200+4>>2]|0)-(c[u+4>>2]|0)+(((c[s+200>>2]|0)-(c[u>>2]|0)|0)*1e6|0)-(c[i+12>>2]|0)|0)>>>0)/1.0e3;if(c[i+16>>2]|0)break;i=c[2395]|0}c[2395]=c[i+20>>2]}while(0);if(f|0)break b}ze(m,s+136|0)}}while(0);n=n+1|0;if((n|0)>=(c[d+232>>2]|0))break a}}while(0);do if(a[d+275>>0]|0){Yi(12298);if((c[d+308>>2]|0)>0){o=0;do{n=c[(c[d+316>>2]|0)+(o<<2)>>2]|0;m=c[n+740>>2]|0;m=(c[m+236>>2]&2|0)==0?0:m;p=c[n+744>>2]|0;p=(c[p+236>>2]&2|0)==0?0:p;f=c[n+748>>2]|0;if((f|0)>0)if(!m){i=0;do{h=+g[57]*+g[p+228>>2];if(h>0.0?(q=+g[n+4+(i*184|0)+120>>2],q!=0.0):0){k=h*+g[n+4+(i*184|0)+64>>2]*q;e=h*+g[n+4+(i*184|0)+68>>2]*q;t=h*+g[n+4+(i*184|0)+72>>2]*q;h=+g[n+4+(i*184|0)+36>>2]-+g[p+56>>2];j=+g[n+4+(i*184|0)+40>>2]-+g[p+60>>2];g[s+16>>2]=+g[n+4+(i*184|0)+32>>2]-+g[p+52>>2];g[s+16+4>>2]=h;g[s+16+8>>2]=j;g[s+16+12>>2]=0.0;g[s>>2]=k;g[s+4>>2]=e;g[s+8>>2]=t;g[s+12>>2]=0.0;Vk(p,s,s+16|0);f=c[n+748>>2]|0}i=i+1|0}while((i|0)<(f|0))}else{i=0;do{h=+g[m+228>>2]*+g[p+228>>2];if(h>0.0?(r=+g[n+4+(i*184|0)+120>>2],r!=0.0):0){k=h*+g[n+4+(i*184|0)+64>>2]*r;e=h*+g[n+4+(i*184|0)+68>>2]*r;t=h*+g[n+4+(i*184|0)+72>>2]*r;g[s+200>>2]=-k;g[s+200+4>>2]=-e;g[s+200+8>>2]=-t;g[s+200+12>>2]=0.0;j=+g[n+4+(i*184|0)+52>>2]-+g[m+56>>2];h=+g[n+4+(i*184|0)+56>>2]-+g[m+60>>2];g[s+80>>2]=+g[n+4+(i*184|0)+48>>2]-+g[m+52>>2];g[s+80+4>>2]=j;g[s+80+8>>2]=h;g[s+80+12>>2]=0.0;h=+g[n+4+(i*184|0)+36>>2]-+g[p+56>>2];j=+g[n+4+(i*184|0)+40>>2]-+g[p+60>>2];g[s+16>>2]=+g[n+4+(i*184|0)+32>>2]-+g[p+52>>2];g[s+16+4>>2]=h;g[s+16+8>>2]=j;g[s+16+12>>2]=0.0;Vk(m,s+200|0,s+80|0);g[s>>2]=k;g[s+4>>2]=e;g[s+8>>2]=t;g[s+12>>2]=0.0;Vk(p,s,s+16|0);f=c[n+748>>2]|0}i=i+1|0}while((i|0)<(f|0))}o=o+1|0}while((o|0)<(c[d+308>>2]|0))}f=c[2395]|0;u=(c[f+16>>2]|0)+-1|0;c[f+16>>2]=u;if(!u){if(c[f+4>>2]|0){Va(s+200|0,0)|0;u=c[6431]|0;g[f+8>>2]=+g[f+8>>2]+ +(((c[s+200+4>>2]|0)-(c[u+4>>2]|0)+(((c[s+200>>2]|0)-(c[u>>2]|0)|0)*1e6|0)-(c[f+12>>2]|0)|0)>>>0)/1.0e3;if(c[f+16>>2]|0)break;f=c[2395]|0}c[2395]=c[f+20>>2]}}while(0);f=c[2395]|0;u=(c[f+16>>2]|0)+-1|0;c[f+16>>2]=u;if(u|0){l=s;return}do if(c[f+4>>2]|0){Va(s+200|0,0)|0;u=c[6431]|0;g[f+8>>2]=+g[f+8>>2]+ +(((c[s+200+4>>2]|0)-(c[u+4>>2]|0)+(((c[s+200>>2]|0)-(c[u>>2]|0)|0)*1e6|0)-(c[f+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[f+16>>2]|0)){f=c[2395]|0;break}else{l=s;return}}while(0);c[2395]=c[f+20>>2];l=s;return}function Tc(b,d,e){b=b|0;d=d|0;e=+e;var f=0,h=0,i=0,j=0,k=0,m=0.0,n=0.0,o=0,p=0.0,q=0,r=0,s=0;s=l;l=l+112|0;q=c[b+716>>2]|0;if((q|0)==(c[b+712>>2]|0)){a:do if(q){j=c[b+720>>2]|0;if((q|0)>0){h=j;i=0;while(1){f=c[h+(i*104|0)+96>>2]|0;if(f|0)c[f+36>>2]=i;f=i+1|0;if((f|0)==(q|0))break a;h=c[b+720>>2]|0;i=f}}}else j=0;while(0);f=c[b+732>>2]|0;if((f|0)>0){h=0;do{o=(c[b+740>>2]|0)+(h*52|0)+8|0;c[o>>2]=((c[o>>2]|0)-j|0)/104|0;o=(c[b+740>>2]|0)+(h*52|0)+12|0;c[o>>2]=((c[o>>2]|0)-j|0)/104|0;h=h+1|0}while((h|0)!=(f|0))}f=c[b+752>>2]|0;if((f|0)>0){i=0;do{h=(c[b+760>>2]|0)+(i*44|0)+8|0;c[h>>2]=((c[h>>2]|0)-j|0)/104|0;h=(c[b+760>>2]|0)+(i*44|0)+12|0;c[h>>2]=((c[h>>2]|0)-j|0)/104|0;h=(c[b+760>>2]|0)+(i*44|0)+16|0;c[h>>2]=((c[h>>2]|0)-j|0)/104|0;h=c[(c[b+760>>2]|0)+(i*44|0)+40>>2]|0;if(h|0)c[h+36>>2]=i;i=i+1|0}while((i|0)!=(f|0))}f=c[b+792>>2]|0;if((f|0)>0){h=c[b+800>>2]|0;i=0;do{o=h+(i*96|0)|0;c[o>>2]=((c[o>>2]|0)-j|0)/104|0;i=i+1|0}while((i|0)!=(f|0))}i=c[b+692>>2]|0;if((i|0)>0){f=c[b+700>>2]|0;k=0;do{if((c[f+(k*60|0)+24>>2]|0)>0){h=0;do{f=f+(k*60|0)+28+(h<<2)|0;c[f>>2]=((c[f>>2]|0)-j|0)/104|0;h=h+1|0;f=c[b+700>>2]|0}while((h|0)<(c[f+(k*60|0)+24>>2]|0))}k=k+1|0}while((k|0)!=(i|0))}if((q|0)<(q<<1|1|0)){c[6432]=(c[6432]|0)+1;f=ec(((q<<1|1)*104|3)+16|0)|0;if(!f)i=0;else{c[(f+4+15&-16)+-4>>2]=f;i=f+4+15&-16}f=c[b+712>>2]|0;if((f|0)>0){h=0;do{k=i+(h*104|0)|0;j=(c[b+720>>2]|0)+(h*104|0)|0;o=k+104|0;do{c[k>>2]=c[j>>2];k=k+4|0;j=j+4|0}while((k|0)<(o|0));h=h+1|0}while((h|0)!=(f|0))}f=c[b+720>>2]|0;if(f|0){if(a[b+724>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[b+720>>2]=0}a[b+724>>0]=1;c[b+720>>2]=i;c[b+716>>2]=q<<1|1;i=c[b+712>>2]|0}else i=q;b:do if(i){j=c[b+720>>2]|0;if((i|0)>0){k=j;f=0;while(1){h=c[k+(f*104|0)+96>>2]|0;if(h|0)c[h+36>>2]=k+(f*104|0);f=f+1|0;if((f|0)==(i|0)){k=j;break b}k=c[b+720>>2]|0}}else k=j}else k=0;while(0);f=c[b+732>>2]|0;if((f|0)>0){h=0;do{q=(c[b+740>>2]|0)+(h*52|0)+8|0;c[q>>2]=k+((c[q>>2]|0)*104|0);q=(c[b+740>>2]|0)+(h*52|0)+12|0;c[q>>2]=k+((c[q>>2]|0)*104|0);h=h+1|0}while((h|0)!=(f|0))}f=c[b+752>>2]|0;if((f|0)>0){j=0;do{h=(c[b+760>>2]|0)+(j*44|0)+8|0;c[h>>2]=k+((c[h>>2]|0)*104|0);h=(c[b+760>>2]|0)+(j*44|0)+12|0;c[h>>2]=k+((c[h>>2]|0)*104|0);h=(c[b+760>>2]|0)+(j*44|0)+16|0;c[h>>2]=k+((c[h>>2]|0)*104|0);h=c[b+760>>2]|0;i=c[h+(j*44|0)+40>>2]|0;if(i|0)c[i+36>>2]=h+(j*44|0);j=j+1|0}while((j|0)!=(f|0))}h=c[b+792>>2]|0;if((h|0)>0){f=c[b+800>>2]|0;i=0;do{q=f+(i*96|0)|0;c[q>>2]=k+((c[q>>2]|0)*104|0);i=i+1|0}while((i|0)!=(h|0))}i=c[b+692>>2]|0;if((i|0)>0){f=c[b+700>>2]|0;j=0;do{if((c[f+(j*60|0)+24>>2]|0)>0){h=0;do{f=f+(j*60|0)+28+(h<<2)|0;c[f>>2]=k+((c[f>>2]|0)*104|0);h=h+1|0;f=c[b+700>>2]|0}while((h|0)<(c[f+(j*60|0)+24>>2]|0))}j=j+1|0}while((j|0)!=(i|0))}}k=c[b+192>>2]|0;p=+zb[c[(c[k>>2]|0)+48>>2]&15](k);k=s;o=k+100|0;do{c[k>>2]=0;k=k+4|0}while((k|0)<(o|0));f=c[b+712>>2]|0;if((f|0)==(c[b+716>>2]|0)?(r=f|0?f<<1:1,(f|0)<(r|0)):0){if(!r)h=0;else{c[6432]=(c[6432]|0)+1;f=ec((r*104|3)+16|0)|0;if(!f)h=0;else{c[(f+4+15&-16)+-4>>2]=f;h=f+4+15&-16}f=c[b+712>>2]|0}if((f|0)>0){i=0;do{k=h+(i*104|0)|0;j=(c[b+720>>2]|0)+(i*104|0)|0;o=k+104|0;do{c[k>>2]=c[j>>2];k=k+4|0;j=j+4|0}while((k|0)<(o|0));i=i+1|0}while((i|0)!=(f|0))}f=c[b+720>>2]|0;if(f|0){if(a[b+724>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[b+720>>2]=0}a[b+724>>0]=1;c[b+720>>2]=h;c[b+716>>2]=r;f=c[b+712>>2]|0}k=c[b+720>>2]|0;c[k+(f*104|0)>>2]=0;k=k+(f*104|0)+4|0;j=s;o=k+100|0;do{c[k>>2]=c[j>>2];k=k+4|0;j=j+4|0}while((k|0)<(o|0));h=c[b+712>>2]|0;c[b+712>>2]=h+1;i=c[b+720>>2]|0;k=i+(h*104|0)|0;o=k+104|0;do{c[k>>2]=0;k=k+4|0}while((k|0)<(o|0));c[i+(h*104|0)+8>>2]=c[d>>2];c[i+(h*104|0)+8+4>>2]=c[d+4>>2];c[i+(h*104|0)+8+8>>2]=c[d+8>>2];c[i+(h*104|0)+8+12>>2]=c[d+12>>2];fp(i+(h*104|0)+24|0,d|0,16)|0;g[i+(h*104|0)+88>>2]=e>0.0?1.0/e:0.0;c[i+(h*104|0)+4>>2]=c[c[b+880>>2]>>2];e=+g[i+(h*104|0)+8>>2];m=+g[i+(h*104|0)+12>>2];n=+g[i+(h*104|0)+16>>2];f=c[b+932>>2]|0;if(f|0){c[b+932>>2]=0;d=f;r=d+32|0;c[r>>2]=0;r=d+36|0;c[r>>2]=i+(h*104|0);r=d+40|0;c[r>>2]=0;g[d>>2]=e-p;r=d+4|0;g[r>>2]=m-p;r=d+8|0;g[r>>2]=n-p;r=d+12|0;g[r>>2]=0.0;r=d+16|0;g[r>>2]=p+e;r=d+20|0;g[r>>2]=p+m;r=d+24|0;g[r>>2]=p+n;r=d+28|0;g[r>>2]=0.0;r=c[b+928>>2]|0;We(b+928|0,r,d);b=b+940|0;r=c[b>>2]|0;r=r+1|0;c[b>>2]=r;b=i+(h*104|0)+96|0;c[b>>2]=d;l=s;return}c[6432]=(c[6432]|0)+1;f=ec(63)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}k=f;o=k+44|0;do{c[k>>2]=0;k=k+4|0}while((k|0)<(o|0));d=f;r=d+32|0;c[r>>2]=0;r=d+36|0;c[r>>2]=i+(h*104|0);r=d+40|0;c[r>>2]=0;g[d>>2]=e-p;r=d+4|0;g[r>>2]=m-p;r=d+8|0;g[r>>2]=n-p;r=d+12|0;g[r>>2]=0.0;r=d+16|0;g[r>>2]=p+e;r=d+20|0;g[r>>2]=p+m;r=d+24|0;g[r>>2]=p+n;r=d+28|0;g[r>>2]=0.0;r=c[b+928>>2]|0;We(b+928|0,r,d);b=b+940|0;r=c[b>>2]|0;r=r+1|0;c[b>>2]=r;b=i+(h*104|0)+96|0;c[b>>2]=d;l=s;return}function Uc(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0,j=0,k=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0.0,O=0.0,P=0.0,Q=0.0;s=l;l=l+224|0;r=(a[b+28>>0]|0)!=0;q=r?e:d;r=r?d:e;p=c[q+4>>2]|0;if((c[p+68>>2]|0)!=(c[b+40>>2]|0)){i=c[b+12>>2]|0;if((i|0)>0){k=0;do{j=c[(c[b+20>>2]|0)+(k<<2)>>2]|0;if(j|0){hb[c[c[j>>2]>>2]&511](j);n=c[b+4>>2]|0;jb[c[(c[n>>2]|0)+60>>2]&127](n,c[(c[b+20>>2]|0)+(k<<2)>>2]|0)}k=k+1|0}while((k|0)!=(i|0))}Ng(b,d,e)}n=c[p+64>>2]|0;i=c[b+4>>2]|0;j=c[b+20>>2]|0;m=c[b+32>>2]|0;c[s+192>>2]=6316;c[s+192+4>>2]=q;c[s+192+8>>2]=r;c[s+192+12>>2]=i;c[s+192+16>>2]=f;c[s+192+20>>2]=h;c[s+192+24>>2]=j;c[s+192+28>>2]=m;a[s+128+16>>0]=1;m=s+128+12|0;c[m>>2]=0;c[s+128+4>>2]=0;c[s+128+8>>2]=0;i=c[b+12>>2]|0;if((i|0)>0){d=0;while(1){j=c[j+(d<<2)>>2]|0;if(j){jb[c[(c[j>>2]|0)+16>>2]&127](j,s+128|0);i=c[s+128+4>>2]|0;if((i|0)>0){f=0;do{k=c[(c[m>>2]|0)+(f<<2)>>2]|0;if(c[k+748>>2]|0){c[h+4>>2]=k;i=c[k+740>>2]|0;j=c[(c[h+8>>2]|0)+8>>2]|0;e=c[(c[h+12>>2]|0)+8>>2]|0;if((i|0)==(j|0))Le(k,i+4|0,e+4|0);else Le(k,e+4|0,j+4|0);c[h+4>>2]=0;i=c[s+128+4>>2]|0}f=f+1|0}while((f|0)<(i|0))}if((i|0)<0){if((c[s+128+8>>2]|0)<0){j=c[m>>2]|0;if(j|0){if(a[s+128+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0)}c[m>>2]=0}a[s+128+16>>0]=1;c[m>>2]=0;c[s+128+8>>2]=0}do{c[(c[m>>2]|0)+(i<<2)>>2]=0;i=i+1|0}while((i|0)!=0)}c[s+128+4>>2]=0;i=c[b+12>>2]|0}d=d+1|0;if((d|0)>=(i|0))break;j=c[b+20>>2]|0}i=c[m>>2]|0;if(i|0){if(a[s+128+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[m>>2]=0}}if(!n){j=c[b+12>>2]|0;if((j|0)>0){i=0;do{Ae(s+192|0,c[(c[p+24>>2]|0)+(i*80|0)+64>>2]|0,i);i=i+1|0}while((i|0)<(j|0));o=38}}else{o=c[q+12>>2]|0;H=+g[o>>2];G=+g[o+16>>2];F=+g[o+32>>2];E=+g[o+4>>2];D=+g[o+20>>2];C=+g[o+36>>2];y=+g[o+8>>2];w=+g[o+24>>2];u=+g[o+40>>2];B=-+g[o+48>>2];A=-+g[o+52>>2];z=-+g[o+56>>2];o=c[r+12>>2]|0;Q=+g[o>>2];P=+g[o+16>>2];O=+g[o+32>>2];N=+g[o+4>>2];M=+g[o+20>>2];L=+g[o+36>>2];K=+g[o+8>>2];J=+g[o+24>>2];I=+g[o+40>>2];x=+g[o+48>>2];v=+g[o+52>>2];t=+g[o+56>>2];g[s+48>>2]=H*Q+G*P+F*O;g[s+48+4>>2]=H*N+G*M+F*L;g[s+48+8>>2]=H*K+G*J+F*I;g[s+48+12>>2]=0.0;g[s+48+16>>2]=E*Q+D*P+C*O;g[s+48+20>>2]=E*N+D*M+C*L;g[s+48+24>>2]=E*K+D*J+C*I;g[s+48+28>>2]=0.0;g[s+48+32>>2]=y*Q+w*P+u*O;g[s+48+36>>2]=y*N+w*M+u*L;g[s+48+40>>2]=y*K+w*J+u*I;g[s+48+44>>2]=0.0;g[s+48+48>>2]=H*B+G*A+F*z+(H*x+G*v+F*t);g[s+48+52>>2]=E*B+D*A+C*z+(E*x+D*v+C*t);g[s+48+56>>2]=y*B+w*A+u*z+(y*x+w*v+u*t);g[s+48+60>>2]=0.0;o=c[r+4>>2]|0;Vb[c[(c[o>>2]|0)+8>>2]&127](o,s+48|0,s+128|0,s+112|0);c[s+16>>2]=c[s+128>>2];c[s+16+4>>2]=c[s+128+4>>2];c[s+16+8>>2]=c[s+128+8>>2];c[s+16+12>>2]=c[s+128+12>>2];c[s+16+16>>2]=c[s+112>>2];c[s+16+16+4>>2]=c[s+112+4>>2];c[s+16+16+8>>2]=c[s+112+8>>2];c[s+16+16+12>>2]=c[s+112+12>>2];Qe(c[n>>2]|0,s+16|0,s+192|0);o=38}if((o|0)==38)j=c[b+12>>2]|0;if((j|0)<=0){l=s;return}d=0;do{do if(c[(c[b+20>>2]|0)+(d<<2)>>2]|0){n=c[p+24>>2]|0;o=c[n+(d*80|0)+64>>2]|0;h=c[q+12>>2]|0;w=+g[h>>2];x=+g[h+4>>2];y=+g[h+8>>2];z=+g[h+16>>2];A=+g[h+20>>2];B=+g[h+24>>2];I=+g[h+32>>2];K=+g[h+36>>2];M=+g[h+40>>2];C=+g[n+(d*80|0)>>2];D=+g[n+(d*80|0)+16>>2];E=+g[n+(d*80|0)+32>>2];F=+g[n+(d*80|0)+4>>2];G=+g[n+(d*80|0)+20>>2];H=+g[n+(d*80|0)+36>>2];J=+g[n+(d*80|0)+8>>2];L=+g[n+(d*80|0)+24>>2];N=+g[n+(d*80|0)+40>>2];u=+g[n+(d*80|0)+48>>2];v=+g[n+(d*80|0)+52>>2];Q=+g[n+(d*80|0)+56>>2];O=+g[h+48>>2]+(w*u+x*v+y*Q);P=+g[h+52>>2]+(z*u+A*v+B*Q);Q=+g[h+56>>2]+(I*u+K*v+M*Q);g[s+128>>2]=w*C+x*D+y*E;g[s+128+4>>2]=w*F+x*G+y*H;g[s+128+8>>2]=w*J+x*L+y*N;g[s+128+12>>2]=0.0;g[s+128+16>>2]=z*C+A*D+B*E;g[s+128+20>>2]=z*F+A*G+B*H;g[s+128+24>>2]=z*J+A*L+B*N;g[s+128+28>>2]=0.0;g[s+128+32>>2]=I*C+K*D+M*E;g[s+128+36>>2]=I*F+K*G+M*H;g[s+128+40>>2]=I*J+K*L+M*N;g[s+128+44>>2]=0.0;g[s+128+48>>2]=O;g[s+128+52>>2]=P;g[s+128+56>>2]=Q;g[s+128+60>>2]=0.0;Vb[c[(c[o>>2]|0)+8>>2]&127](o,s+128|0,s+112|0,s+48|0);o=c[r+4>>2]|0;Vb[c[(c[o>>2]|0)+8>>2]&127](o,c[r+12>>2]|0,s+16|0,s);if(!(+g[s+112>>2]>+g[s>>2])?!(+g[s+48>>2]<+g[s+16>>2]):0)i=1;else i=0;if(!(!(+g[s+112+8>>2]>+g[s+8>>2])?!(+g[s+48+8>>2]<+g[s+16+8>>2]):0))i=0;if(!(+g[s+112+4>>2]>+g[s+4>>2])?!(+g[s+48+4>>2]<+g[s+16+4>>2]|i^1):0)break;o=c[(c[b+20>>2]|0)+(d<<2)>>2]|0;hb[c[c[o>>2]>>2]&511](o);o=c[b+4>>2]|0;jb[c[(c[o>>2]|0)+60>>2]&127](o,c[(c[b+20>>2]|0)+(d<<2)>>2]|0);c[(c[b+20>>2]|0)+(d<<2)>>2]=0}while(0);d=d+1|0}while((d|0)<(j|0));l=s;return}function Vc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0,i=0,j=0,k=0,l=0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,C=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0.0,O=0.0,P=0.0,Q=0.0,R=0.0,S=0.0,T=0.0,U=0.0,V=0.0,W=0.0;c[b>>2]=c[a>>2];c[b+4>>2]=c[a+4>>2];c[b+8>>2]=c[a+8>>2];c[b+12>>2]=c[a+12>>2];c[b+16>>2]=c[a+16>>2];c[b+16+4>>2]=c[a+16+4>>2];c[b+16+8>>2]=c[a+16+8>>2];c[b+16+12>>2]=c[a+16+12>>2];c[b+32>>2]=c[a+32>>2];c[b+32+4>>2]=c[a+32+4>>2];c[b+32+8>>2]=c[a+32+8>>2];c[b+32+12>>2]=c[a+32+12>>2];r=+g[a+20>>2];m=+g[a+40>>2];p=+g[a+24>>2];n=+g[a+36>>2];o=+g[a+32>>2];s=+g[a+16>>2];t=+g[a>>2];u=+g[a+4>>2];q=+g[a+8>>2];v=1.0/((r*m-p*n)*t+u*(p*o-m*s)+(n*s-r*o)*q);g[d>>2]=(r*m-p*n)*v;g[d+4>>2]=(n*q-m*u)*v;g[d+8>>2]=(p*u-r*q)*v;g[d+12>>2]=0.0;g[d+16>>2]=(p*o-m*s)*v;g[d+20>>2]=(m*t-o*q)*v;g[d+24>>2]=(s*q-p*t)*v;g[d+28>>2]=0.0;g[d+32>>2]=(n*s-r*o)*v;g[d+36>>2]=(o*u-n*t)*v;g[d+40>>2]=(r*t-s*u)*v;g[d+44>>2]=0.0;a:do if(!(c[5785]|0)){e=b;f=b+40|0;h=b+24|0;i=b+8|0;j=b+36|0;k=b+20|0;l=b+4|0}else{F=(r*m-p*n)*v;G=(p*o-m*s)*v;H=(n*s-r*o)*v;I=(n*q-m*u)*v;E=(m*t-o*q)*v;A=(o*u-n*t)*v;C=(p*u-r*q)*v;z=(s*q-p*t)*v;n=(r*t-s*u)*v;e=0;while(1){p=+B(+F);o=+B(+G);N=+B(+H);W=+B(+I);O=+B(+E);M=+B(+A);Q=+B(+C);P=+B(+z);x=+B(+n);R=p+o+N>W+O+M?p+o+N:W+O+M;O=p+W+Q>o+O+P?p+W+Q:o+O+P;o=+g[b>>2];W=+B(+o);p=+g[b+16>>2];T=+B(+p);q=+g[b+32>>2];K=+B(+q);r=+g[b+4>>2];V=+B(+r);s=+g[b+20>>2];S=+B(+s);t=+g[b+36>>2];J=+B(+t);u=+g[b+8>>2];U=+B(+u);v=+g[b+24>>2];L=+B(+v);w=+g[b+40>>2];y=+B(+w);m=W+T+K>V+S+J?W+T+K:V+S+J;m=m>U+L+y?m:U+L+y;L=W+V+U>T+S+L?W+V+U:T+S+L;x=(R>Q+P+x?R:Q+P+x)*(O>N+M+x?O:N+M+x);y=m*(L>K+J+y?L:K+J+y);if(+B(+x)<1.1920928955078125e-07){e=b;f=b+40|0;h=b+24|0;i=b+8|0;j=b+36|0;k=b+20|0;l=b+4|0;break a}if(+B(+y)<1.1920928955078125e-07){e=b;f=b+40|0;h=b+24|0;i=b+8|0;j=b+36|0;k=b+20|0;l=b+4|0;break a}W=+D(+(x/y),.25);O=(o*(W+-2.0)+F*(1.0/W))*.5;Q=(r*(W+-2.0)+1.0/W*G)*.5;S=(u*(W+-2.0)+1.0/W*H)*.5;P=(p*(W+-2.0)+1.0/W*I)*.5;R=(s*(W+-2.0)+1.0/W*E)*.5;T=(v*(W+-2.0)+1.0/W*A)*.5;U=(q*(W+-2.0)+1.0/W*C)*.5;V=(t*(W+-2.0)+1.0/W*z)*.5;W=(w*(W+-2.0)+1.0/W*n)*.5;g[b>>2]=o+O;g[b+4>>2]=r+Q;g[b+8>>2]=u+S;g[b+12>>2]=0.0;g[b+16>>2]=p+P;g[b+20>>2]=s+R;g[b+24>>2]=v+T;g[b+28>>2]=0.0;g[b+32>>2]=q+U;g[b+36>>2]=t+V;g[b+40>>2]=w+W;g[b+44>>2]=0.0;N=1.0/(((w+W)*(s+R)-(v+T)*(t+V))*(o+O)+(r+Q)*((v+T)*(q+U)-(w+W)*(p+P))+((t+V)*(p+P)-(s+R)*(q+U))*(u+S));F=((w+W)*(s+R)-(v+T)*(t+V))*N;I=((t+V)*(u+S)-(w+W)*(r+Q))*N;C=((v+T)*(r+Q)-(s+R)*(u+S))*N;G=((v+T)*(q+U)-(w+W)*(p+P))*N;E=((w+W)*(o+O)-(q+U)*(u+S))*N;z=((p+P)*(u+S)-(v+T)*(o+O))*N;H=((t+V)*(p+P)-(s+R)*(q+U))*N;A=((q+U)*(r+Q)-(t+V)*(o+O))*N;n=((s+R)*(o+O)-(p+P)*(r+Q))*N;g[d>>2]=F;g[d+4>>2]=I;g[d+8>>2]=C;g[d+12>>2]=0.0;g[d+16>>2]=G;g[d+20>>2]=E;g[d+24>>2]=z;g[d+28>>2]=0.0;g[d+32>>2]=H;g[d+36>>2]=A;g[d+40>>2]=n;g[d+44>>2]=0.0;U=+B(+O)+ +B(+P)+ +B(+U);V=+B(+Q)+ +B(+R)+ +B(+V);W=+B(+S)+ +B(+T)+ +B(+W);V=U>V?U:V;if((V>W?V:W)<=m*+g[5784])break;e=e+1|0;if(e>>>0>=(c[5785]|0)>>>0){e=b;f=b+40|0;h=b+24|0;i=b+8|0;j=b+36|0;k=b+20|0;l=b+4|0;break a}}M=+g[b>>2];O=+g[b+16>>2];Q=+g[b+32>>2];H=+g[b+4>>2];J=+g[b+20>>2];L=+g[b+36>>2];A=+g[b+8>>2];E=+g[b+24>>2];G=+g[b+40>>2];N=+g[a>>2];P=+g[a+16>>2];R=+g[a+32>>2];I=+g[a+4>>2];K=+g[a+20>>2];T=+g[a+36>>2];C=+g[a+8>>2];F=+g[a+24>>2];W=+g[a+40>>2];S=H*N+J*P+L*R+(M*I+O*K+Q*T);U=A*N+E*P+G*R+(M*C+O*F+Q*W);V=A*I+E*K+G*T+(H*C+J*F+L*W);W=A*C+E*F+G*W+(A*C+E*F+G*W);T=H*I+J*K+L*T+(H*I+J*K+L*T);R=M*N+O*P+Q*R+(M*N+O*P+Q*R);S=S*.5;U=U*.5;V=V*.5;R=R*.5;g[d>>2]=R;g[d+4>>2]=S;g[d+8>>2]=U;g[d+12>>2]=0.0;g[d+16>>2]=S;T=T*.5;g[d+20>>2]=T;g[d+24>>2]=V;g[d+28>>2]=0.0;g[d+32>>2]=U;g[d+36>>2]=V;W=W*.5;g[d+40>>2]=W;g[d+44>>2]=0.0;return}while(0);M=+g[e>>2];O=+g[b+16>>2];Q=+g[b+32>>2];H=+g[l>>2];J=+g[k>>2];L=+g[j>>2];A=+g[i>>2];E=+g[h>>2];G=+g[f>>2];N=+g[a>>2];P=+g[a+16>>2];R=+g[a+32>>2];I=+g[a+4>>2];K=+g[a+20>>2];T=+g[a+36>>2];C=+g[a+8>>2];F=+g[a+24>>2];W=+g[a+40>>2];S=H*N+J*P+L*R+(M*I+O*K+Q*T);U=A*N+E*P+G*R+(M*C+O*F+Q*W);V=A*I+E*K+G*T+(H*C+J*F+L*W);W=A*C+E*F+G*W+(A*C+E*F+G*W);T=H*I+J*K+L*T+(H*I+J*K+L*T);R=M*N+O*P+Q*R+(M*N+O*P+Q*R);S=S*.5;U=U*.5;V=V*.5;R=R*.5;g[d>>2]=R;g[d+4>>2]=S;g[d+8>>2]=U;g[d+12>>2]=0.0;g[d+16>>2]=S;T=T*.5;g[d+20>>2]=T;g[d+24>>2]=V;g[d+28>>2]=0.0;g[d+32>>2]=U;g[d+36>>2]=V;W=W*.5;g[d+40>>2]=W;g[d+44>>2]=0.0;return}function Wc(a,b,f,i){a=a|0;b=b|0;f=f|0;i=i|0;var j=0.0,k=0.0,m=0.0,n=0,o=0,p=0.0,q=0.0,r=0,s=0,t=0,u=0;o=l;l=l+80|0;f=lb[c[(c[a>>2]|0)+28>>2]&127](a)|0;j=+g[a+4>>2];k=+g[a+8>>2];m=+g[a+12>>2];if((f|0)<=0){l=o;return}n=0;do{Fb[c[(c[a>>2]|0)+16>>2]&3](a,o+76|0,o+52|0,o+64|0,o+56|0,o+72|0,o+68|0,o+48|0,o+60|0,n);a:do switch(c[o+64>>2]|0){case 0:{switch(c[o+60>>2]|0){case 2:{if((c[o+48>>2]|0)>0)i=0;else break a;do{r=(c[o+72>>2]|0)+(O(c[o+68>>2]|0,i)|0)|0;t=c[o+76>>2]|0;s=c[o+56>>2]|0;u=t+(O(s,c[r>>2]|0)|0)|0;q=k*+g[u+4>>2];p=m*+g[u+8>>2];g[o>>2]=j*+g[u>>2];g[o+4>>2]=q;g[o+8>>2]=p;g[o+12>>2]=0.0;u=t+(O(s,c[r+4>>2]|0)|0)|0;p=k*+g[u+4>>2];q=m*+g[u+8>>2];g[o+16>>2]=j*+g[u>>2];g[o+20>>2]=p;g[o+24>>2]=q;g[o+28>>2]=0.0;r=t+(O(s,c[r+8>>2]|0)|0)|0;q=k*+g[r+4>>2];p=m*+g[r+8>>2];g[o+32>>2]=j*+g[r>>2];g[o+36>>2]=q;g[o+40>>2]=p;g[o+44>>2]=0.0;Vb[c[(c[b>>2]|0)+8>>2]&127](b,o,n,i);i=i+1|0}while((i|0)<(c[o+48>>2]|0));break}case 3:{if((c[o+48>>2]|0)>0)i=0;else break a;do{t=(c[o+72>>2]|0)+(O(c[o+68>>2]|0,i)|0)|0;s=c[o+76>>2]|0;u=c[o+56>>2]|0;r=s+(O(e[t>>1]|0,u)|0)|0;p=k*+g[r+4>>2];q=m*+g[r+8>>2];g[o>>2]=j*+g[r>>2];g[o+4>>2]=p;g[o+8>>2]=q;g[o+12>>2]=0.0;r=s+(O(e[t+2>>1]|0,u)|0)|0;q=k*+g[r+4>>2];p=m*+g[r+8>>2];g[o+16>>2]=j*+g[r>>2];g[o+20>>2]=q;g[o+24>>2]=p;g[o+28>>2]=0.0;u=s+(O(e[t+4>>1]|0,u)|0)|0;p=k*+g[u+4>>2];q=m*+g[u+8>>2];g[o+32>>2]=j*+g[u>>2];g[o+36>>2]=p;g[o+40>>2]=q;g[o+44>>2]=0.0;Vb[c[(c[b>>2]|0)+8>>2]&127](b,o,n,i);i=i+1|0}while((i|0)<(c[o+48>>2]|0));break}case 5:{if((c[o+48>>2]|0)>0)i=0;else break a;do{t=(c[o+72>>2]|0)+(O(c[o+68>>2]|0,i)|0)|0;s=c[o+76>>2]|0;u=c[o+56>>2]|0;r=s+(O(d[t>>0]|0,u)|0)|0;p=k*+g[r+4>>2];q=m*+g[r+8>>2];g[o>>2]=j*+g[r>>2];g[o+4>>2]=p;g[o+8>>2]=q;g[o+12>>2]=0.0;r=s+(O(d[t+1>>0]|0,u)|0)|0;q=k*+g[r+4>>2];p=m*+g[r+8>>2];g[o+16>>2]=j*+g[r>>2];g[o+20>>2]=q;g[o+24>>2]=p;g[o+28>>2]=0.0;u=s+(O(d[t+2>>0]|0,u)|0)|0;p=k*+g[u+4>>2];q=m*+g[u+8>>2];g[o+32>>2]=j*+g[u>>2];g[o+36>>2]=p;g[o+40>>2]=q;g[o+44>>2]=0.0;Vb[c[(c[b>>2]|0)+8>>2]&127](b,o,n,i);i=i+1|0}while((i|0)<(c[o+48>>2]|0));break}default:break a}break}case 1:{switch(c[o+60>>2]|0){case 2:{if((c[o+48>>2]|0)>0)i=0;else break a;do{u=(c[o+72>>2]|0)+(O(c[o+68>>2]|0,i)|0)|0;s=c[o+76>>2]|0;t=c[o+56>>2]|0;r=s+(O(t,c[u>>2]|0)|0)|0;p=k*+h[r+8>>3];q=m*+h[r+16>>3];g[o>>2]=j*+h[r>>3];g[o+4>>2]=p;g[o+8>>2]=q;g[o+12>>2]=0.0;r=s+(O(t,c[u+4>>2]|0)|0)|0;q=k*+h[r+8>>3];p=m*+h[r+16>>3];g[o+16>>2]=j*+h[r>>3];g[o+20>>2]=q;g[o+24>>2]=p;g[o+28>>2]=0.0;u=s+(O(t,c[u+8>>2]|0)|0)|0;p=k*+h[u+8>>3];q=m*+h[u+16>>3];g[o+32>>2]=j*+h[u>>3];g[o+36>>2]=p;g[o+40>>2]=q;g[o+44>>2]=0.0;Vb[c[(c[b>>2]|0)+8>>2]&127](b,o,n,i);i=i+1|0}while((i|0)<(c[o+48>>2]|0));break}case 3:{if((c[o+48>>2]|0)>0)i=0;else break a;do{t=(c[o+72>>2]|0)+(O(c[o+68>>2]|0,i)|0)|0;s=c[o+76>>2]|0;u=c[o+56>>2]|0;r=s+(O(e[t>>1]|0,u)|0)|0;p=k*+h[r+8>>3];q=m*+h[r+16>>3];g[o>>2]=j*+h[r>>3];g[o+4>>2]=p;g[o+8>>2]=q;g[o+12>>2]=0.0;r=s+(O(e[t+2>>1]|0,u)|0)|0;q=k*+h[r+8>>3];p=m*+h[r+16>>3];g[o+16>>2]=j*+h[r>>3];g[o+20>>2]=q;g[o+24>>2]=p;g[o+28>>2]=0.0;u=s+(O(e[t+4>>1]|0,u)|0)|0;p=k*+h[u+8>>3];q=m*+h[u+16>>3];g[o+32>>2]=j*+h[u>>3];g[o+36>>2]=p;g[o+40>>2]=q;g[o+44>>2]=0.0;Vb[c[(c[b>>2]|0)+8>>2]&127](b,o,n,i);i=i+1|0}while((i|0)<(c[o+48>>2]|0));break}case 5:{if((c[o+48>>2]|0)>0)i=0;else break a;do{t=(c[o+72>>2]|0)+(O(c[o+68>>2]|0,i)|0)|0;s=c[o+76>>2]|0;u=c[o+56>>2]|0;r=s+(O(d[t>>0]|0,u)|0)|0;p=k*+h[r+8>>3];q=m*+h[r+16>>3];g[o>>2]=j*+h[r>>3];g[o+4>>2]=p;g[o+8>>2]=q;g[o+12>>2]=0.0;r=s+(O(d[t+1>>0]|0,u)|0)|0;q=k*+h[r+8>>3];p=m*+h[r+16>>3];g[o+16>>2]=j*+h[r>>3];g[o+20>>2]=q;g[o+24>>2]=p;g[o+28>>2]=0.0;u=s+(O(d[t+2>>0]|0,u)|0)|0;p=k*+h[u+8>>3];q=m*+h[u+16>>3];g[o+32>>2]=j*+h[u>>3];g[o+36>>2]=p;g[o+40>>2]=q;g[o+44>>2]=0.0;Vb[c[(c[b>>2]|0)+8>>2]&127](b,o,n,i);i=i+1|0}while((i|0)<(c[o+48>>2]|0));break}default:break a}break}default:{}}while(0);jb[c[(c[a>>2]|0)+24>>2]&127](a,n);n=n+1|0}while((n|0)!=(f|0));l=o;return}function Xc(d,e,f,h,i){d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;var j=0.0,k=0.0,m=0,n=0,o=0,p=0.0,q=0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0;A=l;l=l+128|0;a[d+60>>0]=f&1;if(f){r=+g[h>>2]+-1.0;u=+g[h+4>>2]+-1.0;t=+g[h+8>>2]+-1.0;g[d+4>>2]=r;g[d+8>>2]=u;g[d+12>>2]=t;g[d+16>>2]=0.0;w=+g[i>>2]+1.0;z=+g[i+4>>2]+1.0;y=+g[i+8>>2]+1.0;g[d+20>>2]=w;g[d+24>>2]=z;g[d+28>>2]=y;g[d+32>>2]=0.0;g[d+36>>2]=65533.0/(w-r);g[d+40>>2]=65533.0/(z-u);g[d+44>>2]=65533.0/(y-t);g[d+48>>2]=0.0;a[d+60>>0]=1;j=r+ +(~~((r-r)*(65533.0/(w-r)))&65535&-2&65535)/(65533.0/(w-r))+-1.0;k=u+ +(~~((u-u)*(65533.0/(z-u)))&65535&-2&65535)/(65533.0/(z-u))+-1.0;p=t+ +(~~((t-t)*(65533.0/(y-t)))&65535&-2&65535)/(65533.0/(y-t))+-1.0;if(j<r){g[d+4>>2]=j;x=j}else x=r;if(k<u){g[d+8>>2]=k;v=k}else v=u;if(p<t){g[d+12>>2]=p;s=p}else s=t;p=x+ +((~~((w-x)*(65533.0/(w-r))+1.0)&65535|1)&65535)/(65533.0/(w-r))+1.0;k=v+ +((~~((z-v)*(65533.0/(z-u))+1.0)&65535|1)&65535)/(65533.0/(z-u))+1.0;j=s+ +((~~((y-s)*(65533.0/(y-t))+1.0)&65535|1)&65535)/(65533.0/(y-t))+1.0;if(w<p)g[d+20>>2]=p;else p=w;if(z<k)g[d+24>>2]=k;else k=z;if(y<j)g[d+28>>2]=j;else j=y;g[d+36>>2]=65533.0/(p-x);g[d+40>>2]=65533.0/(k-v);g[d+44>>2]=65533.0/(j-s);g[d+48>>2]=0.0;c[A+96>>2]=8144;c[A+96+4>>2]=d+104;c[A+96+8>>2]=d;Vb[c[(c[e>>2]|0)+8>>2]&127](e,A+96|0,d+4|0,d+20|0);f=c[d+108>>2]|0;c[A+80>>2]=0;c[A+80+4>>2]=0;c[A+80+8>>2]=0;c[A+80+12>>2]=0;m=c[d+128>>2]|0;if((m|0)<(f<<1|0)){if((c[d+132>>2]|0)<(f<<1|0)){if(!f){i=m;e=0}else{c[6432]=(c[6432]|0)+1;h=ec(f<<5|19)|0;if(!h)h=0;else{c[(h+4+15&-16)+-4>>2]=h;h=h+4+15&-16}i=c[d+128>>2]|0;e=h}if((i|0)>0){h=0;do{q=e+(h<<4)|0;o=(c[d+136>>2]|0)+(h<<4)|0;c[q>>2]=c[o>>2];c[q+4>>2]=c[o+4>>2];c[q+8>>2]=c[o+8>>2];c[q+12>>2]=c[o+12>>2];h=h+1|0}while((h|0)!=(i|0))}h=c[d+136>>2]|0;if(h|0){if(a[d+140>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[d+136>>2]=0}a[d+140>>0]=1;c[d+136>>2]=e;c[d+132>>2]=f<<1;i=d+136|0}else i=d+136|0;h=m;do{q=(c[i>>2]|0)+(h<<4)|0;c[q>>2]=c[A+80>>2];c[q+4>>2]=c[A+80+4>>2];c[q+8>>2]=c[A+80+8>>2];c[q+12>>2]=c[A+80+12>>2];h=h+1|0}while((h|0)!=(f<<1|0))}c[d+128>>2]=f<<1}else{c[A+96>>2]=8164;c[A+96+4>>2]=d+64;c[A+80>>2]=-581039253;c[A+80+4>>2]=-581039253;c[A+80+8>>2]=-581039253;g[A+80+12>>2]=0.0;c[A+64>>2]=1566444395;c[A+64+4>>2]=1566444395;c[A+64+8>>2]=1566444395;g[A+64+12>>2]=0.0;Vb[c[(c[e>>2]|0)+8>>2]&127](e,A+96|0,A+80|0,A+64|0);f=c[d+68>>2]|0;m=A;o=m+64|0;do{c[m>>2]=0;m=m+4|0}while((m|0)<(o|0));q=c[d+88>>2]|0;if((q|0)<(f<<1|0)){if((c[d+92>>2]|0)<(f<<1|0)){if(!f){i=q;e=0}else{c[6432]=(c[6432]|0)+1;h=ec(f<<7|19)|0;if(!h)h=0;else{c[(h+4+15&-16)+-4>>2]=h;h=h+4+15&-16}i=c[d+88>>2]|0;e=h}if((i|0)>0){h=0;do{m=e+(h<<6)|0;n=(c[d+96>>2]|0)+(h<<6)|0;o=m+64|0;do{c[m>>2]=c[n>>2];m=m+4|0;n=n+4|0}while((m|0)<(o|0));h=h+1|0}while((h|0)!=(i|0))}h=c[d+96>>2]|0;if(h|0){if(a[d+100>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[d+96>>2]=0}a[d+100>>0]=1;c[d+96>>2]=e;c[d+92>>2]=f<<1;i=d+96|0}else i=d+96|0;h=q;do{m=(c[i>>2]|0)+(h<<6)|0;n=A;o=m+64|0;do{c[m>>2]=c[n>>2];m=m+4|0;n=n+4|0}while((m|0)<(o|0));h=h+1|0}while((h|0)!=(f<<1|0))}c[d+88>>2]=f<<1}c[d+56>>2]=0;qc(d,0,f);if(a[d+60>>0]|0?(c[d+152>>2]|0)==0:0){if(!(c[d+156>>2]|0)){c[6432]=(c[6432]|0)+1;f=ec(51)|0;if(!f)e=0;else{c[(f+4+15&-16)+-4>>2]=f;e=f+4+15&-16}f=c[d+152>>2]|0;if((f|0)>0){h=0;do{q=e+(h<<5)|0;o=(c[d+160>>2]|0)+(h<<5)|0;c[q>>2]=c[o>>2];c[q+4>>2]=c[o+4>>2];c[q+8>>2]=c[o+8>>2];c[q+12>>2]=c[o+12>>2];c[q+16>>2]=c[o+16>>2];c[q+20>>2]=c[o+20>>2];c[q+24>>2]=c[o+24>>2];c[q+28>>2]=c[o+28>>2];h=h+1|0}while((h|0)!=(f|0))}f=c[d+160>>2]|0;if(f|0){if(a[d+164>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[d+160>>2]=0}a[d+164>>0]=1;c[d+160>>2]=e;c[d+156>>2]=1;i=(c[d+152>>2]|0)+1|0;f=e;h=d+160|0}else{i=1;f=c[d+160>>2]|0;h=d+160|0}c[d+152>>2]=i;c[f>>2]=c[A+96>>2];c[f+4>>2]=c[A+96+4>>2];c[f+8>>2]=c[A+96+8>>2];c[f+12>>2]=c[A+96+12>>2];c[f+16>>2]=c[A+96+16>>2];c[f+20>>2]=c[A+96+20>>2];c[f+24>>2]=c[A+96+24>>2];c[f+28>>2]=c[A+96+28>>2];q=c[h>>2]|0;o=c[d+136>>2]|0;b[q>>1]=b[o>>1]|0;b[q+2>>1]=b[o+2>>1]|0;b[q+4>>1]=b[o+4>>1]|0;b[q+6>>1]=b[o+6>>1]|0;b[q+8>>1]=b[o+8>>1]|0;b[q+10>>1]=b[o+10>>1]|0;c[q+12>>2]=0;o=c[o+12>>2]|0;c[q+16>>2]=(o|0)>-1?1:0-o|0}c[d+168>>2]=c[d+152>>2];f=c[d+116>>2]|0;if(f|0){if(a[d+120>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[d+116>>2]=0}a[d+120>>0]=1;c[d+116>>2]=0;c[d+108>>2]=0;c[d+112>>2]=0;f=c[d+76>>2]|0;if(!f){a[d+80>>0]=1;c[d+76>>2]=0;c[d+68>>2]=0;d=d+72|0;c[d>>2]=0;l=A;return}if(a[d+80>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[d+76>>2]=0;a[d+80>>0]=1;c[d+76>>2]=0;c[d+68>>2]=0;d=d+72|0;c[d>>2]=0;l=A;return}function Yc(b,d,e,f,h,i){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;var j=0,k=0.0,m=0.0,n=0.0,o=0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0,v=0.0,w=0.0,x=0,y=0,z=0.0,A=0.0,B=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0,L=0.0,M=0.0,N=0.0,O=0.0,P=0.0,Q=0.0,R=0.0,S=0.0,T=0.0,U=0.0,V=0.0,W=0.0,X=0.0,Y=0.0,Z=0.0,_=0.0,$=0.0,aa=0.0,ba=0.0,ca=0.0,da=0.0,ea=0,fa=0.0;ea=l;l=l+128|0;K=c[b+4>>2]|0;a[K+312>>0]=0;c[K>>2]=0;a[K+356>>0]=1;c[K+292>>2]=1566444395;c[K+296>>2]=1566444395;c[K+300>>2]=1566444395;g[K+304>>2]=0.0;c[K+336>>2]=0;c[K+336+4>>2]=0;c[K+336+8>>2]=0;c[K+336+12>>2]=0;a[K+336+16>>0]=0;a[K+332>>0]=a[K+332>>0]&-16;k=+g[d+48>>2];m=+g[d+52>>2];n=+g[d+56>>2];p=+g[f+48>>2];q=+g[f+52>>2];r=+g[f+56>>2];L=+g[d>>2];M=+g[d+4>>2];N=+g[d+8>>2];O=+g[d+16>>2];P=+g[d+20>>2];Q=+g[d+24>>2];R=+g[d+32>>2];S=+g[d+36>>2];T=+g[d+40>>2];U=+g[f>>2];V=+g[f+4>>2];W=+g[f+8>>2];X=+g[f+16>>2];Y=+g[f+20>>2];Z=+g[f+24>>2];_=+g[f+32>>2];$=+g[f+36>>2];aa=+g[f+40>>2];ba=+g[e+48>>2]-k-(+g[h+48>>2]-p);ca=+g[e+52>>2]-m-(+g[h+52>>2]-q);da=+g[e+56>>2]-n-(+g[h+56>>2]-r);K=c[b+8>>2]|0;y=c[(c[K>>2]|0)+64>>2]|0;g[ea+96>>2]=L*-ba+O*-ca+R*-da;g[ea+96+4>>2]=M*-ba+P*-ca+S*-da;g[ea+96+8>>2]=N*-ba+Q*-ca+T*-da;g[ea+96+12>>2]=0.0;Rb[y&127](ea+112|0,K,ea+96|0);I=+g[ea+112>>2];J=+g[ea+112+4>>2];H=+g[ea+112+8>>2];s=I*+g[d>>2]+J*+g[d+4>>2]+H*+g[d+8>>2]+ +g[d+48>>2];v=I*+g[d+16>>2]+J*+g[d+20>>2]+H*+g[d+24>>2]+ +g[d+52>>2];H=I*+g[d+32>>2]+J*+g[d+36>>2]+H*+g[d+40>>2]+ +g[d+56>>2];K=c[b+12>>2]|0;y=c[(c[K>>2]|0)+64>>2]|0;J=ba*+g[f+4>>2]+ca*+g[f+20>>2]+da*+g[f+36>>2];I=ba*+g[f+8>>2]+ca*+g[f+24>>2]+da*+g[f+40>>2];g[ea+64>>2]=ba*+g[f>>2]+ca*+g[f+16>>2]+da*+g[f+32>>2];g[ea+64+4>>2]=J;g[ea+64+8>>2]=I;g[ea+64+12>>2]=0.0;Rb[y&127](ea+80|0,K,ea+64|0);I=+g[ea+80>>2];J=+g[ea+80+4>>2];t=+g[ea+80+8>>2];s=s-(I*+g[f>>2]+J*+g[f+4>>2]+t*+g[f+8>>2]+ +g[f+48>>2]);v=v-(I*+g[f+16>>2]+J*+g[f+20>>2]+t*+g[f+24>>2]+ +g[f+52>>2]);t=H-(I*+g[f+32>>2]+J*+g[f+36>>2]+t*+g[f+40>>2]+ +g[f+56>>2]);a:do if(s*s+v*v+t*t>9.999999747378752e-05){D=k;B=m;z=n;A=p;p=0.0;n=0.0;m=0.0;j=0;k=0.0;K=32;o=0;while(1){if(!K)break a;K=K+-1|0;y=c[b+8>>2]|0;x=c[(c[y>>2]|0)+64>>2]|0;G=-s;fa=-v;w=-t;g[ea+32>>2]=L*G+O*fa+R*w;g[ea+32+4>>2]=M*G+P*fa+S*w;g[ea+32+8>>2]=N*G+Q*fa+T*w;g[ea+32+12>>2]=0.0;Rb[x&127](ea+48|0,y,ea+32|0);w=+g[ea+48>>2];fa=+g[ea+48+4>>2];G=+g[ea+48+8>>2];E=D+(L*w+M*fa+N*G);F=B+(O*w+P*fa+Q*G);G=z+(R*w+S*fa+T*G);y=c[b+12>>2]|0;x=c[(c[y>>2]|0)+64>>2]|0;g[ea>>2]=U*s+X*v+_*t;g[ea+4>>2]=V*s+Y*v+$*t;g[ea+8>>2]=W*s+Z*v+aa*t;g[ea+12>>2]=0.0;Rb[x&127](ea+16|0,y,ea);fa=+g[ea+16>>2];w=+g[ea+16+4>>2];J=+g[ea+16+8>>2];H=A+(U*fa+V*w+W*J);I=q+(X*fa+Y*w+Z*J);J=r+(_*fa+$*w+aa*J);w=s*(E-H)+v*(F-I)+t*(G-J);if(k>1.0){j=0;o=24;break}if(w>0.0){m=ba*s+ca*v+da*t;if(m>=-1.4210854715202004e-14){j=0;o=24;break}k=k-w/m;z=(1.0-k)*+g[d+56>>2]+k*+g[e+56>>2];B=(1.0-k)*+g[d+52>>2]+k*+g[e+52>>2];w=+g[d+48>>2]*(1.0-k)+k*+g[e+48>>2];r=(1.0-k)*+g[f+56>>2]+k*+g[h+56>>2];q=(1.0-k)*+g[f+52>>2]+k*+g[h+52>>2];A=(1.0-k)*+g[f+48>>2]+k*+g[h+48>>2];j=o;m=t;n=v;p=s}else w=D;x=c[b+4>>2]|0;y=c[x>>2]|0;if((y|0)>0){s=+g[x+308>>2];u=0;o=0;do{v=E-H-+g[x+4+(o<<4)>>2];D=F-I-+g[x+4+(o<<4)+4>>2];fa=G-J-+g[x+4+(o<<4)+8>>2];u=u|v*v+D*D+fa*fa<=s;o=o+1|0}while((o|0)!=(y|0))}else u=0;if((+g[x+304>>2]==0.0?G-J==+g[x+300>>2]:0)?F-I==+g[x+296>>2]:0)o=E-H==+g[x+292>>2];else o=0;if(!(u|o)){g[x+292>>2]=E-H;g[x+296>>2]=F-I;g[x+300>>2]=G-J;g[x+304>>2]=0.0;a[x+356>>0]=1;g[x+4+(y<<4)>>2]=E-H;g[x+4+(y<<4)+4>>2]=F-I;g[x+4+(y<<4)+8>>2]=G-J;g[x+4+(y<<4)+12>>2]=0.0;y=c[x>>2]|0;g[x+84+(y<<4)>>2]=E;g[x+84+(y<<4)+4>>2]=F;g[x+84+(y<<4)+8>>2]=G;g[x+84+(y<<4)+12>>2]=0.0;y=c[x>>2]|0;g[x+164+(y<<4)>>2]=H;g[x+164+(y<<4)+4>>2]=I;g[x+164+(y<<4)+8>>2]=J;g[x+164+(y<<4)+12>>2]=0.0;c[x>>2]=(c[x>>2]|0)+1;x=c[b+4>>2]|0}y=Cc(x)|0;s=+g[x+276>>2];v=+g[x+280>>2];t=+g[x+284>>2];if(!y)break a;if(!(s*s+v*v+t*t>9.999999747378752e-05))break a;else{D=w;o=c[x+288>>2]|0}}if((o|0)==24){l=ea;return j|0}}else{j=0;p=0.0;n=0.0;m=0.0;k=0.0}while(0);g[i+164>>2]=k;k=m*m+(n*n+p*p);if(!(k>=1.4210854715202004e-14)){c[i+132>>2]=0;c[i+132+4>>2]=0;c[i+132+8>>2]=0;c[i+132+12>>2]=0;k=0.0;m=0.0;n=0.0}else{aa=1.0/+C(+k);k=p*aa;fa=n*aa;n=m*aa;g[i+132>>2]=k;g[i+136>>2]=fa;g[i+140>>2]=n;c[i+144>>2]=j;m=fa}if(ba*k+ca*m+da*n>=-+g[i+172>>2]){b=0;l=ea;return b|0}b=c[b+4>>2]|0;Cc(b)|0;fp(i+148|0,b+260|0,16)|0;b=1;l=ea;return b|0}function Zc(b,d,e,f,h,i,k,l,m,n,o){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;k=k|0;l=l|0;m=+m;n=+n;o=+o;var p=0,q=0,r=0.0,s=0,t=0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0,N=0,O=0.0,P=0.0,Q=0.0;N=c[b+68>>2]|0;if((N|0)==(c[b+72>>2]|0)?(t=N|0?N<<1:1,(N|0)<(t|0)):0){if(!t){q=N;s=0}else{c[6432]=(c[6432]|0)+1;p=ec((t*152|3)+16|0)|0;if(!p)p=0;else{c[(p+4+15&-16)+-4>>2]=p;p=p+4+15&-16}q=c[b+68>>2]|0;s=p}if((q|0)>0){p=0;do{Th(s+(p*152|0)|0,(c[b+76>>2]|0)+(p*152|0)|0,152)|0;p=p+1|0}while((p|0)!=(q|0))}p=c[b+76>>2]|0;if(p|0){if(a[b+80>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[p+-4>>2]|0)}c[b+76>>2]=0}a[b+80>>0]=1;c[b+76>>2]=s;c[b+72>>2]=t;p=c[b+68>>2]|0}else p=N;c[b+68>>2]=p+1;M=c[b+76>>2]|0;c[M+(N*152|0)+140>>2]=h;s=c[b+16>>2]|0;p=c[s+(e*244|0)+240>>2]|0;t=c[s+(f*244|0)+240>>2]|0;c[M+(N*152|0)+144>>2]=e;c[M+(N*152|0)+148>>2]=f;q=c[i+84>>2]|0;c[M+(N*152|0)+104>>2]=q;c[M+(N*152|0)+132>>2]=0;g[M+(N*152|0)+100>>2]=0.0;g[M+(N*152|0)+96>>2]=0.0;I=(c[j>>2]=q,+g[j>>2]);if(p|0){c[M+(N*152|0)+16>>2]=c[d>>2];c[M+(N*152|0)+16+4>>2]=c[d+4>>2];c[M+(N*152|0)+16+8>>2]=c[d+8>>2];c[M+(N*152|0)+16+12>>2]=c[d+12>>2];L=+g[k+4>>2];D=+g[M+(N*152|0)+24>>2];H=+g[k+8>>2];J=+g[M+(N*152|0)+20>>2];E=+g[M+(N*152|0)+16>>2];K=+g[k>>2];g[M+(N*152|0)>>2]=L*D-H*J;g[M+(N*152|0)+4>>2]=H*E-D*K;g[M+(N*152|0)+8>>2]=J*K-L*E;g[M+(N*152|0)+12>>2]=0.0;v=((L*D-H*J)*+g[p+264>>2]+(H*E-D*K)*+g[p+268>>2]+(J*K-L*E)*+g[p+272>>2])*+g[p+544>>2];r=((L*D-H*J)*+g[p+280>>2]+(H*E-D*K)*+g[p+284>>2]+(J*K-L*E)*+g[p+288>>2])*+g[p+548>>2];u=((L*D-H*J)*+g[p+296>>2]+(H*E-D*K)*+g[p+300>>2]+(J*K-L*E)*+g[p+304>>2])*+g[p+552>>2];g[M+(N*152|0)+64>>2]=v;g[M+(N*152|0)+68>>2]=r;g[M+(N*152|0)+72>>2]=u;g[M+(N*152|0)+76>>2]=0.0;z=E;A=J;B=D;C=L*D-H*J;D=H*E-D*K;E=J*K-L*E}else{c[M+(N*152|0)+64>>2]=0;c[M+(N*152|0)+64+4>>2]=0;c[M+(N*152|0)+64+8>>2]=0;c[M+(N*152|0)+64+12>>2]=0;c[M+(N*152|0)>>2]=0;c[M+(N*152|0)+4>>2]=0;c[M+(N*152|0)+8>>2]=0;c[M+(N*152|0)+12>>2]=0;c[M+(N*152|0)+16>>2]=0;c[M+(N*152|0)+20>>2]=0;c[M+(N*152|0)+24>>2]=0;c[M+(N*152|0)+28>>2]=0;r=0.0;u=0.0;v=0.0;z=0.0;A=0.0;B=0.0;C=0.0;D=0.0;E=0.0}if(t|0){J=-+g[d>>2];K=-+g[d+4>>2];L=-+g[d+8>>2];g[M+(N*152|0)+48>>2]=J;g[M+(N*152|0)+52>>2]=K;g[M+(N*152|0)+56>>2]=L;g[M+(N*152|0)+60>>2]=0.0;H=+g[l+4>>2];G=+g[l+8>>2];O=+g[l>>2];g[M+(N*152|0)+32>>2]=H*L-G*K;g[M+(N*152|0)+36>>2]=G*J-O*L;g[M+(N*152|0)+40>>2]=O*K-H*J;g[M+(N*152|0)+44>>2]=0.0;w=((H*L-G*K)*+g[t+264>>2]+(G*J-O*L)*+g[t+268>>2]+(O*K-H*J)*+g[t+272>>2])*+g[t+544>>2];x=((H*L-G*K)*+g[t+280>>2]+(G*J-O*L)*+g[t+284>>2]+(O*K-H*J)*+g[t+288>>2])*+g[t+548>>2];y=((H*L-G*K)*+g[t+296>>2]+(G*J-O*L)*+g[t+300>>2]+(O*K-H*J)*+g[t+304>>2])*+g[t+552>>2];g[M+(N*152|0)+80>>2]=w;g[M+(N*152|0)+84>>2]=x;g[M+(N*152|0)+88>>2]=y;g[M+(N*152|0)+92>>2]=0.0;F=H*L-G*K;G=G*J-O*L;H=O*K-H*J}else{c[M+(N*152|0)+80>>2]=0;c[M+(N*152|0)+80+4>>2]=0;c[M+(N*152|0)+80+8>>2]=0;c[M+(N*152|0)+80+12>>2]=0;c[M+(N*152|0)+32>>2]=0;c[M+(N*152|0)+32+4>>2]=0;c[M+(N*152|0)+32+8>>2]=0;c[M+(N*152|0)+32+12>>2]=0;c[M+(N*152|0)+32+16>>2]=0;c[M+(N*152|0)+32+20>>2]=0;c[M+(N*152|0)+32+24>>2]=0;c[M+(N*152|0)+32+28>>2]=0;F=0.0;G=0.0;H=0.0;w=0.0;x=0.0;y=0.0;J=0.0;K=0.0;L=0.0}if(p|0){Q=+g[k+8>>2];P=+g[k+4>>2];O=+g[k>>2];u=+g[p+344>>2]+((r*Q-u*P)*+g[d>>2]+(u*O-Q*v)*+g[d+4>>2]+(P*v-r*O)*+g[d+8>>2])}else u=0.0;if(t|0){P=-w;r=-x;x=-y;y=+g[l+8>>2];O=+g[l+4>>2];Q=+g[l>>2];r=+g[t+344>>2]+((y*r-O*x)*+g[d>>2]+(Q*x-y*P)*+g[d+4>>2]+(O*P-Q*r)*+g[d+8>>2])}else r=0.0;x=m/(u+r);g[M+(N*152|0)+108>>2]=x;if(p|0){u=+g[s+(e*244|0)+192>>2];v=+g[s+(e*244|0)+196>>2];w=+g[s+(e*244|0)+200>>2];r=(+g[s+(e*244|0)+176>>2]+ +g[s+(e*244|0)+208>>2])*z+(+g[s+(e*244|0)+180>>2]+ +g[s+(e*244|0)+212>>2])*A+(+g[s+(e*244|0)+184>>2]+ +g[s+(e*244|0)+216>>2])*B}else{u=0.0;v=0.0;w=0.0;r=z*0.0+A*0.0+B*0.0}r=r+(u*C+v*D+w*E);if(t|0){m=+g[s+(f*244|0)+192>>2];O=+g[s+(f*244|0)+196>>2];Q=+g[s+(f*244|0)+200>>2];P=(+g[s+(f*244|0)+176>>2]+ +g[s+(f*244|0)+208>>2])*J+(+g[s+(f*244|0)+180>>2]+ +g[s+(f*244|0)+212>>2])*K+(+g[s+(f*244|0)+184>>2]+ +g[s+(f*244|0)+216>>2])*L;m=m*F;O=O*G;O=m+O;Q=Q*H;Q=O+Q;Q=P+Q;Q=r+Q;Q=n-Q;Q=x*Q;f=M+(N*152|0)+112|0;g[f>>2]=Q;f=M+(N*152|0)+116|0;g[f>>2]=o;Q=-I;f=M+(N*152|0)+120|0;g[f>>2]=Q;f=M+(N*152|0)+124|0;c[f>>2]=q;return}else{m=0.0;O=0.0;Q=0.0;P=J*0.0+K*0.0+L*0.0;m=m*F;O=O*G;O=m+O;Q=Q*H;Q=O+Q;Q=P+Q;Q=r+Q;Q=n-Q;Q=x*Q;f=M+(N*152|0)+112|0;g[f>>2]=Q;f=M+(N*152|0)+116|0;g[f>>2]=o;Q=-I;f=M+(N*152|0)+120|0;g[f>>2]=Q;f=M+(N*152|0)+124|0;c[f>>2]=q;return}}function _c(b,d,e){b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0;A=+g[b+48>>2];h=+g[d>>2];B=+g[b+64>>2];j=+g[d+4>>2];H=+g[b+80>>2];p=+g[d+8>>2];s=+g[b+52>>2];r=+g[b+68>>2];q=+g[b+84>>2];w=+g[b+56>>2];G=+g[b+72>>2];x=+g[b+88>>2];v=+g[d+16>>2];u=+g[d+20>>2];t=+g[d+24>>2];F=+g[d+32>>2];D=+g[d+36>>2];E=+g[d+40>>2];k=+g[b+96>>2];f=+g[b+100>>2];z=+g[b+104>>2];y=+g[d+48>>2]+(h*k+j*f+p*z);i=v*k+u*f+t*z+ +g[d+52>>2];z=F*k+D*f+E*z+ +g[d+56>>2];g[b+1064>>2]=A*h+B*j+H*p;g[b+1068>>2]=h*s+j*r+p*q;g[b+1072>>2]=h*w+j*G+p*x;g[b+1076>>2]=0.0;g[b+1080>>2]=A*v+B*u+H*t;g[b+1084>>2]=s*v+r*u+q*t;g[b+1088>>2]=w*v+G*u+x*t;g[b+1092>>2]=0.0;g[b+1096>>2]=A*F+B*D+H*E;g[b+1100>>2]=s*F+r*D+q*E;g[b+1104>>2]=w*F+G*D+x*E;g[b+1108>>2]=0.0;g[b+1112>>2]=y;g[b+1116>>2]=i;g[b+1120>>2]=z;g[b+1124>>2]=0.0;z=+g[b+112>>2];i=+g[e>>2];y=+g[b+128>>2];E=+g[e+4>>2];x=+g[b+144>>2];D=+g[e+8>>2];G=+g[b+116>>2];F=+g[b+132>>2];w=+g[b+148>>2];q=+g[b+120>>2];r=+g[b+136>>2];s=+g[b+152>>2];H=+g[e+16>>2];B=+g[e+20>>2];A=+g[e+24>>2];t=+g[e+32>>2];u=+g[e+36>>2];v=+g[e+40>>2];p=+g[b+160>>2];j=+g[b+164>>2];h=+g[b+168>>2];f=+g[e+48>>2]+(i*p+E*j+D*h);k=H*p+B*j+A*h+ +g[e+52>>2];h=t*p+u*j+v*h+ +g[e+56>>2];g[b+1128>>2]=z*i+y*E+x*D;g[b+1132>>2]=i*G+E*F+D*w;g[b+1136>>2]=i*q+E*r+D*s;g[b+1140>>2]=0.0;g[b+1144>>2]=z*H+y*B+x*A;g[b+1148>>2]=G*H+F*B+w*A;g[b+1152>>2]=q*H+r*B+s*A;g[b+1156>>2]=0.0;g[b+1160>>2]=z*t+y*u+x*v;g[b+1164>>2]=G*t+F*u+w*v;g[b+1168>>2]=q*t+r*u+s*v;g[b+1172>>2]=0.0;g[b+1176>>2]=f;g[b+1180>>2]=k;g[b+1184>>2]=h;g[b+1188>>2]=0.0;f=f-+g[b+1112>>2];k=k-+g[b+1116>>2];h=h-+g[b+1120>>2];w=+g[b+1084>>2];F=+g[b+1104>>2];G=+g[b+1088>>2];x=+g[b+1100>>2];y=+g[b+1096>>2];z=+g[b+1080>>2];A=+g[b+1064>>2];B=+g[b+1068>>2];H=+g[b+1072>>2];D=1.0/((w*F-G*x)*A+B*(G*y-F*z)+(x*z-w*y)*H);E=(x*z-w*y)*D;i=h*(G*B-w*H)*D+(f*(w*F-G*x)*D+k*(x*H-F*B)*D);j=h*(z*H-G*A)*D+(f*(G*y-F*z)*D+k*(F*A-y*H)*D);k=h*(w*A-z*B)*D+(f*E+k*(y*B-x*A)*D);g[b+1256>>2]=i;g[b+1260>>2]=j;g[b+1264>>2]=k;g[b+1268>>2]=0.0;g[b+840>>2]=i;f=+g[b+680>>2];h=+g[b+696>>2];do if(!(f>h)){if(f>i){c[b+856>>2]=2;f=i-f;break}if(h<i){c[b+856>>2]=1;f=i-h;break}else{c[b+856>>2]=0;f=0.0;break}}else{c[b+856>>2]=0;f=0.0}while(0);g[b+824>>2]=f;g[b+844>>2]=j;f=+g[b+684>>2];h=+g[b+700>>2];do if(!(f>h)){if(f>j){c[b+860>>2]=2;f=j-f;break}if(h<j){c[b+860>>2]=1;f=j-h;break}else{c[b+860>>2]=0;f=0.0;break}}else{c[b+860>>2]=0;f=0.0}while(0);g[b+828>>2]=f;g[b+848>>2]=k;f=+g[b+688>>2];h=+g[b+704>>2];do if(!(f>h)){if(f>k){c[b+864>>2]=2;f=k-f;break}if(h<k){c[b+864>>2]=1;f=k-h;break}else{c[b+864>>2]=0;f=0.0;break}}else{c[b+864>>2]=0;f=0.0}while(0);g[b+832>>2]=f;n=+g[b+1128>>2];o=+g[b+1144>>2];p=+g[b+1160>>2];h=+g[b+1132>>2];i=+g[b+1148>>2];j=+g[b+1164>>2];k=(w*F-G*x)*D*h+(x*H-F*B)*D*i+(G*B-w*H)*D*j;m=h*(G*y-F*z)*D+(F*A-y*H)*D*i+(z*H-G*A)*D*j;l=p*(w*A-z*B)*D+(n*E+o*(y*B-x*A)*D);f=E*+g[b+1136>>2]+(y*B-x*A)*D*+g[b+1152>>2]+(w*A-z*B)*D*(q*t+r*u+s*v);do if(l<1.0)if(l>-1.0){g[b+1192>>2]=+K(+-(h*E+(y*B-x*A)*D*i+(w*A-z*B)*D*j),+f);f=l<-1.0?-1.0:l;g[b+1196>>2]=+I(+(f>1.0?1.0:f));f=+K(+-(p*(z*H-G*A)*D+(n*(G*y-F*z)*D+o*(F*A-y*H)*D)),+(p*(G*B-w*H)*D+(n*(w*F-G*x)*D+o*(x*H-F*B)*D)));break}else{g[b+1192>>2]=-+K(+k,+m);g[b+1196>>2]=-1.5707963705062866;f=0.0;break}else{g[b+1192>>2]=+K(+k,+m);g[b+1196>>2]=1.5707963705062866;f=0.0}while(0);g[b+1200>>2]=f;g[b+1236>>2]=0.0;x=F*(n*F-p*H)-G*(o*H-n*G);y=H*(o*H-n*G)-F*(p*G-o*F);z=G*(p*G-o*F)-H*(n*F-p*H);g[b+1220>>2]=0.0;B=o*(o*H-n*G)-p*(n*F-p*H);D=p*(p*G-o*F)-n*(o*H-n*G);E=n*(n*F-p*H)-o*(p*G-o*F);g[b+1252>>2]=0.0;A=1.0/+C(+(x*x+y*y+z*z));g[b+1208>>2]=x*A;g[b+1212>>2]=y*A;g[b+1216>>2]=z*A;A=1.0/+C(+((p*G-o*F)*(p*G-o*F)+(n*F-p*H)*(n*F-p*H)+(o*H-n*G)*(o*H-n*G)));g[b+1224>>2]=(p*G-o*F)*A;g[b+1228>>2]=(n*F-p*H)*A;g[b+1232>>2]=(o*H-n*G)*A;H=1.0/+C(+(B*B+D*D+E*E));g[b+1240>>2]=B*H;g[b+1244>>2]=D*H;g[b+1248>>2]=E*H;if(!(a[b+1301>>0]|0))return;G=+g[(c[b+28>>2]|0)+344>>2];H=+g[(c[b+32>>2]|0)+344>>2];a[b+1280>>0]=(G<1.1920928955078125e-07|H<1.1920928955078125e-07)&1;H=G+H>0.0?H/(G+H):.5;g[b+1272>>2]=H;g[b+1276>>2]=1.0-H;return}function $c(b,d){b=b|0;d=d|0;var e=0,f=0,h=0.0,i=0,j=0,k=0,m=0,n=0,o=0,p=0,q=0,r=0;r=l;l=l+48|0;Sf(b+4|0,((O(c[b+152>>2]|0,c[b+16>>2]|0)|0)/100|0)+1|0);if(c[b+164>>2]|0){p=((O(c[b+148>>2]|0,c[b+76>>2]|0)|0)/100|0)+1|0;Sf(b+64|0,p);p=(c[b+164>>2]|0)-p|0;c[b+164>>2]=(p|0)>0?p:0}e=((c[b+144>>2]|0)+1|0)%2|0;c[b+144>>2]=e;e=c[b+124+(e<<2)>>2]|0;if(e|0){do{j=e+56|0;m=e;e=c[j>>2]|0;i=c[m+52>>2]|0;if(!i)i=b+124+(c[m+60>>2]<<2)|0;else i=i+56|0;c[i>>2]=e;i=c[j>>2]|0;if(i|0)c[i+52>>2]=c[m+52>>2];c[m+52>>2]=0;c[j>>2]=c[b+132>>2];i=c[b+132>>2]|0;if(i|0)c[i+52>>2]=m;c[b+132>>2]=m;i=c[m+48>>2]|0;Kg(b+4|0,i)|0;j=c[b+8>>2]|0;if(j|0){c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0)}c[b+8>>2]=i;c[b+16>>2]=(c[b+16>>2]|0)+-1;c[r+16>>2]=c[m+16>>2];c[r+16+4>>2]=c[m+16+4>>2];c[r+16+8>>2]=c[m+16+8>>2];c[r+16+12>>2]=c[m+16+12>>2];c[r+16+16>>2]=c[m+32>>2];c[r+16+16+4>>2]=c[m+32+4>>2];c[r+16+16+8>>2]=c[m+32+8>>2];c[r+16+16+12>>2]=c[m+32+12>>2];i=c[b+68>>2]|0;if(!i){c[6432]=(c[6432]|0)+1;i=ec(63)|0;if(!i)i=0;else{c[(i+4+15&-16)+-4>>2]=i;i=i+4+15&-16}j=i;k=j+44|0;do{c[j>>2]=0;j=j+4|0}while((j|0)<(k|0))}else c[b+68>>2]=0;c[i+32>>2]=0;c[i+36>>2]=m;c[i+40>>2]=0;c[i>>2]=c[r+16>>2];c[i+4>>2]=c[r+16+4>>2];c[i+8>>2]=c[r+16+8>>2];c[i+12>>2]=c[r+16+12>>2];c[i+16>>2]=c[r+16+16>>2];c[i+20>>2]=c[r+16+20>>2];c[i+24>>2]=c[r+16+24>>2];c[i+28>>2]=c[r+16+28>>2];We(b+64|0,c[b+64>>2]|0,i);j=(c[b+76>>2]|0)+1|0;c[b+76>>2]=j;c[m+48>>2]=i;c[m+60>>2]=2}while((e|0)!=0);c[b+164>>2]=j;a[b+194>>0]=1}c[r>>2]=9028;c[r+4>>2]=b;if(a[b+193>>0]|0?(ae(b+4|0,c[b+4>>2]|0,c[b+64>>2]|0,r),a[b+193>>0]|0):0){p=c[b+4>>2]|0;ae(b+4|0,p,p,r)}do if(a[b+194>>0]|0?(n=c[b+136>>2]|0,n=lb[c[(c[n>>2]|0)+28>>2]&127](n)|0,f=c[n+4>>2]|0,(f|0)>0):0){e=(O(c[b+156>>2]|0,f)|0)/100|0;p=c[b+160>>2]|0;e=(p|0)>(e|0)?p:e;e=(f|0)<(e|0)?f:e;if((e|0)>0){i=0;do{k=((c[b+184>>2]|0)+i|0)%(f|0)|0;o=c[n+12>>2]|0;j=c[o+(k<<4)>>2]|0;k=c[o+(k<<4)+4>>2]|0;o=c[j+48>>2]|0;p=c[k+48>>2]|0;if(!(((((+g[o>>2]<=+g[p+16>>2]?+g[o+16>>2]>=+g[p>>2]:0)?+g[o+4>>2]<=+g[p+20>>2]:0)?+g[o+20>>2]>=+g[p+4>>2]:0)?+g[o+8>>2]<=+g[p+24>>2]:0)?+g[o+24>>2]>=+g[p+8>>2]:0)){f=c[b+136>>2]|0;pb[c[(c[f>>2]|0)+12>>2]&31](f,j,k,d)|0;f=c[n+4>>2]|0;i=i+-1|0;e=e+-1|0}i=i+1|0}while((i|0)<(e|0));if((f|0)<=0){c[b+184>>2]=0;break}}c[b+184>>2]=((c[b+184>>2]|0)+e|0)%(f|0)|0}while(0);c[b+180>>2]=(c[b+180>>2]|0)+1;c[b+160>>2]=1;a[b+194>>0]=0;f=c[b+168>>2]|0;e=c[b+172>>2]|0;if(!f)h=0.0;else h=+(e>>>0)/+(f>>>0);g[b+176>>2]=h;c[b+172>>2]=e>>>1;c[b+168>>2]=f>>>1;p=c[b+136>>2]|0;if(!(lb[c[(c[p>>2]|0)+56>>2]&127](p)|0)){l=r;return}p=c[b+136>>2]|0;p=lb[c[(c[p>>2]|0)+28>>2]&127](p)|0;e=c[p+4>>2]|0;if((e|0)>1){Ee(p,0,e+-1|0);k=0;f=0;j=0;i=0;q=44}else{o=0;k=0;j=0;i=0}while(1){if((q|0)==44){q=0;e=c[p+4>>2]|0;o=f}if((j|0)>=(e|0))break;n=c[p+12>>2]|0;m=n+(j<<4)|0;f=c[m>>2]|0;n=n+(j<<4)+4|0;e=c[n>>2]|0;if(!((f|0)==(o|0)&(e|0)==(k|0))){k=c[f+48>>2]|0;o=c[e+48>>2]|0;if(!(((((+g[k>>2]<=+g[o+16>>2]?+g[k+16>>2]>=+g[o>>2]:0)?+g[k+4>>2]<=+g[o+20>>2]:0)?+g[k+20>>2]>=+g[o+4>>2]:0)?+g[k+8>>2]<=+g[o+24>>2]:0)?+g[k+24>>2]>=+g[o+8>>2]:0))q=53}else{e=k;q=53}if((q|0)==53){q=c[b+136>>2]|0;Rb[c[(c[q>>2]|0)+32>>2]&127](q,m,d);c[m>>2]=0;c[n>>2]=0;i=i+1|0}k=e;j=j+1|0;q=44}if((e|0)>1){Ee(p,0,e+-1|0);j=c[p+4>>2]|0}else j=e;k=j-i|0;if((i|0)<0){if((c[p+8>>2]|0)<(k|0)){if((j|0)!=(i|0)){c[6432]=(c[6432]|0)+1;e=ec((k<<4|3)+16|0)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}f=c[p+4>>2]|0;if((f|0)>0){i=0;do{q=c[p+12>>2]|0;c[e+(i<<4)>>2]=c[q+(i<<4)>>2];c[e+(i<<4)+4>>2]=c[q+(i<<4)+4>>2];c[e+(i<<4)+8>>2]=c[q+(i<<4)+8>>2];c[e+(i<<4)+12>>2]=c[q+(i<<4)+12>>2];i=i+1|0}while((i|0)!=(f|0));f=p+12|0}else f=p+12|0}else{e=0;f=p+12|0}i=c[f>>2]|0;if(i|0){if(a[p+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[f>>2]=0}a[p+16>>0]=1;c[f>>2]=e;c[p+8>>2]=k}else f=p+12|0;e=j;do{q=(c[f>>2]|0)+(e<<4)|0;e=e+1|0;c[q>>2]=0;c[q+4>>2]=0;c[q+8>>2]=0;c[q+12>>2]=0}while((e|0)!=(k|0))}c[p+4>>2]=k;l=r;return}function ad(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;x=l;l=l+80|0;e=c[b+8>>2]|0;if((e|0)>0){g=0;do{f=c[(c[b+16>>2]|0)+(g<<2)>>2]|0;if((c[f+236>>2]|0)==1){jb[c[(c[f>>2]|0)+24>>2]&127](f,d);e=c[b+8>>2]|0}g=g+1|0}while((g|0)<(e|0))}a[x+16>>0]=1;c[x+12>>2]=0;c[x+4>>2]=0;c[x+8>>2]=0;a[x+36>>0]=1;c[x+32>>2]=0;c[x+24>>2]=0;c[x+28>>2]=0;a[x+56>>0]=1;c[x+52>>2]=0;c[x+44>>2]=0;c[x+48>>2]=0;a[x+76>>0]=1;c[x+72>>2]=0;c[x+64>>2]=0;c[x+68>>2]=0;if((e|0)<=0){Ui(x);l=x;return}i=0;j=0;g=0;f=0;r=0;while(1){q=c[(c[(c[b+16>>2]|0)+(r<<2)>>2]|0)+192>>2]|0;o=(q+~(q<<15)>>10^q+~(q<<15))*9|0;o=(o>>6^o)+~((o>>6^o)<<11)>>16^(o>>6^o)+~((o>>6^o)<<11);n=o&i+-1;m=n>>>0<j>>>0;a:do if(m){h=c[g+(n<<2)>>2]|0;if((h|0)!=-1){k=c[x+72>>2]|0;while(1){if((q|0)==(c[k+(h<<3)>>2]|0)){p=13;break}j=c[f+(h<<2)>>2]|0;if((j|0)==-1)break;else h=j}if((p|0)==13?(p=0,(c[x+52>>2]|0)+(h<<2)|0):0)break;if(!m){p=20;break}}e=c[g+(n<<2)>>2]|0;if((e|0)!=-1){h=c[x+72>>2]|0;while(1){if((q|0)==(c[h+(e<<3)>>2]|0))break;e=c[f+(e<<2)>>2]|0;if((e|0)==-1){p=20;break a}}c[(c[x+52>>2]|0)+(e<<2)>>2]=q;e=i;p=78}else p=20}else p=20;while(0);if((p|0)==20){p=0;m=c[x+44>>2]|0;if((m|0)==(i|0)){e=i|0?i<<1:1;if((i|0)<(e|0)){if((e|0)!=0?(c[6432]=(c[6432]|0)+1,s=ec((e<<2|3)+16|0)|0,(s|0)!=0):0){c[(s+4+15&-16)+-4>>2]=s;g=s+4+15&-16}else g=0;if((i|0)>0){f=0;do{c[g+(f<<2)>>2]=c[(c[x+52>>2]|0)+(f<<2)>>2];f=f+1|0}while((f|0)!=(i|0))}f=c[x+52>>2]|0;if(f|0){if(a[x+56>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[x+52>>2]=0}a[x+56>>0]=1;c[x+52>>2]=g;c[x+48>>2]=e;f=i}else{e=i;f=i}}else{e=i;f=m}c[(c[x+52>>2]|0)+(f<<2)>>2]=q;c[x+44>>2]=f+1;f=c[x+64>>2]|0;if((f|0)==(c[x+68>>2]|0)?(w=f|0?f<<1:1,(f|0)<(w|0)):0){if((w|0)!=0?(c[6432]=(c[6432]|0)+1,u=ec((w<<3|3)+16|0)|0,(u|0)!=0):0){c[(u+4+15&-16)+-4>>2]=u;g=u+4+15&-16}else g=0;if((f|0)>0){e=0;do{h=(c[x+72>>2]|0)+(e<<3)|0;j=c[h+4>>2]|0;k=g+(e<<3)|0;c[k>>2]=c[h>>2];c[k+4>>2]=j;e=e+1|0}while((e|0)!=(f|0))}e=c[x+72>>2]|0;if(e|0){if(a[x+76>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}c[x+72>>2]=0}a[x+76>>0]=1;c[x+72>>2]=g;c[x+68>>2]=w;f=c[x+64>>2]|0;e=c[x+48>>2]|0}k=(c[x+72>>2]|0)+(f<<3)|0;c[k>>2]=q;c[k+4>>2]=0;c[x+64>>2]=f+1;if((i|0)<(e|0)){k=c[x+4>>2]|0;do if((k|0)<(e|0)){if((c[x+8>>2]|0)<(e|0)){if((e|0)!=0?(c[6432]=(c[6432]|0)+1,t=ec((e<<2|3)+16|0)|0,(t|0)!=0):0){c[(t+4+15&-16)+-4>>2]=t;f=t+4+15&-16}else f=0;g=c[x+12>>2]|0;if((k|0)>0){h=0;do{c[f+(h<<2)>>2]=c[g+(h<<2)>>2];h=h+1|0}while((h|0)!=(k|0));if(a[x+16>>0]|0)p=55}else if(!((g|0)==0|(a[x+16>>0]|0)==0))p=55;if((p|0)==55){p=0;c[6433]=(c[6433]|0)+1;Pc(c[g+-4>>2]|0)}a[x+16>>0]=1;c[x+12>>2]=f;c[x+8>>2]=e}else f=c[x+12>>2]|0;j=e<<2;Hk(f+(k<<2)|0,0,j-(k<<2)|0)|0;c[x+4>>2]=e;i=c[x+24>>2]|0;if((i|0)<(e|0)){if((c[x+28>>2]|0)<(e|0)){if((e|0)!=0?(c[6432]=(c[6432]|0)+1,v=ec((j|3)+16|0)|0,(v|0)!=0):0){c[(v+4+15&-16)+-4>>2]=v;f=v+4+15&-16}else f=0;g=c[x+32>>2]|0;if((i|0)>0){h=0;do{c[f+(h<<2)>>2]=c[g+(h<<2)>>2];h=h+1|0}while((h|0)!=(i|0));if(a[x+36>>0]|0)p=67}else if(!((g|0)==0|(a[x+36>>0]|0)==0))p=67;if((p|0)==67){c[6433]=(c[6433]|0)+1;Pc(c[g+-4>>2]|0)}a[x+36>>0]=1;c[x+32>>2]=f;c[x+28>>2]=e}else f=c[x+32>>2]|0;Hk(f+(i<<2)|0,0,j-(i<<2)|0)|0}c[x+24>>2]=e;if((e|0)>0){Hk(c[x+12>>2]|0,-1,j|0)|0;Hk(c[x+32>>2]|0,-1,j|0)|0}if((k|0)<=0){e=c[x+48>>2]|0;break}f=c[x+72>>2]|0;g=c[x+12>>2]|0;h=c[x+32>>2]|0;e=c[x+48>>2]|0;i=0;do{p=c[f+(i<<3)>>2]|0;p=(p+~(p<<15)>>10^p+~(p<<15))*9|0;p=g+((((p>>6^p)+~((p>>6^p)<<11)>>16^(p>>6^p)+~((p>>6^p)<<11))&e+-1)<<2)|0;c[h+(i<<2)>>2]=c[p>>2];c[p>>2]=i;i=i+1|0}while((i|0)!=(k|0))}while(0);f=e;e=o&e+-1}else{f=e;e=n}g=c[x+12>>2]|0;e=g+(e<<2)|0;p=c[x+32>>2]|0;c[p+(m<<2)>>2]=c[e>>2];c[e>>2]=m;e=f;f=p;p=78}if((p|0)==78){p=0;jb[c[(c[q>>2]|0)+60>>2]&127](q,d);i=e;e=c[b+8>>2]|0}h=r+1|0;if((h|0)>=(e|0))break;j=c[x+4>>2]|0;r=h}Ui(x);l=x;return}function bd(b,d){b=b|0;d=d|0;var e=0.0,f=0.0,h=0,i=0,j=0,k=0,l=0,m=0,n=0.0,o=0.0,p=0.0,q=0,r=0,s=0.0,t=0.0,u=0.0,v=0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0;q=c[b+28>>2]|0;j=c[b+32>>2]|0;kc(b,q+4|0,j+4|0,q+264|0,j+264|0);r=c[d+8>>2]|0;g[r>>2]=1.0;l=c[d+24>>2]|0;g[r+(l+1<<2)>>2]=1.0;g[r+((l<<1)+2<<2)>>2]=1.0;p=+g[b+348>>2];u=+g[b+352>>2];f=+g[b+356>>2];s=+g[q+4>>2]*p+ +g[q+8>>2]*u+ +g[q+12>>2]*f;o=p*+g[q+20>>2]+u*+g[q+24>>2]+f*+g[q+28>>2];f=p*+g[q+36>>2]+u*+g[q+40>>2]+f*+g[q+44>>2];r=c[d+12>>2]|0;c[r>>2]=0;g[r+4>>2]=f;g[r+8>>2]=-o;g[r+12>>2]=0.0;g[r+(l<<2)>>2]=-f;c[r+(l<<2)+4>>2]=0;g[r+(l<<2)+8>>2]=s;g[r+(l<<2)+12>>2]=0.0;g[r+(l<<1<<2)>>2]=o;g[r+(l<<1<<2)+4>>2]=-s;c[r+(l<<1<<2)+8>>2]=0;g[r+(l<<1<<2)+12>>2]=0.0;r=c[d+16>>2]|0;g[r>>2]=-1.0;g[r+(l+1<<2)>>2]=-1.0;g[r+((l<<1)+2<<2)>>2]=-1.0;u=+g[b+412>>2];p=+g[b+416>>2];e=+g[b+420>>2];t=+g[j+4>>2]*u+ +g[j+8>>2]*p+ +g[j+12>>2]*e;n=u*+g[j+20>>2]+p*+g[j+24>>2]+e*+g[j+28>>2];e=u*+g[j+36>>2]+p*+g[j+40>>2]+e*+g[j+44>>2];l=c[d+20>>2]|0;r=c[d+24>>2]|0;c[l>>2]=0;g[l+4>>2]=-e;g[l+8>>2]=n;g[l+12>>2]=0.0;g[l+(r<<2)>>2]=e;c[l+(r<<2)+4>>2]=0;g[l+(r<<2)+8>>2]=-t;g[l+(r<<2)+12>>2]=0.0;g[l+(r<<1<<2)>>2]=-n;g[l+(r<<1<<2)+4>>2]=t;c[l+(r<<1<<2)+8>>2]=0;g[l+(r<<1<<2)+12>>2]=0.0;m=c[b+592>>2]|0;p=+g[(m&2|0?b+600|0:d+4|0)>>2]*+g[d>>2];h=c[d+28>>2]|0;i=c[d+36>>2]|0;k=c[d+40>>2]|0;g[h>>2]=p*(t+ +g[j+52>>2]-s-+g[q+52>>2]);g[i>>2]=-3402823466385288598117041.0e14;g[k>>2]=3402823466385288598117041.0e14;if(!(m&1)){g[h+(r<<2)>>2]=p*(n+ +g[j+56>>2]-o-+g[q+56>>2]);g[i+(r<<2)>>2]=-3402823466385288598117041.0e14;g[k+(r<<2)>>2]=3402823466385288598117041.0e14;g[h+(r<<1<<2)>>2]=p*(e+ +g[j+60>>2]-f-+g[q+60>>2]);g[i+(r<<1<<2)>>2]=-3402823466385288598117041.0e14;g[k+(r<<1<<2)>>2]=3402823466385288598117041.0e14}else{v=c[d+32>>2]|0;c[v>>2]=c[b+596>>2];g[h+(r<<2)>>2]=p*(n+ +g[j+56>>2]-o-+g[q+56>>2]);g[i+(r<<2)>>2]=-3402823466385288598117041.0e14;g[k+(r<<2)>>2]=3402823466385288598117041.0e14;c[v+(r<<2)>>2]=c[b+596>>2];g[h+(r<<1<<2)>>2]=p*(e+ +g[j+60>>2]-f-+g[q+60>>2]);g[i+(r<<1<<2)>>2]=-3402823466385288598117041.0e14;g[k+(r<<1<<2)>>2]=3402823466385288598117041.0e14;c[v+(r<<1<<2)>>2]=c[b+596>>2]}if(!(a[b+526>>0]|0)){m=i;i=r*3|0}else{j=c[d+12>>2]|0;u=+g[b+456>>2];if(+g[b+444>>2]<u?+g[b+448>>2]<u:0){z=+g[q+4>>2];y=+g[q+8>>2];x=+g[q+12>>2];D=+g[b+304>>2];C=+g[b+320>>2];B=+g[b+336>>2];n=+g[b+308>>2];p=+g[b+324>>2];t=+g[b+340>>2];w=+g[q+20>>2];e=+g[q+24>>2];f=+g[q+28>>2];o=+g[q+36>>2];s=+g[q+40>>2];u=+g[q+44>>2];g[j+(r*3<<2)>>2]=z*D+y*C+x*B;g[j+((r*3|0)+1<<2)>>2]=D*w+C*e+B*f;g[j+((r*3|0)+2<<2)>>2]=D*o+C*s+B*u;g[j+(r<<2<<2)>>2]=z*n+y*p+x*t;g[j+((r<<2|1)<<2)>>2]=n*w+p*e+t*f;g[j+((r<<2|2)<<2)>>2]=n*o+p*s+t*u;g[l+(r*3<<2)>>2]=-(z*D+y*C+x*B);g[l+((r*3|0)+1<<2)>>2]=-(D*w+C*e+B*f);g[l+((r*3|0)+2<<2)>>2]=-(D*o+C*s+B*u);g[l+(r<<2<<2)>>2]=-(z*n+y*p+x*t);g[l+((r<<2|1)<<2)>>2]=-(n*w+p*e+t*f);g[l+((r<<2|2)<<2)>>2]=-(n*o+p*s+t*u);A=+g[d>>2]*+g[b+436>>2];h=c[d+28>>2]|0;g[h+(r*3<<2)>>2]=A*((z*D+y*C+x*B)*+g[b+460>>2]+(D*w+C*e+B*f)*+g[b+464>>2]+(D*o+C*s+B*u)*+g[b+468>>2]);g[h+(r<<2<<2)>>2]=A*((z*n+y*p+x*t)*+g[b+460>>2]+(n*w+p*e+t*f)*+g[b+464>>2]+(n*o+p*s+t*u)*+g[b+468>>2]);i=c[d+36>>2]|0;g[i+(r*3<<2)>>2]=-3402823466385288598117041.0e14;k=c[d+40>>2]|0;g[k+(r*3<<2)>>2]=3402823466385288598117041.0e14;g[i+(r<<2<<2)>>2]=-3402823466385288598117041.0e14;l=c[d+24>>2]|0;j=r<<2}else{D=+g[b+436>>2];B=D*+g[b+460>>2]*D;C=D*D*+g[b+464>>2];D=D*D*+g[b+468>>2];g[j+(r*3<<2)>>2]=B;g[j+((r*3|0)+1<<2)>>2]=C;g[j+((r*3|0)+2<<2)>>2]=D;g[l+(r*3<<2)>>2]=-B;g[l+((r*3|0)+1<<2)>>2]=-C;g[l+((r*3|0)+2<<2)>>2]=-D;g[h+(r*3<<2)>>2]=+g[d>>2]*+g[b+432>>2]*+g[b+504>>2];if(m&4|0)c[(c[d+32>>2]|0)+(r*3<<2)>>2]=c[b+604>>2];g[i+(r*3<<2)>>2]=0.0;l=r;j=r*3|0}g[k+(j<<2)>>2]=3402823466385288598117041.0e14;m=i;i=l+j|0}if(!(a[b+525>>0]|0))return;D=+g[b+436>>2];B=D*+g[b+476>>2]*D;C=D*D*+g[b+480>>2];D=D*D*+g[b+484>>2];l=c[d+12>>2]|0;r=c[d+20>>2]|0;g[l+(i<<2)>>2]=B;q=i+1|0;g[l+(q<<2)>>2]=C;v=i+2|0;g[l+(v<<2)>>2]=D;g[r+(i<<2)>>2]=-B;g[r+(q<<2)>>2]=-C;g[r+(v<<2)>>2]=-D;g[h+(i<<2)>>2]=+g[d>>2]*+g[b+432>>2]*+g[b+508>>2];if(c[b+592>>2]&4|0)c[(c[d+32>>2]|0)+(i<<2)>>2]=c[b+604>>2];if(+g[b+452>>2]>0.0){v=+g[b+508>>2]>0.0;e=v?0.0:-3402823466385288598117041.0e14;f=v?3402823466385288598117041.0e14:0.0}else{e=-3402823466385288598117041.0e14;f=3402823466385288598117041.0e14}g[m+(i<<2)>>2]=e;g[k+(i<<2)>>2]=f;return}function cd(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=+h;var i=0.0,j=0.0,k=0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0,z=0,A=0,B=0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0;B=l;l=l+320|0;c[B+176>>2]=c[d>>2];c[B+176+4>>2]=c[d+4>>2];c[B+176+8>>2]=c[d+8>>2];c[B+176+12>>2]=c[d+12>>2];c[B+176+16>>2]=c[d+16>>2];c[B+176+16+4>>2]=c[d+16+4>>2];c[B+176+16+8>>2]=c[d+16+8>>2];c[B+176+16+12>>2]=c[d+16+12>>2];c[B+176+32>>2]=c[d+32>>2];c[B+176+32+4>>2]=c[d+32+4>>2];c[B+176+32+8>>2]=c[d+32+8>>2];c[B+176+32+12>>2]=c[d+32+12>>2];c[B+176+48>>2]=c[d+48>>2];c[B+176+48+4>>2]=c[d+48+4>>2];c[B+176+48+8>>2]=c[d+48+8>>2];c[B+176+48+12>>2]=c[d+48+12>>2];c[B+96>>2]=c[e>>2];c[B+96+4>>2]=c[e+4>>2];c[B+96+8>>2]=c[e+8>>2];c[B+96+12>>2]=c[e+12>>2];c[B+96+16>>2]=c[e+16>>2];c[B+96+16+4>>2]=c[e+16+4>>2];c[B+96+16+8>>2]=c[e+16+8>>2];c[B+96+16+12>>2]=c[e+16+12>>2];c[B+96+32>>2]=c[e+32>>2];c[B+96+32+4>>2]=c[e+32+4>>2];c[B+96+32+8>>2]=c[e+32+8>>2];c[B+96+32+12>>2]=c[e+32+12>>2];c[B+96+48>>2]=c[e+48>>2];c[B+96+48+4>>2]=c[e+48+4>>2];c[B+96+48+8>>2]=c[e+48+8>>2];c[B+96+48+12>>2]=c[e+48+12>>2];i=+g[B+96+52>>2]-+g[B+176+52>>2];G=+g[B+96+56>>2]-+g[B+176+56>>2];g[B+64>>2]=+g[B+96+48>>2]-+g[B+176+48>>2];g[B+64+4>>2]=i;g[B+64+8>>2]=G;g[B+64+12>>2]=0.0;rf(B+176|0,B+96|0,B+248|0,B+240|0);G=+g[B+240>>2];i=G*+g[B+248+4>>2];D=G*+g[B+248+8>>2];g[B+48>>2]=+g[B+248>>2]*G;g[B+48+4>>2]=i;g[B+48+8>>2]=D;g[B+48+12>>2]=0.0;c[B+248+48>>2]=0;c[B+248+48+4>>2]=0;c[B+248+48+8>>2]=0;c[B+248+48+12>>2]=0;eh(B+176|0,B+32|0);D=+g[B+32>>2];i=+g[B+32+4>>2];G=+g[B+32+8>>2];E=+g[B+32+12>>2];C=D*(2.0/(D*D+i*i+G*G+E*E));j=i*(2.0/(D*D+i*i+G*G+E*E));F=G*(2.0/(D*D+i*i+G*G+E*E));g[B+248>>2]=1.0-(i*j+G*F);g[B+248+4>>2]=D*j-E*F;g[B+248+8>>2]=D*F+E*j;g[B+248+12>>2]=0.0;g[B+248+16>>2]=D*j+E*F;g[B+248+20>>2]=1.0-(D*C+G*F);g[B+248+24>>2]=i*F-E*C;g[B+248+28>>2]=0.0;g[B+248+32>>2]=D*F-E*j;g[B+248+36>>2]=i*F+E*C;g[B+248+40>>2]=1.0-(D*C+i*j);g[B+248+44>>2]=0.0;Sg(b,B+248|0,B+64|0,B+48|0,B+160|0,B+80|0);if((c[a+268>>2]|0)<=0){l=B;return}A=0;do{k=c[(c[a+276>>2]|0)+(A<<2)>>2]|0;if(Gb[c[(c[f>>2]|0)+8>>2]&31](f,c[k+188>>2]|0)|0?(y=c[k+192>>2]|0,Vb[c[(c[y>>2]|0)+8>>2]&127](y,k+4|0,B+16|0,B),m=+g[B+16>>2]+ +g[B+160>>2],n=+g[B+16+4>>2]+ +g[B+160+4>>2],o=+g[B+16+8>>2]+ +g[B+160+8>>2],g[B+16>>2]=m,g[B+16+4>>2]=n,g[B+16+8>>2]=o,g[B+16+12>>2]=0.0,p=+g[B>>2]+ +g[B+80>>2],q=+g[B+4>>2]+ +g[B+80+4>>2],r=+g[B+8>>2]+ +g[B+80+8>>2],g[B>>2]=p,g[B+4>>2]=q,g[B+8>>2]=r,g[B+12>>2]=0.0,s=+g[d+48>>2]-(p+m)*.5,t=+g[d+52>>2]-(q+n)*.5,u=+g[d+56>>2]-(r+o)*.5,v=+g[e+48>>2]-(p+m)*.5,w=+g[e+52>>2]-(q+n)*.5,x=+g[e+56>>2]-(r+o)*.5,y=s<-((p-m)*.5)|(s>(p-m)*.5?8:0)|(t<-((q-n)*.5)?2:0)|(t>(q-n)*.5?16:0)|(u<-((r-o)*.5)?4:0)|(u>(r-o)*.5?32:0),z=v<-((p-m)*.5)|(v>(p-m)*.5?8:0)|(w<-((q-n)*.5)?2:0)|(w>(q-n)*.5?16:0)|(x<-((r-o)*.5)?4:0)|(x>(r-o)*.5?32:0),(y&z|0)==0):0){if(s<-((p-m)*.5))if(!((-s-(p-m)*.5)/(v-s)>=0.0)){i=1.0;j=0.0}else{i=1.0;j=(-s-(p-m)*.5)/(v-s)}else if(v<-((p-m)*.5)?(-s-(p-m)*.5)/(v-s)<1.0:0){i=(-s-(p-m)*.5)/(v-s);j=0.0}else{i=1.0;j=0.0}if(t<-((q-n)*.5)){if(j<=(-t-(q-n)*.5)/(w-t))j=(-t-(q-n)*.5)/(w-t)}else if(w<-((q-n)*.5)?(-t-(q-n)*.5)/(w-t)<i:0)i=(-t-(q-n)*.5)/(w-t);if(u<-((r-o)*.5)){if(j<=(-u-(r-o)*.5)/(x-u))j=(-u-(r-o)*.5)/(x-u)}else if(x<-((r-o)*.5)?(-u-(r-o)*.5)/(x-u)<i:0)i=(-u-(r-o)*.5)/(x-u);if(s>(p-m)*.5){if(j<=((p-m)*.5-s)/(v-s))j=((p-m)*.5-s)/(v-s)}else if(v>(p-m)*.5?((p-m)*.5-s)/(v-s)<i:0)i=((p-m)*.5-s)/(v-s);if(t>(q-n)*.5){if(j<=((q-n)*.5-t)/(w-t))j=((q-n)*.5-t)/(w-t)}else if(w>(q-n)*.5?((q-n)*.5-t)/(w-t)<i:0)i=((q-n)*.5-t)/(w-t);if(!(y&32)){if((z&32|0)!=0?((r-o)*.5-u)/(x-u)<i:0)i=((r-o)*.5-u)/(x-u)}else if(j<=((r-o)*.5-u)/(x-u))j=((r-o)*.5-u)/(x-u);if(j<=i){H=c[k+192>>2]|0;c[B+248>>2]=0;c[B+248+4>>2]=H;c[B+248+8>>2]=k;c[B+248+12>>2]=k+4;c[B+248+16>>2]=-1;c[B+248+20>>2]=-1;nc(b,B+176|0,B+96|0,B+248|0,f,h)}}A=A+1|0}while((A|0)<(c[a+268>>2]|0));l=B;return}function dd(a){a=a|0;var b=0,d=0,e=0.0,f=0.0,h=0.0,i=0,j=0.0,k=0.0,m=0.0,n=0,o=0,p=0.0,q=0.0,r=0.0;n=l;l=l+16|0;b=c[a+372>>2]|0;a:do switch(c[b+32>>2]|0){case 1:{i=b;d=1;b=0;while(1){c[n>>2]=0;c[n+4>>2]=0;c[n+8>>2]=0;c[n+12>>2]=0;g[n+(b<<2)>>2]=1.0;o=i+32|0;g[i+16+(d<<2)>>2]=0.0;d=(c[a+364>>2]|0)+-1|0;c[a+364>>2]=d;c[i+(c[o>>2]<<2)>>2]=c[a+348+(d<<2)>>2];d=c[o>>2]|0;c[o>>2]=d+1;e=+g[n>>2];f=+g[n+4>>2];h=+g[n+8>>2];mh(a,e,f,h,c[i+(d<<2)>>2]|0);if(dd(a)|0)break;i=c[a+372>>2]|0;o=(c[i+32>>2]|0)+-1|0;c[i+32>>2]=o;o=c[i+(o<<2)>>2]|0;i=c[a+364>>2]|0;c[a+364>>2]=i+1;c[a+348+(i<<2)>>2]=o;i=c[a+372>>2]|0;g[i+16+(c[i+32>>2]<<2)>>2]=0.0;o=(c[a+364>>2]|0)+-1|0;c[a+364>>2]=o;c[i+(c[i+32>>2]<<2)>>2]=c[a+348+(o<<2)>>2];o=c[i+32>>2]|0;c[i+32>>2]=o+1;mh(a,-e,-f,-h,c[i+(o<<2)>>2]|0);if(dd(a)|0)break;o=c[a+372>>2]|0;i=(c[o+32>>2]|0)+-1|0;c[o+32>>2]=i;i=c[o+(i<<2)>>2]|0;o=c[a+364>>2]|0;c[a+364>>2]=o+1;c[a+348+(o<<2)>>2]=i;b=b+1|0;if(b>>>0>=3)break a;d=c[a+372>>2]|0;i=d;d=c[d+32>>2]|0}o=1;l=n;return o|0}case 2:{o=c[b+4>>2]|0;b=c[b>>2]|0;j=+g[o+16>>2]-+g[b+16>>2];m=+g[o+20>>2]-+g[b+20>>2];k=+g[o+24>>2]-+g[b+24>>2];b=0;while(1){c[n>>2]=0;c[n+4>>2]=0;c[n+8>>2]=0;c[n+12>>2]=0;g[n+(b<<2)>>2]=1.0;e=+g[n+8>>2];f=+g[n+4>>2];h=+g[n>>2];if((m*e-k*f)*(m*e-k*f)+(k*h-j*e)*(k*h-j*e)+(j*f-m*h)*(j*f-m*h)>0.0){i=c[a+372>>2]|0;g[i+16+(c[i+32>>2]<<2)>>2]=0.0;o=(c[a+364>>2]|0)+-1|0;c[a+364>>2]=o;c[i+(c[i+32>>2]<<2)>>2]=c[a+348+(o<<2)>>2];o=c[i+32>>2]|0;c[i+32>>2]=o+1;mh(a,m*e-k*f,k*h-j*e,j*f-m*h,c[i+(o<<2)>>2]|0);if(dd(a)|0)break;i=c[a+372>>2]|0;o=(c[i+32>>2]|0)+-1|0;c[i+32>>2]=o;o=c[i+(o<<2)>>2]|0;i=c[a+364>>2]|0;c[a+364>>2]=i+1;c[a+348+(i<<2)>>2]=o;i=c[a+372>>2]|0;g[i+16+(c[i+32>>2]<<2)>>2]=0.0;o=(c[a+364>>2]|0)+-1|0;c[a+364>>2]=o;c[i+(c[i+32>>2]<<2)>>2]=c[a+348+(o<<2)>>2];o=c[i+32>>2]|0;c[i+32>>2]=o+1;mh(a,-(m*e-k*f),-(k*h-j*e),-(j*f-m*h),c[i+(o<<2)>>2]|0);if(dd(a)|0)break;o=c[a+372>>2]|0;i=(c[o+32>>2]|0)+-1|0;c[o+32>>2]=i;i=c[o+(i<<2)>>2]|0;o=c[a+364>>2]|0;c[a+364>>2]=o+1;c[a+348+(o<<2)>>2]=i}b=b+1|0;if(b>>>0>=3)break a}o=1;l=n;return o|0}case 3:{o=c[b+4>>2]|0;i=c[b>>2]|0;e=+g[i+16>>2];f=+g[o+16>>2]-e;k=+g[i+20>>2];m=+g[o+20>>2]-k;h=+g[i+24>>2];j=+g[o+24>>2]-h;o=c[b+8>>2]|0;e=+g[o+16>>2]-e;k=+g[o+20>>2]-k;h=+g[o+24>>2]-h;if((m*h-j*k)*(m*h-j*k)+(j*e-f*h)*(j*e-f*h)+(f*k-m*e)*(f*k-m*e)>0.0){g[b+28>>2]=0.0;o=(c[a+364>>2]|0)+-1|0;c[a+364>>2]=o;c[b+12>>2]=c[a+348+(o<<2)>>2];o=c[b+32>>2]|0;c[b+32>>2]=o+1;mh(a,m*h-j*k,j*e-f*h,f*k-m*e,c[b+(o<<2)>>2]|0);if(dd(a)|0){o=1;l=n;return o|0}i=c[a+372>>2]|0;o=(c[i+32>>2]|0)+-1|0;c[i+32>>2]=o;o=c[i+(o<<2)>>2]|0;i=c[a+364>>2]|0;c[a+364>>2]=i+1;c[a+348+(i<<2)>>2]=o;i=c[a+372>>2]|0;g[i+16+(c[i+32>>2]<<2)>>2]=0.0;o=(c[a+364>>2]|0)+-1|0;c[a+364>>2]=o;c[i+(c[i+32>>2]<<2)>>2]=c[a+348+(o<<2)>>2];o=c[i+32>>2]|0;c[i+32>>2]=o+1;mh(a,-(m*h-j*k),-(j*e-f*h),-(f*k-m*e),c[i+(o<<2)>>2]|0);if(dd(a)|0){o=1;l=n;return o|0}else{o=c[a+372>>2]|0;i=(c[o+32>>2]|0)+-1|0;c[o+32>>2]=i;i=c[o+(i<<2)>>2]|0;o=c[a+364>>2]|0;c[a+364>>2]=o+1;c[a+348+(o<<2)>>2]=i;break a}}break}case 4:{o=c[b>>2]|0;a=c[b+12>>2]|0;m=+g[a+16>>2];r=+g[o+16>>2]-m;p=+g[a+20>>2];e=+g[o+20>>2]-p;h=+g[a+24>>2];j=+g[o+24>>2]-h;o=c[b+4>>2]|0;f=+g[o+16>>2]-m;k=+g[o+20>>2]-p;q=+g[o+24>>2]-h;o=c[b+8>>2]|0;m=+g[o+16>>2]-m;p=+g[o+20>>2]-p;h=+g[o+24>>2]-h;if(!((0.0!=0.0?1:r*k*h+(e*q*m+j*f*p-r*q*p-e*f*h)-j*k*m!=r*k*h+(e*q*m+j*f*p-r*q*p-e*f*h)-j*k*m)|r*k*h+(e*q*m+j*f*p-r*q*p-e*f*h)-j*k*m==0.0)){o=1;l=n;return o|0}break}default:{}}while(0);o=0;l=n;return o|0}function ed(d,e){d=d|0;e=e|0;var f=0,i=0,j=0,k=0,m=0,n=0,o=0,p=0,q=0;q=l;l=l+64|0;g[d+20>>2]=+h[e+32>>3];g[d+24>>2]=+h[e+40>>3];g[d+28>>2]=+h[e+48>>3];g[d+32>>2]=+h[e+56>>3];g[d+4>>2]=+h[e>>3];g[d+8>>2]=+h[e+8>>3];g[d+12>>2]=+h[e+16>>3];g[d+16>>2]=+h[e+24>>3];g[d+36>>2]=+h[e+64>>3];g[d+40>>2]=+h[e+72>>3];g[d+44>>2]=+h[e+80>>3];g[d+48>>2]=+h[e+88>>3];c[d+56>>2]=c[e+96>>2];a[d+60>>0]=(c[e+100>>2]|0)!=0&1;p=c[e+104>>2]|0;k=q;n=k+64|0;do{c[k>>2]=0;k=k+4|0}while((k|0)<(n|0));o=c[d+88>>2]|0;if((o|0)<(p|0)){if((c[d+92>>2]|0)<(p|0)){if(!p){i=o;j=0}else{c[6432]=(c[6432]|0)+1;f=ec(p<<6|19)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}i=c[d+88>>2]|0;j=f}if((i|0)>0){f=0;do{k=j+(f<<6)|0;m=(c[d+96>>2]|0)+(f<<6)|0;n=k+64|0;do{c[k>>2]=c[m>>2];k=k+4|0;m=m+4|0}while((k|0)<(n|0));f=f+1|0}while((f|0)!=(i|0))}f=c[d+96>>2]|0;if(f|0){if(a[d+100>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[d+96>>2]=0}a[d+100>>0]=1;c[d+96>>2]=j;c[d+92>>2]=p;i=d+96|0}else i=d+96|0;f=o;do{k=(c[i>>2]|0)+(f<<6)|0;m=q;n=k+64|0;do{c[k>>2]=c[m>>2];k=k+4|0;m=m+4|0}while((k|0)<(n|0));f=f+1|0}while((f|0)!=(p|0))}c[d+88>>2]=p;if((p|0)>0){f=c[d+96>>2]|0;i=0;j=c[e+112>>2]|0;while(1){g[f+(i<<6)+16>>2]=+h[j+32>>3];g[f+(i<<6)+20>>2]=+h[j+40>>3];g[f+(i<<6)+24>>2]=+h[j+48>>3];g[f+(i<<6)+28>>2]=+h[j+56>>3];g[f+(i<<6)>>2]=+h[j>>3];g[f+(i<<6)+4>>2]=+h[j+8>>3];g[f+(i<<6)+8>>2]=+h[j+16>>3];g[f+(i<<6)+12>>2]=+h[j+24>>3];c[f+(i<<6)+32>>2]=c[j+64>>2];c[f+(i<<6)+36>>2]=c[j+68>>2];c[f+(i<<6)+40>>2]=c[j+72>>2];i=i+1|0;if((i|0)==(p|0))break;else j=j+80|0}}m=c[e+108>>2]|0;c[q>>2]=0;c[q+4>>2]=0;c[q+8>>2]=0;c[q+12>>2]=0;k=c[d+128>>2]|0;if((k|0)<(m|0)){if((c[d+132>>2]|0)<(m|0)){if(!m){i=k;j=0}else{c[6432]=(c[6432]|0)+1;f=ec((m<<4|3)+16|0)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}i=c[d+128>>2]|0;j=f}if((i|0)>0){f=0;do{p=j+(f<<4)|0;o=(c[d+136>>2]|0)+(f<<4)|0;c[p>>2]=c[o>>2];c[p+4>>2]=c[o+4>>2];c[p+8>>2]=c[o+8>>2];c[p+12>>2]=c[o+12>>2];f=f+1|0}while((f|0)!=(i|0))}f=c[d+136>>2]|0;if(f|0){if(a[d+140>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[d+136>>2]=0}a[d+140>>0]=1;c[d+136>>2]=j;c[d+132>>2]=m;i=d+136|0}else i=d+136|0;f=k;do{p=(c[i>>2]|0)+(f<<4)|0;c[p>>2]=c[q>>2];c[p+4>>2]=c[q+4>>2];c[p+8>>2]=c[q+8>>2];c[p+12>>2]=c[q+12>>2];f=f+1|0}while((f|0)!=(m|0))}c[d+128>>2]=m;if((m|0)>0){f=c[d+136>>2]|0;i=0;j=c[e+116>>2]|0;while(1){c[f+(i<<4)+12>>2]=c[j+12>>2];b[f+(i<<4)+6>>1]=b[j+6>>1]|0;b[f+(i<<4)+8>>1]=b[j+8>>1]|0;b[f+(i<<4)+10>>1]=b[j+10>>1]|0;b[f+(i<<4)>>1]=b[j>>1]|0;b[f+(i<<4)+2>>1]=b[j+2>>1]|0;b[f+(i<<4)+4>>1]=b[j+4>>1]|0;i=i+1|0;if((i|0)==(m|0))break;else j=j+16|0}}c[d+144>>2]=c[e+120>>2];m=c[e+124>>2]|0;k=c[d+152>>2]|0;if((k|0)<(m|0)){if((c[d+156>>2]|0)<(m|0)){if(!m){i=k;j=0}else{c[6432]=(c[6432]|0)+1;f=ec(m<<5|19)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}i=c[d+152>>2]|0;j=f}if((i|0)>0){f=0;do{p=j+(f<<5)|0;o=(c[d+160>>2]|0)+(f<<5)|0;c[p>>2]=c[o>>2];c[p+4>>2]=c[o+4>>2];c[p+8>>2]=c[o+8>>2];c[p+12>>2]=c[o+12>>2];c[p+16>>2]=c[o+16>>2];c[p+20>>2]=c[o+20>>2];c[p+24>>2]=c[o+24>>2];c[p+28>>2]=c[o+28>>2];f=f+1|0}while((f|0)!=(i|0))}f=c[d+160>>2]|0;if(f|0){if(a[d+164>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[d+160>>2]=0}a[d+164>>0]=1;c[d+160>>2]=j;c[d+156>>2]=m;i=d+160|0}else i=d+160|0;f=k;do{p=(c[i>>2]|0)+(f<<5)|0;c[p>>2]=c[q>>2];c[p+4>>2]=c[q+4>>2];c[p+8>>2]=c[q+8>>2];c[p+12>>2]=c[q+12>>2];c[p+16>>2]=c[q+16>>2];c[p+20>>2]=c[q+20>>2];c[p+24>>2]=c[q+24>>2];c[p+28>>2]=c[q+28>>2];f=f+1|0}while((f|0)!=(m|0))}c[d+152>>2]=m;if((m|0)<=0){l=q;return}i=c[d+160>>2]|0;j=0;f=c[e+128>>2]|0;while(1){b[i+(j<<5)+6>>1]=b[f+14>>1]|0;b[i+(j<<5)+8>>1]=b[f+16>>1]|0;b[i+(j<<5)+10>>1]=b[f+18>>1]|0;b[i+(j<<5)>>1]=b[f+8>>1]|0;b[i+(j<<5)+2>>1]=b[f+10>>1]|0;b[i+(j<<5)+4>>1]=b[f+12>>1]|0;c[i+(j<<5)+12>>2]=c[f>>2];c[i+(j<<5)+16>>2]=c[f+4>>2];j=j+1|0;if((j|0)==(m|0))break;else f=f+20|0}l=q;return}function fd(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,h=0.0,i=0,j=0,k=0.0,l=0,m=0.0,n=0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0.0,O=0.0,P=0.0,Q=0.0,R=0.0,S=0.0,T=0.0,U=0.0,V=0.0,W=0.0,X=0,Y=0,Z=0;Y=c[d+36>>2]|0;X=c[e+36>>2]|0;L=+g[Y+8>>2];N=+g[Y+12>>2];M=+g[Y+16>>2];e=c[X+8>>2]|0;U=+g[e+8>>2];V=+g[e+12>>2];W=+g[e+16>>2];f=c[X+12>>2]|0;Q=+g[f+8>>2];O=+g[f+12>>2];P=+g[f+16>>2];d=c[X+16>>2]|0;R=+g[d+8>>2];S=+g[d+12>>2];T=+g[d+16>>2];x=Q-L-(U-L);F=O-N-(V-N);z=P-M-(W-M);w=F*(T-M-(W-M))-z*(S-N-(V-N));E=z*(R-L-(U-L))-x*(T-M-(W-M));B=x*(S-N-(V-N))-F*(R-L-(U-L));do if(B*B+(w*w+E*E)>1.1920928955078125e-07?(I=1.0/+C(+(B*B+(w*w+E*E))),H=(W-M)*B*I+((U-L)*w*I+(V-N)*E*I),H*H<3402823466385288598117041.0e14):0){r=U-L-w*I*H;v=V-N-E*I*H;t=W-M-B*I*H;h=Q-L-w*I*H;u=O-N-E*I*H;s=P-M-B*I*H;if((B*(u*r-v*h)+(w*(v*s-t*u)+E*(t*h-s*r))>0.0?(y=R-L-w*I*H,D=S-N-E*I*H,A=T-M-B*I*H,B*(D*h-u*y)+(w*(u*A-s*D)+E*(s*y-A*h))>0.0):0)?B*(v*y-D*r)+(w*(D*t-A*v)+E*(A*r-t*y))>0.0:0){q=H*H;p=w*I*H;o=B*I*H;m=E*I*H;break}if(x*x+F*F+z*z>1.1920928955078125e-07?(G=-((U-L)*x+(V-N)*F+(W-M)*z)/(x*x+F*F+z*z),G=G<0.0?0.0:G>1.0?1.0:G,q=(W-M+z*G)*(W-M+z*G)+((U-L+x*G)*(U-L+x*G)+(V-N+F*G)*(V-N+F*G)),q<3402823466385288598117041.0e14):0){s=U-L+x*G;t=W-M+z*G;r=V-N+F*G}else{q=3402823466385288598117041.0e14;s=0.0;t=0.0;r=0.0}h=(R-L-(Q-L))*(R-L-(Q-L))+(S-N-(O-N))*(S-N-(O-N))+(T-M-(P-M))*(T-M-(P-M));if(h>1.1920928955078125e-07?(o=-((Q-L)*(R-L-(Q-L))+(O-N)*(S-N-(O-N))+(P-M)*(T-M-(P-M)))/h,o=o<0.0?0.0:o>1.0?1.0:o,p=Q-L+(R-L-(Q-L))*o,k=O-N+(S-N-(O-N))*o,o=P-M+(T-M-(P-M))*o,o*o+(p*p+k*k)<q):0)q=o*o+(p*p+k*k);else{p=s;o=t;k=r}h=(U-L-(R-L))*(U-L-(R-L))+(V-N-(S-N))*(V-N-(S-N))+(W-M-(T-M))*(W-M-(T-M));if(h>1.1920928955078125e-07?(K=-((R-L)*(U-L-(R-L))+(S-N)*(V-N-(S-N))+(T-M)*(W-M-(T-M)))/h,K=K<0.0?0.0:K>1.0?1.0:K,J=R-L+(U-L-(R-L))*K,m=S-N+(V-N-(S-N))*K,K=T-M+(W-M-(T-M))*K,K*K+(J*J+m*m)<q):0){q=K*K+(J*J+m*m);p=J;o=K}else m=k}else{q=3402823466385288598117041.0e14;p=0.0;o=0.0;m=0.0}while(0);J=L-+g[Y+24>>2];K=N-+g[Y+28>>2];u=M-+g[Y+32>>2];u=+g[b+12>>2]+ +C(+(J*J+K*K+u*u))*2.0;if(!(q<u*u))return;r=L+p;h=N+m;k=M+o;t=+C(+(((U-r)*(O-h)-(V-h)*(Q-r))*((U-r)*(O-h)-(V-h)*(Q-r))+(((V-h)*(P-k)-(W-k)*(O-h))*((V-h)*(P-k)-(W-k)*(O-h))+((W-k)*(Q-r)-(U-r)*(P-k))*((W-k)*(Q-r)-(U-r)*(P-k)))));s=+C(+(((Q-r)*(S-h)-(O-h)*(R-r))*((Q-r)*(S-h)-(O-h)*(R-r))+(((O-h)*(T-k)-(P-k)*(S-h))*((O-h)*(T-k)-(P-k)*(S-h))+((P-k)*(R-r)-(Q-r)*(T-k))*((P-k)*(R-r)-(Q-r)*(T-k)))));r=+C(+(((V-h)*(R-r)-(U-r)*(S-h))*((V-h)*(R-r)-(U-r)*(S-h))+(((W-k)*(S-h)-(V-h)*(T-k))*((W-k)*(S-h)-(V-h)*(T-k))+((U-r)*(T-k)-(W-k)*(R-r))*((U-r)*(T-k)-(W-k)*(R-r)))));k=+g[Y+88>>2];V=+g[e+88>>2];W=+g[f+88>>2];h=+g[d+88>>2];h=!(V<=0.0)&!(W<=0.0)&!(h<=0.0)?V*s*(1.0/(t+s+r))+W*r*(1.0/(t+s+r))+t*(1.0/(t+s+r))*h:0.0;if(!(k+h>0.0))return;W=1.0/-+C(+q);q=p*W;p=m*W;o=o*W;n=c[b+4>>2]|0;d=c[b+8>>2]|0;l=c[(+g[n+316>>2]>+g[d+316>>2]?n+316|0:d+316|0)>>2]|0;m=k/(k+h)*+g[n+332>>2];h=h/(k+h)*+g[d+332>>2];d=c[n+832>>2]|0;if((d|0)==(c[n+836>>2]|0)?(Z=d|0?d<<1:1,(d|0)<(Z|0)):0){if(!Z)e=0;else{c[6432]=(c[6432]|0)+1;d=ec((Z*56|3)+16|0)|0;if(!d)e=0;else{c[(d+4+15&-16)+-4>>2]=d;e=d+4+15&-16}d=c[n+832>>2]|0}if((d|0)>0){f=0;do{b=e+(f*56|0)|0;i=(c[n+840>>2]|0)+(f*56|0)|0;j=b+56|0;do{c[b>>2]=c[i>>2];b=b+4|0;i=i+4|0}while((b|0)<(j|0));f=f+1|0}while((f|0)!=(d|0))}d=c[n+840>>2]|0;if(d|0){if(a[n+844>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[n+840>>2]=0}a[n+844>>0]=1;c[n+840>>2]=e;c[n+836>>2]=Z;d=c[n+832>>2]|0}Z=c[n+840>>2]|0;c[Z+(d*56|0)>>2]=Y;c[Z+(d*56|0)+4>>2]=X;g[Z+(d*56|0)+8>>2]=s*(1.0/(t+s+r));g[Z+(d*56|0)+12>>2]=r*(1.0/(t+s+r));g[Z+(d*56|0)+16>>2]=t*(1.0/(t+s+r));g[Z+(d*56|0)+20>>2]=0.0;g[Z+(d*56|0)+24>>2]=q;g[Z+(d*56|0)+28>>2]=p;g[Z+(d*56|0)+32>>2]=o;g[Z+(d*56|0)+36>>2]=0.0;g[Z+(d*56|0)+40>>2]=u;c[Z+(d*56|0)+44>>2]=l;g[Z+(d*56|0)+48>>2]=m;g[Z+(d*56|0)+52>>2]=h;c[n+832>>2]=(c[n+832>>2]|0)+1;return}function gd(d,e){d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,m=0,n=0,o=0;o=l;l=l+64|0;c[d+20>>2]=c[e+16>>2];c[d+24>>2]=c[e+20>>2];c[d+28>>2]=c[e+24>>2];c[d+32>>2]=c[e+28>>2];c[d+4>>2]=c[e>>2];c[d+8>>2]=c[e+4>>2];c[d+12>>2]=c[e+8>>2];c[d+16>>2]=c[e+12>>2];c[d+36>>2]=c[e+32>>2];c[d+40>>2]=c[e+36>>2];c[d+44>>2]=c[e+40>>2];c[d+48>>2]=c[e+44>>2];c[d+56>>2]=c[e+48>>2];a[d+60>>0]=(c[e+52>>2]|0)!=0&1;n=c[e+56>>2]|0;i=o;k=i+64|0;do{c[i>>2]=0;i=i+4|0}while((i|0)<(k|0));m=c[d+88>>2]|0;if((m|0)<(n|0)){if((c[d+92>>2]|0)<(n|0)){if(!n){g=m;h=0}else{c[6432]=(c[6432]|0)+1;f=ec(n<<6|19)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}g=c[d+88>>2]|0;h=f}if((g|0)>0){f=0;do{i=h+(f<<6)|0;j=(c[d+96>>2]|0)+(f<<6)|0;k=i+64|0;do{c[i>>2]=c[j>>2];i=i+4|0;j=j+4|0}while((i|0)<(k|0));f=f+1|0}while((f|0)!=(g|0))}f=c[d+96>>2]|0;if(f|0){if(a[d+100>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[d+96>>2]=0}a[d+100>>0]=1;c[d+96>>2]=h;c[d+92>>2]=n;g=d+96|0}else g=d+96|0;f=m;do{i=(c[g>>2]|0)+(f<<6)|0;j=o;k=i+64|0;do{c[i>>2]=c[j>>2];i=i+4|0;j=j+4|0}while((i|0)<(k|0));f=f+1|0}while((f|0)!=(n|0))}c[d+88>>2]=n;if((n|0)>0){f=c[d+96>>2]|0;g=0;h=c[e+64>>2]|0;while(1){c[f+(g<<6)+16>>2]=c[h+16>>2];c[f+(g<<6)+20>>2]=c[h+20>>2];c[f+(g<<6)+24>>2]=c[h+24>>2];c[f+(g<<6)+28>>2]=c[h+28>>2];c[f+(g<<6)>>2]=c[h>>2];c[f+(g<<6)+4>>2]=c[h+4>>2];c[f+(g<<6)+8>>2]=c[h+8>>2];c[f+(g<<6)+12>>2]=c[h+12>>2];c[f+(g<<6)+32>>2]=c[h+32>>2];c[f+(g<<6)+36>>2]=c[h+36>>2];c[f+(g<<6)+40>>2]=c[h+40>>2];g=g+1|0;if((g|0)==(n|0))break;else h=h+48|0}}j=c[e+60>>2]|0;c[o>>2]=0;c[o+4>>2]=0;c[o+8>>2]=0;c[o+12>>2]=0;i=c[d+128>>2]|0;if((i|0)<(j|0)){if((c[d+132>>2]|0)<(j|0)){if(!j){g=i;h=0}else{c[6432]=(c[6432]|0)+1;f=ec((j<<4|3)+16|0)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}g=c[d+128>>2]|0;h=f}if((g|0)>0){f=0;do{n=h+(f<<4)|0;m=(c[d+136>>2]|0)+(f<<4)|0;c[n>>2]=c[m>>2];c[n+4>>2]=c[m+4>>2];c[n+8>>2]=c[m+8>>2];c[n+12>>2]=c[m+12>>2];f=f+1|0}while((f|0)!=(g|0))}f=c[d+136>>2]|0;if(f|0){if(a[d+140>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[d+136>>2]=0}a[d+140>>0]=1;c[d+136>>2]=h;c[d+132>>2]=j;g=d+136|0}else g=d+136|0;f=i;do{n=(c[g>>2]|0)+(f<<4)|0;c[n>>2]=c[o>>2];c[n+4>>2]=c[o+4>>2];c[n+8>>2]=c[o+8>>2];c[n+12>>2]=c[o+12>>2];f=f+1|0}while((f|0)!=(j|0))}c[d+128>>2]=j;if((j|0)>0){f=c[d+136>>2]|0;g=0;h=c[e+68>>2]|0;while(1){c[f+(g<<4)+12>>2]=c[h+12>>2];b[f+(g<<4)+6>>1]=b[h+6>>1]|0;b[f+(g<<4)+8>>1]=b[h+8>>1]|0;b[f+(g<<4)+10>>1]=b[h+10>>1]|0;b[f+(g<<4)>>1]=b[h>>1]|0;b[f+(g<<4)+2>>1]=b[h+2>>1]|0;b[f+(g<<4)+4>>1]=b[h+4>>1]|0;g=g+1|0;if((g|0)==(j|0))break;else h=h+16|0}}c[d+144>>2]=c[e+76>>2];j=c[e+80>>2]|0;i=c[d+152>>2]|0;if((i|0)<(j|0)){if((c[d+156>>2]|0)<(j|0)){if(!j){g=i;h=0}else{c[6432]=(c[6432]|0)+1;f=ec(j<<5|19)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}g=c[d+152>>2]|0;h=f}if((g|0)>0){f=0;do{n=h+(f<<5)|0;m=(c[d+160>>2]|0)+(f<<5)|0;c[n>>2]=c[m>>2];c[n+4>>2]=c[m+4>>2];c[n+8>>2]=c[m+8>>2];c[n+12>>2]=c[m+12>>2];c[n+16>>2]=c[m+16>>2];c[n+20>>2]=c[m+20>>2];c[n+24>>2]=c[m+24>>2];c[n+28>>2]=c[m+28>>2];f=f+1|0}while((f|0)!=(g|0))}f=c[d+160>>2]|0;if(f|0){if(a[d+164>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[d+160>>2]=0}a[d+164>>0]=1;c[d+160>>2]=h;c[d+156>>2]=j;g=d+160|0}else g=d+160|0;f=i;do{n=(c[g>>2]|0)+(f<<5)|0;c[n>>2]=c[o>>2];c[n+4>>2]=c[o+4>>2];c[n+8>>2]=c[o+8>>2];c[n+12>>2]=c[o+12>>2];c[n+16>>2]=c[o+16>>2];c[n+20>>2]=c[o+20>>2];c[n+24>>2]=c[o+24>>2];c[n+28>>2]=c[o+28>>2];f=f+1|0}while((f|0)!=(j|0))}c[d+152>>2]=j;if((j|0)<=0){l=o;return}g=c[d+160>>2]|0;h=0;f=c[e+72>>2]|0;while(1){b[g+(h<<5)+6>>1]=b[f+14>>1]|0;b[g+(h<<5)+8>>1]=b[f+16>>1]|0;b[g+(h<<5)+10>>1]=b[f+18>>1]|0;b[g+(h<<5)>>1]=b[f+8>>1]|0;b[g+(h<<5)+2>>1]=b[f+10>>1]|0;b[g+(h<<5)+4>>1]=b[f+12>>1]|0;c[g+(h<<5)+12>>2]=c[f>>2];c[g+(h<<5)+16>>2]=c[f+4>>2];h=h+1|0;if((h|0)==(j|0))break;else f=f+20|0}l=o;return}function hd(b){b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0;c[b>>2]=3308;d=c[b+192>>2]|0;if(d|0)hb[c[(c[d>>2]|0)+4>>2]&511](d);a:do if((c[b+1112>>2]|0)>0)do{h=c[c[b+1120>>2]>>2]|0;d=c[h+348>>2]|0;if(d|0){Kg(b+1048|0,d)|0;e=c[b+1052>>2]|0;if(e|0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}c[b+1052>>2]=d;c[b+1060>>2]=(c[b+1060>>2]|0)+-1}d=c[h+52>>2]|0;if(d|0){if(a[h+56>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[h+52>>2]=0}a[h+56>>0]=1;c[h+52>>2]=0;c[h+44>>2]=0;c[h+48>>2]=0;d=c[h+32>>2]|0;if(d|0){if(a[h+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[h+32>>2]=0}a[h+36>>0]=1;c[h+32>>2]=0;c[h+24>>2]=0;c[h+28>>2]=0;d=c[h+12>>2]|0;if(d|0){if(a[h+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[h+12>>2]=0}a[h+16>>0]=1;c[h+12>>2]=0;c[h+4>>2]=0;c[h+8>>2]=0;c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0);d=c[b+1112>>2]|0;if((d|0)<=0)break a;g=c[b+1120>>2]|0;e=0;do{f=g+(e<<2)|0;if((c[f>>2]|0)==(h|0)){i=28;break}e=e+1|0}while((e|0)<(d|0));if((i|0)==28){i=0;if((e|0)<(d|0)){c[f>>2]=c[g+(d+-1<<2)>>2];c[(c[b+1120>>2]|0)+(d+-1<<2)>>2]=h;c[b+1112>>2]=d+-1;d=d+-1|0}}}while((d|0)>0);while(0);d=c[b+872>>2]|0;if((d|0)>0){f=0;do{e=c[(c[b+880>>2]|0)+(f<<2)>>2]|0;if(e){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0);d=c[b+872>>2]|0}f=f+1|0}while((f|0)<(d|0))}d=c[b+852>>2]|0;if((d|0)>0){f=0;do{e=c[(c[b+860>>2]|0)+(f<<2)>>2]|0;if(e){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0);d=c[b+852>>2]|0}f=f+1|0}while((f|0)<(d|0))}d=c[b+1244>>2]|0;if(d|0){if(a[b+1248>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+1244>>2]=0}a[b+1248>>0]=1;c[b+1244>>2]=0;c[b+1236>>2]=0;c[b+1240>>2]=0;d=c[b+1140>>2]|0;if(d|0){if(a[b+1144>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+1140>>2]=0}a[b+1144>>0]=1;c[b+1140>>2]=0;c[b+1132>>2]=0;c[b+1136>>2]=0;d=c[b+1120>>2]|0;if(d|0){if(a[b+1124>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+1120>>2]=0}a[b+1124>>0]=1;c[b+1120>>2]=0;c[b+1112>>2]=0;c[b+1116>>2]=0;Oh(b+1048|0);Oh(b+988|0);Oh(b+928|0);d=c[b+880>>2]|0;if(d|0){if(a[b+884>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+880>>2]=0}a[b+884>>0]=1;c[b+880>>2]=0;c[b+872>>2]=0;c[b+876>>2]=0;d=c[b+860>>2]|0;if(d|0){if(a[b+864>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+860>>2]=0}a[b+864>>0]=1;c[b+860>>2]=0;c[b+852>>2]=0;c[b+856>>2]=0;d=c[b+840>>2]|0;if(d|0){if(a[b+844>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+840>>2]=0}a[b+844>>0]=1;c[b+840>>2]=0;c[b+832>>2]=0;c[b+836>>2]=0;d=c[b+820>>2]|0;if(d|0){if(a[b+824>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+820>>2]=0}a[b+824>>0]=1;c[b+820>>2]=0;c[b+812>>2]=0;c[b+816>>2]=0;d=c[b+800>>2]|0;if(d|0){if(a[b+804>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+800>>2]=0}a[b+804>>0]=1;c[b+800>>2]=0;c[b+792>>2]=0;c[b+796>>2]=0;d=c[b+780>>2]|0;if(d|0){if(a[b+784>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+780>>2]=0}a[b+784>>0]=1;c[b+780>>2]=0;c[b+772>>2]=0;c[b+776>>2]=0;d=c[b+760>>2]|0;if(d|0){if(a[b+764>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+760>>2]=0}a[b+764>>0]=1;c[b+760>>2]=0;c[b+752>>2]=0;c[b+756>>2]=0;d=c[b+740>>2]|0;if(d|0){if(a[b+744>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+740>>2]=0}a[b+744>>0]=1;c[b+740>>2]=0;c[b+732>>2]=0;c[b+736>>2]=0;d=c[b+720>>2]|0;if(d|0){if(a[b+724>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+720>>2]=0}a[b+724>>0]=1;c[b+720>>2]=0;c[b+712>>2]=0;c[b+716>>2]=0;d=c[b+700>>2]|0;if(d|0){if(a[b+704>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+700>>2]=0}a[b+704>>0]=1;c[b+700>>2]=0;c[b+692>>2]=0;c[b+696>>2]=0;d=c[b+512>>2]|0;if(d|0){if(a[b+516>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+512>>2]=0}a[b+516>>0]=1;c[b+512>>2]=0;c[b+504>>2]=0;c[b+508>>2]=0;d=c[b+492>>2]|0;if(d|0){if(a[b+496>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+492>>2]=0}a[b+496>>0]=1;c[b+492>>2]=0;c[b+484>>2]=0;c[b+488>>2]=0;ts(b+288|0);d=c[b+276>>2]|0;if(!d){a[b+280>>0]=1;c[b+276>>2]=0;c[b+268>>2]=0;i=b+272|0;c[i>>2]=0;c[b>>2]=5132;return}if(a[b+280>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+276>>2]=0;a[b+280>>0]=1;c[b+276>>2]=0;c[b+268>>2]=0;i=b+272|0;c[i>>2]=0;c[b>>2]=5132;return}function id(b,d,e,f,h,i,j,k,m){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;j=j|0;k=k|0;m=m|0;var n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0,I=0;I=l;l=l+128|0;c[I+16>>2]=i;c[I+16+4>>2]=j;c[I+16+8>>2]=k;c[I>>2]=e;c[I+4>>2]=f;c[I+8>>2]=h;if(!(+g[d+52>>2]<+g[b+12>>2])){m=0;l=I;return m|0}x=+g[d+36>>2];z=+g[d+40>>2];y=+g[d+44>>2];h=c[d+48>>2]|0;w=1.0/+C(+(x*x+z*z+y*y));k=bi(I)|0;A=+g[d+4>>2]-+g[k+48>>2];F=+g[d+8>>2]-+g[k+52>>2];D=+g[d+12>>2]-+g[k+56>>2];k=bi(I+16|0)|0;B=+g[d+20>>2]-+g[k+48>>2];G=+g[d+24>>2]-+g[k+52>>2];E=+g[d+28>>2]-+g[k+56>>2];if(!f)if(!e){n=0.0;q=0.0;s=0.0;o=0.0;r=0.0;p=0.0}else{s=+g[e+336>>2];q=+g[e+340>>2];o=+g[e+332>>2];n=D*s-F*q;q=A*q-D*o;s=F*o-A*s;o=+g[e+316>>2];r=+g[e+320>>2];p=+g[e+324>>2]}else{s=+g[f+332>>2];q=+g[f+336>>2];o=+g[f+328>>2];n=D*s-F*q;q=A*q-D*o;s=F*o-A*s;o=+g[f+312>>2];r=+g[f+316>>2];p=+g[f+320>>2]}v=o+n;u=r+q;r=p+s;if(!j)if(!i){o=0.0;p=0.0;q=0.0;s=0.0;t=0.0;n=0.0}else{q=+g[i+336>>2];p=+g[i+340>>2];s=+g[i+332>>2];o=E*q-G*p;p=B*p-E*s;q=G*s-B*q;s=+g[i+316>>2];t=+g[i+320>>2];n=+g[i+324>>2]}else{q=+g[j+332>>2];p=+g[j+336>>2];s=+g[j+328>>2];o=E*q-G*p;p=B*p-E*s;q=G*s-B*q;s=+g[j+312>>2];t=+g[j+316>>2];n=+g[j+320>>2]}s=v-(s+o);u=u-(t+p);t=r-(n+q);v=y*w*t+(z*w*u+x*w*s);r=+g[d+52>>2]-+g[b+12>>2];c[m+4>>2]=c[I>>2];c[m+4+4>>2]=c[I+4>>2];c[m+4+8>>2]=c[I+8>>2];c[m+16>>2]=c[I+16>>2];c[m+16+4>>2]=c[I+16+4>>2];c[m+16+8>>2]=c[I+16+8>>2];d=bi(I)|0;q=A*+g[d+4>>2]+F*+g[d+20>>2]+D*+g[d+36>>2];p=A*+g[d+8>>2]+F*+g[d+24>>2]+D*+g[d+40>>2];g[m+28>>2]=A*+g[d>>2]+F*+g[d+16>>2]+D*+g[d+32>>2];g[m+32>>2]=q;g[m+36>>2]=p;g[m+40>>2]=0.0;d=bi(I+16|0)|0;p=B*+g[d+4>>2]+G*+g[d+20>>2]+E*+g[d+36>>2];q=B*+g[d+8>>2]+G*+g[d+24>>2]+E*+g[d+40>>2];g[m+44>>2]=B*+g[d>>2]+G*+g[d+16>>2]+E*+g[d+32>>2];g[m+48>>2]=p;g[m+52>>2]=q;g[m+56>>2]=0.0;g[m+164>>2]=A;g[m+168>>2]=F;g[m+172>>2]=D;g[m+176>>2]=0.0;g[m+180>>2]=B;g[m+184>>2]=G;g[m+188>>2]=E;g[m+192>>2]=0.0;g[m+60>>2]=1.0;g[m+64>>2]=1.0;c[m+156>>2]=0;c[m+160>>2]=0;g[m+68>>2]=1.0;g[m+72>>2]=x*w*r;g[m+76>>2]=z*w*r;g[m+80>>2]=y*w*r;g[m+84>>2]=0.0;g[m+196>>2]=x*w;g[m+200>>2]=z*w;g[m+204>>2]=y*w;c[m+208>>2]=h;a[m+152>>0]=0;G=+g[b+16>>2];g[m+212>>2]=(t-y*w*v)*(t-y*w*v)+((s-x*w*v)*(s-x*w*v)+(u-z*w*v)*(u-z*w*v))<G*v*v*G?1.0:G;h=c[I+4>>2]|0;if(!h){h=c[I>>2]|0;if(!h)o=0.0;else{h=h+128|0;H=14}}else{h=h+344|0;H=14}if((H|0)==14)o=+g[h>>2];if((a[22640]|0)==0?jy(22640)|0:0){h=23008;k=h+48|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(k|0))}h=c[I+4>>2]|0;if(!h){e=c[I>>2]|0;e=(e|0)==0?23008:e+180|0}else e=h+264|0;h=c[I+16+4>>2]|0;if(!h){h=c[I+16>>2]|0;if(!h)n=0.0;else{h=h+128|0;H=25}}else{h=h+344|0;H=25}if((H|0)==25)n=+g[h>>2];if((a[22640]|0)==0?jy(22640)|0:0){h=23008;k=h+48|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(k|0))}h=c[I+16+4>>2]|0;if(!h){h=c[I+16>>2]|0;h=(h|0)==0?23008:h+180|0}else h=h+264|0;Ch(I+80|0,o,e,+g[m+164>>2],+g[m+168>>2],+g[m+172>>2]);Ch(I+32|0,n,h,+g[m+180>>2],+g[m+184>>2],+g[m+188>>2]);B=+g[I+80>>2]+ +g[I+32>>2];E=+g[I+80+4>>2]+ +g[I+32+4>>2];x=+g[I+80+8>>2]+ +g[I+32+8>>2];F=+g[I+80+16>>2]+ +g[I+32+16>>2];D=+g[I+80+20>>2]+ +g[I+32+20>>2];y=+g[I+80+24>>2]+ +g[I+32+24>>2];z=+g[I+80+32>>2]+ +g[I+32+32>>2];A=+g[I+80+36>>2]+ +g[I+32+36>>2];w=+g[I+80+40>>2]+ +g[I+32+40>>2];G=1.0/(x*(F*A-D*z)+(B*(D*w-y*A)+E*(y*z-F*w)));g[m+104>>2]=(D*w-y*A)*G;g[m+108>>2]=(x*A-E*w)*G;g[m+112>>2]=(E*y-x*D)*G;g[m+116>>2]=0.0;g[m+120>>2]=(y*z-F*w)*G;g[m+124>>2]=(B*w-x*z)*G;g[m+128>>2]=(x*F-B*y)*G;g[m+132>>2]=0.0;g[m+136>>2]=(F*A-D*z)*G;g[m+140>>2]=(E*z-B*A)*G;g[m+144>>2]=(B*D-E*F)*G;g[m+148>>2]=0.0;m=1;l=I;return m|0}function jd(b,d,e,f,h,i){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;var k=0.0,m=0,n=0,o=0.0,p=0,q=0,r=0.0,s=0.0,t=0.0,u=0,v=0.0,w=0.0;u=l;l=l+288|0;q=c[b+4>>2]|0;a[q+312>>0]=0;c[q>>2]=0;a[q+356>>0]=1;c[q+292>>2]=1566444395;c[q+296>>2]=1566444395;c[q+300>>2]=1566444395;g[q+304>>2]=0.0;c[q+336>>2]=0;c[q+336+4>>2]=0;c[q+336+8>>2]=0;c[q+336+12>>2]=0;a[q+336+16>>0]=0;a[q+332>>0]=a[q+332>>0]&-16;r=+g[e+48>>2]-+g[d+48>>2]-(+g[h+48>>2]-+g[f+48>>2]);s=+g[e+52>>2]-+g[d+52>>2]-(+g[h+52>>2]-+g[f+52>>2]);t=+g[e+56>>2]-+g[d+56>>2]-(+g[h+56>>2]-+g[f+56>>2]);c[u+232>>2]=9312;g[u+232+36>>2]=999999984306749440.0;a[u+232+40>>0]=0;q=c[b+8>>2]|0;p=c[b+12>>2]|0;n=c[b+4>>2]|0;c[u+136>>2]=9360;c[u+136+4>>2]=0;c[u+136+8>>2]=1065353216;c[u+136+12>>2]=0;g[u+136+16>>2]=0.0;c[u+136+20>>2]=0;c[u+136+24>>2]=n;c[u+136+28>>2]=q;c[u+136+32>>2]=p;c[u+136+36>>2]=c[q+4>>2];c[u+136+40>>2]=c[p+4>>2];g[u+136+44>>2]=+zb[c[(c[q>>2]|0)+48>>2]&15](q);g[u+136+48>>2]=+zb[c[(c[p>>2]|0)+48>>2]&15](p);a[u+136+52>>0]=0;c[u+136+60>>2]=-1;c[u+136+72>>2]=1;c[u+136+76>>2]=1;g[u+128>>2]=999999984306749440.0;c[u>>2]=c[d>>2];c[u+4>>2]=c[d+4>>2];c[u+8>>2]=c[d+8>>2];c[u+12>>2]=c[d+12>>2];c[u+16>>2]=c[d+16>>2];c[u+16+4>>2]=c[d+16+4>>2];c[u+16+8>>2]=c[d+16+8>>2];c[u+16+12>>2]=c[d+16+12>>2];c[u+32>>2]=c[d+32>>2];c[u+32+4>>2]=c[d+32+4>>2];c[u+32+8>>2]=c[d+32+8>>2];c[u+32+12>>2]=c[d+32+12>>2];c[u+48>>2]=c[d+48>>2];c[u+48+4>>2]=c[d+48+4>>2];c[u+48+8>>2]=c[d+48+8>>2];c[u+48+12>>2]=c[d+48+12>>2];c[u+64>>2]=c[f>>2];c[u+64+4>>2]=c[f+4>>2];c[u+64+8>>2]=c[f+8>>2];c[u+64+12>>2]=c[f+12>>2];c[u+80>>2]=c[f+16>>2];c[u+80+4>>2]=c[f+16+4>>2];c[u+80+8>>2]=c[f+16+8>>2];c[u+80+12>>2]=c[f+16+12>>2];c[u+96>>2]=c[f+32>>2];c[u+96+4>>2]=c[f+32+4>>2];c[u+96+8>>2]=c[f+32+8>>2];c[u+96+12>>2]=c[f+32+12>>2];c[u+112>>2]=c[f+48>>2];c[u+112+4>>2]=c[f+48+4>>2];c[u+112+8>>2]=c[f+48+8>>2];c[u+112+12>>2]=c[f+48+12>>2];Ac(u+136|0,u,u+232|0,0,0);p=(a[u+232+40>>0]|0)==0;q=u+232+20|0;c[u+216>>2]=c[q>>2];c[u+216+4>>2]=c[q+4>>2];c[u+216+8>>2]=c[q+8>>2];c[u+216+12>>2]=c[q+12>>2];if(p){i=0;l=u;return i|0}o=+g[u+232+36>>2];k=+g[u+232+16>>2];n=c[u+232+4>>2]|0;m=c[u+232+8>>2]|0;b=c[u+232+12>>2]|0;do if(o>1.0000000474974513e-03){k=0.0;p=0;while(1){if((p|0)>31){b=0;p=13;break}w=r*(c[j>>2]=n,+g[j>>2]);w=w+s*(c[j>>2]=m,+g[j>>2]);v=k;k=k-o/(w+t*(c[j>>2]=b,+g[j>>2]));if(!(!(k<=v)&(!(k<0.0)&!(k>1.0)))){b=0;p=13;break}gb[c[c[i>>2]>>2]&31](i,k);w=1.0-k;g[u+48>>2]=w*+g[d+48>>2]+k*+g[e+48>>2];g[u+52>>2]=w*+g[d+52>>2]+k*+g[e+52>>2];g[u+56>>2]=w*+g[d+56>>2]+k*+g[e+56>>2];g[u+112>>2]=w*+g[f+48>>2]+k*+g[h+48>>2];g[u+116>>2]=w*+g[f+52>>2]+k*+g[h+52>>2];g[u+120>>2]=w*+g[f+56>>2]+k*+g[h+56>>2];Ac(u+136|0,u,u+232|0,0,0);if(!(a[u+232+40>>0]|0)){b=0;p=13;break}o=+g[u+232+36>>2];if(o<0.0){p=8;break}c[u+216>>2]=c[q>>2];c[u+216+4>>2]=c[q+4>>2];c[u+216+8>>2]=c[q+8>>2];c[u+216+12>>2]=c[q+12>>2];n=c[u+232+4>>2]|0;m=c[u+232+8>>2]|0;b=c[u+232+12>>2]|0;if(!(o>1.0000000474974513e-03)){p=10;break}else p=p+1|0}if((p|0)==8){g[i+164>>2]=k;f=c[u+232+8>>2]|0;e=c[u+232+12>>2]|0;h=c[u+232+16>>2]|0;c[i+132>>2]=c[u+232+4>>2];c[i+136>>2]=f;c[i+140>>2]=e;c[i+144>>2]=h;c[i+148>>2]=c[q>>2];c[i+148+4>>2]=c[q+4>>2];c[i+148+8>>2]=c[q+8>>2];c[i+148+12>>2]=c[q+12>>2];i=1;l=u;return i|0}else if((p|0)==10){o=+g[u+232+16>>2];break}else if((p|0)==13){l=u;return b|0}}else{o=k;k=0.0}while(0);w=r*(c[j>>2]=n,+g[j>>2]);w=w+s*(c[j>>2]=m,+g[j>>2]);if(w+t*(c[j>>2]=b,+g[j>>2])>=-+g[i+172>>2]){i=0;l=u;return i|0}g[i+164>>2]=k;c[i+132>>2]=n;c[i+136>>2]=m;c[i+140>>2]=b;g[i+144>>2]=o;c[i+148>>2]=c[u+216>>2];c[i+148+4>>2]=c[u+216+4>>2];c[i+148+8>>2]=c[u+216+8>>2];c[i+148+12>>2]=c[u+216+12>>2];i=1;l=u;return i|0}function kd(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0,i=0,j=0,k=0,m=0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0;m=l;l=l+240|0;c[a+4>>2]=(c[a+4>>2]|0)+1;j=c[b+36>>2]|0;i=c[d+36>>2]|0;f=c[a+8>>2]|0;K=c[(c[f+4>>2]|0)+24>>2]|0;d=c[K+(j*80|0)+64>>2]|0;b=(c[(c[a+12>>2]|0)+4>>2]|0)+24|0;e=c[(c[b>>2]|0)+(i*80|0)+64>>2]|0;f=c[f+12>>2]|0;n=+g[f>>2];I=+g[f+4>>2];J=+g[f+8>>2];q=+g[f+16>>2];s=+g[f+20>>2];u=+g[f+24>>2];r=+g[f+32>>2];v=+g[f+36>>2];D=+g[f+40>>2];w=+g[K+(j*80|0)>>2];x=+g[K+(j*80|0)+16>>2];y=+g[K+(j*80|0)+32>>2];z=+g[K+(j*80|0)+4>>2];A=+g[K+(j*80|0)+20>>2];B=+g[K+(j*80|0)+36>>2];t=+g[K+(j*80|0)+8>>2];C=+g[K+(j*80|0)+24>>2];E=+g[K+(j*80|0)+40>>2];o=+g[K+(j*80|0)+48>>2];p=+g[K+(j*80|0)+52>>2];H=+g[K+(j*80|0)+56>>2];F=+g[f+48>>2]+(n*o+I*p+J*H);G=+g[f+52>>2]+(q*o+s*p+u*H);H=+g[f+56>>2]+(r*o+v*p+D*H);g[m+176>>2]=n*w+I*x+J*y;g[m+176+4>>2]=n*z+I*A+J*B;g[m+176+8>>2]=n*t+I*C+J*E;g[m+176+12>>2]=0.0;g[m+176+16>>2]=q*w+s*x+u*y;g[m+176+20>>2]=q*z+s*A+u*B;g[m+176+24>>2]=q*t+s*C+u*E;g[m+176+28>>2]=0.0;g[m+176+32>>2]=r*w+v*x+D*y;g[m+176+36>>2]=r*z+v*A+D*B;g[m+176+40>>2]=r*t+v*C+D*E;g[m+176+44>>2]=0.0;g[m+176+48>>2]=F;g[m+176+52>>2]=G;g[m+176+56>>2]=H;g[m+176+60>>2]=0.0;f=c[(c[a+12>>2]|0)+12>>2]|0;H=+g[f>>2];G=+g[f+4>>2];F=+g[f+8>>2];E=+g[f+16>>2];D=+g[f+20>>2];C=+g[f+24>>2];v=+g[f+32>>2];t=+g[f+36>>2];r=+g[f+40>>2];b=c[b>>2]|0;B=+g[b+(i*80|0)>>2];A=+g[b+(i*80|0)+16>>2];z=+g[b+(i*80|0)+32>>2];y=+g[b+(i*80|0)+4>>2];x=+g[b+(i*80|0)+20>>2];w=+g[b+(i*80|0)+36>>2];u=+g[b+(i*80|0)+8>>2];s=+g[b+(i*80|0)+24>>2];q=+g[b+(i*80|0)+40>>2];J=+g[b+(i*80|0)+48>>2];I=+g[b+(i*80|0)+52>>2];n=+g[b+(i*80|0)+56>>2];p=+g[f+48>>2]+(H*J+G*I+F*n);o=+g[f+52>>2]+(E*J+D*I+C*n);n=+g[f+56>>2]+(v*J+t*I+r*n);g[m+112>>2]=H*B+G*A+F*z;g[m+112+4>>2]=H*y+G*x+F*w;g[m+112+8>>2]=H*u+G*s+F*q;g[m+112+12>>2]=0.0;g[m+112+16>>2]=E*B+D*A+C*z;g[m+112+20>>2]=E*y+D*x+C*w;g[m+112+24>>2]=E*u+D*s+C*q;g[m+112+28>>2]=0.0;g[m+112+32>>2]=v*B+t*A+r*z;g[m+112+36>>2]=v*y+t*x+r*w;g[m+112+40>>2]=v*u+t*s+r*q;g[m+112+44>>2]=0.0;g[m+112+48>>2]=p;g[m+112+52>>2]=o;g[m+112+56>>2]=n;g[m+112+60>>2]=0.0;Vb[c[(c[d>>2]|0)+8>>2]&127](d,m+176|0,m+96|0,m+80|0);Vb[c[(c[e>>2]|0)+8>>2]&127](e,m+112|0,m+64|0,m+48|0);if(!(+g[m+96>>2]>+g[m+48>>2])?!(+g[m+80>>2]<+g[m+64>>2]):0)b=1;else b=0;if(!(!(+g[m+96+8>>2]>+g[m+48+8>>2])?!(+g[m+80+8>>2]<+g[m+64+8>>2]):0))b=0;if(+g[m+96+4>>2]>+g[m+48+4>>2]){l=m;return}if(+g[m+80+4>>2]<+g[m+64+4>>2]|b^1){l=m;return}f=c[a+8>>2]|0;b=c[f+8>>2]|0;c[m+24>>2]=f;c[m+24+4>>2]=d;c[m+24+8>>2]=b;c[m+24+12>>2]=m+176;c[m+24+16>>2]=-1;c[m+24+20>>2]=j;b=c[a+12>>2]|0;f=c[b+8>>2]|0;c[m>>2]=b;c[m+4>>2]=e;c[m+8>>2]=f;c[m+12>>2]=m+112;c[m+16>>2]=-1;c[m+20>>2]=i;f=c[a+28>>2]|0;c[6420]=(c[6420]|0)+1;b=((i<<16|j)+~((i<<16|j)<<15)>>10^(i<<16|j)+~((i<<16|j)<<15))*9|0;b=(c[f+12>>2]|0)+-1&((b>>6^b)+~((b>>6^b)<<11)>>16^(b>>6^b)+~((b>>6^b)<<11));a:do if((b|0)<(c[f+32>>2]|0)?(h=c[(c[f+40>>2]|0)+(b<<2)>>2]|0,(h|0)!=-1):0){e=c[f+16>>2]|0;b=h;while(1){d=e+(b*12|0)|0;if((c[d>>2]|0)==(j|0)?(c[e+(b*12|0)+4>>2]|0)==(i|0):0)break;b=c[(c[f+60>>2]|0)+(b<<2)>>2]|0;if((b|0)==-1){k=16;break a}}if(d)b=c[e+(b*12|0)+8>>2]|0;else k=16}else k=16;while(0);if((k|0)==16){b=c[a+16>>2]|0;b=pb[c[(c[b>>2]|0)+8>>2]&31](b,m+24|0,m,c[a+32>>2]|0)|0;K=c[a+28>>2]|0;c[(vb[c[(c[K>>2]|0)+12>>2]&63](K,j,i)|0)+8>>2]=b}K=c[a+24>>2]|0;h=c[K+8>>2]|0;k=c[K+12>>2]|0;c[K+8>>2]=m+24;c[K+12>>2]=m;Rb[c[(c[K>>2]|0)+8>>2]&127](K,-1,j);K=c[a+24>>2]|0;Rb[c[(c[K>>2]|0)+12>>2]&127](K,-1,i);fb[c[(c[b>>2]|0)+8>>2]&31](b,m+24|0,m,c[a+20>>2]|0,c[a+24>>2]|0);K=c[a+24>>2]|0;c[K+8>>2]=h;c[K+12>>2]=k;l=m;return}function ld(a,d,f,h,i,j,k,m,n){a=a|0;d=d|0;f=f|0;h=h|0;i=i|0;j=j|0;k=k|0;m=m|0;n=n|0;var o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;w=l;l=l+16|0;cj(a,w+6|0,+g[d>>2],+g[d+4>>2],+g[d+8>>2],0);cj(a,w,+g[f>>2],+g[f+4>>2],+g[f+8>>2],1);v=b[a+64>>1]|0;u=c[a+60>>2]|0;b[a+64>>1]=b[u+((v&65535)<<6)+48>>1]|0;p=(b[a+56>>1]|0)+1<<16>>16;b[a+56>>1]=p;c[u+((v&65535)<<6)+12>>2]=v&65535;c[u+((v&65535)<<6)>>2]=i;b[u+((v&65535)<<6)+4>>1]=j;b[u+((v&65535)<<6)+6>>1]=k;c[u+((v&65535)<<6)+8>>2]=n;r=(p&65535)<<1&65534;b[u+54>>1]=(e[u+54>>1]|0)+2;o=c[a+68>>2]|0;n=e[o+(r+-1<<2)>>1]|e[o+(r+-1<<2)+2>>1]<<16;b[o+((r|1)<<2)>>1]=n;b[o+((r|1)<<2)+2>>1]=n>>>16;o=c[a+68>>2]|0;b[o+(r+-1<<2)>>1]=b[w+6>>1]|0;b[o+(r+-1<<2)+2>>1]=v;b[o+(r<<2)>>1]=b[w>>1]|0;b[o+(r<<2)+2>>1]=v;b[u+((v&65535)<<6)+48>>1]=r+-1;b[u+((v&65535)<<6)+54>>1]=(p&65535)<<1;o=(c[a+60>>2]|0)+56|0;b[o>>1]=(e[o>>1]|0)+2;o=c[a+72>>2]|0;n=e[o+(r+-1<<2)>>1]|e[o+(r+-1<<2)+2>>1]<<16;b[o+((r|1)<<2)>>1]=n;b[o+((r|1)<<2)+2>>1]=n>>>16;o=c[a+72>>2]|0;b[o+(r+-1<<2)>>1]=b[w+6+2>>1]|0;b[o+(r+-1<<2)+2>>1]=v;b[o+(r<<2)>>1]=b[w+2>>1]|0;b[o+(r<<2)+2>>1]=v;b[u+((v&65535)<<6)+50>>1]=r+-1;b[u+((v&65535)<<6)+56>>1]=(p&65535)<<1;o=(c[a+60>>2]|0)+58|0;b[o>>1]=(e[o>>1]|0)+2;o=c[a+76>>2]|0;n=e[o+(r+-1<<2)>>1]|e[o+(r+-1<<2)+2>>1]<<16;b[o+((r|1)<<2)>>1]=n;b[o+((r|1)<<2)+2>>1]=n>>>16;o=c[a+76>>2]|0;b[o+(r+-1<<2)>>1]=b[w+6+4>>1]|0;b[o+(r+-1<<2)+2>>1]=v;b[o+(r<<2)>>1]=b[w+4>>1]|0;b[o+(r<<2)+2>>1]=v;b[u+((v&65535)<<6)+52>>1]=r+-1;b[u+((v&65535)<<6)+58>>1]=(p&65535)<<1;p=c[a+68>>2]|0;r=e[u+((v&65535)<<6)+48>>1]|0;o=c[a+60>>2]|0;n=b[p+(r+-1<<2)>>1]|0;if((e[p+(r<<2)>>1]|0)<(n&65535)){s=o+((e[p+(r<<2)+2>>1]|0)<<6)+48|0;q=p+(r<<2)|0;p=p+(r+-1<<2)|0;while(1){t=e[p+2>>1]|0;n=(n&1)==0?o+(t<<6)+48|0:o+(t<<6)+54|0;b[n>>1]=(b[n>>1]|0)+1<<16>>16;b[s>>1]=(b[s>>1]|0)+-1<<16>>16;n=e[q>>1]|e[q+2>>1]<<16;t=e[p>>1]|e[p+2>>1]<<16;b[q>>1]=t;b[q+2>>1]=t>>>16;b[p>>1]=n;b[p+2>>1]=n>>>16;q=q+-4|0;p=p+-4|0;n=b[p>>1]|0;if((e[q>>1]|0)>=(n&65535))break;o=c[a+60>>2]|0}p=c[a+68>>2]|0}o=e[u+((v&65535)<<6)+54>>1]|0;q=p+(o<<2)|0;r=p+(o+-1<<2)|0;n=b[r>>1]|0;a:do if((e[q>>1]|0)<(n&65535)){s=c[a+60>>2]|0;t=s+((e[p+(o<<2)+2>>1]|0)<<6)+54|0;p=q;o=r;while(1){r=e[o+2>>1]|0;n=(n&1)==0?s+(r<<6)+48|0:s+(r<<6)+54|0;b[n>>1]=(b[n>>1]|0)+1<<16>>16;b[t>>1]=(b[t>>1]|0)+-1<<16>>16;n=e[p>>1]|e[p+2>>1]<<16;s=e[o>>1]|e[o+2>>1]<<16;b[p>>1]=s;b[p+2>>1]=s>>>16;b[o>>1]=n;b[o+2>>1]=n>>>16;p=p+-4|0;o=o+-4|0;n=b[o>>1]|0;if((e[p>>1]|0)>=(n&65535))break a;s=c[a+60>>2]|0}}while(0);p=c[a+72>>2]|0;r=e[u+((v&65535)<<6)+50>>1]|0;o=c[a+60>>2]|0;n=b[p+(r+-1<<2)>>1]|0;if((e[p+(r<<2)>>1]|0)<(n&65535)){s=o+((e[p+(r<<2)+2>>1]|0)<<6)+50|0;q=p+(r<<2)|0;p=p+(r+-1<<2)|0;while(1){t=e[p+2>>1]|0;n=(n&1)==0?o+(t<<6)+50|0:o+(t<<6)+56|0;b[n>>1]=(b[n>>1]|0)+1<<16>>16;b[s>>1]=(b[s>>1]|0)+-1<<16>>16;n=e[q>>1]|e[q+2>>1]<<16;t=e[p>>1]|e[p+2>>1]<<16;b[q>>1]=t;b[q+2>>1]=t>>>16;b[p>>1]=n;b[p+2>>1]=n>>>16;q=q+-4|0;p=p+-4|0;n=b[p>>1]|0;if((e[q>>1]|0)>=(n&65535))break;o=c[a+60>>2]|0}p=c[a+72>>2]|0}o=e[u+((v&65535)<<6)+56>>1]|0;q=p+(o<<2)|0;r=p+(o+-1<<2)|0;n=b[r>>1]|0;b:do if((e[q>>1]|0)<(n&65535)){s=c[a+60>>2]|0;t=s+((e[p+(o<<2)+2>>1]|0)<<6)+56|0;p=q;o=r;while(1){r=e[o+2>>1]|0;n=(n&1)==0?s+(r<<6)+50|0:s+(r<<6)+56|0;b[n>>1]=(b[n>>1]|0)+1<<16>>16;b[t>>1]=(b[t>>1]|0)+-1<<16>>16;n=e[p>>1]|e[p+2>>1]<<16;s=e[o>>1]|e[o+2>>1]<<16;b[p>>1]=s;b[p+2>>1]=s>>>16;b[o>>1]=n;b[o+2>>1]=n>>>16;p=p+-4|0;o=o+-4|0;n=b[o>>1]|0;if((e[p>>1]|0)>=(n&65535))break b;s=c[a+60>>2]|0}}while(0);ch(a,2,b[u+((v&65535)<<6)+52>>1]|0);_g(a,2,b[u+((v&65535)<<6)+58>>1]|0,m);o=c[a+60>>2]|0;n=c[a+108>>2]|0;if(!n){i=o+((v&65535)<<6)|0;l=w;return i|0}c[o+((v&65535)<<6)+60>>2]=Pb[c[(c[n>>2]|0)+8>>2]&3](n,d,f,h,i,j,k,m,0)|0;i=o+((v&65535)<<6)|0;l=w;return i|0}function md(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0,h=0.0,i=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0,q=0,r=0.0,s=0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0;z=l;l=l+48|0;switch(c[b+4>>2]|0){case 8:{c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;l=z;return}case 0:{w=+g[b+28>>2];x=+g[b+28+4>>2];x=+g[d+4>>2]>=0.0?x:-x;y=+g[b+28+8>>2];y=+g[d+8>>2]>=0.0?y:-y;g[a>>2]=+g[d>>2]>=0.0?w:-w;g[a+4>>2]=x;g[a+8>>2]=y;g[a+12>>2]=0.0;l=z;return}case 1:{u=+g[d>>2];v=+g[d+4>>2];w=+g[d+8>>2];x=u*+g[b+56>>2]+v*+g[b+56+4>>2]+w*+g[b+56+8>>2];y=u*+g[b+56+16>>2]+v*+g[b+56+20>>2]+w*+g[b+56+24>>2];w=u*+g[b+56+32>>2]+v*+g[b+56+36>>2]+w*+g[b+56+40>>2];g[z+32>>2]=x;g[z+32+4>>2]=y;g[z+32+8>>2]=w;g[z+32+12>>2]=0.0;p=+g[z+32+((x<y&1)<<2)>>2]<w?2:x<y&1;q=c[b+56+(p<<4)+4>>2]|0;s=c[b+56+(p<<4)+8>>2]|0;c[a>>2]=c[b+56+(p<<4)>>2];c[a+4>>2]=q;c[a+8>>2]=s;g[a+12>>2]=0.0;l=z;return}case 13:{c[z+32>>2]=c[b+28>>2];c[z+32+4>>2]=c[b+28+4>>2];c[z+32+8>>2]=c[b+28+8>>2];c[z+32+12>>2]=c[b+28+12>>2];c[z+16>>2]=c[d>>2];f=c[d+4>>2]|0;c[z+16+4>>2]=f;s=c[d+8>>2]|0;c[z+16+8>>2]=s;g[z+16+12>>2]=0.0;d=c[b+52>>2]|0;e=(c[j>>2]=s,+g[j>>2]);switch(d|0){case 2:{e=(c[j>>2]=f,+g[j>>2]);b=0;p=2;q=1;break}case 1:{b=0;p=1;q=2;break}default:{b=1;p=0;q=2}}o=+g[z+32+(b<<2)>>2];h=+g[z+32+(d<<2)>>2];m=+g[z+16+(b<<2)>>2];n=+C(+(m*m+e*e));i=+g[z+16+(p<<2)>>2];if(n!=0.0){k=o/n*e;f=z;h=i<0.0?-h:h;e=m*(o/n)}else{k=0.0;f=z;h=i<0.0?-h:h;e=o}g[z+(b<<2)>>2]=e;g[z+(p<<2)>>2]=h;g[z+(q<<2)>>2]=k;c[a>>2]=c[f>>2];c[a+4>>2]=c[z+4>>2];c[a+8>>2]=c[z+8>>2];g[a+12>>2]=0.0;l=z;return}case 10:{e=+g[d>>2];h=+g[d+4>>2];i=+g[d+8>>2];f=c[b+52>>2]|0;x=+g[b+28+(f<<2)>>2];k=+g[b+28+(((f+2|0)%3|0)<<2)>>2];if(e*e+h*h+i*i<9.999999747378752e-05){y=1.0;w=0.0;v=0.0}else{v=1.0/+C(+(e*e+h*h+i*i));y=e*v;w=h*v;v=i*v}c[z+32>>2]=0;c[z+32+4>>2]=0;c[z+32+8>>2]=0;c[z+32+12>>2]=0;g[z+32+(f<<2)>>2]=x;t=k*y;u=k*w;r=k*v;o=+g[b+44>>2];m=y*o;n=w*o;o=v*o;k=t+ +g[z+32>>2]-m;i=u+ +g[z+32+4>>2]-n;h=r+ +g[z+32+8>>2]-o;e=v*h+(y*k+w*i);if(e>-999999984306749440.0){q=(g[j>>2]=h,c[j>>2]|0);s=(g[j>>2]=i,c[j>>2]|0);h=e;p=(g[j>>2]=k,c[j>>2]|0)}else{h=-999999984306749440.0;p=0;q=0;s=0}c[z+32>>2]=0;c[z+32+4>>2]=0;c[z+32+8>>2]=0;c[z+32+12>>2]=0;g[z+32+(f<<2)>>2]=-x;t=t+ +g[z+32>>2]-m;x=u+ +g[z+32+4>>2]-n;e=r+ +g[z+32+8>>2]-o;b=v*e+(y*t+w*x)>h;f=(g[j>>2]=t,c[j>>2]|0);d=(g[j>>2]=x,c[j>>2]|0);q=b?(g[j>>2]=e,c[j>>2]|0):q;c[a>>2]=b?f:p;c[a+4>>2]=b?d:s;c[a+8>>2]=q;g[a+12>>2]=0.0;l=z;return}case 5:{q=c[b+92>>2]|0;p=c[b+96>>2]|0;o=+g[b+12>>2];r=+g[b+16>>2];n=+g[b+20>>2];k=+g[d>>2]*o;m=+g[d+4>>2]*r;i=+g[d+8>>2]*n;if((p|0)>0){b=0;h=-3402823466385288598117041.0e14;f=-1;while(1){e=k*+g[q+(b<<4)>>2]+m*+g[q+(b<<4)+4>>2]+i*+g[q+(b<<4)+8>>2];d=e>h;f=d?b:f;b=b+1|0;if((b|0)==(p|0))break;else h=d?e:h}}else f=-1;x=r*+g[q+(f<<4)+4>>2];y=n*+g[q+(f<<4)+8>>2];g[a>>2]=o*+g[q+(f<<4)>>2];g[a+4>>2]=x;g[a+8>>2]=y;g[a+12>>2]=0.0;l=z;return}case 4:{q=c[b+104>>2]|0;p=c[b+96>>2]|0;o=+g[b+12>>2];r=+g[b+16>>2];n=+g[b+20>>2];k=+g[d>>2]*o;m=+g[d+4>>2]*r;i=+g[d+8>>2]*n;if((p|0)>0){b=0;h=-3402823466385288598117041.0e14;f=-1;while(1){e=k*+g[q+(b<<4)>>2]+m*+g[q+(b<<4)+4>>2]+i*+g[q+(b<<4)+8>>2];d=e>h;f=d?b:f;b=b+1|0;if((b|0)==(p|0))break;else h=d?e:h}}else f=-1;x=r*+g[q+(f<<4)+4>>2];y=n*+g[q+(f<<4)+8>>2];g[a>>2]=o*+g[q+(f<<4)>>2];g[a+4>>2]=x;g[a+8>>2]=y;g[a+12>>2]=0.0;l=z;return}default:{Rb[c[(c[b>>2]|0)+68>>2]&127](a,b,d);l=z;return}}}function nd(a,b,d,e,f,g,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0;i=c[d+8>>2]|0;if(!i){a=0;return a|0}j=i;D=i;i=0;do{if((c[D+20>>2]|0)>(c[a+100>>2]|0)){y=c[D+12>>2]|0;w=c[y+88>>2]|0;A=w-(c[d+88>>2]|0)|0;x=c[y+92>>2]|0;B=x-(c[d+92>>2]|0)|0;y=c[y+96>>2]|0;C=y-(c[d+96>>2]|0)|0;k=Xr(c[g>>2]|0,c[g+4>>2]|0,A|0,((A|0)<0)<<31>>31|0)|0;n=z;j=Xr(c[g+8>>2]|0,c[g+8+4>>2]|0,B|0,((B|0)<0)<<31>>31|0)|0;n=xv(j|0,z|0,k|0,n|0)|0;k=z;j=Xr(c[g+16>>2]|0,c[g+16+4>>2]|0,C|0,((C|0)<0)<<31>>31|0)|0;j=xv(n|0,k|0,j|0,z|0)|0;k=z;n=Xr(c[f>>2]|0,c[f+4>>2]|0,A|0,((A|0)<0)<<31>>31|0)|0;v=z;m=Xr(c[f+8>>2]|0,c[f+8+4>>2]|0,B|0,((B|0)<0)<<31>>31|0)|0;v=xv(m|0,z|0,n|0,v|0)|0;n=z;m=Xr(c[f+16>>2]|0,c[f+16+4>>2]|0,C|0,((C|0)<0)<<31>>31|0)|0;m=xv(v|0,n|0,m|0,z|0)|0;n=z;if((k|0)>0|(k|0)==0&j>>>0>0){u=j;v=k;l=1}else{u=St(0,0,j|0,k|0)|0;u=(j|0)!=0|(k|0)!=0?u:0;v=(j|0)!=0|(k|0)!=0?z:0;l=((j|0)!=0|(k|0)!=0)<<31>>31}if(!((n|0)>0|(n|0)==0&m>>>0>0)){j=St(0,0,m|0,n|0)|0;j=(m|0)!=0|(n|0)!=0?j:0;k=(m|0)!=0|(n|0)!=0?z:0;if((j|0)!=0|(k|0)!=0|(l|0)!=0){t=j;l=(m|0)!=0|(n|0)!=0?0-l|0:l;o=8}}else{t=m;k=n;o=8}a:do if((o|0)==8){o=0;if(!i){c[h>>2]=u;c[h+4>>2]=v;c[h+8>>2]=t;c[h+8+4>>2]=k;c[h+16>>2]=l;i=D;break}j=c[h+16>>2]|0;if((l|0)==(j|0)){if(l|0){n=c[h+8>>2]|0;q=c[h+8+4>>2]|0;m=Xr(n|0,0,u|0,0)|0;j=z;r=Xr(q|0,0,u|0,0)|0;p=z;n=Xr(n|0,0,v|0,0)|0;o=z;q=Xr(q|0,0,v|0,0)|0;G=z;n=xv(r|0,0,n|0,0)|0;r=z;G=xv(p|0,0,q|0,G|0)|0;o=xv(G|0,z|0,o|0,0)|0;r=xv(o|0,z|0,r|0,0)|0;o=z;j=xv(0,n|0,m|0,j|0)|0;m=z;n=xv(r|0,o|0,(m>>>0<n>>>0|(m|0)==(n|0)&j>>>0<0)&1|0,0)|0;o=z;r=c[h>>2]|0;G=c[h+4>>2]|0;q=Xr(r|0,0,t|0,0)|0;p=z;E=Xr(G|0,0,t|0,0)|0;H=z;r=Xr(r|0,0,k|0,0)|0;s=z;G=Xr(G|0,0,k|0,0)|0;F=z;r=xv(E|0,0,r|0,0)|0;E=z;F=xv(H|0,0,G|0,F|0)|0;s=xv(F|0,z|0,s|0,0)|0;E=xv(s|0,z|0,E|0,0)|0;s=z;p=xv(0,r|0,q|0,p|0)|0;q=z;r=xv(E|0,s|0,(q>>>0<r>>>0|(q|0)==(r|0)&p>>>0<0)&1|0,0)|0;s=z;if(!(o>>>0<s>>>0|(o|0)==(s|0)&n>>>0<r>>>0))if(o>>>0>s>>>0|(o|0)==(s|0)&n>>>0>r>>>0)j=1;else j=m>>>0<q>>>0|(m|0)==(q|0)&j>>>0<p>>>0?-1:(m>>>0>q>>>0|(m|0)==(q|0)&j>>>0>p>>>0)&1;else j=-1;j=O(j,l)|0;o=17}}else{j=l-j|0;o=17}do if((o|0)==17){o=0;if((j|0)>=0)if(!j)break;else break a;else{c[h>>2]=u;c[h+4>>2]=v;c[h+8>>2]=t;c[h+8+4>>2]=k;c[h+16>>2]=l;i=D;break a}}while(0);j=(c[i+4>>2]|0)==(D|0);if((c[i>>2]|0)==(D|0))if(j){H=c[e+8>>2]|0;E=O(H,B)|0;u=c[e+4>>2]|0;E=E-(O(u,C)|0)|0;G=c[e>>2]|0;H=(O(G,C)|0)-(O(H,A)|0)|0;G=(O(u,A)|0)-(O(G,B)|0)|0;u=c[i+12>>2]|0;j=c[(c[D+8>>2]|0)+12>>2]|0;B=c[j+88>>2]|0;A=(c[u+88>>2]|0)-B|0;v=c[j+92>>2]|0;C=(c[u+92>>2]|0)-v|0;j=c[j+96>>2]|0;u=(c[u+96>>2]|0)-j|0;F=(O(y-j|0,C)|0)-(O(x-v|0,u)|0)|0;j=(O(w-B|0,u)|0)-(O(y-j|0,A)|0)|0;C=(O(x-v|0,A)|0)-(O(w-B|0,C)|0)|0;E=Xr(F|0,((F|0)<0)<<31>>31|0,E|0,((E|0)<0)<<31>>31|0)|0;F=z;H=Xr(j|0,((j|0)<0)<<31>>31|0,H|0,((H|0)<0)<<31>>31|0)|0;j=z;G=Xr(C|0,((C|0)<0)<<31>>31|0,G|0,((G|0)<0)<<31>>31|0)|0;G=xv(E|0,F|0,G|0,z|0)|0;j=xv(G|0,z|0,H|0,j|0)|0;H=z;j=(H|0)>0|(H|0)==0&j>>>0>0?2:1}else j=2;else j=j&1;i=(j|0)==2^b?i:D}while(0);j=c[d+8>>2]|0}D=c[D>>2]|0}while((D|0)!=(j|0));return i|0}function od(a,b){a=a|0;b=b|0;var d=0,e=0.0,f=0.0,h=0.0,i=0,k=0,m=0.0,n=0,o=0.0,p=0.0,q=0,r=0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,D=0.0,E=0.0,F=0,G=0,H=0,I=0,J=0,K=0;H=l;l=l+96|0;d=c[a+216>>2]|0;if(+g[d+4>>2]==0.0){G=0;l=H;return G|0}G=c[b>>2]|0;if(!(Gb[c[(c[d>>2]|0)+8>>2]&31](d,c[G+188>>2]|0)|0)){G=1;l=H;return G|0}b=c[G+192>>2]|0;F=c[a+216>>2]|0;if((c[b+4>>2]|0)!=32){c[H+32>>2]=0;c[H+32+4>>2]=b;c[H+32+8>>2]=G;c[H+32+12>>2]=G+4;c[H+32+16>>2]=-1;c[H+32+20>>2]=-1;Jc(a+68|0,a+132|0,H+32|0,F);G=1;l=H;return G|0}if((G|0)==0?1:(c[G+236>>2]|0)!=8){G=1;l=H;return G|0}if(c[G+752>>2]|0?(c[G+988>>2]|0)==0:0)Jg(G);B=+g[a+180>>2]-+g[a+116>>2];E=+g[a+184>>2]-+g[a+120>>2];D=+g[a+188>>2]-+g[a+124>>2];b=c[G+988>>2]|0;if(!b){i=c[G+752>>2]|0;if((i|0)>0){q=c[G+760>>2]|0;f=1.0;e=1.0;b=0;r=0;k=-1;n=1065353216;d=0;do{K=c[q+(r*44|0)+8>>2]|0;J=c[q+(r*44|0)+12>>2]|0;I=c[q+(r*44|0)+16>>2]|0;h=+lh(a+116|0,B,E,D,+g[K+8>>2],+g[K+12>>2],+g[K+16>>2],+g[J+8>>2],+g[J+12>>2],+g[J+16>>2],+g[I+8>>2],+g[I+12>>2],+g[I+16>>2],f);if(h>0.0){e=h;f=h;b=b+1|0;k=r;n=(g[j>>2]=h,c[j>>2]|0);d=3}r=r+1|0}while((r|0)!=(i|0))}else{e=1.0;b=0;k=-1;n=1065353216;d=0}}else{c[H+32>>2]=3348;c[H+32+4>>2]=c[a+116>>2];c[H+32+4+4>>2]=c[a+116+4>>2];c[H+32+4+8>>2]=c[a+116+8>>2];c[H+32+4+12>>2]=c[a+116+12>>2];g[H+32+36>>2]=B;g[H+32+40>>2]=E;g[H+32+44>>2]=D;g[H+32+48>>2]=0.0;c[H+32+20>>2]=c[a+180>>2];c[H+32+20+4>>2]=c[a+180+4>>2];c[H+32+20+8>>2]=c[a+180+8>>2];c[H+32+20+12>>2]=c[a+180+12>>2];c[H+32+52>>2]=1065353216;c[H+32+56>>2]=0;c[H+32+60>>2]=0;pe(b,a+116|0,a+180|0,H+32|0);b=c[H+32+56>>2]|0;if(!b){e=1.0;i=0;k=-1;n=1065353216;d=0}else{n=c[H+32+52>>2]|0;e=(c[j>>2]=n,+g[j>>2]);i=1;k=(b-(c[G+760>>2]|0)|0)/44|0;d=3}b=i}q=c[G+772>>2]|0;if((q|0)>0){r=c[G+780>>2]|0;i=0;do{K=c[r+(i*104|0)+8>>2]|0;v=+g[K+8>>2];w=+g[K+12>>2];x=+g[K+16>>2];K=c[r+(i*104|0)+12>>2]|0;m=+g[K+8>>2];o=+g[K+12>>2];p=+g[K+16>>2];K=c[r+(i*104|0)+16>>2]|0;y=+g[K+8>>2];z=+g[K+12>>2];A=+g[K+16>>2];f=(c[j>>2]=n,+g[j>>2]);h=+lh(a+116|0,B,E,D,v,w,x,m,o,p,y,z,A,f);if(h>0.0){f=h;e=h;b=b+1|0;k=i;n=(g[j>>2]=h,c[j>>2]|0);d=4}K=c[r+(i*104|0)+20>>2]|0;s=+g[K+8>>2];t=+g[K+12>>2];u=+g[K+16>>2];f=+lh(a+116|0,B,E,D,v,w,x,m,o,p,s,t,u,f);if(f>0.0){h=f;e=f;b=b+1|0;k=i;n=(g[j>>2]=f,c[j>>2]|0);d=4}else h=(c[j>>2]=n,+g[j>>2]);f=+lh(a+116|0,B,E,D,m,o,p,y,z,A,s,t,u,h);if(f>0.0){h=f;e=f;b=b+1|0;k=i;n=(g[j>>2]=f,c[j>>2]|0);d=4}else h=(c[j>>2]=n,+g[j>>2]);f=+lh(a+116|0,B,E,D,v,w,x,y,z,A,s,t,u,h);if(f>0.0){e=f;b=b+1|0;k=i;n=(g[j>>2]=f,c[j>>2]|0);d=4}i=i+1|0}while((i|0)!=(q|0));s=e}else s=e;if(!b){K=1;l=H;return K|0}if(!(s<=+g[F+4>>2])){K=1;l=H;return K|0}c[H+32>>2]=0;c[H+32+4>>2]=k;m=+g[a+180>>2]-+g[a+116>>2];p=+g[a+184>>2]-+g[a+120>>2];o=+g[a+188>>2]-+g[a+124>>2];e=1.0/+C(+(m*m+p*p+o*o));if((d|0)==3){b=c[G+748+12>>2]|0;e=+g[b+(k*44|0)+20>>2];h=+g[b+(k*44|0)+24>>2];f=+g[b+(k*44|0)+28>>2];if(m*e+p*h+o*f>0.0){m=-e;h=-h;f=-f;e=0.0}else{m=e;e=+g[b+(k*44|0)+32>>2]}}else{m=-(m*e);h=-(p*e);f=-(o*e);e=0.0}c[H>>2]=G;c[H+4>>2]=H+32;g[H+8>>2]=m;g[H+12>>2]=h;g[H+16>>2]=f;g[H+20>>2]=e;g[H+24>>2]=s;+Hb[c[(c[F>>2]|0)+12>>2]&15](F,H,1);K=1;l=H;return K|0}function pd(b,d,e,f,h,i,j,k,l,m,n,o,p){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;o=o|0;p=p|0;var q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0,z=0,A=0,B=0,C=0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0;B=O(c[l+24>>2]|0,m)|0;y=a[d+44>>0]|0;A=c[d+56>>2]|0;if(!(y<<24>>24!=0|(A|0)!=0)){d=0;return d|0}C=c[(o|0?l+12|0:l+8|0)>>2]|0;m=c[(o|0?l+20|0:l+16|0)>>2]|0;c[C+(B<<2)>>2]=c[n>>2];c[C+(B+1<<2)>>2]=c[n+4>>2];c[C+(B+2<<2)>>2]=c[n+8>>2];g[m+(B<<2)>>2]=-+g[n>>2];g[m+(B+1<<2)>>2]=-+g[n+4>>2];g[m+(B+2<<2)>>2]=-+g[n+8>>2];if(!o){q=+g[b+1176>>2];if(!(a[b+1301>>0]|0)){q=q-+g[e+48>>2];r=+g[b+1180>>2]-+g[e+52>>2];w=+g[b+1184>>2]-+g[e+56>>2];u=+g[n+8>>2];v=+g[n+4>>2];x=+g[n>>2];e=c[l+12>>2]|0;g[e+(B<<2)>>2]=r*u-w*v;g[e+(B+1<<2)>>2]=w*x-q*u;g[e+(B+2<<2)>>2]=q*v-r*x;x=+g[b+1176>>2]-+g[f+48>>2];r=+g[b+1180>>2]-+g[f+52>>2];v=+g[b+1184>>2]-+g[f+56>>2];q=+g[n+8>>2];u=+g[n+4>>2];w=+g[n>>2];e=c[l+20>>2]|0;g[e+(B<<2)>>2]=-(r*q-v*u);r=x*u-r*w;m=e;q=-(v*w-x*q)}else{I=q-+g[f+48>>2];H=+g[b+1180>>2]-+g[f+52>>2];F=+g[b+1184>>2]-+g[f+56>>2];r=+g[n>>2];G=+g[n+4>>2];E=+g[n+8>>2];K=+g[b+1112>>2]-+g[e+48>>2];u=+g[b+1116>>2]-+g[e+52>>2];q=+g[b+1120>>2]-+g[e+56>>2];w=+g[d+52>>2]-+g[d+48>>2];J=r*(r*K+G*u+E*q)+r*w-r*(I*r+H*G+F*E);D=G*(r*K+G*u+E*q)+G*w-G*(I*r+H*G+F*E);w=E*(r*K+G*u+E*q)+E*w-E*(I*r+H*G+F*E);x=+g[b+1272>>2];v=+g[b+1276>>2];t=E*(u-G*(r*K+G*u+E*q)+x*D)-G*(q-E*(r*K+G*u+E*q)+x*w);s=r*(q-E*(r*K+G*u+E*q)+x*w)-E*(K-r*(r*K+G*u+E*q)+x*J);q=G*(K-r*(r*K+G*u+E*q)+x*J)-r*(u-G*(r*K+G*u+E*q)+x*D);u=(H-G*(I*r+H*G+F*E)-v*D)*E-(F-E*(I*r+H*G+F*E)-v*w)*G;w=(F-E*(I*r+H*G+F*E)-v*w)*r-(I-r*(I*r+H*G+F*E)-v*J)*E;r=(I-r*(I*r+H*G+F*E)-v*J)*G-(H-G*(I*r+H*G+F*E)-v*D)*r;if(!((p|0)!=0|(a[b+1280>>0]|0)==0)){r=v*r;u=v*u;w=v*w;t=x*t;s=x*s;q=x*q}e=(c[l+12>>2]|0)+(B<<2)|0;g[e>>2]=t;g[e+4>>2]=s;g[e+8>>2]=q;e=c[l+20>>2]|0;g[e+(B<<2)>>2]=-u;m=e;q=-w}g[e+(B+1<<2)>>2]=q;g[m+(B+2<<2)>>2]=-r}if(A|0?+g[d>>2]==+g[d+4>>2]:0){m=c[l+28>>2]|0;g[m+(B<<2)>>2]=0.0;q=0.0}else z=12;do if((z|0)==12){e=c[l+28>>2]|0;g[e+(B<<2)>>2]=0.0;if(!(y<<24>>24)){if(A|0){m=e;q=0.0;break}else m=1;return m|0}c[(c[l+32>>2]|0)+(B<<2)>>2]=c[d+28>>2];if(A|0){m=e;q=+g[e+(B<<2)>>2];break}v=+g[d+8>>2];t=o|0?v:-v;q=+g[d+52>>2];r=+g[d>>2];s=+g[d+4>>2];u=+g[l>>2]*+g[d+32>>2];do if(!(r>s))if(!(r==s)){if(t/u<0.0)if(q>=r?r-t/u>q:0){q=(r-q)/(t/u);break}else{q=q<r?0.0:1.0;break}if(t/u>0.0)if(q<=s?s-t/u<q:0){q=(s-q)/(t/u);break}else{q=q>s?0.0:1.0;break}else q=0.0}else q=0.0;else q=1.0;while(0);g[e+(B<<2)>>2]=q*v+ +g[e+(B<<2)>>2];g[(c[l+36>>2]|0)+(B<<2)>>2]=-+g[d+12>>2];c[(c[l+40>>2]|0)+(B<<2)>>2]=c[d+12>>2];C=1;return C|0}while(0);K=+g[l>>2]*+g[d+32>>2];f=m+(B<<2)|0;g[f>>2]=q+ +g[d+48>>2]*(o|0?-K:K);c[(c[l+32>>2]|0)+(B<<2)>>2]=c[d+36>>2];e=c[l+36>>2]|0;m=c[l+40>>2]|0;if(+g[d>>2]==+g[d+4>>2]){g[e+(B<<2)>>2]=-3402823466385288598117041.0e14;g[m+(B<<2)>>2]=3402823466385288598117041.0e14;C=1;return C|0}g[e+(B<<2)>>2]=(A|0)==1?0.0:-3402823466385288598117041.0e14;g[m+(B<<2)>>2]=(A|0)==1?3402823466385288598117041.0e14:0.0;r=+g[d+40>>2];if(!(r>0.0)){C=1;return C|0}d=o|0?j:h;C=o|0?k:i;J=+g[n>>2];K=+g[n+4>>2];q=+g[n+8>>2];q=+g[d>>2]*J+ +g[d+4>>2]*K+ +g[d+8>>2]*q-(J*+g[C>>2]+K*+g[C+4>>2]+q*+g[C+8>>2]);if((A|0)==1){if(!(q<0.0)){C=1;return C|0}if(!(+g[f>>2]<-(r*q))){C=1;return C|0}g[f>>2]=-(r*q);C=1;return C|0}else{if(!(q>0.0)){C=1;return C|0}if(!(+g[f>>2]>-(r*q))){C=1;return C|0}g[f>>2]=-(r*q);C=1;return C|0}return 0}function qd(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0.0,j=0,k=0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0;v=l;l=l+544|0;j=h;k=j+36|0;do{c[j>>2]=0;j=j+4|0}while((j|0)<(k|0));c[v+384>>2]=a;c[v+384+4>>2]=d;o=+g[e>>2];F=+g[b>>2];n=+g[e+16>>2];i=+g[b+16>>2];m=+g[e+32>>2];G=+g[b+32>>2];w=+g[b+4>>2];H=+g[b+20>>2];x=+g[b+36>>2];t=+g[b+8>>2];r=+g[b+24>>2];p=+g[b+40>>2];E=+g[e+4>>2];D=+g[e+20>>2];B=+g[e+36>>2];A=+g[e+8>>2];z=+g[e+24>>2];y=+g[e+40>>2];g[v+384+8>>2]=o*F+n*i+m*G;g[v+384+12>>2]=o*w+n*H+m*x;g[v+384+16>>2]=o*t+n*r+m*p;g[v+384+20>>2]=0.0;g[v+384+24>>2]=F*E+i*D+G*B;g[v+384+28>>2]=w*E+H*D+x*B;g[v+384+32>>2]=t*E+r*D+p*B;g[v+384+36>>2]=0.0;g[v+384+40>>2]=F*A+i*z+G*y;g[v+384+44>>2]=w*A+H*z+x*y;g[v+384+48>>2]=t*A+r*z+p*y;g[v+384+52>>2]=0.0;p=+g[e+48>>2]-+g[b+48>>2];r=+g[e+52>>2]-+g[b+52>>2];t=+g[e+56>>2]-+g[b+56>>2];x=+g[b>>2];H=+g[e>>2];w=+g[b+16>>2];G=+g[e+16>>2];i=+g[b+32>>2];F=+g[e+32>>2];m=+g[b+4>>2];n=+g[b+20>>2];o=+g[b+36>>2];q=+g[b+8>>2];s=+g[b+24>>2];u=+g[b+40>>2];g[v+384+56>>2]=x*H+w*G+i*F;g[v+384+60>>2]=x*E+w*D+i*B;g[v+384+64>>2]=x*A+w*z+i*y;g[v+384+68>>2]=0.0;g[v+384+72>>2]=H*m+G*n+F*o;g[v+384+76>>2]=E*m+D*n+B*o;g[v+384+80>>2]=A*m+z*n+y*o;g[v+384+84>>2]=0.0;g[v+384+88>>2]=H*q+G*s+F*u;g[v+384+92>>2]=E*q+D*s+B*u;g[v+384+96>>2]=A*q+z*s+y*u;g[v+384+100>>2]=0.0;g[v+384+104>>2]=p*x+r*w+t*i;g[v+384+108>>2]=p*m+r*n+t*o;g[v+384+112>>2]=p*q+r*s+t*u;g[v+384+116>>2]=0.0;c[v+384+120>>2]=80;c[v+384+124>>2]=0;c[v+364>>2]=0;c[v+128>>2]=0;c[v+128+4>>2]=0;c[v+128+8>>2]=0;c[v+128+12>>2]=0;c[v+376>>2]=2;c[v+368>>2]=0;g[v+144>>2]=0.0;f=wc(v,v+384|0,f)|0;if(f|0){c[h>>2]=(f|0)==1?1:2;b=0;l=v;return b|0}f=c[v+372>>2]|0;if(!(c[f+32>>2]|0)){q=0.0;p=0.0;o=0.0;n=0.0;m=0.0;i=0.0}else{i=0.0;m=0.0;n=0.0;o=0.0;p=0.0;q=0.0;e=0;do{u=+g[f+16+(e<<2)>>2];a=c[v+384+120>>2]|0;k=c[v+384+124>>2]|0;d=(c[v+384>>2]|0)+(k>>1)|0;if(k&1)a=c[(c[d>>2]|0)+a>>2]|0;Rb[a&127](v+528|0,d,c[f+(e<<2)>>2]|0);o=o+u*+g[v+528>>2];p=p+u*+g[v+528+4>>2];q=q+u*+g[v+528+8>>2];f=c[(c[v+372>>2]|0)+(e<<2)>>2]|0;r=-+g[f>>2];s=-+g[f+4>>2];t=-+g[f+8>>2];f=c[v+384+120>>2]|0;k=c[v+384+124>>2]|0;a=(c[v+384+4>>2]|0)+(k>>1)|0;if(k&1)f=c[(c[a>>2]|0)+f>>2]|0;G=+g[v+384+24>>2]*r+ +g[v+384+28>>2]*s+ +g[v+384+32>>2]*t;F=+g[v+384+40>>2]*r+ +g[v+384+44>>2]*s+ +g[v+384+48>>2]*t;g[v+512>>2]=+g[v+384+8>>2]*r+ +g[v+384+12>>2]*s+ +g[v+384+16>>2]*t;g[v+512+4>>2]=G;g[v+512+8>>2]=F;g[v+512+12>>2]=0.0;Rb[f&127](v+528|0,a,v+512|0);F=+g[v+528>>2];G=+g[v+528+4>>2];H=+g[v+528+8>>2];i=i+u*(F*+g[v+384+56>>2]+G*+g[v+384+60>>2]+H*+g[v+384+64>>2]+ +g[v+384+104>>2]);m=m+u*(F*+g[v+384+72>>2]+G*+g[v+384+76>>2]+H*+g[v+384+80>>2]+ +g[v+384+108>>2]);n=n+u*(F*+g[v+384+88>>2]+G*+g[v+384+92>>2]+H*+g[v+384+96>>2]+ +g[v+384+112>>2]);e=e+1|0;f=c[v+372>>2]|0}while(e>>>0<(c[f+32>>2]|0)>>>0)}E=o*+g[b+16>>2]+p*+g[b+20>>2]+q*+g[b+24>>2]+ +g[b+52>>2];F=o*+g[b+32>>2]+p*+g[b+36>>2]+q*+g[b+40>>2]+ +g[b+56>>2];g[h+4>>2]=o*+g[b>>2]+p*+g[b+4>>2]+q*+g[b+8>>2]+ +g[b+48>>2];g[h+8>>2]=E;g[h+12>>2]=F;g[h+16>>2]=0.0;F=i*+g[b+16>>2]+m*+g[b+20>>2]+n*+g[b+24>>2]+ +g[b+52>>2];E=i*+g[b+32>>2]+m*+g[b+36>>2]+n*+g[b+40>>2]+ +g[b+56>>2];g[h+20>>2]=i*+g[b>>2]+m*+g[b+4>>2]+n*+g[b+8>>2]+ +g[b+48>>2];g[h+24>>2]=F;g[h+28>>2]=E;g[h+32>>2]=0.0;E=o-i;F=p-m;H=q-n;g[h+48>>2]=0.0;G=+C(+(E*E+F*F+H*H));g[h+52>>2]=G;G=G>9.999999747378752e-05?1.0/G:1.0;g[h+36>>2]=G*E;g[h+40>>2]=G*F;g[h+44>>2]=G*H;b=1;l=v;return b|0}function rd(b,d,e,f,h,i){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;var k=0,l=0,m=0.0,n=0,o=0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0,C=0,D=0;D=c[b+88>>2]|0;if((D|0)==(c[b+92>>2]|0)?(o=D|0?D<<1:1,(D|0)<(o|0)):0){if(!o){l=D;n=0}else{c[6432]=(c[6432]|0)+1;k=ec((o*152|3)+16|0)|0;if(!k)k=0;else{c[(k+4+15&-16)+-4>>2]=k;k=k+4+15&-16}l=c[b+88>>2]|0;n=k}if((l|0)>0){k=0;do{Th(n+(k*152|0)|0,(c[b+96>>2]|0)+(k*152|0)|0,152)|0;k=k+1|0}while((k|0)!=(l|0))}k=c[b+96>>2]|0;if(k|0){if(a[b+100>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[k+-4>>2]|0)}c[b+96>>2]=0}a[b+100>>0]=1;c[b+96>>2]=n;c[b+92>>2]=o;k=c[b+88>>2]|0}else k=D;c[b+88>>2]=k+1;C=c[b+96>>2]|0;c[C+(D*152|0)+140>>2]=h;c[C+(D*152|0)+16>>2]=0;c[C+(D*152|0)+16+4>>2]=0;c[C+(D*152|0)+16+8>>2]=0;c[C+(D*152|0)+16+12>>2]=0;g[C+(D*152|0)+48>>2]=-0.0;g[C+(D*152|0)+52>>2]=-0.0;g[C+(D*152|0)+56>>2]=-0.0;g[C+(D*152|0)+60>>2]=0.0;b=c[b+16>>2]|0;o=c[b+(e*244|0)+240>>2]|0;B=c[b+(f*244|0)+240>>2]|0;c[C+(D*152|0)+144>>2]=e;c[C+(D*152|0)+148>>2]=f;h=c[i+88>>2]|0;c[C+(D*152|0)+104>>2]=h;c[C+(D*152|0)+132>>2]=0;g[C+(D*152|0)+100>>2]=0.0;g[C+(D*152|0)+96>>2]=0.0;x=-+g[d>>2];y=-+g[d+4>>2];z=-+g[d+8>>2];g[C+(D*152|0)>>2]=x;g[C+(D*152|0)+4>>2]=y;g[C+(D*152|0)+8>>2]=z;g[C+(D*152|0)+12>>2]=0.0;A=(c[j>>2]=h,+g[j>>2]);if(o|0){k=(g[j>>2]=(+g[o+264>>2]*x+ +g[o+268>>2]*y+ +g[o+272>>2]*z)*+g[o+544>>2],c[j>>2]|0);l=(g[j>>2]=(+g[o+280>>2]*x+ +g[o+284>>2]*y+ +g[o+288>>2]*z)*+g[o+548>>2],c[j>>2]|0);n=(g[j>>2]=(+g[o+296>>2]*x+ +g[o+300>>2]*y+ +g[o+304>>2]*z)*+g[o+552>>2],c[j>>2]|0)}else{k=0;l=0;n=0}c[C+(D*152|0)+64>>2]=k;c[C+(D*152|0)+68>>2]=l;c[C+(D*152|0)+72>>2]=n;g[C+(D*152|0)+76>>2]=0.0;u=+g[d>>2];v=+g[d+4>>2];w=+g[d+8>>2];d=c[d+12>>2]|0;g[C+(D*152|0)+32>>2]=u;g[C+(D*152|0)+36>>2]=v;g[C+(D*152|0)+40>>2]=w;c[C+(D*152|0)+44>>2]=d;if(B|0){k=(g[j>>2]=(u*+g[B+264>>2]+v*+g[B+268>>2]+w*+g[B+272>>2])*+g[B+544>>2],c[j>>2]|0);l=(g[j>>2]=(u*+g[B+280>>2]+v*+g[B+284>>2]+w*+g[B+288>>2])*+g[B+548>>2],c[j>>2]|0);n=(g[j>>2]=(u*+g[B+296>>2]+v*+g[B+300>>2]+w*+g[B+304>>2])*+g[B+552>>2],c[j>>2]|0)}else{k=0;l=0;n=0}c[C+(D*152|0)+80>>2]=k;c[C+(D*152|0)+84>>2]=l;c[C+(D*152|0)+88>>2]=n;g[C+(D*152|0)+92>>2]=0.0;if(o|0){m=+g[o+264>>2]*x+ +g[o+268>>2]*y+ +g[o+272>>2]*z;p=+g[o+280>>2]*x+ +g[o+284>>2]*y+ +g[o+288>>2]*z;q=+g[o+296>>2]*x+ +g[o+300>>2]*y+ +g[o+304>>2]*z}else{m=0.0;p=0.0;q=0.0}if(B|0){r=+g[B+264>>2]*u+ +g[B+268>>2]*v+ +g[B+272>>2]*w;s=u*+g[B+280>>2]+v*+g[B+284>>2]+w*+g[B+288>>2];t=u*+g[B+296>>2]+v*+g[B+300>>2]+w*+g[B+304>>2]}else{r=0.0;s=0.0;t=0.0}s=1.0/(m*x+p*y+q*z+0.0+(r*u+s*v+t*w));g[C+(D*152|0)+108>>2]=s;if(o|0){p=+g[b+(e*244|0)+192>>2];q=+g[b+(e*244|0)+196>>2];r=+g[b+(e*244|0)+200>>2];m=(+g[b+(e*244|0)+176>>2]+ +g[b+(e*244|0)+208>>2])*0.0+(+g[b+(e*244|0)+180>>2]+ +g[b+(e*244|0)+212>>2])*0.0+(+g[b+(e*244|0)+184>>2]+ +g[b+(e*244|0)+216>>2])*0.0}else{p=0.0;q=0.0;r=0.0;m=0.0}m=m+(p*x+q*y+r*z);if(!B){t=0.0;x=0.0;z=0.0;y=-0.0;u=t*u;x=x*v;x=u+x;z=z*w;z=x+z;z=y+z;z=m+z;z=0.0-z;z=s*z;f=C+(D*152|0)+112|0;g[f>>2]=z;f=C+(D*152|0)+116|0;g[f>>2]=0.0;A=-A;f=C+(D*152|0)+120|0;g[f>>2]=A;f=C+(D*152|0)+124|0;c[f>>2]=h;return}t=+g[b+(f*244|0)+192>>2];x=+g[b+(f*244|0)+196>>2];z=+g[b+(f*244|0)+200>>2];y=(+g[b+(f*244|0)+176>>2]+ +g[b+(f*244|0)+208>>2])*-0.0+(+g[b+(f*244|0)+180>>2]+ +g[b+(f*244|0)+212>>2])*-0.0+(+g[b+(f*244|0)+184>>2]+ +g[b+(f*244|0)+216>>2])*-0.0;u=t*u;x=x*v;x=u+x;z=z*w;z=x+z;z=y+z;z=m+z;z=0.0-z;z=s*z;f=C+(D*152|0)+112|0;g[f>>2]=z;f=C+(D*152|0)+116|0;g[f>>2]=0.0;A=-A;f=C+(D*152|0)+120|0;g[f>>2]=A;f=C+(D*152|0)+124|0;c[f>>2]=h;return}function sd(b,d){b=b|0;d=d|0;var e=0,f=0.0,h=0,i=0,k=0,m=0.0,n=0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0;n=l;l=l+16|0;c[b+236>>2]=2;c[b+312>>2]=0;c[b+312+4>>2]=0;c[b+312+8>>2]=0;c[b+312+12>>2]=0;c[b+312+16>>2]=0;c[b+312+20>>2]=0;c[b+312+24>>2]=0;c[b+312+28>>2]=0;c[b+544>>2]=1065353216;c[b+548>>2]=1065353216;c[b+552>>2]=1065353216;g[b+556>>2]=0.0;c[b+348>>2]=1065353216;c[b+352>>2]=1065353216;c[b+356>>2]=1065353216;e=b+360|0;h=e+36|0;do{c[e>>2]=0;e=e+4|0}while((e|0)<(h|0));c[b+412>>2]=0;c[b+412+4>>2]=0;c[b+412+8>>2]=0;c[b+412+12>>2]=0;c[b+412+16>>2]=0;c[b+412+20>>2]=0;c[b+412+24>>2]=0;c[b+412+28>>2]=0;f=+g[d+92>>2];m=+g[d+96>>2];g[n+12>>2]=f;g[n+8>>2]=m;g[n+4>>2]=0.0;g[n>>2]=1.0;c[b+444>>2]=c[(f<0.0?n+4|0:f>1.0?n:n+12|0)>>2];g[n+4>>2]=0.0;g[n>>2]=1.0;c[b+448>>2]=c[(m<0.0?n+4|0:m>1.0?n:n+8|0)>>2];c[b+472>>2]=c[d+112>>2];c[b+476>>2]=c[d+116>>2];e=c[d+4>>2]|0;c[b+480>>2]=e;c[b+608>>2]=0;c[b+612>>2]=0;a[b+452>>0]=a[d+120>>0]|0;c[b+456>>2]=c[d+124>>2];c[b+460>>2]=c[d+128>>2];c[b+464>>2]=c[d+132>>2];c[b+468>>2]=c[d+136>>2];if(!e){c[b+4>>2]=c[d+8>>2];c[b+4+4>>2]=c[d+8+4>>2];c[b+4+8>>2]=c[d+8+8>>2];c[b+4+12>>2]=c[d+8+12>>2];c[b+20>>2]=c[d+24>>2];c[b+20+4>>2]=c[d+24+4>>2];c[b+20+8>>2]=c[d+24+8>>2];c[b+20+12>>2]=c[d+24+12>>2];c[b+36>>2]=c[d+40>>2];c[b+36+4>>2]=c[d+40+4>>2];c[b+36+8>>2]=c[d+40+8>>2];c[b+36+12>>2]=c[d+40+12>>2];c[b+52>>2]=c[d+56>>2];c[b+52+4>>2]=c[d+56+4>>2];c[b+52+8>>2]=c[d+56+8>>2];c[b+52+12>>2]=c[d+56+12>>2];e=b+20|0;h=b+36|0;i=b+52|0;k=b+4|0}else{jb[c[(c[e>>2]|0)+8>>2]&127](e,b+4|0);e=b+20|0;h=b+36|0;i=b+52|0;k=b+4|0}c[b+68>>2]=c[k>>2];c[b+68+4>>2]=c[k+4>>2];c[b+68+8>>2]=c[k+8>>2];c[b+68+12>>2]=c[k+12>>2];c[b+84>>2]=c[e>>2];c[b+84+4>>2]=c[e+4>>2];c[b+84+8>>2]=c[e+8>>2];c[b+84+12>>2]=c[e+12>>2];c[b+100>>2]=c[h>>2];c[b+100+4>>2]=c[h+4>>2];c[b+100+8>>2]=c[h+8>>2];c[b+100+12>>2]=c[h+12>>2];c[b+116>>2]=c[i>>2];c[b+116+4>>2]=c[i+4>>2];c[b+116+8>>2]=c[i+8>>2];c[b+116+12>>2]=c[i+12>>2];c[b+132>>2]=0;c[b+132+4>>2]=0;c[b+132+8>>2]=0;c[b+132+12>>2]=0;c[b+132+16>>2]=0;c[b+132+20>>2]=0;c[b+132+24>>2]=0;c[b+132+28>>2]=0;c[b+224>>2]=c[d+100>>2];c[b+232>>2]=c[d+104>>2];c[b+228>>2]=c[d+108>>2];jb[c[(c[b>>2]|0)+12>>2]&127](b,c[d+72>>2]|0);e=c[5812]|0;c[5812]=e+1;c[b+508>>2]=e;f=+g[d>>2];e=c[b+204>>2]|0;if(f==0.0){c[b+204>>2]=e|1;m=0.0}else{c[b+204>>2]=e&-2;m=1.0/f}g[b+344>>2]=m;p=f*+g[b+384>>2];o=f*+g[b+388>>2];g[b+364>>2]=f*+g[b+380>>2];g[b+368>>2]=p;g[b+372>>2]=o;g[b+376>>2]=0.0;f=+g[d+76>>2];h=f!=0.0?(g[j>>2]=1.0/f,c[j>>2]|0):0;f=+g[d+80>>2];e=f!=0.0?(g[j>>2]=1.0/f,c[j>>2]|0):0;f=+g[d+84>>2];d=f!=0.0?(g[j>>2]=1.0/f,c[j>>2]|0):0;c[b+396>>2]=h;c[b+400>>2]=e;c[b+404>>2]=d;g[b+408>>2]=0.0;r=m*+g[b+352>>2];x=m*+g[b+356>>2];g[b+560>>2]=m*+g[b+348>>2];g[b+564>>2]=r;g[b+568>>2]=x;g[b+572>>2]=0.0;x=+g[b+4>>2];r=(c[j>>2]=h,+g[j>>2]);w=+g[b+8>>2];f=(c[j>>2]=e,+g[j>>2]);v=+g[b+12>>2];o=(c[j>>2]=d,+g[j>>2]);u=+g[b+20>>2];t=+g[b+24>>2];s=+g[b+28>>2];q=+g[b+36>>2];p=+g[b+40>>2];m=+g[b+44>>2];g[b+264>>2]=x*x*r+w*w*f+v*v*o;g[b+268>>2]=x*r*u+w*f*t+v*o*s;g[b+272>>2]=x*r*q+w*f*p+v*o*m;g[b+276>>2]=0.0;g[b+280>>2]=x*r*u+w*f*t+v*o*s;g[b+284>>2]=u*r*u+t*f*t+s*o*s;g[b+288>>2]=r*u*q+f*t*p+o*s*m;g[b+292>>2]=0.0;g[b+296>>2]=x*r*q+w*f*p+v*o*m;g[b+300>>2]=u*r*q+t*f*p+s*o*m;g[b+304>>2]=q*r*q+p*f*p+m*o*m;g[b+308>>2]=0.0;c[b+504>>2]=0;c[b+512>>2]=0;c[b+512+4>>2]=0;c[b+512+8>>2]=0;c[b+512+12>>2]=0;c[b+512+16>>2]=0;c[b+512+20>>2]=0;c[b+512+24>>2]=0;c[b+512+28>>2]=0;m=+g[b+344>>2];o=m*+g[b+352>>2];p=m*+g[b+356>>2];g[b+560>>2]=+g[b+348>>2]*m;g[b+564>>2]=o;g[b+568>>2]=p;e=b+572|0;h=e+36|0;do{c[e>>2]=0;e=e+4|0}while((e|0)<(h|0));l=n;return}function td(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0,L=0,M=0,N=0,O=0;h=l;l=l+240|0;if(!(c[b+16>>2]|0)){K=c[b+12>>2]|0;b=c[b+20>>2]|0;x=+g[d>>2];q=+g[d+4>>2];u=+g[d+8>>2];j=+g[d+16>>2];r=+g[d+20>>2];i=+g[d+24>>2];m=+g[d+32>>2];s=+g[d+36>>2];n=+g[d+40>>2];F=+g[d+48>>2];E=+g[d+52>>2];D=+g[d+56>>2];J=+g[e>>2];I=+g[e+16>>2];z=+g[e+32>>2];H=+g[e+4>>2];G=+g[e+20>>2];y=+g[e+36>>2];v=+g[e+8>>2];k=+g[e+24>>2];p=+g[e+40>>2];C=-+g[e+48>>2];B=-+g[e+52>>2];w=-+g[e+56>>2];d=c[(c[K>>2]|0)+64>>2]|0;A=-+g[b+48>>2];t=-+g[b+52>>2];o=-+g[b+56>>2];g[h+16>>2]=(x*J+j*I+m*z)*A+(x*H+j*G+m*y)*t+(x*v+j*k+m*p)*o;g[h+16+4>>2]=(q*J+r*I+s*z)*A+(q*H+r*G+s*y)*t+(q*v+r*k+s*p)*o;g[h+16+8>>2]=(u*J+i*I+n*z)*A+(u*H+i*G+n*y)*t+(u*v+i*k+n*p)*o;g[h+16+12>>2]=0.0;Rb[d&127](h+152|0,K,h+16|0);o=+g[h+152>>2];t=+g[h+152+4>>2];A=+g[h+152+8>>2];z=F*J+E*I+D*z+(J*C+I*B+z*w)+((x*J+j*I+m*z)*o+(q*J+r*I+s*z)*t+(u*J+i*I+n*z)*A);y=F*H+E*G+D*y+(H*C+G*B+y*w)+((x*H+j*G+m*y)*o+(q*H+r*G+s*y)*t+(u*H+i*G+n*y)*A);A=F*v+E*k+D*p+(v*C+k*B+p*w)+((x*v+j*k+m*p)*o+(q*v+r*k+s*p)*t+(u*v+i*k+n*p)*A);p=+g[b+48>>2];n=+g[b+52>>2];k=+g[b+56>>2];i=k*A+(p*z+n*y)-+g[b+64>>2];v=+g[e>>2];u=+g[e+4>>2];t=+g[e+8>>2];s=+g[e+16>>2];r=+g[e+20>>2];q=+g[e+24>>2];o=+g[e+32>>2];m=+g[e+36>>2];j=+g[e+40>>2];x=(z-p*i)*s+(y-n*i)*r+(A-k*i)*q+ +g[e+52>>2];w=(z-p*i)*o+(y-n*i)*m+(A-k*i)*j+ +g[e+56>>2];g[h+16>>2]=t*(A-k*i)+(v*(z-p*i)+u*(y-n*i))+ +g[e+48>>2];g[h+16+4>>2]=x;g[h+16+8>>2]=w;g[h+16+12>>2]=0.0;g[h>>2]=v*p+u*n+t*k;g[h+4>>2]=p*s+n*r+k*q;g[h+8>>2]=p*o+n*m+k*j;g[h+12>>2]=0.0;Qb[c[(c[f>>2]|0)+16>>2]&15](f,h,h+16|0,i);l=h;return}else{N=c[b+4>>2]|0;a[N+312>>0]=0;c[N>>2]=0;a[N+356>>0]=1;c[N+292>>2]=1566444395;c[N+296>>2]=1566444395;c[N+300>>2]=1566444395;g[N+304>>2]=0.0;c[N+336>>2]=0;c[N+336+4>>2]=0;c[N+336+8>>2]=0;c[N+336+12>>2]=0;a[N+336+16>>0]=0;a[N+332>>0]=a[N+332>>0]&-16;N=c[b+12>>2]|0;M=c[b+16>>2]|0;L=c[N+4>>2]|0;K=c[M+4>>2]|0;I=+zb[c[(c[N>>2]|0)+48>>2]&15](N);O=c[b+16>>2]|0;J=+zb[c[(c[O>>2]|0)+48>>2]&15](O);O=c[b+4>>2]|0;b=c[b+8>>2]|0;c[h+152>>2]=9360;c[h+152+4>>2]=0;c[h+152+8>>2]=1065353216;c[h+152+12>>2]=0;g[h+152+16>>2]=0.0;c[h+152+20>>2]=b;c[h+152+24>>2]=O;c[h+152+28>>2]=N;c[h+152+32>>2]=M;c[h+152+36>>2]=L;c[h+152+40>>2]=K;g[h+152+44>>2]=I;g[h+152+48>>2]=J;a[h+152+52>>0]=0;c[h+152+60>>2]=-1;c[h+152+72>>2]=1;c[h+152+76>>2]=1;g[h+16+128>>2]=999999984306749440.0;c[h+16>>2]=c[d>>2];c[h+16+4>>2]=c[d+4>>2];c[h+16+8>>2]=c[d+8>>2];c[h+16+12>>2]=c[d+12>>2];c[h+16+16>>2]=c[d+16>>2];c[h+16+16+4>>2]=c[d+16+4>>2];c[h+16+16+8>>2]=c[d+16+8>>2];c[h+16+16+12>>2]=c[d+16+12>>2];c[h+16+32>>2]=c[d+32>>2];c[h+16+32+4>>2]=c[d+32+4>>2];c[h+16+32+8>>2]=c[d+32+8>>2];c[h+16+32+12>>2]=c[d+32+12>>2];c[h+16+48>>2]=c[d+48>>2];c[h+16+48+4>>2]=c[d+48+4>>2];c[h+16+48+8>>2]=c[d+48+8>>2];c[h+16+48+12>>2]=c[d+48+12>>2];c[h+16+64>>2]=c[e>>2];c[h+16+64+4>>2]=c[e+4>>2];c[h+16+64+8>>2]=c[e+8>>2];c[h+16+64+12>>2]=c[e+12>>2];c[h+16+80>>2]=c[e+16>>2];c[h+16+80+4>>2]=c[e+16+4>>2];c[h+16+80+8>>2]=c[e+16+8>>2];c[h+16+80+12>>2]=c[e+16+12>>2];c[h+16+96>>2]=c[e+32>>2];c[h+16+96+4>>2]=c[e+32+4>>2];c[h+16+96+8>>2]=c[e+32+8>>2];c[h+16+96+12>>2]=c[e+32+12>>2];c[h+16+112>>2]=c[e+48>>2];c[h+16+112+4>>2]=c[e+48+4>>2];c[h+16+112+8>>2]=c[e+48+8>>2];c[h+16+112+12>>2]=c[e+48+12>>2];Ac(h+152|0,h+16|0,f,0,0);l=h;return}}function ud(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=+h;var i=0,j=0,k=0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0,t=0.0;i=l;l=l+464|0;Yi(15855);c[i+128>>2]=c[d>>2];c[i+128+4>>2]=c[d+4>>2];c[i+128+8>>2]=c[d+8>>2];c[i+128+12>>2]=c[d+12>>2];c[i+128+16>>2]=c[d+16>>2];c[i+128+16+4>>2]=c[d+16+4>>2];c[i+128+16+8>>2]=c[d+16+8>>2];c[i+128+16+12>>2]=c[d+16+12>>2];c[i+128+32>>2]=c[d+32>>2];c[i+128+32+4>>2]=c[d+32+4>>2];c[i+128+32+8>>2]=c[d+32+8>>2];c[i+128+32+12>>2]=c[d+32+12>>2];k=i+128+48|0;c[k>>2]=c[d+48>>2];c[k+4>>2]=c[d+48+4>>2];c[k+8>>2]=c[d+48+8>>2];c[k+12>>2]=c[d+48+12>>2];c[i+64>>2]=c[e>>2];c[i+64+4>>2]=c[e+4>>2];c[i+64+8>>2]=c[e+8>>2];c[i+64+12>>2]=c[e+12>>2];c[i+64+16>>2]=c[e+16>>2];c[i+64+16+4>>2]=c[e+16+4>>2];c[i+64+16+8>>2]=c[e+16+8>>2];c[i+64+16+12>>2]=c[e+16+12>>2];c[i+64+32>>2]=c[e+32>>2];c[i+64+32+4>>2]=c[e+32+4>>2];c[i+64+32+8>>2]=c[e+32+8>>2];c[i+64+32+12>>2]=c[e+32+12>>2];j=i+64+48|0;c[j>>2]=c[e+48>>2];c[j+4>>2]=c[e+48+4>>2];c[j+8>>2]=c[e+48+8>>2];c[j+12>>2]=c[e+48+12>>2];rf(i+128|0,i+64|0,i+256|0,i+192|0);t=+g[i+192>>2];m=t*+g[i+256+4>>2];r=t*+g[i+256+8>>2];g[i+16>>2]=+g[i+256>>2]*t;g[i+16+4>>2]=m;g[i+16+8>>2]=r;g[i+16+12>>2]=0.0;c[i+256>>2]=0;c[i+256+4>>2]=0;c[i+256+8>>2]=0;c[i+256+12>>2]=0;c[i+192+48>>2]=0;c[i+192+48+4>>2]=0;c[i+192+48+8>>2]=0;c[i+192+48+12>>2]=0;eh(i+128|0,i);r=+g[i>>2];m=+g[i+4>>2];t=+g[i+8>>2];q=+g[i+12>>2];o=r*(2.0/(r*r+m*m+t*t+q*q));n=m*(2.0/(r*r+m*m+t*t+q*q));p=t*(2.0/(r*r+m*m+t*t+q*q));g[i+192>>2]=1.0-(m*n+t*p);g[i+192+4>>2]=r*n-q*p;g[i+192+8>>2]=r*p+q*n;g[i+192+12>>2]=0.0;g[i+192+16>>2]=r*n+q*p;g[i+192+20>>2]=1.0-(r*o+t*p);g[i+192+24>>2]=m*p-q*o;g[i+192+28>>2]=0.0;g[i+192+32>>2]=r*p-q*n;g[i+192+36>>2]=m*p+q*o;g[i+192+40>>2]=1.0-(r*o+m*n);g[i+192+44>>2]=0.0;Sg(b,i+192|0,i+256|0,i+16|0,i+48|0,i+32|0);c[i+256>>2]=6060;c[i+256+36>>2]=c[d>>2];c[i+256+36+4>>2]=c[d+4>>2];c[i+256+36+8>>2]=c[d+8>>2];c[i+256+36+12>>2]=c[d+12>>2];c[i+256+52>>2]=c[d+16>>2];c[i+256+52+4>>2]=c[d+16+4>>2];c[i+256+52+8>>2]=c[d+16+8>>2];c[i+256+52+12>>2]=c[d+16+12>>2];c[i+256+68>>2]=c[d+32>>2];c[i+256+68+4>>2]=c[d+32+4>>2];c[i+256+68+8>>2]=c[d+32+8>>2];c[i+256+68+12>>2]=c[d+32+12>>2];s=i+256+84|0;c[s>>2]=c[d+48>>2];c[s+4>>2]=c[d+48+4>>2];c[s+8>>2]=c[d+48+8>>2];c[s+12>>2]=c[d+48+12>>2];c[i+256+100>>2]=c[e>>2];c[i+256+100+4>>2]=c[e+4>>2];c[i+256+100+8>>2]=c[e+8>>2];c[i+256+100+12>>2]=c[e+12>>2];c[i+256+116>>2]=c[e+16>>2];c[i+256+116+4>>2]=c[e+16+4>>2];c[i+256+116+8>>2]=c[e+16+8>>2];c[i+256+116+12>>2]=c[e+16+12>>2];c[i+256+132>>2]=c[e+32>>2];c[i+256+132+4>>2]=c[e+32+4>>2];c[i+256+132+8>>2]=c[e+32+8>>2];c[i+256+132+12>>2]=c[e+32+12>>2];d=i+256+148|0;c[d>>2]=c[e+48>>2];c[d+4>>2]=c[e+48+4>>2];c[d+8>>2]=c[e+48+8>>2];c[d+12>>2]=c[e+48+12>>2];c[i+256+180>>2]=a;c[i+256+184>>2]=f;g[i+256+188>>2]=h;c[i+256+192>>2]=b;n=+g[d>>2]-+g[s>>2];m=+g[i+256+152>>2]-+g[i+256+88>>2];o=+g[i+256+156>>2]-+g[i+256+92>>2];h=1.0/+C(+(n*n+m*m+o*o));r=n*h==0.0?999999984306749440.0:1.0/(n*h);g[i+256+4>>2]=r;q=m*h==0.0?999999984306749440.0:1.0/(m*h);g[i+256+8>>2]=q;p=o*h==0.0?999999984306749440.0:1.0/(o*h);g[i+256+12>>2]=p;c[i+256+20>>2]=r<0.0&1;c[i+256+24>>2]=q<0.0&1;c[i+256+28>>2]=p<0.0&1;g[i+256+32>>2]=o*o*h+(n*n*h+m*m*h);b=c[a+68>>2]|0;xb[c[(c[b>>2]|0)+24>>2]&7](b,k,j,i+256|0,i+48|0,i+32|0);b=c[2395]|0;a=(c[b+16>>2]|0)+-1|0;c[b+16>>2]=a;if(a|0){l=i;return}do if(c[b+4>>2]|0){Va(i+256|0,0)|0;s=c[6431]|0;g[b+8>>2]=+g[b+8>>2]+ +(((c[i+256+4>>2]|0)-(c[s+4>>2]|0)+(((c[i+256>>2]|0)-(c[s>>2]|0)|0)*1e6|0)-(c[b+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[b+16>>2]|0)){b=c[2395]|0;break}else{l=i;return}}while(0);c[2395]=c[b+20>>2];l=i;return}\nfunction ec(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0;H=l;l=l+16|0;do if(a>>>0<245){r=a>>>0<11?16:a+11&-8;o=c[6450]|0;if(o>>>(r>>>3)&3|0){d=25840+((o>>>(r>>>3)&1^1)+(r>>>3)<<1<<2)|0;a=c[d+8>>2]|0;b=c[a+8>>2]|0;do if((d|0)!=(b|0)){if(b>>>0<(c[6454]|0)>>>0)Qa();if((c[b+12>>2]|0)==(a|0)){c[b+12>>2]=d;c[d+8>>2]=b;break}else Qa()}else c[6450]=o&~(1<<(o>>>(r>>>3)&1^1)+(r>>>3));while(0);G=(o>>>(r>>>3)&1^1)+(r>>>3)<<3;c[a+4>>2]=G|3;c[a+G+4>>2]=c[a+G+4>>2]|1;G=a+8|0;l=H;return G|0}p=c[6452]|0;if(r>>>0>p>>>0){if(o>>>(r>>>3)|0){a=o>>>(r>>>3)<<(r>>>3)&(2<<(r>>>3)|0-(2<<(r>>>3)));d=((a&0-a)+-1|0)>>>(((a&0-a)+-1|0)>>>12&16);e=d>>>(d>>>5&8)>>>(d>>>(d>>>5&8)>>>2&4);e=(d>>>5&8|((a&0-a)+-1|0)>>>12&16|d>>>(d>>>5&8)>>>2&4|e>>>1&2|e>>>(e>>>1&2)>>>1&1)+(e>>>(e>>>1&2)>>>(e>>>(e>>>1&2)>>>1&1))|0;d=c[25840+(e<<1<<2)+8>>2]|0;a=c[d+8>>2]|0;do if((25840+(e<<1<<2)|0)!=(a|0)){if(a>>>0<(c[6454]|0)>>>0)Qa();if((c[a+12>>2]|0)==(d|0)){c[a+12>>2]=25840+(e<<1<<2);c[25840+(e<<1<<2)+8>>2]=a;f=o;break}else Qa()}else{c[6450]=o&~(1<<e);f=o&~(1<<e)}while(0);c[d+4>>2]=r|3;c[d+r+4>>2]=(e<<3)-r|1;c[d+r+((e<<3)-r)>>2]=(e<<3)-r;if(p|0){b=c[6455]|0;if(f&1<<(p>>>3)){a=c[25840+(p>>>3<<1<<2)+8>>2]|0;if(a>>>0<(c[6454]|0)>>>0)Qa();else{h=25840+(p>>>3<<1<<2)+8|0;i=a}}else{c[6450]=f|1<<(p>>>3);h=25840+(p>>>3<<1<<2)+8|0;i=25840+(p>>>3<<1<<2)|0}c[h>>2]=b;c[i+12>>2]=b;c[b+8>>2]=i;c[b+12>>2]=25840+(p>>>3<<1<<2)}c[6452]=(e<<3)-r;c[6455]=d+r;G=d+8|0;l=H;return G|0}k=c[6451]|0;if(k){b=((k&0-k)+-1|0)>>>(((k&0-k)+-1|0)>>>12&16);d=b>>>(b>>>5&8)>>>(b>>>(b>>>5&8)>>>2&4);d=c[26104+((b>>>5&8|((k&0-k)+-1|0)>>>12&16|b>>>(b>>>5&8)>>>2&4|d>>>1&2|d>>>(d>>>1&2)>>>1&1)+(d>>>(d>>>1&2)>>>(d>>>(d>>>1&2)>>>1&1))<<2)>>2]|0;b=(c[d+4>>2]&-8)-r|0;a=c[d+16+(((c[d+16>>2]|0)==0&1)<<2)>>2]|0;if(!a)j=b;else{do{F=(c[a+4>>2]&-8)-r|0;G=F>>>0<b>>>0;b=G?F:b;d=G?a:d;a=c[a+16+(((c[a+16>>2]|0)==0&1)<<2)>>2]|0}while((a|0)!=0);j=b}g=c[6454]|0;if(d>>>0<g>>>0)Qa();i=d+r|0;if(d>>>0>=i>>>0)Qa();h=c[d+24>>2]|0;a=c[d+12>>2]|0;do if((a|0)==(d|0)){b=d+20|0;a=c[b>>2]|0;if(!a){b=d+16|0;a=c[b>>2]|0;if(!a){m=0;break}}while(1){f=a+20|0;e=c[f>>2]|0;if(e|0){a=e;b=f;continue}f=a+16|0;e=c[f>>2]|0;if(!e)break;else{a=e;b=f}}if(b>>>0<g>>>0)Qa();else{c[b>>2]=0;m=a;break}}else{b=c[d+8>>2]|0;if(b>>>0<g>>>0)Qa();if((c[b+12>>2]|0)!=(d|0))Qa();if((c[a+8>>2]|0)==(d|0)){c[b+12>>2]=a;c[a+8>>2]=b;m=a;break}else Qa()}while(0);a:do if(h|0){a=c[d+28>>2]|0;do if((d|0)==(c[26104+(a<<2)>>2]|0)){c[26104+(a<<2)>>2]=m;if(!m){c[6451]=k&~(1<<a);break a}}else if(h>>>0>=(c[6454]|0)>>>0){c[h+16+(((c[h+16>>2]|0)!=(d|0)&1)<<2)>>2]=m;if(!m)break a;else break}else Qa();while(0);b=c[6454]|0;if(m>>>0<b>>>0)Qa();c[m+24>>2]=h;a=c[d+16>>2]|0;do if(a|0)if(a>>>0<b>>>0)Qa();else{c[m+16>>2]=a;c[a+24>>2]=m;break}while(0);a=c[d+20>>2]|0;if(a|0)if(a>>>0<(c[6454]|0)>>>0)Qa();else{c[m+20>>2]=a;c[a+24>>2]=m;break}}while(0);if(j>>>0<16){G=j+r|0;c[d+4>>2]=G|3;G=d+G+4|0;c[G>>2]=c[G>>2]|1}else{c[d+4>>2]=r|3;c[i+4>>2]=j|1;c[i+j>>2]=j;if(p|0){b=c[6455]|0;if(o&1<<(p>>>3)){a=c[25840+(p>>>3<<1<<2)+8>>2]|0;if(a>>>0<(c[6454]|0)>>>0)Qa();else{n=25840+(p>>>3<<1<<2)+8|0;q=a}}else{c[6450]=o|1<<(p>>>3);n=25840+(p>>>3<<1<<2)+8|0;q=25840+(p>>>3<<1<<2)|0}c[n>>2]=b;c[q+12>>2]=b;c[b+8>>2]=q;c[b+12>>2]=25840+(p>>>3<<1<<2)}c[6452]=j;c[6455]=i}G=d+8|0;l=H;return G|0}}}else if(a>>>0<=4294967231){r=a+11&-8;k=c[6451]|0;if(k){if((a+11|0)>>>8)if(r>>>0>16777215)j=31;else{j=(a+11|0)>>>8<<((((a+11|0)>>>8)+1048320|0)>>>16&8);j=14-((j+520192|0)>>>16&4|(((a+11|0)>>>8)+1048320|0)>>>16&8|((j<<((j+520192|0)>>>16&4))+245760|0)>>>16&2)+(j<<((j+520192|0)>>>16&4)<<(((j<<((j+520192|0)>>>16&4))+245760|0)>>>16&2)>>>15)|0;j=r>>>(j+7|0)&1|j<<1}else j=0;a=c[26104+(j<<2)>>2]|0;b:do if(!a){d=0-r|0;a=0;b=0;z=81}else{h=0-r|0;f=0;i=r<<((j|0)==31?0:25-(j>>>1)|0);b=0;while(1){d=(c[a+4>>2]&-8)-r|0;if(d>>>0<h>>>0)if(!d){d=0;e=a;b=a;z=85;break b}else b=a;else d=h;e=c[a+20>>2]|0;a=c[a+16+(i>>>31<<2)>>2]|0;f=(e|0)==0|(e|0)==(a|0)?f:e;e=(a|0)==0;if(e){a=f;z=81;break}else{h=d;i=i<<((e^1)&1)}}}while(0);if((z|0)==81){if((a|0)==0&(b|0)==0){a=2<<j;if(!(k&(a|0-a)))break;q=(k&(a|0-a)&0-(k&(a|0-a)))+-1|0;b=q>>>(q>>>12&16)>>>(q>>>(q>>>12&16)>>>5&8);a=b>>>(b>>>2&4)>>>(b>>>(b>>>2&4)>>>1&2);a=c[26104+((q>>>(q>>>12&16)>>>5&8|q>>>12&16|b>>>2&4|b>>>(b>>>2&4)>>>1&2|a>>>1&1)+(a>>>(a>>>1&1))<<2)>>2]|0;b=0}if(!a){i=d;j=b}else{e=a;z=85}}if((z|0)==85)while(1){z=0;a=(c[e+4>>2]&-8)-r|0;q=a>>>0<d>>>0;a=q?a:d;b=q?e:b;e=c[e+16+(((c[e+16>>2]|0)==0&1)<<2)>>2]|0;if(!e){i=a;j=b;break}else{d=a;z=85}}if((j|0)!=0?i>>>0<((c[6452]|0)-r|0)>>>0:0){f=c[6454]|0;if(j>>>0<f>>>0)Qa();h=j+r|0;if(j>>>0>=h>>>0)Qa();g=c[j+24>>2]|0;a=c[j+12>>2]|0;do if((a|0)==(j|0)){b=j+20|0;a=c[b>>2]|0;if(!a){b=j+16|0;a=c[b>>2]|0;if(!a){o=0;break}}while(1){e=a+20|0;d=c[e>>2]|0;if(d|0){a=d;b=e;continue}e=a+16|0;d=c[e>>2]|0;if(!d)break;else{a=d;b=e}}if(b>>>0<f>>>0)Qa();else{c[b>>2]=0;o=a;break}}else{b=c[j+8>>2]|0;if(b>>>0<f>>>0)Qa();if((c[b+12>>2]|0)!=(j|0))Qa();if((c[a+8>>2]|0)==(j|0)){c[b+12>>2]=a;c[a+8>>2]=b;o=a;break}else Qa()}while(0);c:do if(g){a=c[j+28>>2]|0;do if((j|0)==(c[26104+(a<<2)>>2]|0)){c[26104+(a<<2)>>2]=o;if(!o){c[6451]=k&~(1<<a);v=k&~(1<<a);break c}}else if(g>>>0>=(c[6454]|0)>>>0){c[g+16+(((c[g+16>>2]|0)!=(j|0)&1)<<2)>>2]=o;if(!o){v=k;break c}else break}else Qa();while(0);b=c[6454]|0;if(o>>>0<b>>>0)Qa();c[o+24>>2]=g;a=c[j+16>>2]|0;do if(a|0)if(a>>>0<b>>>0)Qa();else{c[o+16>>2]=a;c[a+24>>2]=o;break}while(0);a=c[j+20>>2]|0;if(a)if(a>>>0<(c[6454]|0)>>>0)Qa();else{c[o+20>>2]=a;c[a+24>>2]=o;v=k;break}else v=k}else v=k;while(0);do if(i>>>0>=16){c[j+4>>2]=r|3;c[h+4>>2]=i|1;c[h+i>>2]=i;b=i>>>3;if(i>>>0<256){a=c[6450]|0;if(a&1<<b){a=c[25840+(b<<1<<2)+8>>2]|0;if(a>>>0<(c[6454]|0)>>>0)Qa();else{p=25840+(b<<1<<2)+8|0;u=a}}else{c[6450]=a|1<<b;p=25840+(b<<1<<2)+8|0;u=25840+(b<<1<<2)|0}c[p>>2]=h;c[u+12>>2]=h;c[h+8>>2]=u;c[h+12>>2]=25840+(b<<1<<2);break}a=i>>>8;if(a)if(i>>>0>16777215)a=31;else{G=a<<((a+1048320|0)>>>16&8)<<(((a<<((a+1048320|0)>>>16&8))+520192|0)>>>16&4);a=14-(((a<<((a+1048320|0)>>>16&8))+520192|0)>>>16&4|(a+1048320|0)>>>16&8|(G+245760|0)>>>16&2)+(G<<((G+245760|0)>>>16&2)>>>15)|0;a=i>>>(a+7|0)&1|a<<1}else a=0;d=26104+(a<<2)|0;c[h+28>>2]=a;c[h+16+4>>2]=0;c[h+16>>2]=0;b=1<<a;if(!(v&b)){c[6451]=v|b;c[d>>2]=h;c[h+24>>2]=d;c[h+12>>2]=h;c[h+8>>2]=h;break}b=i<<((a|0)==31?0:25-(a>>>1)|0);e=c[d>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(i|0)){z=139;break}d=e+16+(b>>>31<<2)|0;a=c[d>>2]|0;if(!a){z=136;break}else{b=b<<1;e=a}}if((z|0)==136)if(d>>>0<(c[6454]|0)>>>0)Qa();else{c[d>>2]=h;c[h+24>>2]=e;c[h+12>>2]=h;c[h+8>>2]=h;break}else if((z|0)==139){b=e+8|0;a=c[b>>2]|0;G=c[6454]|0;if(a>>>0>=G>>>0&e>>>0>=G>>>0){c[a+12>>2]=h;c[b>>2]=h;c[h+8>>2]=a;c[h+12>>2]=e;c[h+24>>2]=0;break}else Qa()}}else{G=i+r|0;c[j+4>>2]=G|3;G=j+G+4|0;c[G>>2]=c[G>>2]|1}while(0);G=j+8|0;l=H;return G|0}}}else r=-1;while(0);d=c[6452]|0;if(d>>>0>=r>>>0){b=d-r|0;a=c[6455]|0;if(b>>>0>15){G=a+r|0;c[6455]=G;c[6452]=b;c[G+4>>2]=b|1;c[G+b>>2]=b;c[a+4>>2]=r|3}else{c[6452]=0;c[6455]=0;c[a+4>>2]=d|3;c[a+d+4>>2]=c[a+d+4>>2]|1}G=a+8|0;l=H;return G|0}f=c[6453]|0;if(f>>>0>r>>>0){E=f-r|0;c[6453]=E;G=c[6456]|0;F=G+r|0;c[6456]=F;c[F+4>>2]=E|1;c[G+4>>2]=r|3;G=G+8|0;l=H;return G|0}if(!(c[6568]|0)){c[6570]=4096;c[6569]=4096;c[6571]=-1;c[6572]=-1;c[6573]=0;c[6561]=0;c[H>>2]=H&-16^1431655768;c[6568]=H&-16^1431655768;a=4096}else a=c[6570]|0;h=r+48|0;i=r+47|0;k=a+i|0;j=0-a|0;if((k&j)>>>0<=r>>>0){G=0;l=H;return G|0}a=c[6560]|0;if(a|0?(v=c[6558]|0,(v+(k&j)|0)>>>0<=v>>>0?1:(v+(k&j)|0)>>>0>a>>>0):0){G=0;l=H;return G|0}d:do if(!(c[6561]&4)){b=c[6456]|0;e:do if(b){d=26248;while(1){a=c[d>>2]|0;if(a>>>0<=b>>>0?(t=d+4|0,(a+(c[t>>2]|0)|0)>>>0>b>>>0):0)break;a=c[d+8>>2]|0;if(!a){z=163;break e}else d=a}if((k-f&j)>>>0<2147483647){a=bo(k-f&j|0)|0;if((a|0)==((c[d>>2]|0)+(c[t>>2]|0)|0))if((a|0)==(-1|0))a=k-f&j;else{h=a;g=k-f&j;z=180;break d}else{e=a;d=k-f&j;z=171}}else a=0}else z=163;while(0);do if((z|0)==163){b=bo(0)|0;if((b|0)!=(-1|0)?(g=c[6569]|0,g=((g+-1&b|0)==0?0:(g+-1+b&0-g)-b|0)+(k&j)|0,s=c[6558]|0,g>>>0>r>>>0&g>>>0<2147483647):0){v=c[6560]|0;if(v|0?(g+s|0)>>>0<=s>>>0|(g+s|0)>>>0>v>>>0:0){a=0;break}a=bo(g|0)|0;if((a|0)==(b|0)){h=b;z=180;break d}else{e=a;d=g;z=171}}else a=0}while(0);do if((z|0)==171){b=0-d|0;if(!(h>>>0>d>>>0&(d>>>0<2147483647&(e|0)!=(-1|0))))if((e|0)==(-1|0)){a=0;break}else{h=e;g=d;z=180;break d}a=c[6570]|0;a=i-d+a&0-a;if(a>>>0>=2147483647){h=e;g=d;z=180;break d}if((bo(a|0)|0)==(-1|0)){bo(b|0)|0;a=0;break}else{h=e;g=a+d|0;z=180;break d}}while(0);c[6561]=c[6561]|4;z=178}else{a=0;z=178}while(0);if(((z|0)==178?(k&j)>>>0<2147483647:0)?(w=bo(k&j|0)|0,x=bo(0)|0,y=(x-w|0)>>>0>(r+40|0)>>>0,!((w|0)==(-1|0)|y^1|w>>>0<x>>>0&((w|0)!=(-1|0)&(x|0)!=(-1|0))^1)):0){h=w;g=y?x-w|0:a;z=180}if((z|0)==180){a=(c[6558]|0)+g|0;c[6558]=a;if(a>>>0>(c[6559]|0)>>>0)c[6559]=a;k=c[6456]|0;do if(k){f=26248;while(1){a=c[f>>2]|0;e=f+4|0;b=c[e>>2]|0;if((h|0)==(a+b|0)){z=190;break}d=c[f+8>>2]|0;if(!d)break;else f=d}if(((z|0)==190?(c[f+12>>2]&8|0)==0:0)?k>>>0<h>>>0&k>>>0>=a>>>0:0){c[e>>2]=b+g;F=(k+8&7|0)==0?0:0-(k+8)&7;G=(c[6453]|0)+(g-F)|0;c[6456]=k+F;c[6453]=G;c[k+F+4>>2]=G|1;c[k+F+G+4>>2]=40;c[6457]=c[6572];break}a=c[6454]|0;if(h>>>0<a>>>0){c[6454]=h;j=h}else j=a;d=h+g|0;b=26248;while(1){if((c[b>>2]|0)==(d|0)){z=198;break}a=c[b+8>>2]|0;if(!a)break;else b=a}if((z|0)==198?(c[b+12>>2]&8|0)==0:0){c[b>>2]=h;n=b+4|0;c[n>>2]=(c[n>>2]|0)+g;n=h+8|0;n=h+((n&7|0)==0?0:0-n&7)|0;a=d+((d+8&7|0)==0?0:0-(d+8)&7)|0;m=n+r|0;i=a-n-r|0;c[n+4>>2]=r|3;do if((a|0)!=(k|0)){if((a|0)==(c[6455]|0)){G=(c[6452]|0)+i|0;c[6452]=G;c[6455]=m;c[m+4>>2]=G|1;c[m+G>>2]=G;break}h=c[a+4>>2]|0;if((h&3|0)==1){f:do if(h>>>0>=256){g=c[a+24>>2]|0;b=c[a+12>>2]|0;do if((b|0)==(a|0)){b=c[a+16+4>>2]|0;if(!b){b=c[a+16>>2]|0;if(!b){E=0;break}else f=a+16|0}else f=a+16+4|0;while(1){e=b+20|0;d=c[e>>2]|0;if(d|0){b=d;f=e;continue}e=b+16|0;d=c[e>>2]|0;if(!d)break;else{b=d;f=e}}if(f>>>0<j>>>0)Qa();else{c[f>>2]=0;E=b;break}}else{d=c[a+8>>2]|0;if(d>>>0<j>>>0)Qa();if((c[d+12>>2]|0)!=(a|0))Qa();if((c[b+8>>2]|0)==(a|0)){c[d+12>>2]=b;c[b+8>>2]=d;E=b;break}else Qa()}while(0);if(!g)break;b=c[a+28>>2]|0;do if((a|0)!=(c[26104+(b<<2)>>2]|0))if(g>>>0>=(c[6454]|0)>>>0){c[g+16+(((c[g+16>>2]|0)!=(a|0)&1)<<2)>>2]=E;if(!E)break f;else break}else Qa();else{c[26104+(b<<2)>>2]=E;if(E|0)break;c[6451]=c[6451]&~(1<<b);break f}while(0);d=c[6454]|0;if(E>>>0<d>>>0)Qa();c[E+24>>2]=g;b=c[a+16>>2]|0;do if(b|0)if(b>>>0<d>>>0)Qa();else{c[E+16>>2]=b;c[b+24>>2]=E;break}while(0);b=c[a+16+4>>2]|0;if(!b)break;if(b>>>0<(c[6454]|0)>>>0)Qa();else{c[E+20>>2]=b;c[b+24>>2]=E;break}}else{b=c[a+8>>2]|0;d=c[a+12>>2]|0;do if((b|0)!=(25840+(h>>>3<<1<<2)|0)){if(b>>>0<j>>>0)Qa();if((c[b+12>>2]|0)==(a|0))break;Qa()}while(0);if((d|0)==(b|0)){c[6450]=c[6450]&~(1<<(h>>>3));break}do if((d|0)==(25840+(h>>>3<<1<<2)|0))D=d+8|0;else{if(d>>>0<j>>>0)Qa();if((c[d+8>>2]|0)==(a|0)){D=d+8|0;break}Qa()}while(0);c[b+12>>2]=d;c[D>>2]=b}while(0);a=a+(h&-8)|0;f=(h&-8)+i|0}else f=i;b=a+4|0;c[b>>2]=c[b>>2]&-2;c[m+4>>2]=f|1;c[m+f>>2]=f;b=f>>>3;if(f>>>0<256){a=c[6450]|0;do if(!(a&1<<b)){c[6450]=a|1<<b;F=25840+(b<<1<<2)+8|0;G=25840+(b<<1<<2)|0}else{a=c[25840+(b<<1<<2)+8>>2]|0;if(a>>>0>=(c[6454]|0)>>>0){F=25840+(b<<1<<2)+8|0;G=a;break}Qa()}while(0);c[F>>2]=m;c[G+12>>2]=m;c[m+8>>2]=G;c[m+12>>2]=25840+(b<<1<<2);break}a=f>>>8;do if(!a)b=0;else{if(f>>>0>16777215){b=31;break}b=a<<((a+1048320|0)>>>16&8)<<(((a<<((a+1048320|0)>>>16&8))+520192|0)>>>16&4);b=14-(((a<<((a+1048320|0)>>>16&8))+520192|0)>>>16&4|(a+1048320|0)>>>16&8|(b+245760|0)>>>16&2)+(b<<((b+245760|0)>>>16&2)>>>15)|0;b=f>>>(b+7|0)&1|b<<1}while(0);e=26104+(b<<2)|0;c[m+28>>2]=b;c[m+16+4>>2]=0;c[m+16>>2]=0;a=c[6451]|0;d=1<<b;if(!(a&d)){c[6451]=a|d;c[e>>2]=m;c[m+24>>2]=e;c[m+12>>2]=m;c[m+8>>2]=m;break}b=f<<((b|0)==31?0:25-(b>>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(f|0)){z=265;break}d=e+16+(b>>>31<<2)|0;a=c[d>>2]|0;if(!a){z=262;break}else{b=b<<1;e=a}}if((z|0)==262)if(d>>>0<(c[6454]|0)>>>0)Qa();else{c[d>>2]=m;c[m+24>>2]=e;c[m+12>>2]=m;c[m+8>>2]=m;break}else if((z|0)==265){b=e+8|0;a=c[b>>2]|0;G=c[6454]|0;if(a>>>0>=G>>>0&e>>>0>=G>>>0){c[a+12>>2]=m;c[b>>2]=m;c[m+8>>2]=a;c[m+12>>2]=e;c[m+24>>2]=0;break}else Qa()}}else{G=(c[6453]|0)+i|0;c[6453]=G;c[6456]=m;c[m+4>>2]=G|1}while(0);G=n+8|0;l=H;return G|0}b=26248;while(1){a=c[b>>2]|0;if(a>>>0<=k>>>0?(A=a+(c[b+4>>2]|0)|0,A>>>0>k>>>0):0)break;b=c[b+8>>2]|0}f=A+-47+((A+-47+8&7|0)==0?0:0-(A+-47+8)&7)|0;f=f>>>0<(k+16|0)>>>0?k:f;a=h+8|0;a=(a&7|0)==0?0:0-a&7;G=h+a|0;a=g+-40-a|0;c[6456]=G;c[6453]=a;c[G+4>>2]=a|1;c[G+a+4>>2]=40;c[6457]=c[6572];c[f+4>>2]=27;c[f+8>>2]=c[6562];c[f+8+4>>2]=c[6563];c[f+8+8>>2]=c[6564];c[f+8+12>>2]=c[6565];c[6562]=h;c[6563]=g;c[6565]=0;c[6564]=f+8;a=f+24|0;do{G=a;a=a+4|0;c[a>>2]=7}while((G+8|0)>>>0<A>>>0);if((f|0)!=(k|0)){c[f+4>>2]=c[f+4>>2]&-2;c[k+4>>2]=f-k|1;c[f>>2]=f-k;if((f-k|0)>>>0<256){b=25840+((f-k|0)>>>3<<1<<2)|0;a=c[6450]|0;if(a&1<<((f-k|0)>>>3)){a=c[b+8>>2]|0;if(a>>>0<(c[6454]|0)>>>0)Qa();else{B=b+8|0;C=a}}else{c[6450]=a|1<<((f-k|0)>>>3);B=b+8|0;C=b}c[B>>2]=k;c[C+12>>2]=k;c[k+8>>2]=C;c[k+12>>2]=b;break}if((f-k|0)>>>8)if((f-k|0)>>>0>16777215)b=31;else{b=(f-k|0)>>>8<<((((f-k|0)>>>8)+1048320|0)>>>16&8);b=14-((b+520192|0)>>>16&4|(((f-k|0)>>>8)+1048320|0)>>>16&8|((b<<((b+520192|0)>>>16&4))+245760|0)>>>16&2)+(b<<((b+520192|0)>>>16&4)<<(((b<<((b+520192|0)>>>16&4))+245760|0)>>>16&2)>>>15)|0;b=(f-k|0)>>>(b+7|0)&1|b<<1}else b=0;e=26104+(b<<2)|0;c[k+28>>2]=b;c[k+20>>2]=0;c[k+16>>2]=0;a=c[6451]|0;d=1<<b;if(!(a&d)){c[6451]=a|d;c[e>>2]=k;c[k+24>>2]=e;c[k+12>>2]=k;c[k+8>>2]=k;break}b=f-k<<((b|0)==31?0:25-(b>>>1)|0);e=c[e>>2]|0;while(1){if((c[e+4>>2]&-8|0)==(f-k|0)){z=292;break}d=e+16+(b>>>31<<2)|0;a=c[d>>2]|0;if(!a){z=289;break}else{b=b<<1;e=a}}if((z|0)==289)if(d>>>0<(c[6454]|0)>>>0)Qa();else{c[d>>2]=k;c[k+24>>2]=e;c[k+12>>2]=k;c[k+8>>2]=k;break}else if((z|0)==292){b=e+8|0;a=c[b>>2]|0;G=c[6454]|0;if(a>>>0>=G>>>0&e>>>0>=G>>>0){c[a+12>>2]=k;c[b>>2]=k;c[k+8>>2]=a;c[k+12>>2]=e;c[k+24>>2]=0;break}else Qa()}}}else{G=c[6454]|0;if((G|0)==0|h>>>0<G>>>0)c[6454]=h;c[6562]=h;c[6563]=g;c[6565]=0;c[6459]=c[6568];c[6458]=-1;a=0;do{G=25840+(a<<1<<2)|0;c[G+12>>2]=G;c[G+8>>2]=G;a=a+1|0}while((a|0)!=32);G=h+8|0;G=(G&7|0)==0?0:0-G&7;F=h+G|0;G=g+-40-G|0;c[6456]=F;c[6453]=G;c[F+4>>2]=G|1;c[F+G+4>>2]=40;c[6457]=c[6572]}while(0);a=c[6453]|0;if(a>>>0>r>>>0){E=a-r|0;c[6453]=E;G=c[6456]|0;F=G+r|0;c[6456]=F;c[F+4>>2]=E|1;c[G+4>>2]=r|3;G=G+8|0;l=H;return G|0}}c[6577]=12;G=0;l=H;return G|0}function fc(b,d,e,f){b=b|0;d=d|0;e=e|0;f=+f;var h=0,i=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0,s=0,t=0,u=0,v=0.0,w=0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0.0,S=0.0,T=0.0,U=0.0,V=0.0,W=0.0,X=0.0,Y=0.0,Z=0.0,_=0.0,$=0.0,aa=0.0,ba=0.0;Q=l;l=l+448|0;if(!(a[b+527>>0]|0)){l=Q;return}P=c[b+28>>2]|0;J=+g[b+348>>2];I=+g[b+352>>2];B=+g[b+356>>2];k=+g[P+52>>2];z=J*+g[P+4>>2]+I*+g[P+8>>2]+B*+g[P+12>>2]+k;m=+g[P+56>>2];E=J*+g[P+20>>2]+I*+g[P+24>>2]+B*+g[P+28>>2]+m;n=+g[P+60>>2];B=J*+g[P+36>>2]+I*+g[P+40>>2]+B*+g[P+44>>2]+n;P=c[b+32>>2]|0;I=+g[b+412>>2];J=+g[b+416>>2];D=+g[b+420>>2];o=+g[P+52>>2];A=I*+g[P+4>>2]+J*+g[P+8>>2]+D*+g[P+12>>2]+o;p=+g[P+56>>2];F=I*+g[P+20>>2]+J*+g[P+24>>2]+D*+g[P+28>>2]+p;q=+g[P+60>>2];D=I*+g[P+36>>2]+J*+g[P+40>>2]+D*+g[P+44>>2]+q;if(!(a[b+524>>0]|0)){x=+g[d+192>>2]+ +g[d+80>>2];y=+g[d+196>>2]+ +g[d+84>>2];v=+g[d+200>>2]+ +g[d+88>>2];I=+g[e+192>>2]+ +g[e+80>>2];H=+g[e+196>>2]+ +g[e+84>>2];J=+g[e+200>>2]+ +g[e+88>>2];G=+g[d+176>>2]+ +g[d+64>>2]+((B-n)*y-(E-m)*v)-(+g[e+176>>2]+ +g[e+64>>2]+((D-q)*H-(F-p)*J));J=+g[d+180>>2]+ +g[d+68>>2]+((z-k)*v-(B-n)*x)-(+g[e+180>>2]+ +g[e+68>>2]+((A-o)*J-(D-q)*I));H=+g[d+184>>2]+ +g[d+72>>2]+((E-m)*x-(z-k)*y)-(+g[e+184>>2]+ +g[e+72>>2]+((F-p)*I-(A-o)*H));w=(c[d+240>>2]|0)==0;u=0;do{y=1.0/+g[b+48+(u*84|0)+80>>2];r=b+48+(u*84|0)|0;x=+g[r>>2];t=b+48+(u*84|0)+4|0;v=+g[t>>2];s=b+48+(u*84|0)+8|0;I=+g[s>>2];I=y*(((z-A)*x+(E-F)*v+(B-D)*I)*-.30000001192092896/f)-y*(G*x+J*v+H*I);g[b+36>>2]=+g[b+36>>2]+I;v=+g[s>>2];x=+g[t>>2];y=+g[r>>2];h=c[b+28>>2]|0;i=+g[h+344>>2];if(!w){T=((E-m)*v-(B-n)*x)*+g[h+296>>2]+((B-n)*y-(z-k)*v)*+g[h+300>>2]+((z-k)*x-(E-m)*y)*+g[h+304>>2];R=((E-m)*v-(B-n)*x)*+g[h+280>>2]+((B-n)*y-(z-k)*v)*+g[h+284>>2]+((z-k)*x-(E-m)*y)*+g[h+288>>2];S=((E-m)*v-(B-n)*x)*+g[h+264>>2]+((B-n)*y-(z-k)*v)*+g[h+268>>2]+((z-k)*x-(E-m)*y)*+g[h+272>>2];V=I*x*i*+g[d+116>>2];U=I*v*i*+g[d+120>>2];g[d+64>>2]=I*y*i*+g[d+112>>2]+ +g[d+64>>2];g[d+68>>2]=V+ +g[d+68>>2];g[d+72>>2]=U+ +g[d+72>>2];R=R*I*+g[d+100>>2];i=T*I*+g[d+104>>2];g[d+80>>2]=S*I*+g[d+96>>2]+ +g[d+80>>2];g[d+84>>2]=R+ +g[d+84>>2];g[d+88>>2]=i+ +g[d+88>>2]}h=c[b+32>>2]|0;i=+g[h+344>>2];if(c[e+240>>2]|0){V=((F-p)*v-(D-q)*x)*+g[h+296>>2]+((D-q)*y-(A-o)*v)*+g[h+300>>2]+((A-o)*x-(F-p)*y)*+g[h+304>>2];U=((F-p)*v-(D-q)*x)*+g[h+280>>2]+((D-q)*y-(A-o)*v)*+g[h+284>>2]+((A-o)*x-(F-p)*y)*+g[h+288>>2];T=((F-p)*v-(D-q)*x)*+g[h+264>>2]+((D-q)*y-(A-o)*v)*+g[h+268>>2]+((A-o)*x-(F-p)*y)*+g[h+272>>2];R=i*+g[t>>2]*-I*+g[e+116>>2];S=i*+g[s>>2]*-I*+g[e+120>>2];g[e+64>>2]=+g[e+112>>2]*i*+g[r>>2]*-I+ +g[e+64>>2];g[e+68>>2]=R+ +g[e+68>>2];g[e+72>>2]=S+ +g[e+72>>2];U=U*+g[e+100>>2]*-I;V=V*+g[e+104>>2]*-I;g[e+80>>2]=T*+g[e+96>>2]*-I+ +g[e+80>>2];g[e+84>>2]=U+ +g[e+84>>2];g[e+88>>2]=V+ +g[e+88>>2]}u=u+1|0}while((u|0)!=3)}do if(!(a[b+552>>0]|0)){i=+g[b+440>>2];if(!(i>1.1920928955078125e-07)){t=e+192|0;h=d+192|0;w=e+200|0;s=d+200|0;N=e+88|0;K=d+88|0;O=e+80|0;L=d+80|0;u=e+196|0;r=d+196|0;P=e+84|0;M=d+84|0;break}k=+g[e+192>>2]+ +g[e+80>>2]-(+g[d+192>>2]+ +g[d+80>>2]);m=+g[e+196>>2]+ +g[e+84>>2]-(+g[d+196>>2]+ +g[d+84>>2]);o=+g[e+200>>2]+ +g[e+88>>2]-(+g[d+200>>2]+ +g[d+88>>2]);if(k*k+m*m+o*o>1.1920928955078125e-07){E=1.0/+C(+(k*k+m*m+o*o));h=c[b+28>>2]|0;p=+g[h+264>>2];q=+g[h+280>>2];v=+g[h+296>>2];x=+g[h+268>>2];y=+g[h+284>>2];z=+g[h+300>>2];A=+g[h+272>>2];B=+g[h+288>>2];D=+g[h+304>>2];h=c[b+32>>2]|0;i=i*(1.0/(k*E*(p*k*E+m*E*q+o*E*v)+m*E*(k*E*x+m*E*y+o*E*z)+o*E*(k*E*A+m*E*B+o*E*D)+(k*E*(k*E*+g[h+264>>2]+m*E*+g[h+280>>2]+o*E*+g[h+296>>2])+m*E*(k*E*+g[h+268>>2]+m*E*+g[h+284>>2]+o*E*+g[h+300>>2])+o*E*(k*E*+g[h+272>>2]+m*E*+g[h+288>>2]+o*E*+g[h+304>>2]))));E=+C(+(o*i*o*i+(k*i*k*i+m*i*m*i)));n=1.0/E*k*i;k=1.0/E*m*i;i=1.0/E*o*i;if(c[d+240>>2]|0){V=E*0.0*+g[d+116>>2];U=E*0.0*+g[d+120>>2];g[d+64>>2]=E*0.0*+g[d+112>>2]+ +g[d+64>>2];g[d+68>>2]=V+ +g[d+68>>2];g[d+72>>2]=U+ +g[d+72>>2];U=(n*q+k*y+i*B)*E*+g[d+100>>2];V=(n*v+k*z+i*D)*E*+g[d+104>>2];g[d+80>>2]=(n*p+k*x+i*A)*E*+g[d+96>>2]+ +g[d+80>>2];g[d+84>>2]=U+ +g[d+84>>2];g[d+88>>2]=V+ +g[d+88>>2];h=c[b+32>>2]|0}if(c[e+240>>2]|0){V=n*+g[h+296>>2]+k*+g[h+300>>2]+i*+g[h+304>>2];U=n*+g[h+280>>2]+k*+g[h+284>>2]+i*+g[h+288>>2];T=n*+g[h+264>>2]+k*+g[h+268>>2]+i*+g[h+272>>2];R=E*-0.0*+g[e+116>>2];S=E*-0.0*+g[e+120>>2];g[e+64>>2]=E*-0.0*+g[e+112>>2]+ +g[e+64>>2];g[e+68>>2]=R+ +g[e+68>>2];g[e+72>>2]=S+ +g[e+72>>2];U=U*+g[e+100>>2]*-E;V=V*+g[e+104>>2]*-E;g[e+80>>2]=T*+g[e+96>>2]*-E+ +g[e+80>>2];g[e+84>>2]=U+ +g[e+84>>2];g[e+88>>2]=V+ +g[e+88>>2];t=e+192|0;h=d+192|0;w=e+200|0;s=d+200|0;N=e+88|0;K=d+88|0;O=e+80|0;L=d+80|0;u=e+196|0;r=d+196|0;P=e+84|0;M=d+84|0}else{t=e+192|0;h=d+192|0;w=e+200|0;s=d+200|0;N=e+88|0;K=d+88|0;O=e+80|0;L=d+80|0;u=e+196|0;r=d+196|0;P=e+84|0;M=d+84|0}}else{t=e+192|0;h=d+192|0;w=e+200|0;s=d+200|0;N=e+88|0;K=d+88|0;O=e+80|0;L=d+80|0;u=e+196|0;r=d+196|0;P=e+84|0;M=d+84|0}}else{O=c[b+28>>2]|0;c[Q+352>>2]=c[O+4>>2];c[Q+352+4>>2]=c[O+4+4>>2];c[Q+352+8>>2]=c[O+4+8>>2];c[Q+352+12>>2]=c[O+4+12>>2];c[Q+352+16>>2]=c[O+20>>2];c[Q+352+16+4>>2]=c[O+20+4>>2];c[Q+352+16+8>>2]=c[O+20+8>>2];c[Q+352+16+12>>2]=c[O+20+12>>2];c[Q+352+32>>2]=c[O+36>>2];c[Q+352+32+4>>2]=c[O+36+4>>2];c[Q+352+32+8>>2]=c[O+36+8>>2];c[Q+352+32+12>>2]=c[O+36+12>>2];c[Q+352+48>>2]=c[O+52>>2];c[Q+352+48+4>>2]=c[O+52+4>>2];c[Q+352+48+8>>2]=c[O+52+8>>2];c[Q+352+48+12>>2]=c[O+52+12>>2];O=c[b+32>>2]|0;c[Q+288>>2]=c[O+4>>2];c[Q+288+4>>2]=c[O+4+4>>2];c[Q+288+8>>2]=c[O+4+8>>2];c[Q+288+12>>2]=c[O+4+12>>2];c[Q+288+16>>2]=c[O+20>>2];c[Q+288+16+4>>2]=c[O+20+4>>2];c[Q+288+16+8>>2]=c[O+20+8>>2];c[Q+288+16+12>>2]=c[O+20+12>>2];c[Q+288+32>>2]=c[O+36>>2];c[Q+288+32+4>>2]=c[O+36+4>>2];c[Q+288+32+8>>2]=c[O+36+8>>2];c[Q+288+32+12>>2]=c[O+36+12>>2];c[Q+288+48>>2]=c[O+52>>2];c[Q+288+48+4>>2]=c[O+52+4>>2];c[Q+288+48+8>>2]=c[O+52+8>>2];c[Q+288+48+12>>2]=c[O+52+12>>2];T=+g[d+196>>2]+ +g[d+84>>2];v=+g[d+200>>2]+ +g[d+88>>2];g[Q+272>>2]=+g[d+192>>2]+ +g[d+80>>2];g[Q+272+4>>2]=T;g[Q+272+8>>2]=v;g[Q+272+12>>2]=0.0;v=+g[e+196>>2]+ +g[e+84>>2];T=+g[e+200>>2]+ +g[e+88>>2];g[Q+256>>2]=+g[e+192>>2]+ +g[e+80>>2];g[Q+256+4>>2]=v;g[Q+256+8>>2]=T;g[Q+256+12>>2]=0.0;c[Q+192>>2]=1065353216;O=Q+192+4|0;c[O>>2]=0;c[O+4>>2]=0;c[O+8>>2]=0;c[O+12>>2]=0;c[Q+192+20>>2]=1065353216;P=Q+192+24|0;c[P>>2]=0;c[P+4>>2]=0;c[P+8>>2]=0;c[P+12>>2]=0;c[Q+192+40>>2]=1065353216;M=Q+192+44|0;c[M>>2]=0;c[M+4>>2]=0;c[M+8>>2]=0;c[M+12>>2]=0;c[M+16>>2]=0;Cg(Q+352|0,0.0,0.0,0.0,Q+272|0,f,Q+192|0);c[Q+128>>2]=1065353216;M=Q+128+4|0;c[M>>2]=0;c[M+4>>2]=0;c[M+8>>2]=0;c[M+12>>2]=0;c[Q+128+20>>2]=1065353216;N=Q+128+24|0;c[N>>2]=0;c[N+4>>2]=0;c[N+8>>2]=0;c[N+12>>2]=0;c[Q+128+40>>2]=1065353216;L=Q+128+44|0;c[L>>2]=0;c[L+4>>2]=0;c[L+8>>2]=0;c[L+12>>2]=0;c[L+16>>2]=0;Cg(Q+288|0,0.0,0.0,0.0,Q+256|0,f,Q+128|0);T=+g[b+556>>2];v=+g[b+560>>2];U=+g[b+564>>2];x=+g[b+568>>2];H=T*(2.0/(T*T+v*v+U*U+x*x));A=v*(2.0/(T*T+v*v+U*U+x*x));I=U*(2.0/(T*T+v*v+U*U+x*x));X=+g[b+364>>2];W=+g[b+368>>2];_=+g[b+372>>2];k=_*(T*I-x*A)+(W*(T*A+x*I)+X*(1.0-(v*A+U*I)));m=_*(v*I+x*H)+(X*(T*A-x*I)+W*(1.0-(T*H+U*I)));n=X*(T*I+x*A)+W*(v*I-x*H)+_*(1.0-(T*H+v*A));i=+g[b+380>>2];G=+g[b+384>>2];E=+g[b+388>>2];o=(T*I-x*A)*E+(G*(T*A+x*I)+i*(1.0-(v*A+U*I)));p=(v*I+x*H)*E+(i*(T*A-x*I)+G*(1.0-(T*H+U*I)));q=i*(T*I+x*A)+G*(v*I-x*H)+E*(1.0-(T*H+v*A));R=+g[b+396>>2];D=+g[b+400>>2];B=+g[b+404>>2];S=(1.0-(v*A+U*I))*R+(T*A+x*I)*D+(T*I-x*A)*B;U=(T*A-x*I)*R+(1.0-(T*H+U*I))*D+(v*I+x*H)*B;A=(T*I+x*A)*R+(v*I-x*H)*D+(1.0-(T*H+v*A))*B;v=+g[b+300>>2];H=+g[b+316>>2];T=+g[b+332>>2];x=+g[b+304>>2];I=+g[b+320>>2];V=+g[b+336>>2];F=+g[b+308>>2];J=+g[b+324>>2];y=+g[b+340>>2];z=-+g[b+348>>2];ba=-+g[b+352>>2];Z=-+g[b+356>>2];_=X*0.0+W*0.0+_*0.0+ +g[b+412>>2]+(n*(F*z+J*ba+y*Z)+(k*(v*z+H*ba+T*Z)+m*(x*z+I*ba+V*Z)));E=i*0.0+G*0.0+E*0.0+ +g[b+416>>2]+(q*(F*z+J*ba+y*Z)+(o*(v*z+H*ba+T*Z)+p*(x*z+I*ba+V*Z)));Z=R*0.0+D*0.0+B*0.0+ +g[b+420>>2]+(A*(F*z+J*ba+y*Z)+(S*(v*z+H*ba+T*Z)+U*(x*z+I*ba+V*Z)));ba=+g[Q+128>>2];z=+g[M>>2];B=+g[Q+128+8>>2];D=+g[Q+128+16>>2];R=+g[Q+128+20>>2];G=+g[N>>2];i=+g[Q+128+32>>2];W=+g[Q+128+36>>2];X=+g[Q+128+40>>2];Y=B*Z+(ba*_+z*E)+ +g[Q+128+48>>2];$=D*_+E*R+Z*G+ +g[Q+128+52>>2];aa=_*i+E*W+Z*X+ +g[Q+128+56>>2];g[Q+64>>2]=(k*v+m*x+n*F)*ba+(o*v+p*x+q*F)*z+(S*v+U*x+A*F)*B;g[Q+64+4>>2]=(k*H+m*I+n*J)*ba+(o*H+p*I+q*J)*z+(S*H+U*I+A*J)*B;g[Q+64+8>>2]=(k*T+m*V+n*y)*ba+(o*T+p*V+q*y)*z+(S*T+U*V+A*y)*B;g[Q+64+12>>2]=0.0;g[Q+64+16>>2]=(k*v+m*x+n*F)*D+(o*v+p*x+q*F)*R+(S*v+U*x+A*F)*G;g[Q+64+20>>2]=(k*H+m*I+n*J)*D+(o*H+p*I+q*J)*R+(S*H+U*I+A*J)*G;g[Q+64+24>>2]=(k*T+m*V+n*y)*D+(o*T+p*V+q*y)*R+(S*T+U*V+A*y)*G;g[Q+64+28>>2]=0.0;g[Q+64+32>>2]=(k*v+m*x+n*F)*i+(o*v+p*x+q*F)*W+(S*v+U*x+A*F)*X;g[Q+64+36>>2]=(k*H+m*I+n*J)*i+(o*H+p*I+q*J)*W+(S*H+U*I+A*J)*X;g[Q+64+40>>2]=(k*T+m*V+n*y)*i+(o*T+p*V+q*y)*W+(S*T+U*V+A*y)*X;g[Q+64+44>>2]=0.0;g[Q+64+48>>2]=Y;g[Q+64+52>>2]=$;g[Q+64+56>>2]=aa;g[Q+64+60>>2]=0.0;aa=(S*v+U*x+A*F)*-Z+((k*v+m*x+n*F)*-_+(o*v+p*x+q*F)*-E);$=(S*H+U*I+A*J)*-Z+((k*H+m*I+n*J)*-_+(o*H+p*I+q*J)*-E);E=(S*T+U*V+A*y)*-Z+((k*T+m*V+n*y)*-_+(o*T+p*V+q*y)*-E);_=+g[Q+192>>2];Z=+g[O>>2];Y=+g[Q+192+8>>2];X=+g[Q+192+16>>2];W=+g[Q+192+20>>2];i=+g[P>>2];G=+g[Q+192+32>>2];R=+g[Q+192+36>>2];D=+g[Q+192+40>>2];B=aa*_+$*Z+E*Y+ +g[Q+192+48>>2];z=aa*X+$*W+E*i+ +g[Q+192+52>>2];E=aa*G+$*R+E*D+ +g[Q+192+56>>2];g[Q>>2]=(k*v+m*x+n*F)*_+(k*H+m*I+n*J)*Z+(k*T+m*V+n*y)*Y;g[Q+4>>2]=(o*v+p*x+q*F)*_+(o*H+p*I+q*J)*Z+(o*T+p*V+q*y)*Y;g[Q+8>>2]=(S*v+U*x+A*F)*_+(S*H+U*I+A*J)*Z+(S*T+U*V+A*y)*Y;g[Q+12>>2]=0.0;g[Q+16>>2]=(k*v+m*x+n*F)*X+(k*H+m*I+n*J)*W+(k*T+m*V+n*y)*i;g[Q+20>>2]=(o*v+p*x+q*F)*X+(o*H+p*I+q*J)*W+(o*T+p*V+q*y)*i;g[Q+24>>2]=(S*v+U*x+A*F)*X+(S*H+U*I+A*J)*W+(S*T+U*V+A*y)*i;g[Q+28>>2]=0.0;g[Q+32>>2]=(k*v+m*x+n*F)*G+(k*H+m*I+n*J)*R+(k*T+m*V+n*y)*D;g[Q+36>>2]=(o*v+p*x+q*F)*G+(o*H+p*I+q*J)*R+(o*T+p*V+q*y)*D;g[Q+40>>2]=(S*v+U*x+A*F)*G+(S*H+U*I+A*J)*R+(S*T+U*V+A*y)*D;g[Q+44>>2]=0.0;g[Q+48>>2]=B;g[Q+52>>2]=z;g[Q+56>>2]=E;g[Q+60>>2]=0.0;rf(Q+352|0,Q+64|0,Q+424|0,Q+416|0);E=+g[Q+416>>2];z=1.0/f*+g[Q+424>>2]*E;B=1.0/f*E*+g[Q+424+4>>2];E=1.0/f*E*+g[Q+424+8>>2];rf(Q+288|0,Q,Q+424|0,Q+416|0);D=+g[Q+416>>2];z=z-+g[Q+272>>2];B=B-+g[Q+272+4>>2];E=E-+g[Q+272+8>>2];y=1.0/f*+g[Q+424>>2]*D-+g[Q+256>>2];A=1.0/f*D*+g[Q+424+4>>2]-+g[Q+256+4>>2];D=1.0/f*D*+g[Q+424+8>>2]-+g[Q+256+8>>2];if(z*z+B*B+E*E>1.1920928955078125e-07){q=1.0/+C(+(z*z+B*B+E*E));P=c[b+28>>2]|0;i=z*q;m=B*q;o=E*q;q=z*q*(+g[P+264>>2]*z*q+B*q*+g[P+280>>2]+E*q*+g[P+296>>2])+B*q*(z*q*+g[P+268>>2]+B*q*+g[P+284>>2]+E*q*+g[P+300>>2])+E*q*(z*q*+g[P+272>>2]+B*q*+g[P+288>>2]+E*q*+g[P+304>>2])}else{i=0.0;m=0.0;o=0.0;q=0.0}if(y*y+A*A+D*D>1.1920928955078125e-07){v=1.0/+C(+(y*y+A*A+D*D));P=c[b+32>>2]|0;k=y*v;n=A*v;p=D*v;v=y*v*(+g[P+264>>2]*y*v+A*v*+g[P+280>>2]+D*v*+g[P+296>>2])+A*v*(y*v*+g[P+268>>2]+A*v*+g[P+284>>2]+D*v*+g[P+300>>2])+D*v*(y*v*+g[P+272>>2]+A*v*+g[P+288>>2]+D*v*+g[P+304>>2])}else{k=0.0;n=0.0;p=0.0;v=0.0}x=q*i+v*k;k=q*m+v*n;i=q*o+v*p;if(x*x+k*k+i*i>1.1920928955078125e-07){o=1.0/+C(+(x*x+k*k+i*i));r=c[b+28>>2]|0;m=x*o*(+g[r+264>>2]*x*o+k*o*+g[r+280>>2]+i*o*+g[r+296>>2])+k*o*(x*o*+g[r+268>>2]+k*o*+g[r+284>>2]+i*o*+g[r+300>>2])+i*o*(x*o*+g[r+272>>2]+k*o*+g[r+288>>2]+i*o*+g[r+304>>2]);h=c[b+32>>2]|0;o=x*o*(x*o*+g[h+264>>2]+k*o*+g[h+280>>2]+i*o*+g[h+296>>2])+k*o*(x*o*+g[h+268>>2]+k*o*+g[h+284>>2]+i*o*+g[h+300>>2])+i*o*(x*o*+g[h+272>>2]+k*o*+g[h+288>>2]+i*o*+g[h+304>>2]);k=(z*m-y*o)*(1.0/((m+o)*(m+o)));v=(B*m-A*o)*(1.0/((m+o)*(m+o)));o=(E*m-D*o)*(1.0/((m+o)*(m+o)));i=+g[b+572>>2];if(!(i>=0.0))i=v;else{i=(a[b+553>>0]|0)==0?i:i/m;n=+g[b+576>>2];p=+g[b+580>>2];q=+g[b+584>>2];m=+C(+((k+n)*(k+n)+(v+p)*(v+p)+(o+q)*(o+q)));if(m>i){k=i*(k+n)*(1.0/m)-n;o=i*(o+q)*(1.0/m)-q;i=i*(v+p)*(1.0/m)-p}else i=v;g[b+576>>2]=k+n;g[b+580>>2]=i+p;g[b+584>>2]=o+q}n=+C(+(k*k+i*i+o*o));m=k*(1.0/n);k=i*(1.0/n);i=o*(1.0/n);if(c[d+240>>2]|0){ba=m*+g[r+296>>2]+k*+g[r+300>>2]+i*+g[r+304>>2];aa=m*+g[r+280>>2]+k*+g[r+284>>2]+i*+g[r+288>>2];$=m*+g[r+264>>2]+k*+g[r+268>>2]+i*+g[r+272>>2];Z=n*0.0*+g[d+116>>2];_=n*0.0*+g[d+120>>2];g[d+64>>2]=n*0.0*+g[d+112>>2]+ +g[d+64>>2];g[d+68>>2]=Z+ +g[d+68>>2];g[d+72>>2]=_+ +g[d+72>>2];aa=aa*n*+g[d+100>>2];ba=ba*n*+g[d+104>>2];g[d+80>>2]=$*n*+g[d+96>>2]+ +g[d+80>>2];g[d+84>>2]=aa+ +g[d+84>>2];g[d+88>>2]=ba+ +g[d+88>>2];h=c[b+32>>2]|0}if(c[e+240>>2]|0){ba=m*+g[h+296>>2]+k*+g[h+300>>2]+i*+g[h+304>>2];aa=m*+g[h+280>>2]+k*+g[h+284>>2]+i*+g[h+288>>2];$=m*+g[h+264>>2]+k*+g[h+268>>2]+i*+g[h+272>>2];Z=n*-0.0*+g[e+116>>2];_=n*-0.0*+g[e+120>>2];g[e+64>>2]=n*-0.0*+g[e+112>>2]+ +g[e+64>>2];g[e+68>>2]=Z+ +g[e+68>>2];g[e+72>>2]=_+ +g[e+72>>2];aa=aa*+g[e+100>>2]*-n;ba=ba*+g[e+104>>2]*-n;g[e+80>>2]=$*+g[e+96>>2]*-n+ +g[e+80>>2];g[e+84>>2]=aa+ +g[e+84>>2];g[e+88>>2]=ba+ +g[e+88>>2]}}t=e+192|0;h=d+192|0;w=e+200|0;s=d+200|0;N=e+88|0;K=d+88|0;O=e+80|0;L=d+80|0;u=e+196|0;r=d+196|0;P=e+84|0;M=d+84|0}while(0);z=+g[h>>2]+ +g[L>>2];y=+g[r>>2]+ +g[M>>2];x=+g[s>>2]+ +g[K>>2];v=+g[t>>2]+ +g[O>>2];q=+g[u>>2]+ +g[P>>2];p=+g[w>>2]+ +g[N>>2];if(a[b+526>>0]|0){k=+g[b+528>>2];i=k*+g[b+504>>2]*+g[b+432>>2]/f;m=+g[b+460>>2];n=+g[b+464>>2];o=+g[b+468>>2];if((v-z)*m+(q-y)*n+(p-x)*o>0.0)i=i+k*((v-z)*m+(q-y)*n+(p-x)*o)*+g[b+436>>2];aa=+g[b+516>>2];_=aa+i*+g[b+492>>2];g[Q+424>>2]=_;g[Q+416>>2]=0.0;h=c[(_>0.0?Q+424|0:Q+416|0)>>2]|0;c[b+516>>2]=h;aa=(c[j>>2]=h,+g[j>>2])-aa;_=+g[b+536>>2];$=+g[b+540>>2];i=+g[b+544>>2];k=aa*m-_*(aa*m*_+aa*n*$+aa*o*i);ba=aa*n-$*(aa*m*_+aa*n*$+aa*o*i);n=aa*o-i*(aa*m*_+aa*n*$+aa*o*i);i=+C(+(n*n+(k*k+ba*ba)));k=1.0/i*k;m=1.0/i*ba;n=1.0/i*n;h=c[b+28>>2]|0;if(c[d+240>>2]|0){ba=k*+g[h+296>>2]+m*+g[h+300>>2]+n*+g[h+304>>2];aa=k*+g[h+280>>2]+m*+g[h+284>>2]+n*+g[h+288>>2];$=k*+g[h+264>>2]+m*+g[h+268>>2]+n*+g[h+272>>2];Z=i*0.0*+g[d+116>>2];_=i*0.0*+g[d+120>>2];g[d+64>>2]=i*0.0*+g[d+112>>2]+ +g[d+64>>2];g[d+68>>2]=Z+ +g[d+68>>2];g[d+72>>2]=_+ +g[d+72>>2];aa=aa*i*+g[d+100>>2];ba=ba*i*+g[d+104>>2];g[L>>2]=$*i*+g[d+96>>2]+ +g[L>>2];g[M>>2]=aa+ +g[M>>2];g[K>>2]=ba+ +g[K>>2]}h=c[b+32>>2]|0;if(c[e+240>>2]|0){ba=k*+g[h+296>>2]+m*+g[h+300>>2]+n*+g[h+304>>2];aa=k*+g[h+280>>2]+m*+g[h+284>>2]+n*+g[h+288>>2];$=k*+g[h+264>>2]+m*+g[h+268>>2]+n*+g[h+272>>2];Z=i*-0.0*+g[e+116>>2];_=i*-0.0*+g[e+120>>2];g[e+64>>2]=i*-0.0*+g[e+112>>2]+ +g[e+64>>2];g[e+68>>2]=Z+ +g[e+68>>2];g[e+72>>2]=_+ +g[e+72>>2];aa=aa*+g[e+100>>2]*-i;ba=ba*+g[e+104>>2]*-i;g[O>>2]=$*+g[e+96>>2]*-i+ +g[O>>2];g[P>>2]=aa+ +g[P>>2];g[N>>2]=ba+ +g[N>>2]}}if(!(a[b+525>>0]|0)){l=Q;return}o=+g[b+532>>2];n=o*+g[b+508>>2]*+g[b+432>>2]/f;m=+g[b+476>>2];k=+g[b+480>>2];i=+g[b+484>>2];if((v-z)*m+(q-y)*k+(p-x)*i>0.0)n=n+o*((v-z)*m+(q-y)*k+(p-x)*i)*+g[b+436>>2];ba=+g[b+520>>2];n=ba+n*+g[b+496>>2];g[Q+424>>2]=n;g[Q+416>>2]=0.0;h=c[(n>0.0?Q+424|0:Q+416|0)>>2]|0;c[b+520>>2]=h;n=(c[j>>2]=h,+g[j>>2])-ba;h=c[b+28>>2]|0;if(c[d+240>>2]|0){ba=m*+g[h+296>>2]+k*+g[h+300>>2]+i*+g[h+304>>2];aa=m*+g[h+280>>2]+k*+g[h+284>>2]+i*+g[h+288>>2];i=m*+g[h+264>>2]+k*+g[h+268>>2]+i*+g[h+272>>2];m=n*0.0*+g[d+116>>2];k=n*0.0*+g[d+120>>2];g[d+64>>2]=n*0.0*+g[d+112>>2]+ +g[d+64>>2];g[d+68>>2]=m+ +g[d+68>>2];g[d+72>>2]=k+ +g[d+72>>2];k=aa*n*+g[d+100>>2];m=ba*n*+g[d+104>>2];g[L>>2]=i*n*+g[d+96>>2]+ +g[L>>2];g[M>>2]=k+ +g[M>>2];g[K>>2]=m+ +g[K>>2];m=+g[b+476>>2];k=+g[b+480>>2];i=+g[b+484>>2]}h=c[b+32>>2]|0;if(!(c[e+240>>2]|0)){l=Q;return}ba=m*+g[h+296>>2]+k*+g[h+300>>2]+i*+g[h+304>>2];aa=m*+g[h+280>>2]+k*+g[h+284>>2]+i*+g[h+288>>2];$=m*+g[h+264>>2]+k*+g[h+268>>2]+i*+g[h+272>>2];Z=n*-0.0*+g[e+116>>2];_=n*-0.0*+g[e+120>>2];g[e+64>>2]=n*-0.0*+g[e+112>>2]+ +g[e+64>>2];g[e+68>>2]=Z+ +g[e+68>>2];g[e+72>>2]=_+ +g[e+72>>2];aa=aa*+g[e+100>>2]*-n;ba=ba*+g[e+104>>2]*-n;g[O>>2]=$*+g[e+96>>2]*-n+ +g[O>>2];g[P>>2]=aa+ +g[P>>2];g[N>>2]=ba+ +g[N>>2];l=Q;return}function gc(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var h=0.0,i=0.0,k=0,m=0.0,n=0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0,D=0.0,E=0,F=0,G=0,H=0,I=0,J=0,L=0,M=0,N=0.0,O=0.0,P=0.0,Q=0.0,R=0.0,S=0.0,T=0.0,U=0.0,V=0.0,W=0.0,X=0.0,Y=0,Z=0.0,_=0,$=0.0,aa=0.0,ba=0.0,ca=0.0,da=0.0,ea=0,fa=0.0,ga=0,ha=0.0,ia=0.0,ja=0.0,ka=0.0,la=0.0,ma=0.0,na=0.0,oa=0.0,pa=0.0,qa=0.0,ra=0.0,sa=0.0,ta=0.0,ua=0.0,va=0.0,wa=0.0,xa=0.0,ya=0.0,za=0.0,Aa=0,Ba=0.0,Ca=0.0,Da=0.0,Ea=0;Ea=l;l=l+528|0;c[Ea+56>>2]=c[b>>2];c[Ea+8>>2]=c[b+64>>2];k=Ea+56+4|0;c[k>>2]=c[b+4>>2];c[Ea+8+4>>2]=c[b+68>>2];c[Ea+56+8>>2]=c[b+8>>2];c[Ea+8+8>>2]=c[b+72>>2];c[Ea+56+16>>2]=c[b+16>>2];c[Ea+8+16>>2]=c[b+80>>2];c[Ea+56+20>>2]=c[b+20>>2];c[Ea+8+20>>2]=c[b+84>>2];c[Ea+56+24>>2]=c[b+24>>2];c[Ea+8+24>>2]=c[b+88>>2];c[Ea+56+32>>2]=c[b+32>>2];c[Ea+8+32>>2]=c[b+96>>2];c[Ea+56+36>>2]=c[b+36>>2];c[Ea+8+36>>2]=c[b+100>>2];c[Ea+56+40>>2]=c[b+40>>2];c[Ea+8+40>>2]=c[b+104>>2];Aa=c[a+4>>2]|0;la=+g[Aa+28>>2];ma=+g[Aa+32>>2];ka=+g[Aa+36>>2];ia=+zb[c[(c[Aa>>2]|0)+48>>2]&15](Aa);ja=+zb[c[(c[Aa>>2]|0)+48>>2]&15](Aa);ka=(ka+ +zb[c[(c[Aa>>2]|0)+48>>2]&15](Aa))*2.0;Aa=c[a+8>>2]|0;sa=+g[Aa+28>>2];ta=+g[Aa+32>>2];wa=+g[Aa+36>>2];qa=+zb[c[(c[Aa>>2]|0)+48>>2]&15](Aa);ra=+zb[c[(c[Aa>>2]|0)+48>>2]&15](Aa);wa=(wa+ +zb[c[(c[Aa>>2]|0)+48>>2]&15](Aa))*2.0;R=+g[b+112>>2]-+g[b+48>>2];T=+g[b+116>>2]-+g[b+52>>2];S=+g[b+120>>2]-+g[b+56>>2];da=+g[Ea+56>>2];ba=+g[Ea+56+16>>2];ca=+g[Ea+56+32>>2];aa=+g[k>>2];Z=+g[Ea+56+20>>2];$=+g[Ea+56+36>>2];fa=+g[Ea+56+8>>2];ha=+g[Ea+56+24>>2];na=+g[Ea+56+40>>2];g[Ea+412>>2]=(la+ia)*2.0*.5;g[Ea+412+4>>2]=(ma+ja)*2.0*.5;g[Ea+412+8>>2]=ka*.5;g[Ea+400>>2]=(sa+qa)*2.0*.5;g[Ea+400+4>>2]=(ta+ra)*2.0*.5;g[Ea+400+8>>2]=wa*.5;xa=+g[Ea+8>>2];oa=+g[Ea+8+16>>2];ua=+g[Ea+8+32>>2];ya=+g[Ea+8+4>>2];pa=+g[Ea+8+20>>2];va=+g[Ea+8+36>>2];za=+g[Ea+8+8>>2];Ba=+g[Ea+8+24>>2];Ca=+g[Ea+8+40>>2];D=+B(+(da*xa+ba*oa+ca*ua));O=+B(+(da*ya+ba*pa+ca*va));U=+B(+(da*za+ba*Ba+ca*Ca));N=+B(+(xa*aa+oa*Z+ua*$));P=+B(+(ya*aa+pa*Z+va*$));V=+B(+(za*aa+Ba*Z+Ca*$));W=+B(+(xa*fa+oa*ha+ua*na));X=+B(+(ya*fa+pa*ha+va*na));Q=+B(+(za*fa+Ba*ha+Ca*na));h=+B(+(R*da+T*ba+S*ca))-(wa*.5*U+((la+ia)*2.0*.5+D*(sa+qa)*2.0*.5+O*(ta+ra)*2.0*.5));if(h>0.0){l=Ea;return}if(h>-3402823466385288598117041.0e14){f=1;e=R*da+T*ba+S*ca<0.0&1;a=Ea+56|0}else{f=0;e=0;a=0;h=-3402823466385288598117041.0e14}i=+B(+(R*aa+T*Z+S*$))-((ma+ja)*2.0*.5+N*(sa+qa)*2.0*.5+P*(ta+ra)*2.0*.5+V*wa*.5);if(i>0.0){l=Ea;return}if(i>h){f=2;e=R*aa+T*Z+S*$<0.0&1;a=k;h=i}i=+B(+(R*fa+T*ha+S*na))-(ka*.5+W*(sa+qa)*2.0*.5+X*(ta+ra)*2.0*.5+Q*wa*.5);if(i>0.0){l=Ea;return}if(i>h){f=3;e=R*fa+T*ha+S*na<0.0&1;a=Ea+56+8|0;h=i}i=+B(+(R*xa+T*oa+S*ua))-((sa+qa)*2.0*.5+(D*(la+ia)*2.0*.5+N*(ma+ja)*2.0*.5+W*ka*.5));if(i>0.0){l=Ea;return}if(i>h){f=4;e=R*xa+T*oa+S*ua<0.0&1;a=Ea+8|0;h=i}i=+B(+(R*ya+T*pa+S*va))-((ta+ra)*2.0*.5+(O*(la+ia)*2.0*.5+P*(ma+ja)*2.0*.5+X*ka*.5));if(i>0.0){l=Ea;return}if(i>h){f=5;e=R*ya+T*pa+S*va<0.0&1;a=Ea+8+4|0;h=i}i=+B(+(R*za+T*Ba+S*Ca))-(wa*.5+(U*(la+ia)*2.0*.5+V*(ma+ja)*2.0*.5+Q*ka*.5));if(i>0.0){l=Ea;return}if(i>h){f=6;e=R*za+T*Ba+S*Ca<0.0&1;a=Ea+8+8|0;h=i}p=(R*fa+T*ha+S*na)*(xa*aa+oa*Z+ua*$)-(R*aa+T*Z+S*$)*(xa*fa+oa*ha+ua*na);r=+B(+p)-((W+9.999999747378752e-06)*(ma+ja)*2.0*.5+(N+9.999999747378752e-06)*ka*.5+(U+9.999999747378752e-06)*(ta+ra)*2.0*.5+(O+9.999999747378752e-06)*wa*.5);if(r>1.1920928955078125e-07){l=Ea;return}s=(xa*fa+oa*ha+ua*na)*(xa*fa+oa*ha+ua*na)+0.0;x=(xa*aa+oa*Z+ua*$)*(xa*aa+oa*Z+ua*$);q=+C(+(x+s));if(q>1.1920928955078125e-07?r/q*1.0499999523162842>h:0){o=0.0/q;m=-(xa*fa+oa*ha+ua*na)/q;i=(xa*aa+oa*Z+ua*$)/q;f=7;e=p<0.0&1;a=0;h=r/q}else{o=0.0;m=0.0;i=0.0}p=(R*fa+T*ha+S*na)*(ya*aa+pa*Z+va*$)-(R*aa+T*Z+S*$)*(ya*fa+pa*ha+va*na);r=+B(+p)-((X+9.999999747378752e-06)*(ma+ja)*2.0*.5+(P+9.999999747378752e-06)*ka*.5+(U+9.999999747378752e-06)*(sa+qa)*2.0*.5+(D+9.999999747378752e-06)*wa*.5);if(r>1.1920928955078125e-07){l=Ea;return}t=(ya*fa+pa*ha+va*na)*(ya*fa+pa*ha+va*na)+0.0;y=(ya*aa+pa*Z+va*$)*(ya*aa+pa*Z+va*$);q=+C(+(y+t));if(q>1.1920928955078125e-07?r/q*1.0499999523162842>h:0){o=0.0/q;m=-(ya*fa+pa*ha+va*na)/q;i=(ya*aa+pa*Z+va*$)/q;f=8;e=p<0.0&1;a=0;h=r/q}p=(R*fa+T*ha+S*na)*(za*aa+Ba*Z+Ca*$)-(R*aa+T*Z+S*$)*(za*fa+Ba*ha+Ca*na);r=+B(+p)-((Q+9.999999747378752e-06)*(ma+ja)*2.0*.5+(V+9.999999747378752e-06)*ka*.5+(O+9.999999747378752e-06)*(sa+qa)*2.0*.5+(D+9.999999747378752e-06)*(ta+ra)*2.0*.5);if(r>1.1920928955078125e-07){l=Ea;return}v=(za*fa+Ba*ha+Ca*na)*(za*fa+Ba*ha+Ca*na)+0.0;z=(za*aa+Ba*Z+Ca*$)*(za*aa+Ba*Z+Ca*$);q=+C(+(z+v));if(q>1.1920928955078125e-07?r/q*1.0499999523162842>h:0){o=0.0/q;m=-(za*fa+Ba*ha+Ca*na)/q;i=(za*aa+Ba*Z+Ca*$)/q;f=9;e=p<0.0&1;a=0;h=r/q}p=(R*da+T*ba+S*ca)*(xa*fa+oa*ha+ua*na)-(R*fa+T*ha+S*na)*(da*xa+ba*oa+ca*ua);r=+B(+p)-((W+9.999999747378752e-06)*(la+ia)*2.0*.5+(D+9.999999747378752e-06)*ka*.5+(V+9.999999747378752e-06)*(ta+ra)*2.0*.5+(P+9.999999747378752e-06)*wa*.5);if(r>1.1920928955078125e-07){l=Ea;return}w=(da*xa+ba*oa+ca*ua)*(da*xa+ba*oa+ca*ua);q=+C(+(w+s));do if(q>1.1920928955078125e-07){if(!(r/q*1.0499999523162842>h))break;o=(xa*fa+oa*ha+ua*na)/q;m=0.0/q;i=-(da*xa+ba*oa+ca*ua)/q;f=10;e=p<0.0&1;a=0;h=r/q}while(0);p=(R*da+T*ba+S*ca)*(ya*fa+pa*ha+va*na)-(R*fa+T*ha+S*na)*(da*ya+ba*pa+ca*va);r=+B(+p)-((X+9.999999747378752e-06)*(la+ia)*2.0*.5+(O+9.999999747378752e-06)*ka*.5+(V+9.999999747378752e-06)*(sa+qa)*2.0*.5+(N+9.999999747378752e-06)*wa*.5);if(r>1.1920928955078125e-07){l=Ea;return}u=(da*ya+ba*pa+ca*va)*(da*ya+ba*pa+ca*va);q=+C(+(u+t));do if(q>1.1920928955078125e-07){if(!(r/q*1.0499999523162842>h))break;o=(ya*fa+pa*ha+va*na)/q;m=0.0/q;i=-(da*ya+ba*pa+ca*va)/q;f=11;e=p<0.0&1;a=0;h=r/q}while(0);p=(R*da+T*ba+S*ca)*(za*fa+Ba*ha+Ca*na)-(R*fa+T*ha+S*na)*(da*za+ba*Ba+ca*Ca);r=+B(+p)-((Q+9.999999747378752e-06)*(la+ia)*2.0*.5+(U+9.999999747378752e-06)*ka*.5+(P+9.999999747378752e-06)*(sa+qa)*2.0*.5+(N+9.999999747378752e-06)*(ta+ra)*2.0*.5);if(r>1.1920928955078125e-07){l=Ea;return}s=(da*za+ba*Ba+ca*Ca)*(da*za+ba*Ba+ca*Ca);q=+C(+(s+v));do if(q>1.1920928955078125e-07){if(!(r/q*1.0499999523162842>h))break;o=(za*fa+Ba*ha+Ca*na)/q;m=0.0/q;i=-(da*za+ba*Ba+ca*Ca)/q;f=12;e=p<0.0&1;a=0;h=r/q}while(0);q=(R*aa+T*Z+S*$)*(da*xa+ba*oa+ca*ua)-(R*da+T*ba+S*ca)*(xa*aa+oa*Z+ua*$);r=+B(+q)-((N+9.999999747378752e-06)*(la+ia)*2.0*.5+(D+9.999999747378752e-06)*(ma+ja)*2.0*.5+(Q+9.999999747378752e-06)*(ta+ra)*2.0*.5+(X+9.999999747378752e-06)*wa*.5);if(r>1.1920928955078125e-07){l=Ea;return}p=+C(+(w+x+0.0));do if(p>1.1920928955078125e-07){if(!(r/p*1.0499999523162842>h))break;o=-(xa*aa+oa*Z+ua*$)/p;m=(da*xa+ba*oa+ca*ua)/p;i=0.0/p;f=13;e=q<0.0&1;a=0;h=r/p}while(0);r=(R*aa+T*Z+S*$)*(da*ya+ba*pa+ca*va)-(R*da+T*ba+S*ca)*(ya*aa+pa*Z+va*$);q=+B(+r)-((P+9.999999747378752e-06)*(la+ia)*2.0*.5+(O+9.999999747378752e-06)*(ma+ja)*2.0*.5+(Q+9.999999747378752e-06)*(sa+qa)*2.0*.5+(W+9.999999747378752e-06)*wa*.5);if(q>1.1920928955078125e-07){l=Ea;return}p=+C(+(u+y+0.0));do if(p>1.1920928955078125e-07){if(!(q/p*1.0499999523162842>h))break;o=-(ya*aa+pa*Z+va*$)/p;m=(da*ya+ba*pa+ca*va)/p;i=0.0/p;f=14;e=r<0.0&1;a=0;h=q/p}while(0);r=(R*aa+T*Z+S*$)*(da*za+ba*Ba+ca*Ca)-(R*da+T*ba+S*ca)*(za*aa+Ba*Z+Ca*$);q=+B(+r)-((V+9.999999747378752e-06)*(la+ia)*2.0*.5+(U+9.999999747378752e-06)*(ma+ja)*2.0*.5+(X+9.999999747378752e-06)*(sa+qa)*2.0*.5+(W+9.999999747378752e-06)*(ta+ra)*2.0*.5);if(q>1.1920928955078125e-07){l=Ea;return}p=+C(+(s+z+0.0));do if(p>1.1920928955078125e-07){if(!(q/p*1.0499999523162842>h)){Aa=55;break}o=-(za*aa+Ba*Z+Ca*$)/p;m=(da*za+ba*Ba+ca*Ca)/p;i=0.0/p;f=15;e=r<0.0&1;h=q/p;Aa=58}else Aa=55;while(0);do if((Aa|0)==55){if(!f){l=Ea;return}if(!a){Aa=58;break}n=c[a>>2]|0;c[Ea>>2]=n;ga=c[a+16>>2]|0;i=(c[j>>2]=n,+g[j>>2]);p=(c[j>>2]=ga,+g[j>>2]);m=+g[a+32>>2];n=f;f=ga;D=h}while(0);if((Aa|0)==58){Da=o*+g[Ea+56>>2]+m*+g[k>>2]+i*fa;g[Ea>>2]=Da;D=o*+g[Ea+56+16>>2]+m*+g[Ea+56+20>>2]+i*ha;p=D;m=o*+g[Ea+56+32>>2]+m*+g[Ea+56+36>>2]+i*na;i=Da;n=f;f=(g[j>>2]=D,c[j>>2]|0);D=h}if(!e){Da=m;e=f}else{i=-i;g[Ea>>2]=i;Da=-m;e=(g[j>>2]=-p,c[j>>2]|0)}if((n|0)>6){z=(c[j>>2]=e,+g[j>>2]);m=+g[Ea+56>>2];t=+g[Ea+56+16>>2];v=+g[Ea+56+32>>2];u=(i*m+z*t+Da*v>0.0?1.0:-1.0)*(la+ia)*2.0*.5;y=+g[k>>2];x=+g[Ea+56+20>>2];h=+g[Ea+56+36>>2];s=(i*y+z*x+Da*h>0.0?1.0:-1.0)*(ma+ja)*2.0*.5;w=(i*fa+z*ha+Da*na>0.0?1.0:-1.0)*ka*.5;y=+g[b+48>>2]+u*m+s*y+w*fa;x=+g[b+52>>2]+u*t+s*x+w*ha;w=+g[b+56>>2]+u*v+s*h+w*na;c[Ea+456>>2]=c[b+112>>2];c[Ea+456+4>>2]=c[b+112+4>>2];c[Ea+456+8>>2]=c[b+112+8>>2];h=(i*xa+z*oa+Da*ua>0.0?-1.0:1.0)*(sa+qa)*2.0*.5;s=(i*ya+z*pa+Da*va>0.0?-1.0:1.0)*(ta+ra)*2.0*.5;v=+g[Ea+456+4>>2]+h*oa+s*pa;u=+g[Ea+456+8>>2]+h*ua+s*va;t=(i*za+z*Ba+Da*Ca>0.0?-1.0:1.0)*wa*.5;s=+g[Ea+456>>2]+h*xa+s*ya+t*za;g[Ea+456>>2]=s;g[Ea+456+4>>2]=v+t*Ba;g[Ea+456+8>>2]=u+t*Ca;Aa=n+-7|0;h=+g[Ea+56+(((Aa|0)/3|0)<<2)>>2];i=+g[Ea+56+(((Aa|0)/3|0)+4<<2)>>2];m=+g[Ea+56+(((Aa|0)/3|0)+8<<2)>>2];p=+g[Ea+8+(((Aa|0)%3|0)<<2)>>2];q=+g[Ea+8+(((Aa|0)%3|0)+4<<2)>>2];r=+g[Ea+8+(((Aa|0)%3|0)+8<<2)>>2];o=1.0-(h*p+i*q+m*r)*(h*p+i*q+m*r);if(!(o<=9.999999747378752e-05))h=(((s-y)*h+(v+t*Ba-x)*i+(u+t*Ca-w)*m)*(h*p+i*q+m*r)-((s-y)*p+(v+t*Ba-x)*q+(u+t*Ca-w)*r))*(1.0/o);else h=0.0;g[Ea+456>>2]=s+h*p;g[Ea+456+4>>2]=v+t*Ba+h*q;g[Ea+456+8>>2]=u+t*Ca+h*r;Aa=c[(c[d>>2]|0)+16>>2]|0;g[Ea+424>>2]=-+g[Ea>>2];g[Ea+424+4>>2]=-z;g[Ea+424+8>>2]=-Da;g[Ea+424+12>>2]=0.0;Qb[Aa&15](d,Ea+424|0,Ea+456|0,D);l=Ea;return}ea=(n|0)<4;ga=ea?b+48|0:b+112|0;f=ea?b+112|0:b+48|0;a=ea?Ea+56|0:Ea+8|0;_=ea?Ea+8|0:Ea+56|0;M=ea?Ea+412|0:Ea+400|0;k=ea?Ea+400|0:Ea+412|0;fa=(c[j>>2]=e,+g[j>>2]);if(ea){da=fa;ba=i;ca=Da}else{da=-fa;ba=-i;ca=-Da}X=ba*+g[_>>2]+da*+g[_+16>>2]+ca*+g[_+32>>2];g[Ea+384>>2]=X;W=ba*+g[_+4>>2]+da*+g[_+20>>2]+ca*+g[_+36>>2];g[Ea+384+4>>2]=W;V=ba*+g[_+8>>2]+da*+g[_+24>>2]+ca*+g[_+40>>2];g[Ea+384+8>>2]=V;X=+B(+X);W=+B(+W);V=+B(+V);e=W>X?(W>V?1:2):X>V?0:2;Y=(W>X?W>V:X>V)?2:1;p=+g[k+(e<<2)>>2];i=+g[f>>2]-+g[ga>>2];h=p*+g[_+(e<<2)>>2];m=+g[f+4>>2];o=+g[ga+4>>2];if(+g[Ea+384+(e<<2)>>2]<0.0){aa=i+h;$=m-o+p*+g[_+((e|4)<<2)>>2];Z=+g[f+8>>2]-+g[ga+8>>2]+p*+g[_+((e|8)<<2)>>2]}else{aa=i-h;$=m-o-p*+g[_+((e|4)<<2)>>2];Z=+g[f+8>>2]-+g[ga+8>>2]-p*+g[_+((e|8)<<2)>>2]}L=(ea?-1:-4)+n|0;switch(L|0){case 0:{e=1;f=2;break}case 1:{e=0;f=2;break}default:{e=0;f=1}}J=a+(e<<2)|0;T=+g[J>>2];R=+g[J+16>>2];S=+g[J+32>>2];U=aa*T+$*R+Z*S;J=a+(f<<2)|0;x=+g[J>>2];v=+g[J+16>>2];w=+g[J+32>>2];Q=aa*x+$*v+Z*w;J=_+((X>V&(W>X^1)&1)<<2)|0;D=+g[J>>2];y=+g[J+16>>2];z=+g[J+32>>2];P=+g[_+(Y<<2)>>2];N=+g[_+(Y<<2)+16>>2];O=+g[_+(Y<<2)+32>>2];Ba=+g[k+((X>V&(W>X^1)&1)<<2)>>2];Ca=+g[k+(Y<<2)>>2];za=(T*P+R*N+S*O)*Ca;Ca=(x*P+v*N+w*O)*Ca;g[Ea+352>>2]=U-(T*D+R*y+S*z)*Ba-za;g[Ea+352+4>>2]=Q-(x*D+v*y+w*z)*Ba-Ca;g[Ea+352+8>>2]=U-(T*D+R*y+S*z)*Ba+za;g[Ea+352+12>>2]=Q-(x*D+v*y+w*z)*Ba+Ca;g[Ea+352+16>>2]=U+(T*D+R*y+S*z)*Ba+za;g[Ea+352+20>>2]=Q+(x*D+v*y+w*z)*Ba+Ca;g[Ea+352+24>>2]=U+(T*D+R*y+S*z)*Ba-za;g[Ea+352+28>>2]=Q+(x*D+v*y+w*z)*Ba-Ca;c[Ea+344>>2]=c[M+(e<<2)>>2];c[Ea+344+4>>2]=c[M+(f<<2)>>2];I=0;f=4;E=Ea+352|0;H=Ea+280|0;a:while(1){F=Ea+344+(I<<2)|0;G=1-I|0;do if((f|0)>0){a=0;A=E;e=H;while(1){k=A+(I<<2)|0;h=+g[k>>2];i=+g[F>>2];if(i>-h){c[e>>2]=c[A>>2];c[e+4>>2]=c[A+4>>2];a=a+1|0;if(a&8|0){f=a;e=H;break a}h=+g[k>>2];i=+g[F>>2];n=e+8|0}else n=e;b=(f|0)>1;k=A;A=A+8|0;e=b?A:E;m=+g[e+(I<<2)>>2];if(i>-h^i>-m){Ca=+g[k+(G<<2)>>2];g[n+(G<<2)>>2]=Ca+(-i-h)*((+g[e+(G<<2)>>2]-Ca)/(m-h));g[n+(I<<2)>>2]=-+g[F>>2];e=a+1|0;if(!(e&8)){a=e;e=n+8|0}else{f=e;e=H;break a}}else e=n;if(!b)break;else f=f+-1|0}e=(H|0)==(Ea+280|0)?Ea+456|0:Ea+280|0;if((a|0)<=0){f=0;break}A=a;f=0;E=H;a=e;while(1){k=E+(I<<2)|0;i=+g[k>>2];h=+g[F>>2];if(i<h){c[a>>2]=c[E>>2];c[a+4>>2]=c[E+4>>2];f=f+1|0;if(f&8|0)break a;h=+g[F>>2];i=+g[k>>2];a=a+8|0}b=(A|0)>1;n=E;E=E+8|0;k=b?E:H;m=+g[k+(I<<2)>>2];if(i<h^m<h){Ca=+g[n+(G<<2)>>2];g[a+(G<<2)>>2]=Ca+(h-i)*((+g[k+(G<<2)>>2]-Ca)/(m-i));c[a+(I<<2)>>2]=c[F>>2];f=f+1|0;if(!(f&8))a=a+8|0;else break a}if(!b)break;else A=A+-1|0}}else{e=(H|0)==(Ea+280|0)?Ea+456|0:Ea+280|0;f=0}while(0);I=I+1|0;if((I|0)>=2)break;else{E=e;H=(e|0)==(Ea+280|0)?Ea+456|0:Ea+280|0}}if((e|0)!=(Ea+280|0))Th(Ea+280|0,e|0,f<<3|0)|0;if((f|0)>=1){u=1.0/((T*D+R*y+S*z)*(x*P+v*N+w*O)-(x*D+v*y+w*z)*(T*P+R*N+S*O));t=+g[M+(L<<2)>>2];p=+g[J>>2];q=+g[_+(Y<<2)>>2];r=+g[_+((X>V&(W>X^1)&1|4)<<2)>>2];s=+g[_+((Y|4)<<2)>>2];o=+g[_+((X>V&(W>X^1)&1|8)<<2)>>2];m=+g[_+((Y|8)<<2)>>2];a=0;k=0;do{e=k<<1;h=+g[Ea+280+(e<<2)>>2];i=+g[Ea+280+((e|1)<<2)>>2];ya=(x*P+v*N+w*O)*u*(h-U)-(T*P+R*N+S*O)*u*(i-Q);Ca=(T*D+R*y+S*z)*u*(i-Q)-(x*D+v*y+w*z)*u*(h-U);e=a*3|0;za=aa+ya*p+Ca*q;g[Ea+184+(e<<2)>>2]=za;Ba=$+ya*r+Ca*s;g[Ea+184+(e+1<<2)>>2]=Ba;Ca=Z+ya*o+Ca*m;g[Ea+184+(e+2<<2)>>2]=Ca;Ca=t-(ba*za+da*Ba+ca*Ca);g[Ea+152+(a<<2)>>2]=Ca;e=a<<1;if(Ca>=0.0){g[Ea+280+(e<<2)>>2]=h;g[Ea+280+((e|1)<<2)>>2]=i;a=a+1|0}k=k+1|0}while((k|0)!=(f|0));b:do if((a|0)>=1){A=(a|0)<4?a:4;E=(A|0)>1?A:1;if((a|0)<=(E|0))if(ea){h=-Da;e=0;while(1){Aa=e*3|0;g[Ea+456>>2]=+g[Ea+184+(Aa<<2)>>2]+ +g[ga>>2];g[Ea+456+4>>2]=+g[Ea+184+(Aa+1<<2)>>2]+ +g[ga+4>>2];g[Ea+456+8>>2]=+g[Ea+184+(Aa+2<<2)>>2]+ +g[ga+8>>2];Aa=c[(c[d>>2]|0)+16>>2]|0;g[Ea+424>>2]=-+g[Ea>>2];g[Ea+424+4>>2]=-fa;g[Ea+424+8>>2]=h;g[Ea+424+12>>2]=0.0;Qb[Aa&15](d,Ea+424|0,Ea+456|0,-+g[Ea+152+(e<<2)>>2]);e=e+1|0;if((e|0)==(a|0))break b}}else{h=-Da;e=0;while(1){Aa=e*3|0;Ca=+g[Ea+152+(e<<2)>>2];Ba=+g[Ea>>2];g[Ea+456>>2]=+g[Ea+184+(Aa<<2)>>2]+ +g[ga>>2]-Ba*Ca;g[Ea+456+4>>2]=+g[Ea+184+(Aa+1<<2)>>2]+ +g[ga+4>>2]-fa*Ca;g[Ea+456+8>>2]=+g[Ea+184+(Aa+2<<2)>>2]+ +g[ga+8>>2]-Da*Ca;Aa=c[(c[d>>2]|0)+16>>2]|0;g[Ea+424>>2]=-Ba;g[Ea+424+4>>2]=-fa;g[Ea+424+8>>2]=h;g[Ea+424+12>>2]=0.0;Qb[Aa&15](d,Ea+424|0,Ea+456|0,-Ca);e=e+1|0;if((e|0)==(a|0))break b}}c:do if((a|0)>1){f=1;k=0;i=+g[Ea+152>>2];while(1){h=+g[Ea+152+(f<<2)>>2];e=h>i;k=e?f:k;f=f+1|0;if((f|0)==(a|0))break;else i=e?h:i}switch(a|0){case 1:{e=Ea+120|0;f=Ea+120|0;a=1;Aa=111;break c}case 2:{e=Ea+120|0;f=Ea+120|0;a=2;i=(+g[Ea+280>>2]+ +g[Ea+280+8>>2])*.5;h=(+g[Ea+280+4>>2]+ +g[Ea+280+12>>2])*.5;Aa=114;break c}default:{}}f=a+-1|0;h=0.0;i=0.0;r=0.0;e=0;do{_=e<<1;ya=+g[Ea+280+(_<<2)>>2];za=+g[Ea+280+(_+3<<2)>>2];Ba=+g[Ea+280+(_+2<<2)>>2];Ca=+g[Ea+280+((_|1)<<2)>>2];h=h+(ya*za-Ba*Ca);i=i+(ya+Ba)*(ya*za-Ba*Ca);r=r+(za+Ca)*(ya*za-Ba*Ca);e=e+1|0}while((e|0)!=(f|0));_=a<<1;m=+g[Ea+280+(_+-2<<2)>>2];o=+g[Ea+280+4>>2];p=+g[Ea+280>>2];q=+g[Ea+280+(_+-1<<2)>>2];h=h+(m*o-p*q);_=+B(+h)>1.1920928955078125e-07;h=_?1.0/(h*3.0):999999984306749440.0;if((a|0)>0){n=Ea+120|0;b=Ea+456|0;f=Ea+120|0;i=h*(i+(m*o-p*q)*(m+p));h=h*(r+(m*o-p*q)*(q+o));Aa=117;break}f=Ea+120|0;e=0;b=a}else{e=Ea+120|0;f=Ea+120|0;k=0;Aa=111}while(0);if((Aa|0)==111){i=+g[Ea+280>>2];h=+g[Ea+280+4>>2];Aa=114}if((Aa|0)==114){n=e;b=Ea+456|0;Aa=117}if((Aa|0)==117){e=0;do{Aa=e<<1;g[Ea+456+(e<<2)>>2]=+K(+(+g[Ea+280+((Aa|1)<<2)>>2]-h),+(+g[Ea+280+(Aa<<2)>>2]-i));e=e+1|0}while((e|0)!=(a|0));e=0;do{c[Ea+424+(e<<2)>>2]=1;e=e+1|0}while((e|0)!=(a|0));e=1;b=a}a=Ea+424+(k<<2)|0;c[a>>2]=0;c[f>>2]=k;d:do if((A|0)>1){o=+g[Ea+456+(k<<2)>>2];if(e){a=Ea+120+4|0;n=1}else{e=Ea+120+4|0;f=1;while(1){c[e>>2]=k;c[a>>2]=0;f=f+1|0;if((f|0)==(E|0))break d;else e=e+4|0}}while(1){m=6.2831854820251465/+(E|0)*+(n|0)+o;m=m>3.1415927410125732?m+-6.2831854820251465:m;c[a>>2]=k;e=k;f=0;i=1.0e9;while(1){do if(!(c[Ea+424+(f<<2)>>2]|0))h=i;else{h=+B(+(+g[Ea+456+(f<<2)>>2]-m));h=h>3.1415927410125732?6.2831854820251465-h:h;if(!(h<i)){h=i;break}c[a>>2]=f;e=f}while(0);f=f+1|0;if((f|0)==(b|0))break;else i=h}c[Ea+424+(e<<2)>>2]=0;n=n+1|0;if((n|0)==(E|0))break;else a=a+4|0}}while(0);if((E|0)>0){h=-Da;if(ea){e=0;do{Aa=c[Ea+120+(e<<2)>>2]|0;g[Ea+456>>2]=+g[Ea+184+(Aa*3<<2)>>2]+ +g[ga>>2];g[Ea+456+4>>2]=+g[Ea+184+((Aa*3|0)+1<<2)>>2]+ +g[ga+4>>2];g[Ea+456+8>>2]=+g[Ea+184+((Aa*3|0)+2<<2)>>2]+ +g[ga+8>>2];ea=c[(c[d>>2]|0)+16>>2]|0;g[Ea+424>>2]=-+g[Ea>>2];g[Ea+424+4>>2]=-fa;g[Ea+424+8>>2]=h;g[Ea+424+12>>2]=0.0;Qb[ea&15](d,Ea+424|0,Ea+456|0,-+g[Ea+152+(Aa<<2)>>2]);e=e+1|0}while((e|0)<(E|0))}else{e=0;do{ea=c[Ea+120+(e<<2)>>2]|0;xa=+g[Ea+184+(ea*3<<2)>>2]+ +g[ga>>2];g[Ea+456>>2]=xa;za=+g[Ea+184+((ea*3|0)+1<<2)>>2]+ +g[ga+4>>2];g[Ea+456+4>>2]=za;Ba=+g[Ea+184+((ea*3|0)+2<<2)>>2]+ +g[ga+8>>2];g[Ea+456+8>>2]=Ba;Aa=c[(c[d>>2]|0)+16>>2]|0;ya=+g[Ea>>2];g[Ea+424>>2]=-ya;g[Ea+424+4>>2]=-fa;g[Ea+424+8>>2]=h;g[Ea+424+12>>2]=0.0;Ca=+g[Ea+152+(ea<<2)>>2];g[Ea+104>>2]=xa-ya*Ca;g[Ea+104+4>>2]=za-Ca*fa;g[Ea+104+8>>2]=Ba-Ca*Da;g[Ea+104+12>>2]=0.0;Qb[Aa&15](d,Ea+424|0,Ea+104|0,-Ca);e=e+1|0}while((e|0)<(E|0))}}}while(0)}l=Ea;return}function hc(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0;V=c[e>>2]|0;fa=c[f>>2]|0;if(V|0)g=c[V+12>>2]|0;else g=b;h=c[g+88>>2]|0;i=c[g+92>>2]|0;m=c[g+96>>2]|0;if(!fa)g=d;else g=c[fa+12>>2]|0;s=c[g+88>>2]|0;n=c[g+92>>2]|0;t=c[g+96>>2]|0;W=c[b+88>>2]|0;da=(c[d+88>>2]|0)-W|0;v=c[b+92>>2]|0;ea=(c[d+92>>2]|0)-v|0;b=c[b+96>>2]|0;ca=(c[d+96>>2]|0)-b|0;ba=c[(V|0?V:fa)+12>>2]|0;X=(c[ba+88>>2]|0)-W|0;U=(c[ba+92>>2]|0)-v|0;ba=(c[ba+96>>2]|0)-b|0;aa=(O(U,ca)|0)-(O(ba,ea)|0)|0;ba=(O(ba,da)|0)-(O(X,ca)|0)|0;U=(O(X,ea)|0)-(O(U,da)|0)|0;W=Xr(aa|0,((aa|0)<0)<<31>>31|0,W|0,((W|0)<0)<<31>>31|0)|0;X=z;v=Xr(ba|0,((ba|0)<0)<<31>>31|0,v|0,((v|0)<0)<<31>>31|0)|0;u=z;b=Xr(U|0,((U|0)<0)<<31>>31|0,b|0,((b|0)<0)<<31>>31|0)|0;b=xv(W|0,X|0,b|0,z|0)|0;u=xv(b|0,z|0,v|0,u|0)|0;v=z;b=Xr(U|0,((U|0)<0)<<31>>31|0,ea|0,((ea|0)<0)<<31>>31|0)|0;X=z;W=Xr(ba|0,((ba|0)<0)<<31>>31|0,ca|0,((ca|0)<0)<<31>>31|0)|0;W=St(b|0,X|0,W|0,z|0)|0;X=z;b=Xr(aa|0,((aa|0)<0)<<31>>31|0,ca|0,((ca|0)<0)<<31>>31|0)|0;Z=z;Y=Xr(U|0,((U|0)<0)<<31>>31|0,da|0,((da|0)<0)<<31>>31|0)|0;Y=St(b|0,Z|0,Y|0,z|0)|0;Z=z;b=Xr(ba|0,((ba|0)<0)<<31>>31|0,da|0,((da|0)<0)<<31>>31|0)|0;$=z;_=Xr(aa|0,((aa|0)<0)<<31>>31|0,ea|0,((ea|0)<0)<<31>>31|0)|0;_=St(b|0,$|0,_|0,z|0)|0;$=z;b=Xr(W|0,X|0,h|0,((h|0)<0)<<31>>31|0)|0;T=z;g=Xr(Y|0,Z|0,i|0,((i|0)<0)<<31>>31|0)|0;T=xv(g|0,z|0,b|0,T|0)|0;b=z;g=Xr(_|0,$|0,m|0,((m|0)<0)<<31>>31|0)|0;g=xv(T|0,b|0,g|0,z|0)|0;b=z;if((V|0)!=0?(c[V+12>>2]|0)!=0:0){p=V;q=h;o=i;while(1){p=c[(c[p+8>>2]|0)+4>>2]|0;k=p+12|0;i=c[k>>2]|0;d=c[i+88>>2]|0;S=Xr(d|0,((d|0)<0)<<31>>31|0,aa|0,((aa|0)<0)<<31>>31|0)|0;R=z;h=c[i+92>>2]|0;T=Xr(h|0,((h|0)<0)<<31>>31|0,ba|0,((ba|0)<0)<<31>>31|0)|0;R=xv(T|0,z|0,S|0,R|0)|0;S=z;i=c[i+96>>2]|0;T=Xr(i|0,((i|0)<0)<<31>>31|0,U|0,((U|0)<0)<<31>>31|0)|0;T=xv(R|0,S|0,T|0,z|0)|0;S=z;if((S|0)<(v|0)|(S|0)==(v|0)&T>>>0<u>>>0){d=q;i=o;h=m;break}if((c[p+20>>2]|0)==(c[a+100>>2]|0)){d=q;i=o;h=m;break}l=Xr(d|0,((d|0)<0)<<31>>31|0,W|0,X|0)|0;T=z;j=Xr(h|0,((h|0)<0)<<31>>31|0,Y|0,Z|0)|0;T=xv(j|0,z|0,l|0,T|0)|0;l=z;j=Xr(i|0,((i|0)<0)<<31>>31|0,_|0,$|0)|0;j=xv(T|0,l|0,j|0,z|0)|0;l=z;if(!((l|0)>(b|0)|(l|0)==(b|0)&j>>>0>g>>>0)){d=q;i=o;h=m;break}c[e>>2]=p;T=c[k>>2]|0;d=c[T+88>>2]|0;i=c[T+92>>2]|0;h=c[T+96>>2]|0;if(!T){g=j;b=l;break}else{b=l;g=j;q=d;o=i;m=h}}p=c[f>>2]|0;T=d;m=h}else{p=fa;T=h}h=Xr(W|0,X|0,s|0,((s|0)<0)<<31>>31|0)|0;S=z;d=Xr(Y|0,Z|0,n|0,((n|0)<0)<<31>>31|0)|0;S=xv(d|0,z|0,h|0,S|0)|0;h=z;d=Xr(_|0,$|0,t|0,((t|0)<0)<<31>>31|0)|0;d=xv(S|0,h|0,d|0,z|0)|0;h=z;a:do if(p)if(!(c[p+12>>2]|0)){k=s;o=t}else{r=p;q=s;o=t;while(1){p=c[c[r+8>>2]>>2]|0;l=c[p+12>>2]|0;j=c[l+88>>2]|0;R=Xr(j|0,((j|0)<0)<<31>>31|0,aa|0,((aa|0)<0)<<31>>31|0)|0;Q=z;k=c[l+92>>2]|0;S=Xr(k|0,((k|0)<0)<<31>>31|0,ba|0,((ba|0)<0)<<31>>31|0)|0;Q=xv(S|0,z|0,R|0,Q|0)|0;R=z;l=c[l+96>>2]|0;S=Xr(l|0,((l|0)<0)<<31>>31|0,U|0,((U|0)<0)<<31>>31|0)|0;S=xv(Q|0,R|0,S|0,z|0)|0;R=z;if((R|0)<(v|0)|(R|0)==(v|0)&S>>>0<u>>>0){p=r;k=q;break a}if((c[p+20>>2]|0)==(c[a+100>>2]|0)){p=r;k=q;break a}S=Xr(j|0,((j|0)<0)<<31>>31|0,W|0,X|0)|0;R=z;j=Xr(k|0,((k|0)<0)<<31>>31|0,Y|0,Z|0)|0;R=xv(j|0,z|0,S|0,R|0)|0;S=z;j=Xr(l|0,((l|0)<0)<<31>>31|0,_|0,$|0)|0;j=xv(R|0,S|0,j|0,z|0)|0;l=z;if(!((l|0)>(h|0)|(l|0)==(h|0)&j>>>0>d>>>0)){p=r;k=q;break a}c[f>>2]=p;S=c[p+12>>2]|0;k=c[S+88>>2]|0;n=c[S+92>>2]|0;o=c[S+96>>2]|0;if(!S){d=j;h=l;break}else{r=p;h=l;d=j;q=k}}}else{p=0;k=s;o=t}while(0);j=St(d|0,h|0,g|0,b|0)|0;b=z;if((b|0)>0|(b|0)==0&j>>>0>0){R=St(0,0,U|0,((U|0)<0)<<31>>31|0)|0;S=z;l=p;d=j;h=b;t=T;v=i;x=m;N=k;P=n;Q=o;while(1){r=(O(P-v|0,ea)|0)+(O(N-t|0,da)|0)+(O(Q-x|0,ca)|0)|0;g=c[e>>2]|0;if(!g){w=r;D=((r|0)<0)<<31>>31;E=h;q=d;u=r;I=t;H=v;G=x}else{q=r;s=((r|0)<0)<<31>>31;J=r;K=t;L=v;b:while(1){if(!(c[g+12>>2]|0)){u=J;t=K;r=L;g=x;break}I=c[(c[g>>2]|0)+8>>2]|0;if((c[I+20>>2]|0)<=(c[a+100>>2]|0)){u=J;t=K;r=L;g=x;break}M=c[I+12>>2]|0;t=c[M+88>>2]|0;H=t-K|0;r=c[M+92>>2]|0;G=r-L|0;M=c[M+96>>2]|0;l=M-x|0;v=Xr(H|0,((H|0)<0)<<31>>31|0,W|0,X|0)|0;F=z;u=Xr(G|0,((G|0)<0)<<31>>31|0,Y|0,Z|0)|0;F=xv(u|0,z|0,v|0,F|0)|0;v=z;u=Xr(l|0,((l|0)<0)<<31>>31|0,_|0,$|0)|0;u=xv(F|0,v|0,u|0,z|0)|0;v=z;l=(O(G,ea)|0)+(O(H,da)|0)+(O(l,ca)|0)|0;do if((u|0)==0&(v|0)==0){if((l|0)>=0){u=J;t=K;r=L;g=x;break b}}else{if((v|0)>=0){u=J;t=K;r=L;g=x;break b}if((l|0)>0){y=1;A=l;w=((l|0)<0)<<31>>31}else{A=St(0,0,l|0,((l|0)<0)<<31>>31|0)|0;y=((l|0)!=0)<<31>>31;A=l|0?A:0;w=l|0?z:0}D=St(0,0,u|0,v|0)|0;E=z;H=0-y|0;if((J|0)>0){F=q;G=s;l=1}else{l=(J|0)!=0;F=St(0,0,q|0,s|0)|0;F=l?F:0;G=l?z:0;l=l<<31>>31}if((h|0)>0|(h|0)==0&d>>>0>0){u=d;v=h}else{C=(d|0)!=0|(h|0)!=0;u=St(0,0,d|0,h|0)|0;u=C?u:0;v=C?z:0;l=C?0-l|0:l}if((l|0)==(H|0)){if(!y)break;l=Xr(u|0,0,A|0,0)|0;y=z;ja=Xr(v|0,0,A|0,0)|0;ia=z;B=Xr(u|0,0,w|0,0)|0;C=z;ha=Xr(v|0,0,w|0,0)|0;A=z;B=xv(ja|0,0,B|0,0)|0;u=z;A=xv(ia|0,0,ha|0,A|0)|0;C=xv(A|0,z|0,C|0,0)|0;u=xv(C|0,z|0,u|0,0)|0;C=z;y=xv(0,B|0,l|0,y|0)|0;A=z;B=xv(u|0,C|0,(A>>>0<B>>>0|(A|0)==(B|0)&y>>>0<0)&1|0,0)|0;C=z;u=Xr(F|0,0,D|0,0)|0;l=z;ha=Xr(G|0,0,D|0,0)|0;D=z;v=Xr(F|0,0,E|0,0)|0;w=z;E=Xr(G|0,0,E|0,0)|0;F=z;v=xv(ha|0,0,v|0,0)|0;G=z;F=xv(D|0,0,E|0,F|0)|0;w=xv(F|0,z|0,w|0,0)|0;G=xv(w|0,z|0,G|0,0)|0;w=z;l=xv(0,v|0,u|0,l|0)|0;u=z;v=xv(G|0,w|0,(u>>>0<v>>>0|(u|0)==(v|0)&l>>>0<0)&1|0,0)|0;w=z;if(C>>>0<w>>>0|(C|0)==(w|0)&B>>>0<v>>>0)l=-1;else l=C>>>0>w>>>0|(C|0)==(w|0)&B>>>0>v>>>0?1:A>>>0<u>>>0|(A|0)==(u|0)&y>>>0<l>>>0?-1:(A>>>0>u>>>0|(A|0)==(u|0)&y>>>0>l>>>0)&1;l=O(l,H)|0}else l=H-l|0;if((l|0)<=-1){u=J;t=K;r=L;g=x;break b}}while(0);ja=N-t|0;ia=P-r|0;l=Q-M|0;h=Xr(ja|0,((ja|0)<0)<<31>>31|0,W|0,X|0)|0;ha=z;d=Xr(ia|0,((ia|0)<0)<<31>>31|0,Y|0,Z|0)|0;ha=xv(d|0,z|0,h|0,ha|0)|0;h=z;d=Xr(l|0,((l|0)<0)<<31>>31|0,_|0,$|0)|0;d=xv(ha|0,h|0,d|0,z|0)|0;h=z;g=(g|0)==(V|0)?0:I;c[e>>2]=g;l=(O(ia,ea)|0)+(O(ja,da)|0)+(O(l,ca)|0)|0;if(!g){q=l;s=((l|0)<0)<<31>>31;u=l;g=M;break}else{q=l;s=((l|0)<0)<<31>>31;J=l;K=t;L=r;x=M}}l=c[f>>2]|0;w=q;D=s;E=h;q=d;I=t;H=r;G=g}if(!l){g=110;break}if(!(c[l+12>>2]|0)){g=110;break}F=c[c[l+8>>2]>>2]|0;if((c[F+20>>2]|0)<=(c[a+100>>2]|0)){g=110;break}h=c[F+12>>2]|0;s=c[h+88>>2]|0;l=s-N|0;r=c[h+92>>2]|0;d=r-P|0;h=c[h+96>>2]|0;g=h-Q|0;ja=Xr(l|0,((l|0)<0)<<31>>31|0,aa|0,((aa|0)<0)<<31>>31|0)|0;ha=z;ia=Xr(d|0,((d|0)<0)<<31>>31|0,ba|0,((ba|0)<0)<<31>>31|0)|0;ha=xv(ia|0,z|0,ja|0,ha|0)|0;ja=z;ia=Xr(g|0,((g|0)<0)<<31>>31|0,R|0,S|0)|0;if(!((ha|0)==(ia|0)&(ja|0)==(z|0))){g=110;break}v=Xr(l|0,((l|0)<0)<<31>>31|0,W|0,X|0)|0;ja=z;t=Xr(d|0,((d|0)<0)<<31>>31|0,Y|0,Z|0)|0;ja=xv(t|0,z|0,v|0,ja|0)|0;v=z;t=Xr(g|0,((g|0)<0)<<31>>31|0,_|0,$|0)|0;t=xv(ja|0,v|0,t|0,z|0)|0;v=z;g=(O(d,ea)|0)+(O(l,da)|0)+(O(g,ca)|0)|0;ja=s-I|0;ia=r-H|0;d=h-G|0;h=Xr(ja|0,((ja|0)<0)<<31>>31|0,W|0,X|0)|0;ja=z;ia=Xr(ia|0,((ia|0)<0)<<31>>31|0,Y|0,Z|0)|0;ja=xv(ia|0,z|0,h|0,ja|0)|0;h=z;d=Xr(d|0,((d|0)<0)<<31>>31|0,_|0,$|0)|0;d=xv(ja|0,h|0,d|0,z|0)|0;h=z;if(!((h|0)>0|(h|0)==0&d>>>0>0)){g=110;break}if((t|0)==0&(v|0)==0){if((g|0)>=0){g=110;break}}else{if((v|0)>=0){g=110;break}if((g|0)>0){x=1;y=g;s=((g|0)<0)<<31>>31}else{y=St(0,0,g|0,((g|0)<0)<<31>>31|0)|0;x=((g|0)!=0)<<31>>31;y=g|0?y:0;s=g|0?z:0}A=St(0,0,t|0,v|0)|0;B=z;C=0-x|0;if((u|0)>0){r=D;g=1}else{g=(u|0)!=0;w=St(0,0,w|0,D|0)|0;w=g?w:0;r=g?z:0;g=g<<31>>31}if((E|0)>0|(E|0)==0&q>>>0>0)l=E;else{ja=(q|0)!=0|(E|0)!=0;q=St(0,0,q|0,E|0)|0;q=ja?q:0;l=ja?z:0;g=ja?0-g|0:g}if((g|0)==(C|0)){if(!x){g=110;break}g=Xr(q|0,0,y|0,0)|0;t=z;ia=Xr(l|0,0,y|0,0)|0;Q=z;u=Xr(q|0,0,s|0,0)|0;v=z;ja=Xr(l|0,0,s|0,0)|0;s=z;u=xv(ia|0,0,u|0,0)|0;l=z;s=xv(Q|0,0,ja|0,s|0)|0;v=xv(s|0,z|0,v|0,0)|0;l=xv(v|0,z|0,l|0,0)|0;v=z;s=xv(0,u|0,g|0,t|0)|0;t=z;u=xv(l|0,v|0,(t>>>0<u>>>0|(t|0)==(u|0)&s>>>0<0)&1|0,0)|0;v=z;l=Xr(w|0,0,A|0,0)|0;g=z;ja=Xr(r|0,0,A|0,0)|0;Q=z;q=Xr(w|0,0,B|0,0)|0;ia=z;ha=Xr(r|0,0,B|0,0)|0;r=z;q=xv(ja|0,0,q|0,0)|0;ja=z;r=xv(Q|0,0,ha|0,r|0)|0;r=xv(r|0,z|0,ia|0,0)|0;ja=xv(r|0,z|0,ja|0,0)|0;r=z;g=xv(0,q|0,l|0,g|0)|0;l=z;q=xv(ja|0,r|0,(l>>>0<q>>>0|(l|0)==(q|0)&g>>>0<0)&1|0,0)|0;r=z;if(v>>>0<r>>>0|(v|0)==(r|0)&u>>>0<q>>>0)g=-1;else g=v>>>0>r>>>0|(v|0)==(r|0)&u>>>0>q>>>0?1:t>>>0<l>>>0|(t|0)==(l|0)&s>>>0<g>>>0?-1:(t>>>0>l>>>0|(t|0)==(l|0)&s>>>0>g>>>0)&1;g=O(g,C)|0}else g=C-g|0;if((g|0)<=0){g=110;break}}c[f>>2]=F;Q=c[F+12>>2]|0;l=F;t=I;v=H;x=G;N=c[Q+88>>2]|0;P=c[Q+92>>2]|0;Q=c[Q+96>>2]|0}if((g|0)==110)return}if((b|0)>=0)return;F=St(0,0,U|0,((U|0)<0)<<31>>31|0)|0;G=z;h=p;d=T;g=m;E=k;c:while(1){x=h;D=b;C=j;y=d;A=g;d:while(1){B=(O(n-i|0,ea)|0)+(O(E-y|0,da)|0)+(O(o-A|0,ca)|0)|0;do if((x|0?c[x+12>>2]|0:0)?(ga=c[(c[x+4>>2]|0)+8>>2]|0,(c[ga+20>>2]|0)>(c[a+100>>2]|0)):0){w=c[ga+12>>2]|0;u=c[w+88>>2]|0;ja=u-E|0;v=c[w+92>>2]|0;ia=v-n|0;w=c[w+96>>2]|0;g=w-o|0;d=Xr(ja|0,((ja|0)<0)<<31>>31|0,W|0,X|0)|0;ha=z;b=Xr(ia|0,((ia|0)<0)<<31>>31|0,Y|0,Z|0)|0;ha=xv(b|0,z|0,d|0,ha|0)|0;d=z;b=Xr(g|0,((g|0)<0)<<31>>31|0,_|0,$|0)|0;b=xv(ha|0,d|0,b|0,z|0)|0;d=z;g=(O(ia,ea)|0)+(O(ja,da)|0)+(O(g,ca)|0)|0;if((b|0)==0&(d|0)==0)if((g|0)>0)break d;else break;if((d|0)<0){if((g|0)>0){j=1;k=g;h=((g|0)<0)<<31>>31}else{k=St(0,0,g|0,((g|0)<0)<<31>>31|0)|0;j=((g|0)!=0)<<31>>31;k=g|0?k:0;h=g|0?z:0}p=St(0,0,b|0,d|0)|0;q=z;t=0-j|0;if((B|0)>0){r=B;s=((B|0)<0)<<31>>31;g=1}else{r=St(0,0,B|0,((B|0)<0)<<31>>31|0)|0;r=B|0?r:0;s=B|0?z:0;g=((B|0)!=0)<<31>>31}if((D|0)>0|(D|0)==0&C>>>0>0){b=C;d=D}else{ja=(C|0)!=0|(D|0)!=0;b=St(0,0,C|0,D|0)|0;b=ja?b:0;d=ja?z:0;g=ja?0-g|0:g}if((g|0)==(t|0)){if(!j)break d;g=Xr(b|0,0,k|0,0)|0;j=z;ha=Xr(d|0,0,k|0,0)|0;V=z;l=Xr(b|0,0,h|0,0)|0;m=z;ja=Xr(d|0,0,h|0,0)|0;k=z;l=xv(ha|0,0,l|0,0)|0;b=z;k=xv(V|0,0,ja|0,k|0)|0;m=xv(k|0,z|0,m|0,0)|0;b=xv(m|0,z|0,b|0,0)|0;m=z;j=xv(0,l|0,g|0,j|0)|0;k=z;l=xv(b|0,m|0,(k>>>0<l>>>0|(k|0)==(l|0)&j>>>0<0)&1|0,0)|0;m=z;b=Xr(r|0,0,p|0,0)|0;g=z;ja=Xr(s|0,0,p|0,0)|0;V=z;d=Xr(r|0,0,q|0,0)|0;h=z;ha=Xr(s|0,0,q|0,0)|0;ia=z;d=xv(ja|0,0,d|0,0)|0;ja=z;ia=xv(V|0,0,ha|0,ia|0)|0;h=xv(ia|0,z|0,h|0,0)|0;ja=xv(h|0,z|0,ja|0,0)|0;h=z;g=xv(0,d|0,b|0,g|0)|0;b=z;d=xv(ja|0,h|0,(b>>>0<d>>>0|(b|0)==(d|0)&g>>>0<0)&1|0,0)|0;h=z;if(m>>>0<h>>>0|(m|0)==(h|0)&l>>>0<d>>>0)g=-1;else g=m>>>0>h>>>0|(m|0)==(h|0)&l>>>0>d>>>0?1:k>>>0<b>>>0|(k|0)==(b|0)&j>>>0<g>>>0?-1:(k>>>0>b>>>0|(k|0)==(b|0)&j>>>0>g>>>0)&1;g=O(g,t)|0}else g=t-g|0;if((g|0)<1)break d}}while(0);g=c[e>>2]|0;if(!g){g=110;break c}if(!(c[g+12>>2]|0)){g=110;break c}v=c[(c[g+8>>2]|0)+4>>2]|0;if((c[v+20>>2]|0)<=(c[a+100>>2]|0)){g=110;break c}d=c[v+12>>2]|0;k=c[d+88>>2]|0;h=k-y|0;j=c[d+92>>2]|0;b=j-i|0;d=c[d+96>>2]|0;g=d-A|0;ja=Xr(h|0,((h|0)<0)<<31>>31|0,aa|0,((aa|0)<0)<<31>>31|0)|0;ha=z;ia=Xr(b|0,((b|0)<0)<<31>>31|0,ba|0,((ba|0)<0)<<31>>31|0)|0;ha=xv(ia|0,z|0,ja|0,ha|0)|0;ja=z;ia=Xr(g|0,((g|0)<0)<<31>>31|0,F|0,G|0)|0;if(!((ha|0)==(ia|0)&(ja|0)==(z|0))){g=110;break c}l=Xr(h|0,((h|0)<0)<<31>>31|0,W|0,X|0)|0;u=z;i=Xr(b|0,((b|0)<0)<<31>>31|0,Y|0,Z|0)|0;u=xv(i|0,z|0,l|0,u|0)|0;l=z;i=Xr(g|0,((g|0)<0)<<31>>31|0,_|0,$|0)|0;i=xv(u|0,l|0,i|0,z|0)|0;l=z;g=(O(b,ea)|0)+(O(h,da)|0)+(O(g,ca)|0)|0;u=E-k|0;ia=n-j|0;t=o-d|0;u=Xr(u|0,((u|0)<0)<<31>>31|0,W|0,X|0)|0;ja=z;ia=Xr(ia|0,((ia|0)<0)<<31>>31|0,Y|0,Z|0)|0;ja=xv(ia|0,z|0,u|0,ja|0)|0;u=z;t=Xr(t|0,((t|0)<0)<<31>>31|0,_|0,$|0)|0;t=xv(ja|0,u|0,t|0,z|0)|0;u=z;if((u|0)>=0){g=110;break c}if((i|0)==0&(l|0)==0){if((g|0)<=0){g=110;break c}}else{if((l|0)>=0){g=110;break c}if((g|0)>0){j=1;k=g;h=((g|0)<0)<<31>>31}else{k=St(0,0,g|0,((g|0)<0)<<31>>31|0)|0;j=((g|0)!=0)<<31>>31;k=g|0?k:0;h=g|0?z:0}m=St(0,0,i|0,l|0)|0;p=z;s=0-j|0;if((B|0)>0){q=B;r=((B|0)<0)<<31>>31;g=1}else{q=St(0,0,B|0,((B|0)<0)<<31>>31|0)|0;q=B|0?q:0;r=B|0?z:0;g=((B|0)!=0)<<31>>31}if((D|0)>0|(D|0)==0&C>>>0>0){d=C;b=D}else{ja=(C|0)!=0|(D|0)!=0;d=St(0,0,C|0,D|0)|0;d=ja?d:0;b=ja?z:0;g=ja?0-g|0:g}if((g|0)==(s|0)){if(!j){g=110;break c}j=Xr(d|0,0,k|0,0)|0;i=z;ha=Xr(b|0,0,k|0,0)|0;V=z;k=Xr(d|0,0,h|0,0)|0;l=z;ja=Xr(b|0,0,h|0,0)|0;g=z;k=xv(ha|0,0,k|0,0)|0;b=z;g=xv(V|0,0,ja|0,g|0)|0;l=xv(g|0,z|0,l|0,0)|0;b=xv(l|0,z|0,b|0,0)|0;l=z;i=xv(0,k|0,j|0,i|0)|0;j=z;k=xv(b|0,l|0,(j>>>0<k>>>0|(j|0)==(k|0)&i>>>0<0)&1|0,0)|0;l=z;b=Xr(q|0,0,m|0,0)|0;g=z;ja=Xr(r|0,0,m|0,0)|0;V=z;d=Xr(q|0,0,p|0,0)|0;h=z;ha=Xr(r|0,0,p|0,0)|0;ia=z;d=xv(ja|0,0,d|0,0)|0;ja=z;ia=xv(V|0,0,ha|0,ia|0)|0;h=xv(ia|0,z|0,h|0,0)|0;ja=xv(h|0,z|0,ja|0,0)|0;h=z;g=xv(0,d|0,b|0,g|0)|0;b=z;d=xv(ja|0,h|0,(b>>>0<d>>>0|(b|0)==(d|0)&g>>>0<0)&1|0,0)|0;h=z;if(l>>>0<h>>>0|(l|0)==(h|0)&k>>>0<d>>>0)g=-1;else g=l>>>0>h>>>0|(l|0)==(h|0)&k>>>0>d>>>0?1:j>>>0<b>>>0|(j|0)==(b|0)&i>>>0<g>>>0?-1:(j>>>0>b>>>0|(j|0)==(b|0)&i>>>0>g>>>0)&1;g=O(g,s)|0}else g=s-g|0;if((g|0)>=0){g=110;break c}}c[e>>2]=v;A=c[v+12>>2]|0;x=c[f>>2]|0;D=u;C=t;y=c[A+88>>2]|0;i=c[A+92>>2]|0;A=c[A+96>>2]|0}h=u-y|0;d=v-i|0;j=w-A|0;h=Xr(h|0,((h|0)<0)<<31>>31|0,W|0,X|0)|0;b=z;d=Xr(d|0,((d|0)<0)<<31>>31|0,Y|0,Z|0)|0;b=xv(d|0,z|0,h|0,b|0)|0;h=z;j=Xr(j|0,((j|0)<0)<<31>>31|0,_|0,$|0)|0;j=xv(b|0,h|0,j|0,z|0)|0;h=(x|0)==(fa|0)?0:ga;c[f>>2]=h;b=z;d=y;g=A;E=u;n=v;o=w}if((g|0)==110)return}function ic(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,h=0,i=0,k=0.0,m=0,n=0.0,o=0.0,p=0,q=0,r=0.0,s=0,t=0.0,u=0.0,v=0,w=0.0,x=0,y=0.0,z=0,A=0.0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0;H=l;l=l+192|0;if((e|0)<1){f=c[b+12>>2]|0;if(f|0){if(a[b+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[b+12>>2]=0}a[b+16>>0]=1;c[b+12>>2]=0;c[b+4>>2]=0;c[b+8>>2]=0;f=c[b+32>>2]|0;if(f|0){if(a[b+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[b+32>>2]=0}a[b+36>>0]=1;c[b+32>>2]=0;c[b+24>>2]=0;c[b+28>>2]=0;f=c[b+52>>2]|0;if(f|0){if(a[b+56>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[b+52>>2]=0}a[b+56>>0]=1;c[b+52>>2]=0;c[b+44>>2]=0;c[b+48>>2]=0;l=H;return}c[H+32>>2]=0;c[H+36>>2]=0;c[H+40>>2]=0;c[H+44>>2]=256;c[H+48>>2]=0;c[H+52>>2]=0;c[H+56>>2]=0;c[H+60>>2]=256;c[H+64>>2]=0;c[H+68>>2]=0;c[H+72>>2]=0;c[H+76>>2]=256;a[H+96>>0]=1;c[H+92>>2]=0;c[H+84>>2]=0;c[H+88>>2]=0;m=0;p=-246811958;v=-246811958;z=-246811958;s=1900671690;x=1900671690;B=1900671690;q=d;while(1){f=c[q>>2]|0;h=c[q+4>>2]|0;i=c[q+8>>2]|0;k=(c[j>>2]=f,+g[j>>2]);s=k<(c[j>>2]=s,+g[j>>2])?f:s;n=(c[j>>2]=h,+g[j>>2]);x=n<(c[j>>2]=x,+g[j>>2])?h:x;o=(c[j>>2]=i,+g[j>>2]);B=o<(c[j>>2]=B,+g[j>>2])?i:B;p=(c[j>>2]=p,+g[j>>2])<k?f:p;v=(c[j>>2]=v,+g[j>>2])<n?h:v;z=(c[j>>2]=z,+g[j>>2])<o?i:z;m=m+1|0;if((m|0)==(e|0))break;else q=q+16|0}A=(c[j>>2]=p,+g[j>>2]);y=(c[j>>2]=s,+g[j>>2]);w=(c[j>>2]=v,+g[j>>2]);u=(c[j>>2]=x,+g[j>>2]);t=(c[j>>2]=z,+g[j>>2]);r=(c[j>>2]=B,+g[j>>2]);g[H+168>>2]=A-y;s=H+168+4|0;g[s>>2]=w-u;v=H+168+8|0;g[v>>2]=t-r;g[H+168+12>>2]=0.0;h=+g[H+168+((A-y<w-u&1)<<2)>>2]<t-r?2:A-y<w-u&1;c[H+112>>2]=h;f=+g[H+168+((!(A-y<w-u)&1)<<2)>>2]<t-r?!(A-y<w-u)&1:2;if((f|0)==(h|0))f=((h+1|0)>>>0)%3|0;c[H+104>>2]=f;F=(h^3)-f|0;c[H+108>>2]=F;g[H+168>>2]=(A-y)*9.788566967472434e-05;g[s>>2]=(w-u)*9.788566967472434e-05;g[v>>2]=(t-r)*9.788566967472434e-05;if(((F+1|0)%3|0|0)==(h|0)){k=(A-y)*9.788566967472434e-05;n=(w-u)*9.788566967472434e-05;o=(t-r)*9.788566967472434e-05}else{g[H+168>>2]=-((A-y)*9.788566967472434e-05);g[s>>2]=-((w-u)*9.788566967472434e-05);g[v>>2]=-((t-r)*9.788566967472434e-05);k=-((A-y)*9.788566967472434e-05);n=-((w-u)*9.788566967472434e-05);o=-((t-r)*9.788566967472434e-05)}c[H>>2]=c[H+168>>2];c[H+4>>2]=c[H+168+4>>2];c[H+8>>2]=c[H+168+8>>2];c[H+12>>2]=c[H+168+12>>2];if(k!=0.0)g[H+168>>2]=1.0/k;if(n!=0.0)g[s>>2]=1.0/n;if(o!=0.0)g[v>>2]=1.0/o;g[H+16>>2]=(A+y)*.5;g[H+20>>2]=(w+u)*.5;g[H+24>>2]=(t+r)*.5;g[H+28>>2]=0.0;z=H+144+16|0;a[z>>0]=1;x=H+144+12|0;c[x>>2]=0;c[H+144+4>>2]=0;c[H+144+8>>2]=0;c[6432]=(c[6432]|0)+1;f=ec((e<<4|3)+16|0)|0;if(!f)m=0;else{c[(f+4+15&-16)+-4>>2]=f;m=f+4+15&-16}i=c[H+144+4>>2]|0;h=c[x>>2]|0;if((i|0)<=0){if(h|0)G=32}else{f=0;do{G=m+(f<<4)|0;F=h+(f<<4)|0;c[G>>2]=c[F>>2];c[G+4>>2]=c[F+4>>2];c[G+8>>2]=c[F+8>>2];c[G+12>>2]=c[F+12>>2];f=f+1|0}while((f|0)!=(i|0));G=32}if((G|0)==32){if(a[z>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[x>>2]=0}a[z>>0]=1;c[x>>2]=m;c[H+144+8>>2]=e;c[m>>2]=c[H+128>>2];c[m+4>>2]=c[H+128+4>>2];c[m+8>>2]=c[H+128+8>>2];c[m+12>>2]=c[H+128+12>>2];if((e|0)!=1){f=1;do{F=(c[x>>2]|0)+(f<<4)|0;c[F>>2]=c[H+128>>2];c[F+4>>2]=c[H+128+4>>2];c[F+8>>2]=c[H+128+8>>2];c[F+12>>2]=c[H+128+12>>2];f=f+1|0}while((f|0)!=(e|0))}c[H+144+4>>2]=e;m=H+128+(c[H+108>>2]<<2)|0;i=c[x>>2]|0;p=H+128+(c[H+112>>2]<<2)|0;q=H+128+(c[H+104>>2]<<2)|0;o=+g[H+16>>2];r=+g[H+20>>2];t=+g[H+24>>2];u=+g[H+168>>2];n=+g[s>>2];k=+g[v>>2];h=0;f=d;while(1){y=(+g[f+4>>2]-r)*n;A=(+g[f+8>>2]-t)*k;g[H+128>>2]=(+g[f>>2]-o)*u;g[H+128+4>>2]=y;g[H+128+8>>2]=A;g[H+128+12>>2]=0.0;c[i+(h<<4)>>2]=~~+g[m>>2];c[i+(h<<4)+4>>2]=~~+g[p>>2];c[i+(h<<4)+8>>2]=~~+g[q>>2];c[i+(h<<4)+12>>2]=h;h=h+1|0;if((h|0)==(e|0))break;else f=f+16|0}if((e|0)>1)Ig(H+144|0,0,e+-1|0);c[H+36>>2]=c[H+32>>2];c[H+40>>2]=0;c[H+44>>2]=e;f=c[H+84>>2]|0;if((f|0)<(e|0)){if((c[H+88>>2]|0)<(e|0)){if(!e){i=f;m=0}else{c[6432]=(c[6432]|0)+1;h=ec((e<<2|3)+16|0)|0;if(!h)h=0;else{c[(h+4+15&-16)+-4>>2]=h;h=h+4+15&-16}i=c[H+84>>2]|0;m=h}if((i|0)>0){h=0;do{c[m+(h<<2)>>2]=c[(c[H+92>>2]|0)+(h<<2)>>2];h=h+1|0}while((h|0)!=(i|0))}h=c[H+92>>2]|0;if(h|0){if(a[H+96>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[H+92>>2]=0}a[H+96>>0]=1;c[H+92>>2]=m;c[H+88>>2]=e}do{c[(c[H+92>>2]|0)+(f<<2)>>2]=0;f=f+1|0}while((f|0)!=(e|0))}c[H+84>>2]=e;p=0;do{f=c[H+40>>2]|0;if(!f){f=c[H+36>>2]|0;if(!f){c[6432]=(c[6432]|0)+1;f=ec(31)|0;if(!f)h=0;else{c[(f+4+15&-16)+-4>>2]=f;h=f+4+15&-16}f=c[H+44>>2]|0;c[h+4>>2]=f;i=h+8|0;c[i>>2]=0;c[6432]=(c[6432]|0)+1;f=ec((f*112|3)+16|0)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}c[h>>2]=f;c[i>>2]=c[H+32>>2];c[H+32>>2]=h}else{c[H+36>>2]=c[f+8>>2];h=f}f=c[h>>2]|0;h=c[h+4>>2]|0;if((h|0)>0){i=0;m=f;do{i=i+1|0;F=m;m=m+112|0;c[F>>2]=(i|0)<(h|0)?m:0}while((i|0)!=(h|0))}}c[H+40>>2]=c[f>>2];F=f+104|0;c[f>>2]=0;c[f+4>>2]=0;c[f+8>>2]=0;c[f+12>>2]=0;c[f+16>>2]=0;c[F>>2]=-1;c[f+8>>2]=0;D=(c[x>>2]|0)+(p<<4)|0;E=f+88|0;c[E>>2]=c[D>>2];c[E+4>>2]=c[D+4>>2];c[E+8>>2]=c[D+8>>2];c[E+12>>2]=c[D+12>>2];c[F>>2]=-1;c[(c[H+92>>2]|0)+(p<<2)>>2]=f;p=p+1|0}while((p|0)<(e|0));f=c[x>>2]|0;if(f|0){if(a[z>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[x>>2]=0}a[z>>0]=1;c[x>>2]=0;c[H+144+4>>2]=0;c[H+144+8>>2]=0;c[H+52>>2]=c[H+48>>2];c[H+56>>2]=0;c[H+60>>2]=e*6;c[H+116>>2]=0;c[H+120>>2]=0;c[H+100>>2]=-3;c[H+128>>2]=0;c[H+128+4>>2]=0;c[H+128+8>>2]=0;c[H+128+12>>2]=0;cc(H,0,e,H+128|0);c[H+124>>2]=c[H+128>>2];f=c[x>>2]|0;if(f|0){if(a[z>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[x>>2]=0}f=c[b+4>>2]|0;if((f|0)<0){if((c[b+8>>2]|0)<0){h=c[b+12>>2]|0;if(h|0){if(a[b+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[b+12>>2]=0}a[b+16>>0]=1;c[b+12>>2]=0;c[b+8>>2]=0}do{F=(c[b+12>>2]|0)+(f<<4)|0;c[F>>2]=c[H+168>>2];c[F+4>>2]=c[H+168+4>>2];c[F+8>>2]=c[H+168+8>>2];c[F+12>>2]=c[H+168+12>>2];f=f+1|0}while((f|0)!=0)}c[b+4>>2]=0;c[H+168>>2]=0;c[H+168+4>>2]=0;c[H+168+8>>2]=0;f=c[b+24>>2]|0;if((f|0)<0){if((c[b+28>>2]|0)<0){h=c[b+32>>2]|0;if(h|0){if(a[b+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[b+32>>2]=0}a[b+36>>0]=1;c[b+32>>2]=0;c[b+28>>2]=0}do{F=(c[b+32>>2]|0)+(f*12|0)|0;c[F>>2]=c[H+168>>2];c[F+4>>2]=c[H+168+4>>2];c[F+8>>2]=c[H+168+8>>2];f=f+1|0}while((f|0)!=0)}c[b+24>>2]=0;h=c[b+44>>2]|0;if((h|0)<0){f=c[b+52>>2]|0;if((c[b+48>>2]|0)<0){do if(f|0){if(!(a[b+56>>0]|0))break;c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}while(0);a[b+56>>0]=1;c[b+52>>2]=0;c[b+48>>2]=0;f=0}Hk(f+(h<<2)|0,0,O(h,-4)|0)|0}c[b+44>>2]=0;h=c[H+124>>2]|0;do if((c[h+104>>2]|0)<0){c[h+104>>2]=0;c[6432]=(c[6432]|0)+1;f=ec(23)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}c[f>>2]=h;s=f;v=f;F=0;x=1;z=f;i=1;while(1){if((c[h+100>>2]|0)>-1){g[H+168+(c[H+108>>2]<<2)>>2]=+(c[h+88>>2]|0);g[H+168+(c[H+112>>2]<<2)>>2]=+(c[h+92>>2]|0);k=+(c[h+96>>2]|0)}else{E=h+24|0;D=h+32|0;A=+Cm(c[E>>2]|0,c[E+4>>2]|0,c[D>>2]|0,c[D+4>>2]|0);D=h+72|0;E=h+80|0;k=+Cm(c[D>>2]|0,c[D+4>>2]|0,c[E>>2]|0,c[E+4>>2]|0);g[H+168+(c[H+108>>2]<<2)>>2]=A/k;E=h+40|0;D=h+48|0;A=+Cm(c[E>>2]|0,c[E+4>>2]|0,c[D>>2]|0,c[D+4>>2]|0)/k;g[H+168+(c[H+112>>2]<<2)>>2]=A;D=h+56|0;E=h+64|0;k=+Cm(c[D>>2]|0,c[D+4>>2]|0,c[E>>2]|0,c[E+4>>2]|0)/k}g[H+168+(c[H+104>>2]<<2)>>2]=k;k=+g[H+168>>2]*+g[H>>2]+ +g[H+16>>2];o=+g[H+168+4>>2]*+g[H+4>>2]+ +g[H+20>>2];n=+g[H+168+8>>2]*+g[H+8>>2]+ +g[H+24>>2];f=c[b+4>>2]|0;do if((f|0)==(c[b+8>>2]|0)){q=f|0?f<<1:1;if((f|0)>=(q|0))break;if(!q)m=0;else{c[6432]=(c[6432]|0)+1;f=ec((q<<4|3)+16|0)|0;if(!f)m=0;else{c[(f+4+15&-16)+-4>>2]=f;m=f+4+15&-16}f=c[b+4>>2]|0}if((f|0)>0){p=0;do{E=m+(p<<4)|0;D=(c[b+12>>2]|0)+(p<<4)|0;c[E>>2]=c[D>>2];c[E+4>>2]=c[D+4>>2];c[E+8>>2]=c[D+8>>2];c[E+12>>2]=c[D+12>>2];p=p+1|0}while((p|0)!=(f|0))}f=c[b+12>>2]|0;if(f|0){if(a[b+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[b+12>>2]=0}a[b+16>>0]=1;c[b+12>>2]=m;c[b+8>>2]=q;f=c[b+4>>2]|0}while(0);E=c[b+12>>2]|0;g[E+(f<<4)>>2]=k;g[E+(f<<4)+4>>2]=o;g[E+(f<<4)+8>>2]=n;g[E+(f<<4)+12>>2]=0.0;c[b+4>>2]=(c[b+4>>2]|0)+1;E=c[h+8>>2]|0;if(!E){B=v;m=s;p=x}else{m=s;B=v;D=E;h=-1;p=x;C=-1;while(1){e=D+20|0;f=c[e>>2]|0;if((f|0)<0){d=c[b+24>>2]|0;c[H+168>>2]=0;c[H+168+4>>2]=0;c[H+168+8>>2]=0;do if((d|0)==(c[b+28>>2]|0)){v=d|0?d<<1:1;if((d|0)>=(v|0)){f=d;break}if(!v){q=d;s=0}else{c[6432]=(c[6432]|0)+1;f=ec((v*12|3)+16|0)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}q=c[b+24>>2]|0;s=f}if((q|0)>0){f=0;do{x=s+(f*12|0)|0;I=(c[b+32>>2]|0)+(f*12|0)|0;c[x>>2]=c[I>>2];c[x+4>>2]=c[I+4>>2];c[x+8>>2]=c[I+8>>2];f=f+1|0}while((f|0)!=(q|0))}f=c[b+32>>2]|0;if(f|0){if(a[b+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[b+32>>2]=0}a[b+36>>0]=1;c[b+32>>2]=s;c[b+28>>2]=v;f=c[b+24>>2]|0}else f=d;while(0);f=(c[b+32>>2]|0)+(f*12|0)|0;c[f>>2]=c[H+168>>2];c[f+4>>2]=c[H+168+4>>2];c[f+8>>2]=c[H+168+8>>2];f=(c[b+24>>2]|0)+1|0;c[b+24>>2]=f;c[H+168>>2]=0;c[H+168+4>>2]=0;c[H+168+8>>2]=0;do if((f|0)==(c[b+28>>2]|0)){v=f|0?f<<1:1;if((f|0)>=(v|0))break;if(!v)q=0;else{c[6432]=(c[6432]|0)+1;f=ec((v*12|3)+16|0)|0;if(!f)q=0;else{c[(f+4+15&-16)+-4>>2]=f;q=f+4+15&-16}f=c[b+24>>2]|0}if((f|0)>0){s=0;do{I=q+(s*12|0)|0;x=(c[b+32>>2]|0)+(s*12|0)|0;c[I>>2]=c[x>>2];c[I+4>>2]=c[x+4>>2];c[I+8>>2]=c[x+8>>2];s=s+1|0}while((s|0)!=(f|0))}f=c[b+32>>2]|0;if(f|0){if(a[b+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[b+32>>2]=0}a[b+36>>0]=1;c[b+32>>2]=q;c[b+28>>2]=v;f=c[b+24>>2]|0}while(0);x=(c[b+32>>2]|0)+(f*12|0)|0;c[x>>2]=c[H+168>>2];c[x+4>>2]=c[H+168+4>>2];c[x+8>>2]=c[H+168+8>>2];c[b+24>>2]=(c[b+24>>2]|0)+1;x=c[b+32>>2]|0;c[e>>2]=d;c[(c[D+8>>2]|0)+20>>2]=d+1;c[x+(d*12|0)+4>>2]=1;c[x+((d+1|0)*12|0)+4>>2]=-1;v=c[D+12>>2]|0;f=c[v+104>>2]|0;if((f|0)<0){c[v+104>>2]=i;do if((i|0)==(p|0)){s=p|0?p<<1:1;if((p|0)>=(s|0)){f=B;q=z;break}do if(!s)q=0;else{c[6432]=(c[6432]|0)+1;f=ec((s<<2|3)+16|0)|0;if(!f){q=0;break}c[(f+4+15&-16)+-4>>2]=f;q=f+4+15&-16}while(0);if((p|0)>0){f=0;do{c[q+(f<<2)>>2]=c[z+(f<<2)>>2];f=f+1|0}while((f|0)!=(p|0));if(!m){f=q;m=q;p=s;break}}else if((z|0)==0|(m|0)==0){f=q;m=q;p=s;break}c[6433]=(c[6433]|0)+1;Pc(c[m+-4>>2]|0);f=q;m=q;p=s}else{f=B;q=z}while(0);c[q+(i<<2)>>2]=v;s=f;f=i;i=i+1|0}else{s=B;q=z}c[x+(d*12|0)+8>>2]=f;c[x+((d+1|0)*12|0)+8>>2]=F;f=c[e>>2]|0}else{s=B;q=z}if((C|0)>-1)c[(c[b+32>>2]|0)+(f*12|0)>>2]=C-f;else h=f;D=c[D>>2]|0;if((D|0)==(E|0))break;else{B=s;z=q;C=f}}c[(c[b+32>>2]|0)+(h*12|0)>>2]=f-h;B=s;z=q}f=F+1|0;if((f|0)>=(i|0))break;h=c[z+(f<<2)>>2]|0;s=m;v=B;F=f;x=p}if((F|0)>-1){x=0;while(1){s=c[(c[z+(x<<2)>>2]|0)+8>>2]|0;if(s|0){v=s;do{q=v+20|0;f=c[q>>2]|0;if((f|0)>-1){h=c[b+44>>2]|0;do if((h|0)==(c[b+48>>2]|0)){p=h|0?h<<1:1;if((h|0)>=(p|0))break;if(!p){f=h;h=0}else{c[6432]=(c[6432]|0)+1;f=ec((p<<2|3)+16|0)|0;if(!f)h=0;else{c[(f+4+15&-16)+-4>>2]=f;h=f+4+15&-16}f=c[b+44>>2]|0}m=c[b+52>>2]|0;if((f|0)<=0){if(m)G=180}else{i=0;do{c[h+(i<<2)>>2]=c[m+(i<<2)>>2];i=i+1|0}while((i|0)!=(f|0));G=180}if((G|0)==180){G=0;if(a[b+56>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[m+-4>>2]|0)}c[b+52>>2]=0;f=c[b+44>>2]|0}a[b+56>>0]=1;c[b+52>>2]=h;c[b+48>>2]=p;h=f;f=c[q>>2]|0}while(0);c[(c[b+52>>2]|0)+(h<<2)>>2]=f;c[b+44>>2]=(c[b+44>>2]|0)+1;f=v;do{c[f+20>>2]=-1;f=c[(c[f+8>>2]|0)+4>>2]|0}while((f|0)!=(v|0))}v=c[v>>2]|0}while((v|0)!=(s|0))}if((x|0)==(F|0))break;else x=x+1|0}}if((z|0)==0|(B|0)==0)break;c[6433]=(c[6433]|0)+1;Pc(c[B+-4>>2]|0)}while(0);zi(H);l=H;return}function jc(b,d,e,f,h,i,j,k,m){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;j=j|0;k=k|0;m=m|0;var n=0,o=0,p=0,q=0.0,r=0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0.0,O=0.0,P=0.0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0;Y=l;l=l+256|0;c[b+188>>2]=-1;Yi(12978);c[b+184>>2]=0;if((e|0)>0){m=0;do{c[(c[d+(m<<2)>>2]|0)+212>>2]=-1;m=m+1|0}while((m|0)!=(e|0))}m=c[b+12>>2]|0;if((m|0)>(e|0))o=b+8|0;else{if((e+1|0)!=0?(c[6432]=(c[6432]|0)+1,n=ec(((e+1|0)*244|3)+16|0)|0,(n|0)!=0):0){c[(n+4+15&-16)+-4>>2]=n;o=n+4+15&-16}else o=0;m=c[b+8>>2]|0;if((m|0)>0){n=0;do{V=o+(n*244|0)|0;W=c[b+16>>2]|0;U=W+(n*244|0)|0;c[V>>2]=c[U>>2];c[V+4>>2]=c[U+4>>2];c[V+8>>2]=c[U+8>>2];c[V+12>>2]=c[U+12>>2];V=W+(n*244|0)+16|0;U=o+(n*244|0)+16|0;c[U>>2]=c[V>>2];c[U+4>>2]=c[V+4>>2];c[U+8>>2]=c[V+8>>2];c[U+12>>2]=c[V+12>>2];U=W+(n*244|0)+32|0;V=o+(n*244|0)+32|0;c[V>>2]=c[U>>2];c[V+4>>2]=c[U+4>>2];c[V+8>>2]=c[U+8>>2];c[V+12>>2]=c[U+12>>2];V=o+(n*244|0)+48|0;U=W+(n*244|0)+48|0;c[V>>2]=c[U>>2];c[V+4>>2]=c[U+4>>2];c[V+8>>2]=c[U+8>>2];c[V+12>>2]=c[U+12>>2];Th(o+(n*244|0)+64|0,W+(n*244|0)+64|0,180)|0;n=n+1|0}while((n|0)!=(m|0))}m=c[b+16>>2]|0;if(m|0){if(a[b+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[m+-4>>2]|0)}c[b+16>>2]=0}a[b+20>>0]=1;c[b+16>>2]=o;c[b+12>>2]=e+1;m=e+1|0;o=b+8|0}Hk(Y|0,0,244)|0;n=c[o>>2]|0;if((n|0)<0){if((m|0)<0){m=c[b+16>>2]|0;if(m|0){if(a[b+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[m+-4>>2]|0)}c[b+16>>2]=0}a[b+20>>0]=1;c[b+16>>2]=0;c[b+12>>2]=0}m=n;do{W=c[b+16>>2]|0;V=W+(m*244|0)|0;c[V>>2]=c[Y>>2];c[V+4>>2]=c[Y+4>>2];c[V+8>>2]=c[Y+8>>2];c[V+12>>2]=c[Y+12>>2];V=W+(m*244|0)+16|0;c[V>>2]=c[Y+16>>2];c[V+4>>2]=c[Y+16+4>>2];c[V+8>>2]=c[Y+16+8>>2];c[V+12>>2]=c[Y+16+12>>2];V=W+(m*244|0)+32|0;c[V>>2]=c[Y+32>>2];c[V+4>>2]=c[Y+32+4>>2];c[V+8>>2]=c[Y+32+8>>2];c[V+12>>2]=c[Y+32+12>>2];V=W+(m*244|0)+48|0;c[V>>2]=c[Y+48>>2];c[V+4>>2]=c[Y+48+4>>2];c[V+8>>2]=c[Y+48+8>>2];c[V+12>>2]=c[Y+48+12>>2];Th(W+(m*244|0)+64|0,Y+64|0,180)|0;m=m+1|0}while((m|0)!=0)}c[o>>2]=0;if((e|0)>0){o=0;do{m=d+(o<<2)|0;n=Bj(b,c[m>>2]|0,+g[k+12>>2])|0;m=c[m>>2]|0;if((!((m|0)==0?1:(c[m+236>>2]&2|0)==0)?+g[m+344>>2]!=0.0:0)?(p=c[b+16>>2]|0,c[m+504>>2]&2|0):0){q=+g[k+76>>2];M=1.0/+g[m+396>>2];O=1.0/+g[m+400>>2];s=1.0/+g[m+404>>2];G=+g[m+4>>2];H=+g[m+8>>2];I=+g[m+12>>2];J=+g[m+20>>2];K=+g[m+24>>2];L=+g[m+28>>2];N=+g[m+36>>2];P=+g[m+40>>2];u=+g[m+44>>2];w=+g[m+328>>2];x=+g[m+332>>2];t=+g[m+336>>2];z=(M*G*G+O*H*H+s*I*I)*w+(M*G*J+O*H*K+s*I*L)*x+(M*G*N+O*H*P+s*I*u)*t;y=(M*J*G+O*K*H+s*L*I)*w+(M*J*J+O*K*K+s*L*L)*x+(M*J*N+O*K*P+s*L*u)*t;u=(M*N*G+O*P*H+s*u*I)*w+(M*N*J+O*P*K+s*u*L)*x+(M*N*N+O*P*P+s*u*u)*t;s=(x*u-t*y)*(x*u-t*y)+(t*z-w*u)*(t*z-w*u)+(w*y-x*z)*(w*y-x*z);if(s>q*q){q=1.0/+C(+s)*q;v=(x*u-t*y)*q;s=q*(t*z-w*u);q=q*(w*y-x*z)}else{v=x*u-t*y;s=t*z-w*u;q=w*y-x*z}N=+g[k+12>>2];O=(v*+g[m+268>>2]+s*+g[m+284>>2]+q*+g[m+300>>2])*N;P=N*(v*+g[m+272>>2]+s*+g[m+288>>2]+q*+g[m+304>>2]);g[p+(n*244|0)+224>>2]=+g[p+(n*244|0)+224>>2]-(v*+g[m+264>>2]+s*+g[m+280>>2]+q*+g[m+296>>2])*N;g[p+(n*244|0)+228>>2]=+g[p+(n*244|0)+228>>2]-O;g[p+(n*244|0)+232>>2]=+g[p+(n*244|0)+232>>2]-P}o=o+1|0}while((o|0)!=(e|0))}if((j|0)>0){m=0;do{W=c[i+(m<<2)>>2]|0;hb[c[(c[W>>2]|0)+8>>2]&511](W);g[W+36>>2]=0.0;m=m+1|0}while((m|0)<(j|0))}m=c[b+168>>2]|0;if((m|0)<(j|0)?(c[b+172>>2]|0)<(j|0):0){if(!j)n=0;else{c[6432]=(c[6432]|0)+1;m=ec((j<<3|3)+16|0)|0;if(!m)n=0;else{c[(m+4+15&-16)+-4>>2]=m;n=m+4+15&-16}m=c[b+168>>2]|0}if((m|0)>0){o=0;do{U=(c[b+176>>2]|0)+(o<<3)|0;V=c[U+4>>2]|0;W=n+(o<<3)|0;c[W>>2]=c[U>>2];c[W+4>>2]=V;o=o+1|0}while((o|0)!=(m|0))}m=c[b+176>>2]|0;if(m|0){if(a[b+180>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[m+-4>>2]|0)}c[b+176>>2]=0}a[b+180>>0]=1;c[b+176>>2]=n;c[b+172>>2]=j}c[b+168>>2]=j;if((j|0)>0){r=0;m=0;do{d=c[b+176>>2]|0;e=d+(r<<3)|0;p=i+(r<<2)|0;n=c[p>>2]|0;o=c[n+44>>2]|0;if(o){n=o+64|0;do{c[o>>2]=0;o=o+4|0}while((o|0)<(n|0));n=c[p>>2]|0}if(!(a[n+20>>0]|0)){c[e>>2]=0;c[d+(r<<3)+4>>2]=0;n=0}else{jb[c[(c[n>>2]|0)+16>>2]&127](n,e);n=c[e>>2]|0}m=n+m|0;r=r+1|0}while((r|0)<(j|0));p=m}else p=0;m=c[b+48>>2]|0;if((m|0)<(p|0)?(c[b+52>>2]|0)<(p|0):0){if(!p)n=0;else{c[6432]=(c[6432]|0)+1;m=ec((p*152|3)+16|0)|0;if(!m)n=0;else{c[(m+4+15&-16)+-4>>2]=m;n=m+4+15&-16}m=c[b+48>>2]|0}if((m|0)>0){o=0;do{Th(n+(o*152|0)|0,(c[b+56>>2]|0)+(o*152|0)|0,152)|0;o=o+1|0}while((o|0)!=(m|0))}m=c[b+56>>2]|0;if(m|0){if(a[b+60>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[m+-4>>2]|0)}c[b+56>>2]=0}a[b+60>>0]=1;c[b+56>>2]=n;c[b+52>>2]=p}c[b+48>>2]=p;if((j|0)>0){m=c[b+176>>2]|0;V=0;W=0;while(1){U=m+(W<<3)|0;if(!(c[U>>2]|0))n=0;else{m=c[b+56>>2]|0;e=m+(V*152|0)|0;r=i+(W<<2)|0;p=c[r>>2]|0;T=c[p+28>>2]|0;S=c[p+32>>2]|0;Q=Bj(b,T,+g[k+12>>2])|0;R=Bj(b,S,+g[k+12>>2])|0;d=c[b+16>>2]|0;n=c[p+24>>2]|0;n=(n|0)>0?n:c[k+20>>2]|0;if((n|0)>(c[b+184>>2]|0))c[b+184>>2]=n;if((c[U>>2]|0)>0){o=0;do{Hk(e+(o*152|0)|0,0,152)|0;g[e+(o*152|0)+120>>2]=-3402823466385288598117041.0e14;g[e+(o*152|0)+124>>2]=3402823466385288598117041.0e14;g[e+(o*152|0)+100>>2]=0.0;g[e+(o*152|0)+96>>2]=0.0;c[e+(o*152|0)+144>>2]=Q;c[e+(o*152|0)+148>>2]=R;c[e+(o*152|0)+136>>2]=n;o=o+1|0}while((o|0)<(c[U>>2]|0))}c[d+(Q*244|0)+64>>2]=0;c[d+(Q*244|0)+64+4>>2]=0;c[d+(Q*244|0)+64+8>>2]=0;c[d+(Q*244|0)+64+12>>2]=0;c[d+(Q*244|0)+64+16>>2]=0;c[d+(Q*244|0)+64+20>>2]=0;c[d+(Q*244|0)+64+24>>2]=0;c[d+(Q*244|0)+64+28>>2]=0;c[d+(Q*244|0)+144>>2]=0;c[d+(Q*244|0)+144+4>>2]=0;c[d+(Q*244|0)+144+8>>2]=0;c[d+(Q*244|0)+144+12>>2]=0;c[d+(Q*244|0)+144+16>>2]=0;c[d+(Q*244|0)+144+20>>2]=0;c[d+(Q*244|0)+144+24>>2]=0;c[d+(Q*244|0)+144+28>>2]=0;c[d+(R*244|0)+64>>2]=0;c[d+(R*244|0)+64+4>>2]=0;c[d+(R*244|0)+64+8>>2]=0;c[d+(R*244|0)+64+12>>2]=0;c[d+(R*244|0)+64+16>>2]=0;c[d+(R*244|0)+64+20>>2]=0;c[d+(R*244|0)+64+24>>2]=0;c[d+(R*244|0)+64+28>>2]=0;c[d+(R*244|0)+144>>2]=0;c[d+(R*244|0)+144+4>>2]=0;c[d+(R*244|0)+144+8>>2]=0;c[d+(R*244|0)+144+12>>2]=0;c[d+(R*244|0)+144+16>>2]=0;c[d+(R*244|0)+144+20>>2]=0;c[d+(R*244|0)+144+24>>2]=0;c[d+(R*244|0)+144+28>>2]=0;g[Y>>2]=1.0/+g[k+12>>2];c[Y+4>>2]=c[k+32>>2];c[Y+8>>2]=m+(V*152|0)+16;c[Y+12>>2]=e;c[Y+16>>2]=m+(V*152|0)+48;c[Y+20>>2]=m+(V*152|0)+32;c[Y+24>>2]=38;c[Y+28>>2]=m+(V*152|0)+112;o=m+(V*152|0)+116|0;c[o>>2]=c[k+40>>2];c[Y+52>>2]=c[k+4>>2];c[Y+32>>2]=o;c[Y+36>>2]=m+(V*152|0)+120;c[Y+40>>2]=m+(V*152|0)+124;c[Y+48>>2]=c[k+20>>2];o=c[r>>2]|0;jb[c[(c[o>>2]|0)+20>>2]&127](o,Y);if((c[U>>2]|0)>0){n=0;do{m=e+(n*152|0)+124|0;q=+g[(c[r>>2]|0)+16>>2];if(+g[m>>2]>=q)g[m>>2]=q;m=e+(n*152|0)+120|0;if(+g[m>>2]<=-q)g[m>>2]=-q;c[e+(n*152|0)+132>>2]=p;Z=e+(n*152|0)|0;_=c[p+28>>2]|0;O=+g[Z>>2];M=+g[Z+4>>2];N=+g[Z+8>>2];q=(O*+g[_+280>>2]+M*+g[_+284>>2]+N*+g[_+288>>2])*+g[_+548>>2];s=(O*+g[_+296>>2]+M*+g[_+300>>2]+N*+g[_+304>>2])*+g[_+552>>2];o=e+(n*152|0)+64|0;g[o>>2]=(+g[_+264>>2]*O+ +g[_+268>>2]*M+ +g[_+272>>2]*N)*+g[_+544>>2];g[o+4>>2]=q;g[o+8>>2]=s;g[o+12>>2]=0.0;o=e+(n*152|0)+32|0;_=c[p+32>>2]|0;s=+g[o>>2];q=+g[o+4>>2];N=+g[o+8>>2];M=(s*+g[_+280>>2]+q*+g[_+284>>2]+N*+g[_+288>>2])*+g[_+548>>2];O=(s*+g[_+296>>2]+q*+g[_+300>>2]+N*+g[_+304>>2])*+g[_+552>>2];m=e+(n*152|0)+80|0;g[m>>2]=(+g[_+264>>2]*s+ +g[_+268>>2]*q+ +g[_+272>>2]*N)*+g[_+544>>2];g[m+4>>2]=M;g[m+8>>2]=O;g[m+12>>2]=0.0;m=e+(n*152|0)+16|0;O=+g[T+344>>2];M=+g[m>>2];N=+g[m+4>>2];q=+g[m+8>>2];s=+g[Z>>2];t=+g[Z+4>>2];u=+g[Z+8>>2];Z=e+(n*152|0)+48|0;P=+g[S+344>>2];v=+g[Z>>2];w=+g[Z+4>>2];x=+g[Z+8>>2];y=+g[o>>2];z=+g[o+4>>2];A=+g[o+8>>2];P=M*O*M+N*O*N+q*O*q+(s*(+g[T+264>>2]*s+ +g[T+268>>2]*t+ +g[T+272>>2]*u)+t*(s*+g[T+280>>2]+t*+g[T+284>>2]+u*+g[T+288>>2])+u*(s*+g[T+296>>2]+t*+g[T+300>>2]+u*+g[T+304>>2]))+(v*P*v+w*P*w+x*P*x)+(y*(+g[S+264>>2]*y+ +g[S+268>>2]*z+ +g[S+272>>2]*A)+z*(y*+g[S+280>>2]+z*+g[S+284>>2]+A*+g[S+288>>2])+A*(y*+g[S+296>>2]+z*+g[S+300>>2]+A*+g[S+304>>2]));o=+B(+P)>1.1920928955078125e-07;P=o?1.0/P:0.0;g[e+(n*152|0)+108>>2]=P;if(!(c[d+(Q*244|0)+240>>2]|0)){D=0.0;E=0.0;F=0.0;G=0.0;H=0.0;I=0.0}else{D=+g[d+(Q*244|0)+208>>2];E=+g[d+(Q*244|0)+212>>2];F=+g[d+(Q*244|0)+216>>2];G=+g[d+(Q*244|0)+224>>2];H=+g[d+(Q*244|0)+228>>2];I=+g[d+(Q*244|0)+232>>2]}if(!(c[d+(R*244|0)+240>>2]|0)){J=0.0;K=0.0;L=0.0;M=0.0;N=0.0;O=0.0}else{J=+g[d+(R*244|0)+208>>2];K=+g[d+(R*244|0)+212>>2];L=+g[d+(R*244|0)+216>>2];M=+g[d+(R*244|0)+224>>2];N=+g[d+(R*244|0)+228>>2];O=+g[d+(R*244|0)+232>>2]}_=e+(n*152|0)+112|0;g[_>>2]=+g[_>>2]*P+P*(0.0-+g[Y+52>>2]*((D+ +g[T+312>>2])*+g[m>>2]+(E+ +g[T+316>>2])*+g[m+4>>2]+(F+ +g[T+320>>2])*q+((G+ +g[T+328>>2])*s+(H+ +g[T+332>>2])*t+(I+ +g[T+336>>2])*u)+((J+ +g[S+312>>2])*v+(K+ +g[S+316>>2])*w+(L+ +g[S+320>>2])*x+((M+ +g[S+328>>2])*y+(N+ +g[S+332>>2])*z+(O+ +g[S+336>>2])*A))));g[e+(n*152|0)+100>>2]=0.0;n=n+1|0}while((n|0)<(c[U>>2]|0))}m=c[b+176>>2]|0;n=c[m+(W<<3)>>2]|0}W=W+1|0;if((W|0)>=(j|0))break;else V=n+V|0}}Vb[c[(c[b>>2]|0)+28>>2]&127](b,f,h,k);d=c[b+48>>2]|0;e=c[b+28>>2]|0;r=c[b+68>>2]|0;m=c[b+128>>2]|0;if((m|0)<(d|0)?(c[b+132>>2]|0)<(d|0):0){if(!d)n=0;else{c[6432]=(c[6432]|0)+1;m=ec((d<<2|3)+16|0)|0;if(!m)n=0;else{c[(m+4+15&-16)+-4>>2]=m;n=m+4+15&-16}m=c[b+128>>2]|0}p=c[b+136>>2]|0;if((m|0)<=0)if(!p)m=b+140|0;else X=99;else{o=0;do{c[n+(o<<2)>>2]=c[p+(o<<2)>>2];o=o+1|0}while((o|0)!=(m|0));X=99}if((X|0)==99){if(a[b+140>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[p+-4>>2]|0)}c[b+136>>2]=0;m=b+140|0}a[m>>0]=1;c[b+136>>2]=n;c[b+132>>2]=d}c[b+128>>2]=d;if(!(c[k+64>>2]&16)){m=c[b+108>>2]|0;if((m|0)<(e|0)?(c[b+112>>2]|0)<(e|0):0){if(!e)n=0;else{c[6432]=(c[6432]|0)+1;m=ec((e<<2|3)+16|0)|0;if(!m)n=0;else{c[(m+4+15&-16)+-4>>2]=m;n=m+4+15&-16}m=c[b+108>>2]|0}p=c[b+116>>2]|0;if((m|0)<=0)if(!p)m=b+120|0;else X=129;else{o=0;do{c[n+(o<<2)>>2]=c[p+(o<<2)>>2];o=o+1|0}while((o|0)!=(m|0));X=129}if((X|0)==129){if(a[b+120>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[p+-4>>2]|0)}c[b+116>>2]=0;m=b+120|0}a[m>>0]=1;c[b+116>>2]=n;c[b+112>>2]=e}c[b+108>>2]=e}else{m=c[b+108>>2]|0;if((m|0)<(e<<1|0)?(c[b+112>>2]|0)<(e<<1|0):0){if(!e)n=0;else{c[6432]=(c[6432]|0)+1;m=ec((e<<3|3)+16|0)|0;if(!m)n=0;else{c[(m+4+15&-16)+-4>>2]=m;n=m+4+15&-16}m=c[b+108>>2]|0}p=c[b+116>>2]|0;if((m|0)<=0)if(!p)m=b+120|0;else X=114;else{o=0;do{c[n+(o<<2)>>2]=c[p+(o<<2)>>2];o=o+1|0}while((o|0)!=(m|0));X=114}if((X|0)==114){if(a[b+120>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[p+-4>>2]|0)}c[b+116>>2]=0;m=b+120|0}a[m>>0]=1;c[b+116>>2]=n;c[b+112>>2]=e<<1}c[b+108>>2]=e<<1}m=c[b+148>>2]|0;if((m|0)<(r|0)?(c[b+152>>2]|0)<(r|0):0){if(!r)n=0;else{c[6432]=(c[6432]|0)+1;m=ec((r<<2|3)+16|0)|0;if(!m)n=0;else{c[(m+4+15&-16)+-4>>2]=m;n=m+4+15&-16}m=c[b+148>>2]|0}p=c[b+156>>2]|0;if((m|0)<=0)if(!p)m=b+160|0;else X=144;else{o=0;do{c[n+(o<<2)>>2]=c[p+(o<<2)>>2];o=o+1|0}while((o|0)!=(m|0));X=144}if((X|0)==144){if(a[b+160>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[p+-4>>2]|0)}c[b+156>>2]=0;m=b+160|0}a[m>>0]=1;c[b+156>>2]=n;c[b+152>>2]=r}c[b+148>>2]=r;if((d|0)>0){m=c[b+136>>2]|0;n=0;do{c[m+(n<<2)>>2]=n;n=n+1|0}while((n|0)!=(d|0))}if((e|0)>0){m=c[b+116>>2]|0;n=0;do{c[m+(n<<2)>>2]=n;n=n+1|0}while((n|0)!=(e|0))}if((r|0)>0){m=c[b+156>>2]|0;n=0;do{c[m+(n<<2)>>2]=n;n=n+1|0}while((n|0)!=(r|0))}m=c[2395]|0;_=(c[m+16>>2]|0)+-1|0;c[m+16>>2]=_;if(_|0){l=Y;return 0.0}do if(c[m+4>>2]|0){Va(Y|0,0)|0;_=c[6431]|0;g[m+8>>2]=+g[m+8>>2]+ +(((c[Y+4>>2]|0)-(c[_+4>>2]|0)+(((c[Y>>2]|0)-(c[_>>2]|0)|0)*1e6|0)-(c[m+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[m+16>>2]|0)){m=c[2395]|0;break}else{l=Y;return 0.0}}while(0);c[2395]=c[m+20>>2];l=Y;return 0.0}function kc(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,D=0.0,G=0.0,I=0.0,J=0.0,L=0.0,M=0.0,N=0.0,O=0.0,P=0.0,Q=0.0,R=0.0,S=0,T=0.0,U=0.0,V=0.0,W=0.0,X=0.0,Y=0.0,Z=0.0,_=0.0,$=0.0,aa=0.0,ba=0.0,ca=0.0,da=0.0,ea=0.0,fa=0.0,ga=0.0,ha=0.0,ia=0.0,ja=0.0,ka=0.0,la=0,ma=0.0,na=0.0,oa=0.0,pa=0.0,qa=0.0,ra=0.0,sa=0.0;la=l;l=l+80|0;g[b+504>>2]=0.0;g[b+500>>2]=0.0;a[b+525>>0]=0;a[b+526>>0]=0;if(a[b+552>>0]|0?(a[b+527>>0]|0)==0:0){sa=+g[b+556>>2];qa=+g[b+560>>2];ka=+g[b+564>>2];pa=+g[b+568>>2];$=sa*(2.0/(sa*sa+qa*qa+ka*ka+pa*pa));ra=qa*(2.0/(sa*sa+qa*qa+ka*ka+pa*pa));oa=ka*(2.0/(sa*sa+qa*qa+ka*ka+pa*pa));aa=+g[b+300>>2];R=+g[d>>2];ba=+g[b+316>>2];T=+g[d+4>>2];ca=+g[b+332>>2];U=+g[d+8>>2];ea=+g[b+304>>2];ga=+g[b+320>>2];ia=+g[b+336>>2];Y=+g[b+308>>2];Z=+g[b+324>>2];_=+g[b+340>>2];V=+g[d+16>>2];W=+g[d+20>>2];X=+g[d+24>>2];fa=+g[d+32>>2];ha=+g[d+36>>2];ja=+g[d+40>>2];q=+g[b+348>>2];p=+g[b+352>>2];o=+g[b+356>>2];u=+g[b+364>>2];na=+g[e>>2];v=+g[b+380>>2];ma=+g[e+4>>2];w=+g[b+396>>2];k=+g[e+8>>2];x=+g[b+368>>2];y=+g[b+384>>2];z=+g[b+400>>2];r=+g[b+372>>2];s=+g[b+388>>2];t=+g[b+404>>2];m=+g[e+16>>2];n=+g[e+20>>2];j=+g[e+24>>2];A=+g[e+32>>2];G=+g[e+36>>2];J=+g[e+40>>2];D=+g[b+412>>2];I=+g[b+416>>2];i=+g[b+420>>2];M=(1.0-(qa*ra+ka*oa))*(u*na+v*ma+w*k)+(sa*ra+pa*oa)*(na*x+ma*y+k*z)+(sa*oa-pa*ra)*(na*r+ma*s+k*t);N=(sa*ra-pa*oa)*(u*na+v*ma+w*k)+(1.0-(sa*$+ka*oa))*(na*x+ma*y+k*z)+(qa*oa+pa*$)*(na*r+ma*s+k*t);L=(sa*oa+pa*ra)*(u*na+v*ma+w*k)+(qa*oa-pa*$)*(na*x+ma*y+k*z)+(1.0-(sa*$+qa*ra))*(na*r+ma*s+k*t);P=(sa*oa-pa*ra)*(r*m+s*n+t*j)+((1.0-(qa*ra+ka*oa))*(u*m+v*n+w*j)+(sa*ra+pa*oa)*(x*m+y*n+z*j));Q=(qa*oa+pa*$)*(r*m+s*n+t*j)+((sa*ra-pa*oa)*(u*m+v*n+w*j)+(1.0-(sa*$+ka*oa))*(x*m+y*n+z*j));O=(1.0-(sa*$+qa*ra))*(r*m+s*n+t*j)+((sa*oa+pa*ra)*(u*m+v*n+w*j)+(qa*oa-pa*$)*(x*m+y*n+z*j));da=(sa*oa-pa*ra)*(r*A+s*G+t*J)+((1.0-(qa*ra+ka*oa))*(u*A+v*G+w*J)+(sa*ra+pa*oa)*(x*A+y*G+z*J));ka=(qa*oa+pa*$)*(r*A+s*G+t*J)+((sa*ra-pa*oa)*(u*A+v*G+w*J)+(1.0-(sa*$+ka*oa))*(x*A+y*G+z*J));$=(1.0-(sa*$+qa*ra))*(r*A+s*G+t*J)+((sa*oa+pa*ra)*(u*A+v*G+w*J)+(qa*oa-pa*$)*(x*A+y*G+z*J));pa=-(+g[d+48>>2]+(R*q+T*p+U*o));oa=-(V*q+W*p+X*o+ +g[d+52>>2]);o=-(fa*q+ha*p+ja*o+ +g[d+56>>2]);p=(aa*R+ba*T+ca*U)*pa+(aa*V+ba*W+ca*X)*oa+(aa*fa+ba*ha+ca*ja)*o;q=(R*ea+T*ga+U*ia)*pa+(ea*V+ga*W+ia*X)*oa+(ea*fa+ga*ha+ia*ja)*o;o=(R*Y+T*Z+U*_)*pa+(Y*V+Z*W+_*X)*oa+(Y*fa+Z*ha+_*ja)*o;k=o*L+(p*M+q*N)+((u*na+v*ma+w*k)*0.0+(na*x+ma*y+k*z)*0.0+(na*r+ma*s+k*t)*0.0+(+g[e+48>>2]+(na*D+ma*I+k*i)));j=o*O+(p*P+q*Q)+((r*m+s*n+t*j)*0.0+((u*m+v*n+w*j)*0.0+(x*m+y*n+z*j)*0.0)+(m*D+n*I+j*i+ +g[e+52>>2]));i=o*$+(p*da+q*ka)+((r*A+s*G+t*J)*0.0+((u*A+v*G+w*J)*0.0+(x*A+y*G+z*J)*0.0)+(A*D+G*I+J*i+ +g[e+56>>2]));g[la+16>>2]=(R*Y+T*Z+U*_)*L+((aa*R+ba*T+ca*U)*M+(R*ea+T*ga+U*ia)*N);g[la+16+4>>2]=(Y*V+Z*W+_*X)*L+((aa*V+ba*W+ca*X)*M+(ea*V+ga*W+ia*X)*N);g[la+16+8>>2]=(Y*fa+Z*ha+_*ja)*L+((aa*fa+ba*ha+ca*ja)*M+(ea*fa+ga*ha+ia*ja)*N);g[la+16+12>>2]=0.0;g[la+16+16>>2]=(R*Y+T*Z+U*_)*O+((aa*R+ba*T+ca*U)*P+(R*ea+T*ga+U*ia)*Q);g[la+16+20>>2]=(Y*V+Z*W+_*X)*O+((aa*V+ba*W+ca*X)*P+(ea*V+ga*W+ia*X)*Q);g[la+16+24>>2]=(Y*fa+Z*ha+_*ja)*O+((aa*fa+ba*ha+ca*ja)*P+(ea*fa+ga*ha+ia*ja)*Q);g[la+16+28>>2]=0.0;g[la+16+32>>2]=(R*Y+T*Z+U*_)*$+((aa*R+ba*T+ca*U)*da+(R*ea+T*ga+U*ia)*ka);g[la+16+36>>2]=(Y*V+Z*W+_*X)*$+((aa*V+ba*W+ca*X)*da+(ea*V+ga*W+ia*X)*ka);g[la+16+40>>2]=(Y*fa+Z*ha+_*ja)*$+((aa*fa+ba*ha+ca*ja)*da+(ea*fa+ga*ha+ia*ja)*ka);g[la+16+44>>2]=0.0;g[la+16+48>>2]=k;g[la+16+52>>2]=j;g[la+16+56>>2]=i;g[la+16+60>>2]=0.0;eh(la+16|0,la);i=+g[la>>2];j=+g[la+4>>2];k=+g[la+8>>2];if(!(+B(+(i*i+j*j+k*k))<1.1920928955078125e-07)?(g[b+472>>2]=0.0,sa=1.0/+C(+(i*i+j*j+k*k)),g[b+460>>2]=i*sa,g[b+464>>2]=j*sa,g[b+468>>2]=k*sa,sa=+g[la+12>>2],sa=sa<-1.0?-1.0:sa,sa=+H(+(sa>1.0?1.0:sa))*2.0,g[b+504>>2]=sa,!(+B(+sa)<1.1920928955078125e-07)):0)a[b+526>>0]=1;l=la;return}eh(d,la+16|0);eh(b+300|0,la);U=+g[la+16+12>>2];V=+g[la>>2];W=+g[la+16>>2];X=+g[la+12>>2];Y=+g[la+16+4>>2];Z=+g[la+8>>2];_=+g[la+16+8>>2];$=+g[la+4>>2];eh(e,la+16|0);eh(b+364|0,la);aa=+g[la+16+12>>2];ba=+g[la>>2];ca=+g[la+16>>2];da=+g[la+12>>2];ea=+g[la+16+4>>2];fa=+g[la+8>>2];ga=+g[la+16+8>>2];ha=+g[la+4>>2];ia=-(aa*ba+ca*da+ea*fa-ga*ha);ja=-(ba*ga+(da*ea+aa*ha)-ca*fa);ka=-(aa*fa+da*ga+ca*ha-ba*ea);q=(U*X-V*W-Y*$-Z*_)*ia+(U*V+W*X+Y*Z-_*$)*(aa*da-ba*ca-ea*ha-fa*ga)+(U*Z+X*_+W*$-V*Y)*ja-(V*_+(X*Y+U*$)-W*Z)*ka;r=(U*V+W*X+Y*Z-_*$)*ka+((V*_+(X*Y+U*$)-W*Z)*(aa*da-ba*ca-ea*ha-fa*ga)+(U*X-V*W-Y*$-Z*_)*ja)-(U*Z+X*_+W*$-V*Y)*ia;s=(V*_+(X*Y+U*$)-W*Z)*ia+((U*Z+X*_+W*$-V*Y)*(aa*da-ba*ca-ea*ha-fa*ga)+(U*X-V*W-Y*$-Z*_)*ka)-(U*V+W*X+Y*Z-_*$)*ja;t=(U*X-V*W-Y*$-Z*_)*(aa*da-ba*ca-ea*ha-fa*ga)-(U*V+W*X+Y*Z-_*$)*ia-(V*_+(X*Y+U*$)-W*Z)*ja-(U*Z+X*_+W*$-V*Y)*ka;i=-q-r*0.0-s*0.0;k=(s+t*0.0-q*0.0)*-s+(t*(t+r*0.0-s*0.0)+i*-q)-(t*0.0+q*0.0-r)*-r;m=(t*0.0+q*0.0-r)*-q+(t*(s+t*0.0-q*0.0)+i*-r)-(t+r*0.0-s*0.0)*-s;i=(t+r*0.0-s*0.0)*-r+(t*(t*0.0+q*0.0-r)+i*-s)-(s+t*0.0-q*0.0)*-q;j=1.0/+C(+(i*i+(k*k+m*m)));if(j*i*0.0+(j*m*0.0+j*k)<-.9999998807907104){o=1.0;n=-0.0;i=0.0;j=0.0}else{sa=+C(+((j*i*0.0+(j*m*0.0+j*k)+1.0)*2.0));o=(j*k*0.0-j*i)*(1.0/sa);n=(j*i*0.0-j*m*0.0)*(1.0/sa);i=(j*m-j*k*0.0)*(1.0/sa);j=sa*.5}T=1.0/+C(+(n*n+o*o+i*i+j*j));u=n*T;v=o*T;p=i*T;n=j*T;T=1.0/+C(+((t*n-q*-u-r*-v-s*-p)*(t*n-q*-u-r*-v-s*-p)+((r*-u+(s*n+t*-p)-q*-v)*(r*-u+(s*n+t*-p)-q*-v)+((s*-v+(q*n+t*-u)-r*-p)*(s*-v+(q*n+t*-u)-r*-p)+(q*-p+(t*-v+r*n)-s*-u)*(q*-p+(t*-v+r*n)-s*-u)))));k=T*(s*-v+(q*n+t*-u)-r*-p);m=T*(q*-p+(t*-v+r*n)-s*-u);i=T*(r*-u+(s*n+t*-p)-q*-v);T=T*(t*n-q*-u-r*-v-s*-p);t=+g[b+444>>2];j=+g[b+456>>2];if(t>=j?(w=+g[b+448>>2],w>=j):0){s=n<-1.0?-1.0:n;s=+H(+(s>1.0?1.0:s))*2.0;if(s>1.1920928955078125e-07){j=1.0/+C(+(p*p+(u*u+v*v)));if(+B(+(v*j))>1.1920928955078125e-07){r=+C(+((p*j*p*j/(v*j*v*j)+1.0)/(1.0/(w*w)+p*j*p*j/(v*j*v*j)/(t*t))));o=u*j;n=p*j;j=v*j}else{r=t;o=u*j;n=p*j;j=v*j}}else{r=0.0;o=0.0;n=0.0;j=0.0}p=+g[b+428>>2];q=r*p;if(s>q){a[b+526>>0]=1;if(s<r&p<.9999998807907104)p=(s-q)/(r-q);else p=1.0;g[b+528>>2]=p;g[b+504>>2]=s-q;if(+B(+j)>1.1920928955078125e-07){sa=+B(+(j*-n/j*(w/t)));n=n<-0.0?sa:-sa;sa=1.0/+C(+(o*o+j*j+n*n));o=o*sa;n=-(n*sa);j=j*sa}ra=-o;qa=-j;oa=-n;na=(aa*da-ba*ca-ea*ha-fa*ga)*ra+(ba*ga+(da*ea+aa*ha)-ca*fa)*oa-(aa*fa+da*ga+ca*ha-ba*ea)*qa;sa=(aa*fa+da*ga+ca*ha-ba*ea)*ra+(aa*da-ba*ca-ea*ha-fa*ga)*qa-(aa*ba+ca*da+ea*fa-ga*ha)*oa;pa=(aa*ba+ca*da+ea*fa-ga*ha)*qa+(aa*da-ba*ca-ea*ha-fa*ga)*oa-(ba*ga+(da*ea+aa*ha)-ca*fa)*ra;oa=-((aa*ba+ca*da+ea*fa-ga*ha)*ra)-(ba*ga+(da*ea+aa*ha)-ca*fa)*qa-(aa*fa+da*ga+ca*ha-ba*ea)*oa;qa=sa*ka+(oa*ia+(aa*da-ba*ca-ea*ha-fa*ga)*na)-pa*ja;ra=pa*ia+((aa*da-ba*ca-ea*ha-fa*ga)*sa+oa*ja)-na*ka;sa=na*ja+(oa*ka+(aa*da-ba*ca-ea*ha-fa*ga)*pa)-sa*ia;g[b+460>>2]=qa;g[b+464>>2]=ra;g[b+468>>2]=sa;g[b+472>>2]=0.0;c[b+536>>2]=0;c[b+536+4>>2]=0;c[b+536+8>>2]=0;c[b+536+12>>2]=0;g[b+492>>2]=1.0/(qa*(+g[f>>2]*qa+ +g[f+16>>2]*ra+ +g[f+32>>2]*sa)+ra*(qa*+g[f+4>>2]+ra*+g[f+20>>2]+sa*+g[f+36>>2])+sa*(qa*+g[f+8>>2]+ra*+g[f+24>>2]+sa*+g[f+40>>2])+(qa*(qa*+g[h>>2]+ra*+g[h+16>>2]+sa*+g[h+32>>2])+ra*(qa*+g[h+4>>2]+ra*+g[h+20>>2]+sa*+g[h+36>>2])+sa*(qa*+g[h+8>>2]+ra*+g[h+24>>2]+sa*+g[h+40>>2])))}}else S=20;a:do if((S|0)==20){D=+g[b+300>>2];G=+g[b+316>>2];I=+g[b+332>>2];J=+g[d>>2];L=+g[d+4>>2];M=+g[d+8>>2];N=+g[d+16>>2];O=+g[d+20>>2];P=+g[d+24>>2];Q=+g[d+32>>2];R=+g[d+36>>2];s=+g[d+40>>2];t=+g[b+304>>2];u=+g[b+320>>2];v=+g[b+336>>2];w=+g[b+308>>2];x=+g[b+324>>2];y=+g[b+340>>2];n=+g[b+364>>2];q=+g[b+380>>2];r=+g[b+396>>2];A=n*+g[e>>2]+q*+g[e+4>>2]+r*+g[e+8>>2];z=n*+g[e+16>>2]+q*+g[e+20>>2]+r*+g[e+24>>2];r=n*+g[e+32>>2]+q*+g[e+36>>2]+r*+g[e+40>>2];q=(D*J+G*L+I*M)*A+(D*N+G*O+I*P)*z+(D*Q+G*R+I*s)*r;n=(J*t+L*u+M*v)*A+(N*t+O*u+P*v)*z+(Q*t+R*u+s*v)*r;j=(J*w+L*x+M*y)*A+(N*w+O*x+P*y)*z+(Q*w+R*x+s*y)*r;p=+g[b+444>>2];o=+g[b+456>>2];do if(p<o){p=+g[b+448>>2];if(p<o){if(+B(+n)<1.1920928955078125e-07?+B(+j)<1.1920928955078125e-07:0)break a;a[b+526>>0]=1;g[b+460>>2]=-((D*Q+G*R+I*s)*z-(D*N+G*O+I*P)*r);g[b+464>>2]=-((D*J+G*L+I*M)*r-(D*Q+G*R+I*s)*A);g[b+468>>2]=-((D*N+G*O+I*P)*A-(D*J+G*L+I*M)*z);g[b+472>>2]=0.0;break a}if(+B(+q)<1.1920928955078125e-07?+B(+j)<1.1920928955078125e-07:0){o=q;break}a[b+526>>0]=1;if(p>=o){n=+K(+j,+q);if(n>p){o=+E(+p);n=0.0;j=+F(+p);break}if(n<-p){o=+E(+p);n=0.0;j=-+F(+p)}else{o=q;n=0.0}}else o=q}else{if(+B(+q)<1.1920928955078125e-07?+B(+n)<1.1920928955078125e-07:0){o=q;break}a[b+526>>0]=1;if(p>=o){j=+K(+n,+q);if(j>p){o=+E(+p);n=+F(+p);j=0.0;break}if(j<-p){o=+E(+p);n=-+F(+p);j=0.0}else{o=q;j=0.0}}else o=q}while(0);ra=(J*w+L*x+M*y)*j+((J*t+L*u+M*v)*n+(D*J+G*L+I*M)*o);pa=(N*w+O*x+P*y)*j+((N*t+O*u+P*v)*n+(D*N+G*O+I*P)*o);oa=(Q*w+R*x+s*y)*j+((Q*t+R*u+s*v)*n+(D*Q+G*R+I*s)*o);qa=1.0/+C(+(oa*oa+(ra*ra+pa*pa)));g[b+472>>2]=0.0;sa=+C(+((z*qa*oa-r*qa*pa)*(z*qa*oa-r*qa*pa)+(r*qa*ra-A*qa*oa)*(r*qa*ra-A*qa*oa)+(A*qa*pa-z*qa*ra)*(A*qa*pa-z*qa*ra)));g[b+504>>2]=sa;g[b+460>>2]=-((z*qa*oa-r*qa*pa)*(1.0/sa));g[b+464>>2]=-((r*qa*ra-A*qa*oa)*(1.0/sa));g[b+468>>2]=-((A*qa*pa-z*qa*ra)*(1.0/sa))}while(0);p=+g[b+452>>2];if(!(p>=0.0)){g[b+512>>2]=0.0;l=la;return}j=T<-1.0?-1.0:T;j=+H(+(j>1.0?1.0:j))*2.0;if(j>3.1415927410125732){j=-T<-1.0?-1.0:-T;j=+H(+(j>1.0?1.0:j))*2.0;k=-k;m=-m;i=-i}g[b+512>>2]=j;if(j>1.1920928955078125e-07){sa=1.0/+C(+(k*k+m*m+i*i));k=k*sa;o=i*sa;m=m*sa}else o=i;i=+g[b+428>>2];if(j>p*i){a[b+525>>0]=1;n=j-p*i;if(j<p&i<.9999998807907104)i=n/(p-p*i);else i=1.0;g[b+532>>2]=i;g[b+508>>2]=n;ra=-k;qa=-m;oa=-o;na=(aa*da-ba*ca-ea*ha-fa*ga)*ra+(ba*ga+(da*ea+aa*ha)-ca*fa)*oa-(aa*fa+da*ga+ca*ha-ba*ea)*qa;sa=(aa*fa+da*ga+ca*ha-ba*ea)*ra+(aa*da-ba*ca-ea*ha-fa*ga)*qa-(aa*ba+ca*da+ea*fa-ga*ha)*oa;pa=(aa*ba+ca*da+ea*fa-ga*ha)*qa+(aa*da-ba*ca-ea*ha-fa*ga)*oa-(ba*ga+(da*ea+aa*ha)-ca*fa)*ra;oa=-((aa*ba+ca*da+ea*fa-ga*ha)*ra)-(ba*ga+(da*ea+aa*ha)-ca*fa)*qa-(aa*fa+da*ga+ca*ha-ba*ea)*oa;qa=sa*ka+(oa*ia+(aa*da-ba*ca-ea*ha-fa*ga)*na)-pa*ja;ra=pa*ia+((aa*da-ba*ca-ea*ha-fa*ga)*sa+oa*ja)-na*ka;sa=na*ja+(oa*ka+(aa*da-ba*ca-ea*ha-fa*ga)*pa)-sa*ia;g[b+476>>2]=qa;g[b+480>>2]=ra;g[b+484>>2]=sa;g[b+488>>2]=0.0;g[b+496>>2]=1.0/(qa*(+g[f>>2]*qa+ +g[f+16>>2]*ra+ +g[f+32>>2]*sa)+ra*(qa*+g[f+4>>2]+ra*+g[f+20>>2]+sa*+g[f+36>>2])+sa*(qa*+g[f+8>>2]+ra*+g[f+24>>2]+sa*+g[f+40>>2])+(qa*(qa*+g[h>>2]+ra*+g[h+16>>2]+sa*+g[h+32>>2])+ra*(qa*+g[h+4>>2]+ra*+g[h+20>>2]+sa*+g[h+36>>2])+sa*(qa*+g[h+8>>2]+ra*+g[h+24>>2]+sa*+g[h+40>>2])))}if(!(a[b+526>>0]|0)){l=la;return}na=-k;sa=-m;oa=-o;ma=(U*X-V*W-Y*$-Z*_)*na+(V*_+(X*Y+U*$)-W*Z)*oa-(U*Z+X*_+W*$-V*Y)*sa;ra=(U*Z+X*_+W*$-V*Y)*na+(U*X-V*W-Y*$-Z*_)*sa-(U*V+W*X+Y*Z-_*$)*oa;qa=(U*V+W*X+Y*Z-_*$)*sa+(U*X-V*W-Y*$-Z*_)*oa-(V*_+(X*Y+U*$)-W*Z)*na;oa=-((U*V+W*X+Y*Z-_*$)*na)-(V*_+(X*Y+U*$)-W*Z)*sa-(U*Z+X*_+W*$-V*Y)*oa;sa=-(U*V+W*X+Y*Z-_*$);na=-(V*_+(X*Y+U*$)-W*Z);pa=-(U*Z+X*_+W*$-V*Y);g[b+536>>2]=ra*pa+(oa*sa+(U*X-V*W-Y*$-Z*_)*ma)-qa*na;g[b+540>>2]=qa*sa+((U*X-V*W-Y*$-Z*_)*ra+oa*na)-ma*pa;g[b+544>>2]=ma*na+(oa*pa+(U*X-V*W-Y*$-Z*_)*qa)-ra*sa;g[b+548>>2]=0.0;l=la;return}function lc(b,d){b=b|0;d=d|0;var e=0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0,m=0,n=0,o=0.0,p=0.0,q=0,r=0,s=0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0.0,O=0.0,P=0.0,Q=0.0,R=0,S=0,T=0.0,U=0.0,V=0.0,W=0.0,X=0.0,Y=0.0,Z=0.0,_=0.0,$=0.0,aa=0.0,ba=0.0,ca=0.0,da=0.0,ea=0.0,fa=0.0,ga=0.0,ha=0.0,ia=0.0,ja=0.0,ka=0.0,la=0.0,ma=0.0,na=0.0,oa=0.0,pa=0.0,qa=0,ra=0;qa=c[b+28>>2]|0;ra=c[b+32>>2]|0;m=c[d+24>>2]|0;if(!(a[b+739>>0]|0)){y=+g[b+552>>2];T=+g[qa+4>>2];z=+g[b+568>>2];U=+g[qa+8>>2];A=+g[b+584>>2];V=+g[qa+12>>2];B=+g[b+556>>2];D=+g[b+572>>2];E=+g[b+588>>2];W=+g[b+560>>2];X=+g[b+576>>2];Y=+g[b+592>>2];Z=+g[qa+20>>2];_=+g[qa+24>>2];$=+g[qa+28>>2];aa=+g[qa+36>>2];ba=+g[qa+40>>2];ca=+g[qa+44>>2];j=+g[b+600>>2];k=+g[b+604>>2];o=+g[b+608>>2];p=+g[qa+52>>2];t=+g[qa+56>>2];u=+g[qa+60>>2];F=+g[ra+4>>2];G=+g[ra+8>>2];H=+g[ra+12>>2];I=+g[b+624>>2];J=+g[b+640>>2];K=+g[b+656>>2];L=+g[ra+20>>2];M=+g[ra+24>>2];N=+g[ra+28>>2];O=+g[ra+36>>2];P=+g[ra+40>>2];Q=+g[ra+44>>2];oa=+g[b+664>>2];pa=+g[b+668>>2];w=+g[b+672>>2];v=+g[ra+52>>2]+(F*oa+G*pa+H*w);x=L*oa+M*pa+N*w+ +g[ra+56>>2];w=O*oa+P*pa+Q*w+ +g[ra+60>>2];l=(a[b+736>>0]|0)==0;if(l){e=c[d+8>>2]|0;g[e>>2]=1.0;g[e+(m+1<<2)>>2]=1.0;g[e+((m<<1)+2<<2)>>2]=1.0;e=c[d+16>>2]|0;g[e>>2]=-1.0;g[e+(m+1<<2)>>2]=-1.0;g[e+((m<<1)+2<<2)>>2]=-1.0;f=+g[qa+52>>2];h=+g[qa+56>>2];i=+g[qa+60>>2];e=m<<1}else{f=p;h=t;i=u;e=m<<1}f=p+(T*j+U*k+V*o)-f;pa=Z*j+_*k+$*o+t-h;oa=aa*j+ba*k+ca*o+u-i;n=c[d+12>>2]|0;s=n+(e<<2)|0;c[n>>2]=0;g[n+4>>2]=oa;g[n+8>>2]=-pa;g[n+12>>2]=0.0;g[n+(m<<2)>>2]=-oa;c[n+(m<<2)+4>>2]=0;g[n+(m<<2)+8>>2]=f;g[n+(m<<2)+12>>2]=0.0;g[s>>2]=pa;g[s+4>>2]=-f;c[s+8>>2]=0;g[s+12>>2]=0.0;f=v-+g[ra+52>>2];pa=x-+g[ra+56>>2];oa=w-+g[ra+60>>2];s=c[d+20>>2]|0;e=s+(e<<2)|0;c[s>>2]=0;g[s+4>>2]=-oa;g[s+8>>2]=pa;g[s+12>>2]=0.0;g[s+(m<<2)>>2]=oa;c[s+(m<<2)+4>>2]=0;g[s+(m<<2)+8>>2]=-f;g[s+(m<<2)+12>>2]=0.0;g[e>>2]=-pa;g[e+4>>2]=f;c[e+8>>2]=0;g[e+12>>2]=0.0;f=+g[d>>2]*+g[d+4>>2];e=c[d+28>>2]|0;if(l){g[e>>2]=f*(v-(p+(T*j+U*k+V*o)));g[e+(m<<2)>>2]=f*(x-(Z*j+_*k+$*o+t));g[e+(m<<1<<2)>>2]=f*(w-(aa*j+ba*k+ca*o+u))}R=c[d+24>>2]|0;g[n+(R*3<<2)>>2]=y*T+z*U+A*V;g[n+((R*3|0)+1<<2)>>2]=y*Z+z*_+A*$;g[n+((R*3|0)+2<<2)>>2]=y*aa+z*ba+A*ca;g[n+(R<<2<<2)>>2]=T*B+U*D+V*E;g[n+((R<<2|1)<<2)>>2]=B*Z+D*_+E*$;g[n+((R<<2|2)<<2)>>2]=B*aa+D*ba+E*ca;g[s+(R*3<<2)>>2]=-(y*T+z*U+A*V);g[s+((R*3|0)+1<<2)>>2]=-(y*Z+z*_+A*$);g[s+((R*3|0)+2<<2)>>2]=-(y*aa+z*ba+A*ca);g[s+(R<<2<<2)>>2]=-(T*B+U*D+V*E);g[s+((R<<2|1)<<2)>>2]=-(B*Z+D*_+E*$);g[s+((R<<2|2)<<2)>>2]=-(B*aa+D*ba+E*ca);oa=(W*Z+X*_+Y*$)*(I*O+J*P+K*Q)-(W*aa+X*ba+Y*ca)*(I*L+J*M+K*N);pa=(W*aa+X*ba+Y*ca)*(F*I+G*J+H*K)-(T*W+U*X+V*Y)*(I*O+J*P+K*Q);na=(T*W+U*X+V*Y)*(I*L+J*M+K*N)-(W*Z+X*_+Y*$)*(F*I+G*J+H*K);g[e+(R*3<<2)>>2]=((y*aa+z*ba+A*ca)*na+((y*T+z*U+A*V)*oa+(y*Z+z*_+A*$)*pa))*f;g[e+(R<<2<<2)>>2]=((B*aa+D*ba+E*ca)*na+((T*B+U*D+V*E)*oa+(B*Z+D*_+E*$)*pa))*f;if(!(a[b+716>>0]|0)){r=0;p=0.0}else{p=+g[b+708>>2]*+g[b+732>>2];r=p>0.0?1:2}m=a[b+737>>0]|0;q=(r|0)!=0;if(!(m&255|r))return;g[n+(R*5<<2)>>2]=T*W+U*X+V*Y;g[n+((R*5|0)+1<<2)>>2]=W*Z+X*_+Y*$;g[n+((R*5|0)+2<<2)>>2]=W*aa+X*ba+Y*ca;g[s+(R*5<<2)>>2]=-(T*W+U*X+V*Y);g[s+((R*5|0)+1<<2)>>2]=-(W*Z+X*_+Y*$);g[s+((R*5|0)+2<<2)>>2]=-(W*aa+X*ba+Y*ca);h=+g[b+688>>2];i=+g[b+692>>2];f=+Vg(h-i,6.2831854820251465);if(!(f<-3.1415927410125732))if(f>3.1415927410125732)o=f+-6.2831854820251465;else o=f;else o=f+6.2831854820251465;f=+Vg(h+i,6.2831854820251465);if(!(f<-3.1415927410125732)){if(f>3.1415927410125732)f=f+-6.2831854820251465}else f=f+6.2831854820251465;n=o==f;l=e+(R*5<<2)|0;g[l>>2]=0.0;e=c[b+748>>2]|0;k=+g[(e&2|0?b+760|0:d+4|0)>>2];if(!(m<<24>>24==0|q&n)){if(e&4|0)c[(c[d+32>>2]|0)+(R*5<<2)>>2]=c[b+752>>2];i=+g[b+728>>2];j=+g[b+680>>2];h=o>f?1.0:0.0;do if(!(o>=f)){h=j/(k*+g[d>>2]);if(h<0.0)if(i>=o&o-h>i){f=(o-i)/h;break}else{f=i<o?0.0:1.0;break}if(h>0.0)if(i<=f&f-h<i){f=(f-i)/h;break}else{f=i>f?0.0:1.0;break}else f=0.0}else f=h;while(0);g[l>>2]=f*j*+g[b+732>>2]+ +g[l>>2];g[(c[d+36>>2]|0)+(R*5<<2)>>2]=-+g[b+684>>2];c[(c[d+40>>2]|0)+(R*5<<2)>>2]=c[b+684>>2]}if(!q)return;g[l>>2]=+g[l>>2]+p*k*+g[d>>2];if(e&1|0)c[(c[d+32>>2]|0)+(R*5<<2)>>2]=c[b+756>>2];e=c[d+40>>2]|0;if(n){f=-3402823466385288598117041.0e14;h=3402823466385288598117041.0e14}else{S=(r|0)==1;f=S?0.0:-3402823466385288598117041.0e14;h=S?3402823466385288598117041.0e14:0.0}g[(c[d+36>>2]|0)+(R*5<<2)>>2]=f;g[e+(R*5<<2)>>2]=h;h=+g[b+704>>2];do if(h>0.0){f=(T*W+U*X+V*Y)*+g[qa+328>>2]+(W*Z+X*_+Y*$)*+g[qa+332>>2]+(W*aa+X*ba+Y*ca)*+g[qa+336>>2]-((T*W+U*X+V*Y)*+g[ra+328>>2]+(W*Z+X*_+Y*$)*+g[ra+332>>2]+(W*aa+X*ba+Y*ca)*+g[ra+336>>2]);if((r|0)==1){if(!(f<0.0))break;e=(c[d+28>>2]|0)+(R*5<<2)|0;if(!(+g[e>>2]<-(h*f)))break;g[e>>2]=-(h*f);break}else{if(!(f>0.0))break;e=(c[d+28>>2]|0)+(R*5<<2)|0;if(!(+g[e>>2]>-(h*f)))break;g[e>>2]=-(h*f);break}}while(0);d=(c[d+28>>2]|0)+(R*5<<2)|0;g[d>>2]=+g[b+700>>2]*+g[d>>2];return}X=+g[qa+4>>2];da=+g[qa+8>>2];ja=+g[qa+12>>2];t=+g[b+556>>2];u=+g[b+572>>2];v=+g[b+588>>2];ka=+g[b+560>>2];la=+g[b+576>>2];O=+g[b+592>>2];P=+g[qa+20>>2];Q=+g[qa+24>>2];T=+g[qa+28>>2];U=+g[qa+36>>2];V=+g[qa+40>>2];W=+g[qa+44>>2];Z=+g[b+600>>2];Y=+g[b+604>>2];o=+g[b+608>>2];i=+g[qa+52>>2]+(X*Z+da*Y+ja*o);x=P*Z+Q*Y+T*o+ +g[qa+56>>2];o=U*Z+V*Y+W*o+ +g[qa+60>>2];Y=+g[ra+4>>2];Z=+g[ra+8>>2];_=+g[ra+12>>2];$=+g[b+624>>2];aa=+g[b+640>>2];ba=+g[b+656>>2];ca=+g[ra+20>>2];ea=+g[ra+24>>2];fa=+g[ra+28>>2];ga=+g[ra+36>>2];ha=+g[ra+40>>2];ia=+g[ra+44>>2];k=+g[b+664>>2];w=+g[b+668>>2];h=+g[b+672>>2];j=+g[ra+52>>2];y=+g[ra+56>>2];p=+g[ra+60>>2];J=j+(Y*k+Z*w+_*h)-i;L=ca*k+ea*w+fa*h+y-x;K=ga*k+ha*w+ia*h+p-o;z=+g[(c[b+28>>2]|0)+344>>2];A=+g[(c[b+32>>2]|0)+344>>2];I=z+A>0.0?A/(z+A):.5;ma=(X*ka+da*la+ja*O)*I+(Y*$+Z*aa+_*ba)*(1.0-I);oa=(ka*P+la*Q+O*T)*I+($*ca+aa*ea+ba*fa)*(1.0-I);na=(ka*U+la*V+O*W)*I+($*ga+aa*ha+ba*ia)*(1.0-I);pa=1.0/+C(+(ma*ma+oa*oa+na*na));B=(j+(Y*k+Z*w+_*h)-j)*ma*pa+(ca*k+ea*w+fa*h+y-y)*oa*pa+(ga*k+ha*w+ia*h+p-p)*na*pa;j=j+(Y*k+Z*w+_*h)-j-ma*pa*B;y=ca*k+ea*w+fa*h+y-y-oa*pa*B;p=ga*k+ha*w+ia*h+p-p-na*pa*B;i=i-+g[qa+52>>2];x=x-+g[qa+56>>2];o=o-+g[qa+60>>2];h=ma*pa*(i*ma*pa+x*oa*pa+o*na*pa);w=oa*pa*(i*ma*pa+x*oa*pa+o*na*pa);k=na*pa*(i*ma*pa+x*oa*pa+o*na*pa);G=i-h+I*(h-ma*pa*B);H=x-w+I*(w-oa*pa*B);F=o-k+I*(k-na*pa*B);D=j-(1.0-I)*(h-ma*pa*B);E=y-(1.0-I)*(w-oa*pa*B);B=p-(1.0-I)*(k-na*pa*B);f=(I*j+(1.0-I)*(i-h))*(I*j+(1.0-I)*(i-h))+(I*y+(1.0-I)*(x-w))*(I*y+(1.0-I)*(x-w))+(I*p+(1.0-I)*(o-k))*(I*p+(1.0-I)*(o-k));if(f>1.1920928955078125e-07){v=1.0/+C(+f);N=(I*j+(1.0-I)*(i-h))*v;M=v*(I*p+(1.0-I)*(o-k));p=v*(I*y+(1.0-I)*(x-w))}else{N=X*t+da*u+ja*v;M=t*U+u*V+v*W;p=t*P+u*Q+v*T}t=oa*pa*M-na*pa*p;u=na*pa*N-M*ma*pa;v=p*ma*pa-oa*pa*N;S=c[d+12>>2]|0;g[S>>2]=H*M-F*p;g[S+4>>2]=F*N-G*M;g[S+8>>2]=G*p-H*N;S=c[d+20>>2]|0;g[S>>2]=-(E*M-B*p);g[S+4>>2]=-(B*N-D*M);g[S+8>>2]=-(D*p-E*N);if(z<1.1920928955078125e-07|A<1.1920928955078125e-07?(a[b+716>>0]|0)!=0:0){f=(1.0-I)*(E*v-B*u);h=(1.0-I)*(B*t-D*v);i=(1.0-I)*(D*u-E*t);j=I*(H*v-F*u);k=I*(F*t-G*v);o=I*(G*u-H*t)}else{f=E*v-B*u;h=B*t-D*v;i=D*u-E*t;j=H*v-F*u;k=F*t-G*v;o=G*u-H*t}S=(c[d+12>>2]|0)+(m<<2)|0;g[S>>2]=j;g[S+4>>2]=k;g[S+8>>2]=o;S=c[d+20>>2]|0;g[S+(m<<2)>>2]=-f;g[S+(m+1<<2)>>2]=-h;g[S+(m+2<<2)>>2]=-i;if(z<1.1920928955078125e-07|A<1.1920928955078125e-07){o=(1.0-I)*(E*na*pa-B*oa*pa);k=(1.0-I)*(B*ma*pa-D*na*pa);j=(1.0-I)*(D*oa*pa-E*ma*pa);i=I*(H*na*pa-F*oa*pa);h=I*(F*ma*pa-G*na*pa);f=I*(G*oa*pa-H*ma*pa)}else{o=E*na*pa-B*oa*pa;k=B*ma*pa-D*na*pa;j=D*oa*pa-E*ma*pa;i=H*na*pa-F*oa*pa;h=F*ma*pa-G*na*pa;f=G*oa*pa-H*ma*pa}e=(c[d+12>>2]|0)+(m<<1<<2)|0;g[e>>2]=i;g[e+4>>2]=h;g[e+8>>2]=f;e=c[d+20>>2]|0;g[e+(m<<1<<2)>>2]=-o;g[e+((m<<1|1)<<2)>>2]=-k;g[e+((m<<1)+2<<2)>>2]=-j;f=+g[d>>2]*+g[d+4>>2];if(!(a[b+736>>0]|0)){R=c[d+8>>2]|0;g[R>>2]=N;g[R+4>>2]=p;g[R+8>>2]=M;R=(c[d+8>>2]|0)+(m<<2)|0;g[R>>2]=t;g[R+4>>2]=u;g[R+8>>2]=v;R=(c[d+8>>2]|0)+(m<<1<<2)|0;g[R>>2]=ma*pa;g[R+4>>2]=oa*pa;g[R+8>>2]=na*pa;R=c[d+16>>2]|0;h=-N;g[R>>2]=h;g[R+4>>2]=-p;g[R+8>>2]=-M;g[R+(m<<2)>>2]=-t;g[R+(m+1<<2)>>2]=-u;g[R+(m+2<<2)>>2]=-v;g[R+(m<<1<<2)>>2]=-(ma*pa);g[R+((m<<1|1)<<2)>>2]=-(oa*pa);g[R+((m<<1)+2<<2)>>2]=-(na*pa);R=c[d+28>>2]|0;g[R>>2]=f*(J*N+L*p+K*M);g[R+(m<<2)>>2]=f*(J*t+L*u+K*v);g[R+(m<<1<<2)>>2]=f*(J*ma*pa+L*oa*pa+K*na*pa);e=c[d+20>>2]|0;S=d+28|0;f=h;h=-t;i=-u;j=-v}else{R=c[d+28>>2]|0;S=d+28|0;f=-N;h=-t;i=-u;j=-v}l=c[d+12>>2]|0;g[l+(m*3<<2)>>2]=N;g[l+((m*3|0)+1<<2)>>2]=p;g[l+((m*3|0)+2<<2)>>2]=M;g[l+(m<<2<<2)>>2]=t;g[l+((m<<2|1)<<2)>>2]=u;g[l+((m<<2|2)<<2)>>2]=v;g[e+(m*3<<2)>>2]=f;g[e+((m*3|0)+1<<2)>>2]=-p;g[e+((m*3|0)+2<<2)>>2]=-M;g[e+(m<<2<<2)>>2]=h;g[e+((m<<2|1)<<2)>>2]=i;g[e+((m<<2|2)<<2)>>2]=j;K=+g[d>>2]*+g[d+4>>2];L=(ka*P+la*Q+O*T)*($*ga+aa*ha+ba*ia)-(ka*U+la*V+O*W)*($*ca+aa*ea+ba*fa);ia=(ka*U+la*V+O*W)*(Y*$+Z*aa+_*ba)-(X*ka+da*la+ja*O)*($*ga+aa*ha+ba*ia);la=(X*ka+da*la+ja*O)*($*ca+aa*ea+ba*fa)-(ka*P+la*Q+O*T)*(Y*$+Z*aa+_*ba);g[R+(m*3<<2)>>2]=K*(L*N+ia*p+la*M);g[R+(m<<2<<2)>>2]=K*(L*t+ia*u+la*v);if(!(a[b+716>>0]|0)){r=0;p=0.0}else{p=+g[b+708>>2]*+g[b+732>>2];r=p>0.0?1:2}n=a[b+737>>0]|0;q=(r|0)!=0;if(!(n&255|r))return;s=(c[d+24>>2]|0)*5|0;g[l+(s<<2)>>2]=ma*pa;g[l+(s+1<<2)>>2]=oa*pa;g[l+(s+2<<2)>>2]=na*pa;g[e+(s<<2)>>2]=-(ma*pa);g[e+(s+1<<2)>>2]=-(oa*pa);g[e+(s+2<<2)>>2]=-(na*pa);h=+g[b+688>>2];i=+g[b+692>>2];f=+Vg(h-i,6.2831854820251465);if(!(f<-3.1415927410125732))if(f>3.1415927410125732)o=f+-6.2831854820251465;else o=f;else o=f+6.2831854820251465;f=+Vg(h+i,6.2831854820251465);if(!(f<-3.1415927410125732)){if(f>3.1415927410125732)f=f+-6.2831854820251465}else f=f+6.2831854820251465;m=o==f;l=R+(s<<2)|0;g[l>>2]=0.0;e=c[b+748>>2]|0;k=+g[(e&2|0?b+760|0:d+4|0)>>2];if(!(n<<24>>24==0|q&m)){if(e&4|0)c[(c[d+32>>2]|0)+(s<<2)>>2]=c[b+752>>2];i=+g[b+728>>2];j=+g[b+680>>2];h=o>f?1.0:0.0;do if(!(o>=f)){h=j/(k*+g[d>>2]);if(h<0.0)if(i>=o&o-h>i){f=(o-i)/h;break}else{f=i<o?0.0:1.0;break}if(h>0.0)if(i<=f&f-h<i){f=(f-i)/h;break}else{f=i>f?0.0:1.0;break}else f=0.0}else f=h;while(0);g[l>>2]=f*j*+g[b+732>>2]+ +g[l>>2];g[(c[d+36>>2]|0)+(s<<2)>>2]=-+g[b+684>>2];c[(c[d+40>>2]|0)+(s<<2)>>2]=c[b+684>>2]}if(!q)return;g[l>>2]=+g[l>>2]+p*k*+g[d>>2];if(e&1|0)c[(c[d+32>>2]|0)+(s<<2)>>2]=c[b+756>>2];if(m){f=-3402823466385288598117041.0e14;h=3402823466385288598117041.0e14}else{R=(r|0)==1;f=R?0.0:-3402823466385288598117041.0e14;h=R?3402823466385288598117041.0e14:0.0}g[(c[d+36>>2]|0)+(s<<2)>>2]=f;g[(c[d+40>>2]|0)+(s<<2)>>2]=h;h=+g[b+704>>2];do if(h>0.0){f=+g[qa+328>>2]*ma*pa+ +g[qa+332>>2]*oa*pa+ +g[qa+336>>2]*na*pa-(ma*pa*+g[ra+328>>2]+oa*pa*+g[ra+332>>2]+na*pa*+g[ra+336>>2]);if((r|0)==1){if(!(f<0.0))break;e=(c[S>>2]|0)+(s<<2)|0;if(!(+g[e>>2]<-(h*f)))break;g[e>>2]=-(h*f);break}else{if(!(f>0.0))break;e=(c[S>>2]|0)+(s<<2)|0;if(!(+g[e>>2]>-(h*f)))break;g[e>>2]=-(h*f);break}}while(0);d=(c[S>>2]|0)+(s<<2)|0;g[d>>2]=+g[b+700>>2]*+g[d>>2];return}function mc(b,d){b=b|0;d=d|0;var e=0,f=0.0,h=0.0,i=0.0,k=0.0,m=0,n=0.0,o=0.0,p=0.0,q=0,r=0.0,s=0.0,t=0.0,u=0.0,v=0,w=0.0,x=0,y=0,z=0,A=0,D=0,E=0,F=0,G=0,H=0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0.0,P=0.0,Q=0.0,R=0,S=0.0,T=0,U=0,V=0,W=0,X=0.0,Y=0.0,Z=0.0,_=0.0,$=0.0,aa=0.0,ba=0,ca=0,da=0,ea=0,fa=0.0,ga=0,ha=0,ia=0;ia=l;l=l+32|0;ga=c[b+28>>2]|0;ha=c[b+32>>2]|0;_=+g[ga+344>>2];$=+g[ha+344>>2];W=c[d+24>>2]|0;fa=a[b+180>>0]|0?1.0:-1.0;X=+g[b+936>>2]-+g[b+872>>2];Z=+g[b+940>>2]-+g[b+876>>2];Y=+g[b+944>>2]-+g[b+880>>2];aa=_+$>0.0?$/(_+$):.5;A=c[b+824>>2]|0;D=c[b+840>>2]|0;E=c[b+856>>2]|0;F=c[b+888>>2]|0;G=c[b+904>>2]|0;H=c[b+920>>2]|0;R=(a[b+49>>0]|0)==0;do if(!R){i=aa*(c[j>>2]=A,+g[j>>2]);o=aa*(c[j>>2]=D,+g[j>>2]);f=aa*(c[j>>2]=E,+g[j>>2]);h=(1.0-aa)*(c[j>>2]=F,+g[j>>2]);n=(1.0-aa)*(c[j>>2]=G,+g[j>>2]);f=f+(1.0-aa)*(c[j>>2]=H,+g[j>>2]);k=1.0/+C(+((i+h)*(i+h)+(o+n)*(o+n)+f*f));m=(g[j>>2]=(i+h)*k,c[j>>2]|0);q=(g[j>>2]=(o+n)*k,c[j>>2]|0);x=(g[j>>2]=f*k,c[j>>2]|0);if(+B(+(f*k))>.7071067690849304){S=1.0/+C(+(f*k*f*k+(o+n)*k*(o+n)*k));c[ia+24>>2]=0;g[ia+20>>2]=-(f*k*S);g[ia+16>>2]=(o+n)*k*S;g[ia>>2]=(f*k*f*k+(o+n)*k*(o+n)*k)*S;g[ia+4>>2]=-((i+h)*k*(o+n)*k*S);f=(i+h)*k*-(f*k*S);e=2;v=0;h=0.0;U=ia;V=ia+4|0;ca=m;da=q;ea=x;break}else{Q=(i+h)*k*(i+h)*k+(o+n)*k*(o+n)*k;S=1.0/+C(+Q);v=(g[j>>2]=-((o+n)*k*S),c[j>>2]|0);g[ia+24>>2]=-((o+n)*k*S);g[ia+20>>2]=(i+h)*k*S;c[ia+16>>2]=0;g[ia>>2]=-(f*k*(i+h)*k*S);g[ia+4>>2]=f*k*-((o+n)*k*S);f=Q*S;e=2;h=-((o+n)*k*S);U=ia;V=ia+4|0;ca=m;da=q;ea=x;break}}else{U=c[b+828>>2]|0;e=c[b+844>>2]|0;v=c[b+860>>2]|0;c[ia+24>>2]=U;c[ia+20>>2]=e;c[ia+16>>2]=v;v=c[b+848>>2]|0;e=c[b+864>>2]|0;c[ia>>2]=c[b+832>>2];c[ia+4>>2]=v;c[ia+8>>2]=e;f=0.0;e=3;v=U;h=(c[j>>2]=U,+g[j>>2]);U=ia;V=ia+4|0;ca=A;da=D;ea=E}while(0);g[ia+(e<<2)>>2]=f;T=c[d+12>>2]|0;c[T>>2]=v;m=c[ia+20>>2]|0;c[T+4>>2]=m;q=c[ia+16>>2]|0;c[T+8>>2]=q;v=c[ia>>2]|0;c[T+(W<<2)>>2]=v;x=c[V>>2]|0;c[T+(W+1<<2)>>2]=x;y=c[ia+8>>2]|0;c[T+(W+2<<2)>>2]=y;z=c[d+20>>2]|0;g[z>>2]=-h;s=(c[j>>2]=m,+g[j>>2]);g[z+4>>2]=-s;u=(c[j>>2]=q,+g[j>>2]);g[z+8>>2]=-u;t=(c[j>>2]=v,+g[j>>2]);g[z+(W<<2)>>2]=-t;p=(c[j>>2]=x,+g[j>>2]);g[z+(W+1<<2)>>2]=-p;S=(c[j>>2]=y,+g[j>>2]);g[z+(W+2<<2)>>2]=-S;e=c[b+300>>2]|0;f=+g[b+280>>2];if(!(e&128))f=f*+g[d+4>>2];J=f*+g[d>>2];P=(c[j>>2]=D,+g[j>>2]);L=(c[j>>2]=H,+g[j>>2]);K=(c[j>>2]=E,+g[j>>2]);N=(c[j>>2]=G,+g[j>>2]);Q=(c[j>>2]=F,+g[j>>2]);M=(c[j>>2]=A,+g[j>>2]);H=c[d+28>>2]|0;g[H>>2]=J*((P*L-K*N)*h+(K*Q-M*L)*s+(M*N-P*Q)*u);g[H+(W<<2)>>2]=J*((P*L-K*N)*t+(K*Q-M*L)*p+(M*N-P*Q)*S);if(e&64|0){H=c[d+32>>2]|0;c[H>>2]=c[b+292>>2];c[H+(W<<2)>>2]=c[b+292>>2]}N=+g[ga+52>>2];J=+g[ga+56>>2];M=+g[ga+60>>2];o=+g[ha+52>>2];f=+g[ha+56>>2];i=+g[ha+60>>2];if(R){k=(i-M)*h-(o-N)*u;r=(o-N)*s-(f-J)*h;g[T+(W<<1<<2)>>2]=aa*((f-J)*u-(i-M)*s);g[T+((W<<1|1)<<2)>>2]=aa*k;g[T+((W<<1)+2<<2)>>2]=aa*r;g[z+(W<<1<<2)>>2]=(1.0-aa)*((f-J)*u-(i-M)*s);g[z+((W<<1|1)<<2)>>2]=(1.0-aa)*k;g[z+((W<<1)+2<<2)>>2]=(1.0-aa)*r;g[T+(W*3<<2)>>2]=aa*((f-J)*S-(i-M)*p);g[T+((W*3|0)+1<<2)>>2]=aa*((i-M)*t-(o-N)*S);g[T+((W*3|0)+2<<2)>>2]=aa*((o-N)*p-(f-J)*t);g[z+(W*3<<2)>>2]=(1.0-aa)*((f-J)*S-(i-M)*p);g[z+((W*3|0)+1<<2)>>2]=(1.0-aa)*((i-M)*t-(o-N)*S);g[z+((W*3|0)+2<<2)>>2]=(1.0-aa)*((o-N)*p-(f-J)*t);V=c[d+8>>2]|0;U=c[ia+24>>2]|0;c[V+(W<<1<<2)>>2]=U;c[V+((W<<1|1)<<2)>>2]=m;c[V+((W<<1)+2<<2)>>2]=q;c[V+(W*3<<2)>>2]=v;c[V+((W*3|0)+1<<2)>>2]=x;c[V+((W*3|0)+2<<2)>>2]=y;e=c[d+16>>2]|0;r=(c[j>>2]=U,+g[j>>2]);g[e+(W<<1<<2)>>2]=-r;g[e+((W<<1|1)<<2)>>2]=-s;g[e+((W<<1)+2<<2)>>2]=-u;g[e+(W*3<<2)>>2]=-t;g[e+((W*3|0)+1<<2)>>2]=-p;k=S;m=V;q=e;w=0.0;I=0.0;P=0.0;Q=0.0;K=0.0;L=0.0;n=f-J;i=i-M;h=o-N;e=e+((W*3|0)+2<<2)|0;f=-S}else{t=+g[b+936>>2]-o;u=+g[b+940>>2]-f;P=+g[b+944>>2]-i;n=(c[j>>2]=ca,+g[j>>2]);k=(c[j>>2]=da,+g[j>>2]);o=(c[j>>2]=ea,+g[j>>2]);Q=+g[b+872>>2]-N;S=+g[b+876>>2]-J;f=+g[b+880>>2]-M;K=+g[b+1080>>2]-+g[b+1032>>2];L=n*(n*Q+k*S+o*f)+n*K-n*(n*t+k*u+o*P);M=k*(n*Q+k*S+o*f)+k*K-k*(n*t+k*u+o*P);K=o*(n*Q+k*S+o*f)+o*K-o*(n*t+k*u+o*P);J=Q-n*(n*Q+k*S+o*f)+aa*L;w=S-k*(n*Q+k*S+o*f)+aa*M;I=f-o*(n*Q+k*S+o*f)+aa*K;L=t-n*(n*t+k*u+o*P)-(1.0-aa)*L;M=u-k*(n*t+k*u+o*P)-(1.0-aa)*M;K=P-o*(n*t+k*u+o*P)-(1.0-aa)*K;i=aa*(t-n*(n*t+k*u+o*P))+(1.0-aa)*(Q-n*(n*Q+k*S+o*f));h=aa*(u-k*(n*t+k*u+o*P))+(1.0-aa)*(S-k*(n*Q+k*S+o*f));f=aa*(P-o*(n*t+k*u+o*P))+(1.0-aa)*(f-o*(n*Q+k*S+o*f));g[ia+24>>2]=i;g[ia+20>>2]=h;g[ia+16>>2]=f;if(f*f+(i*i+h*h)>1.1920928955078125e-07){r=1.0/+C(+(f*f+(i*i+h*h)));g[ia+24>>2]=i*r;g[ia+20>>2]=r*h;g[ia+16>>2]=r*f;e=(g[j>>2]=i*r,c[j>>2]|0);m=(g[j>>2]=r*h,c[j>>2]|0);q=(g[j>>2]=r*f,c[j>>2]|0);u=r*f;s=r*h;r=i*r}else{e=c[b+828>>2]|0;m=c[b+844>>2]|0;q=c[b+860>>2]|0;c[ia+24>>2]=e;c[ia+20>>2]=m;c[ia+16>>2]=q;u=(c[j>>2]=q,+g[j>>2]);s=(c[j>>2]=m,+g[j>>2]);r=(c[j>>2]=e,+g[j>>2])}t=k*u-o*s;N=n*s-k*r;g[U>>2]=t;g[V>>2]=o*r-n*u;g[ia+8>>2]=N;g[ia+12>>2]=0.0;g[T+(W<<1<<2)>>2]=w*u-I*s;g[T+(W<<1<<2)+4>>2]=I*r-J*u;g[T+(W<<1<<2)+8>>2]=J*s-w*r;U=c[d+20>>2]|0;g[U+(W<<1<<2)>>2]=-(M*u-K*s);g[U+((W<<1|1)<<2)>>2]=-(K*r-L*u);g[U+((W<<1)+2<<2)>>2]=-(L*s-M*r);p=+g[V>>2];if(_<1.1920928955078125e-07|$<1.1920928955078125e-07?(a[b+297>>0]|0)!=0:0){f=(1.0-aa)*(M*N-K*p);h=(1.0-aa)*(K*t-L*N);i=(1.0-aa)*(L*p-M*t);k=aa*(w*N-I*p);n=aa*(J*p-w*t);o=aa*(I*t-J*N)}else{f=M*N-K*p;h=K*t-L*N;i=L*p-M*t;k=w*N-I*p;n=J*p-w*t;o=I*t-J*N}V=(c[d+12>>2]|0)+(W*3<<2)|0;g[V>>2]=k;g[V+4>>2]=o;g[V+8>>2]=n;V=c[d+20>>2]|0;g[V+(W*3<<2)>>2]=-f;g[V+((W*3|0)+1<<2)>>2]=-h;g[V+((W*3|0)+2<<2)>>2]=-i;V=c[d+8>>2]|0;c[V+(W<<1<<2)>>2]=e;c[V+((W<<1|1)<<2)>>2]=m;c[V+((W<<1)+2<<2)>>2]=q;g[V+(W*3<<2)>>2]=t;g[V+((W*3|0)+1<<2)>>2]=p;g[V+((W*3|0)+2<<2)>>2]=N;e=c[d+16>>2]|0;g[e+(W<<1<<2)>>2]=-r;g[e+((W<<1|1)<<2)>>2]=-s;g[e+((W<<1)+2<<2)>>2]=-u;g[e+(W*3<<2)>>2]=-t;g[e+((W*3|0)+1<<2)>>2]=-p;k=N;m=V;q=e;P=J;Q=M;n=0.0;i=0.0;h=0.0;e=e+((W*3|0)+2<<2)|0;f=-N}g[e>>2]=f;A=c[b+300>>2]|0;f=+g[b+264>>2];if(!(A&32))f=f*+g[d+4>>2];S=f*+g[d>>2];D=c[d+28>>2]|0;g[D+(W<<1<<2)>>2]=S*(X*r+Z*s+Y*u);g[D+(W*3<<2)>>2]=S*(X*t+Z*p+Y*k);if(A&16|0){V=c[d+32>>2]|0;c[V+(W<<1<<2)>>2]=c[b+276>>2];c[V+(W*3<<2)>>2]=c[b+276>>2]}if(!(a[b+296>>0]|0)){y=0;p=0.0}else{p=fa*+g[b+1032>>2];y=p>0.0?2:1}v=a[b+1096>>0]|0;x=(y|0)!=0;if(v&255|y){z=c[d+24>>2]<<2;c[m+(z<<2)>>2]=ca;c[m+((z|1)<<2)>>2]=da;c[m+((z|2)<<2)>>2]=ea;r=(c[j>>2]=ca,+g[j>>2]);g[q+(z<<2)>>2]=-r;s=(c[j>>2]=da,+g[j>>2]);g[q+((z|1)<<2)>>2]=-s;t=(c[j>>2]=ea,+g[j>>2]);g[q+((z|2)<<2)>>2]=-t;if(a[b+49>>0]|0){if(!(_<1.1920928955078125e-07|$<1.1920928955078125e-07)){e=c[d+12>>2]|0;g[e+(z<<2)>>2]=t*w-s*I;g[e+((z|1)<<2)>>2]=r*I-t*P;g[e+((z|2)<<2)>>2]=s*P-r*w;e=c[d+20>>2]|0;g[e+(z<<2)>>2]=-(t*Q-s*K);g[e+((z|1)<<2)>>2]=-(r*K-t*L);f=-(s*L-r*Q);ba=30}}else{_=t*n-s*i;$=r*i-t*h;f=s*h-r*n;e=c[d+12>>2]|0;g[e+(z<<2)>>2]=aa*_;g[e+((z|1)<<2)>>2]=aa*$;g[e+((z|2)<<2)>>2]=aa*f;e=c[d+20>>2]|0;g[e+(z<<2)>>2]=(1.0-aa)*_;g[e+((z|1)<<2)>>2]=(1.0-aa)*$;f=(1.0-aa)*f;ba=30}if((ba|0)==30)g[e+((z|2)<<2)>>2]=f;e=+g[b+184>>2]==+g[b+188>>2];g[D+(z<<2)>>2]=0.0;m=(c[d+36>>2]|0)+(z<<2)|0;g[m>>2]=0.0;q=(c[d+40>>2]|0)+(z<<2)|0;g[q>>2]=0.0;o=+g[(A&512|0?b+232|0:d+4|0)>>2];if(!(v<<24>>24==0|x&e)){if(A&1|0)c[(c[d+32>>2]|0)+(z<<2)>>2]=c[b+212>>2];n=+g[b+1100>>2];f=+g[b+1080>>2];h=+g[b+184>>2];i=+g[b+188>>2];k=o*+g[d>>2];do if(!(h>i))if(!(h==i)){if(n/k<0.0)if(f>=h?h-n/k>f:0){f=(h-f)/(n/k);break}else{f=f<h?0.0:1.0;break}if(n/k>0.0)if(f<=i?i-n/k<f:0){f=(i-f)/(n/k);break}else{f=f>i?0.0:1.0;break}else f=0.0}else f=0.0;else f=1.0;while(0);g[D+(z<<2)>>2]=+g[D+(z<<2)>>2]-fa*f*n;g[m>>2]=+g[m>>2]-+g[b+1104>>2]*+g[d>>2];g[q>>2]=+g[b+1104>>2]*+g[d>>2]+ +g[q>>2]}if(x){g[D+(z<<2)>>2]=+g[D+(z<<2)>>2]+p*o*+g[d>>2];if(A&256|0)c[(c[d+32>>2]|0)+(z<<2)>>2]=c[b+244>>2];if(e){f=-3402823466385288598117041.0e14;h=3402823466385288598117041.0e14}else{ba=(y|0)==1;f=ba?-3402823466385288598117041.0e14:0.0;h=ba?0.0:3402823466385288598117041.0e14}g[m>>2]=f;g[q>>2]=h;aa=1.0-+g[b+240>>2];h=+B(+aa);do if(!(aa!=aa|0.0!=0.0|aa==0.0)){f=fa*(r*+g[ga+312>>2]+s*+g[ga+316>>2]+t*+g[ga+320>>2]-(r*+g[ha+312>>2]+s*+g[ha+316>>2]+t*+g[ha+320>>2]));if((y|0)==1){if(!(f<0.0))break;if(!(+g[D+(z<<2)>>2]<-(h*f)))break;g[D+(z<<2)>>2]=-(h*f);break}else{if(!(f>0.0))break;if(!(+g[D+(z<<2)>>2]>-(h*f)))break;g[D+(z<<2)>>2]=-(h*f);break}}while(0);g[D+(z<<2)>>2]=+g[b+232>>2]*+g[D+(z<<2)>>2];e=5}else e=5}else e=4;if(!(a[b+297>>0]|0)){x=0;u=0.0}else{u=+g[b+1088>>2];x=u>0.0?1:2}m=a[b+1112>>0]|0;v=(x|0)!=0;if(!(m&255|x)){l=ia;return}y=O(c[d+24>>2]|0,e)|0;q=c[d+12>>2]|0;c[q+(y<<2)>>2]=ca;c[q+(y+1<<2)>>2]=da;c[q+(y+2<<2)>>2]=ea;w=(c[j>>2]=ca,+g[j>>2]);q=c[d+20>>2]|0;g[q+(y<<2)>>2]=-w;t=(c[j>>2]=da,+g[j>>2]);g[q+(y+1<<2)>>2]=-t;s=(c[j>>2]=ea,+g[j>>2]);g[q+(y+2<<2)>>2]=-s;o=+g[b+192>>2];p=+g[b+196>>2];q=c[b+300>>2]|0;r=+g[(q&2048|0?b+248|0:d+4|0)>>2];if(m<<24>>24==0|v&o==p)e=D;else{if(!(q&4)){h=p;i=o}else{c[(c[d+32>>2]|0)+(y<<2)>>2]=c[b+228>>2];h=+g[b+196>>2];i=+g[b+192>>2]}f=+g[b+1084>>2];n=+g[b+1116>>2];k=r*+g[d>>2];do if(!(i>h))if(!(i==h)){if(n/k<0.0)if(f>=i?i-n/k>f:0){f=(i-f)/(n/k);break}else{f=f<i?0.0:1.0;break}if(n/k>0.0)if(f<=h?h-n/k<f:0){f=(h-f)/(n/k);break}else{f=f>h?0.0:1.0;break}else f=0.0}else f=0.0;else f=1.0;while(0);e=c[d+28>>2]|0;g[e+(y<<2)>>2]=f*n;g[(c[d+36>>2]|0)+(y<<2)>>2]=-(+g[b+1120>>2]*+g[d>>2]);g[(c[d+40>>2]|0)+(y<<2)>>2]=+g[b+1120>>2]*+g[d>>2]}if(!v){l=ia;return}ha=e+(y<<2)|0;g[ha>>2]=+g[ha>>2]+u*r*+g[d>>2];if(q&1024|0)c[(c[d+32>>2]|0)+(y<<2)>>2]=c[b+260>>2];if(o==p){f=-3402823466385288598117041.0e14;h=3402823466385288598117041.0e14}else{ha=(x|0)==1;f=ha?0.0:-3402823466385288598117041.0e14;h=ha?3402823466385288598117041.0e14:0.0}g[(c[d+36>>2]|0)+(y<<2)>>2]=f;g[(c[d+40>>2]|0)+(y<<2)>>2]=h;fa=1.0-+g[b+256>>2];h=+B(+fa);do if(!(fa!=fa|0.0!=0.0|fa==0.0)){ga=c[b+28>>2]|0;ha=c[b+32>>2]|0;f=w*+g[ga+328>>2]+t*+g[ga+332>>2]+s*+g[ga+336>>2]-(w*+g[ha+328>>2]+t*+g[ha+332>>2]+s*+g[ha+336>>2]);if((x|0)==1){if(!(f<0.0))break;e=(c[d+28>>2]|0)+(y<<2)|0;if(!(+g[e>>2]<-(h*f)))break;g[e>>2]=-(h*f);break}else{if(!(f>0.0))break;e=(c[d+28>>2]|0)+(y<<2)|0;if(!(+g[e>>2]>-(h*f)))break;g[e>>2]=-(h*f);break}}while(0);d=(c[d+28>>2]|0)+(y<<2)|0;g[d>>2]=+g[b+248>>2]*+g[d>>2];l=ia;return}function nc(d,e,f,h,i,j){d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;j=+j;var k=0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0,w=0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,D=0.0,E=0,F=0,G=0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0.0,O=0.0,P=0.0;G=l;l=l+896|0;F=c[h+4>>2]|0;E=c[h+12>>2]|0;k=c[F+4>>2]|0;if((k|0)<20){c[G+712>>2]=3816;c[G+712+168>>2]=0;g[G+712+172>>2]=j;c[G+712+164>>2]=c[i+4>>2];g[G+352+308>>2]=9.999999747378752e-05;a[G+352+332>>0]=0;c[G+288>>2]=9272;c[G+64>>2]=9340;c[G+64+4>>2]=G+352;c[G+64+8>>2]=G+288;c[G+64+12>>2]=d;c[G+64+16>>2]=F;c[G+64+20>>2]=0;if((Bd(G+64|0,e,f,E,E,G+712|0)|0?(v=G+712+132|0,s=+g[v>>2],t=+g[G+712+136>>2],m=+g[G+712+140>>2],s*s+t*t+m*m>9.999999747378752e-05):0)?(n=+g[G+712+164>>2],n<+g[i+4>>2]):0){j=1.0/+C(+(s*s+t*t+m*m));g[v>>2]=s*j;g[G+712+136>>2]=t*j;g[G+712+140>>2]=m*j;c[G+16>>2]=c[h+8>>2];c[G+16+4>>2]=0;c[G+16+8>>2]=c[v>>2];c[G+16+8+4>>2]=c[v+4>>2];c[G+16+8+8>>2]=c[v+8>>2];c[G+16+8+12>>2]=c[v+12>>2];c[G+16+24>>2]=c[G+712+148>>2];c[G+16+24+4>>2]=c[G+712+148+4>>2];c[G+16+24+8>>2]=c[G+712+148+8>>2];c[G+16+24+12>>2]=c[G+712+148+12>>2];g[G+16+40>>2]=n;+Hb[c[(c[i>>2]|0)+12>>2]&15](i,G+16|0,1)}l=G;return}if((k+-21|0)>>>0>=9){if((k|0)!=31){l=G;return}Yi(15326);if((c[F+16>>2]|0)>0){k=0;do{v=c[F+24>>2]|0;m=+g[v+(k*80|0)>>2];p=+g[v+(k*80|0)+4>>2];s=+g[v+(k*80|0)+8>>2];n=+g[v+(k*80|0)+16>>2];q=+g[v+(k*80|0)+20>>2];u=+g[v+(k*80|0)+24>>2];o=+g[v+(k*80|0)+32>>2];r=+g[v+(k*80|0)+36>>2];y=+g[v+(k*80|0)+40>>2];O=+g[v+(k*80|0)+48>>2];N=+g[v+(k*80|0)+52>>2];D=+g[v+(k*80|0)+56>>2];v=c[v+(k*80|0)+64>>2]|0;M=+g[E>>2];L=+g[E+4>>2];K=+g[E+8>>2];J=+g[E+16>>2];I=+g[E+20>>2];H=+g[E+24>>2];t=+g[E+32>>2];x=+g[E+36>>2];z=+g[E+40>>2];A=O*M+N*L+D*K+ +g[E+48>>2];B=O*J+N*I+D*H+ +g[E+52>>2];D=O*t+N*x+D*z+ +g[E+56>>2];g[G+712>>2]=m*M+n*L+o*K;g[G+712+4>>2]=p*M+q*L+r*K;g[G+712+8>>2]=s*M+u*L+y*K;g[G+712+12>>2]=0.0;g[G+712+16>>2]=m*J+n*I+o*H;g[G+712+20>>2]=p*J+q*I+r*H;g[G+712+24>>2]=s*J+u*I+y*H;g[G+712+28>>2]=0.0;g[G+712+32>>2]=m*t+n*x+o*z;g[G+712+36>>2]=p*t+q*x+r*z;g[G+712+40>>2]=s*t+u*x+y*z;g[G+712+44>>2]=0.0;g[G+712+48>>2]=A;g[G+712+52>>2]=B;g[G+712+56>>2]=D;g[G+712+60>>2]=0.0;b[G+352+8>>1]=1;b[G+352+10>>1]=-1;c[G+352>>2]=6036;c[G+352+12>>2]=i;c[G+352+16>>2]=k;c[G+352+4>>2]=c[i+4>>2];w=c[h+8>>2]|0;c[G+288>>2]=h;c[G+288+4>>2]=v;c[G+288+8>>2]=w;c[G+288+12>>2]=G+712;c[G+288+16>>2]=-1;c[G+288+20>>2]=k;nc(d,e,f,G+288|0,G+352|0,j);k=k+1|0}while((k|0)<(c[F+16>>2]|0))}k=c[2395]|0;F=(c[k+16>>2]|0)+-1|0;c[k+16>>2]=F;if(F|0){l=G;return}do if(c[k+4>>2]|0){Va(G+712|0,0)|0;F=c[6431]|0;g[k+8>>2]=+g[k+8>>2]+ +(((c[G+712+4>>2]|0)-(c[F+4>>2]|0)+(((c[G+712>>2]|0)-(c[F>>2]|0)|0)*1e6|0)-(c[k+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[k+16>>2]|0)){k=c[2395]|0;break}else{l=G;return}}while(0);c[2395]=c[k+20>>2];l=G;return}switch(k|0){case 21:{m=+g[E>>2];n=+g[E+16>>2];o=+g[E+32>>2];p=+g[E+4>>2];q=+g[E+20>>2];r=+g[E+36>>2];s=+g[E+8>>2];t=+g[E+24>>2];u=+g[E+40>>2];A=-+g[E+48>>2];B=-+g[E+52>>2];D=-+g[E+56>>2];z=+g[e+48>>2];y=+g[e+52>>2];x=+g[e+56>>2];g[G+352>>2]=m*A+n*B+o*D+(m*z+n*y+o*x);g[G+352+4>>2]=p*A+q*B+r*D+(p*z+q*y+r*x);g[G+352+8>>2]=s*A+t*B+u*D+(s*z+t*y+u*x);g[G+352+12>>2]=0.0;x=+g[f+48>>2];y=+g[f+52>>2];z=+g[f+56>>2];P=+g[f>>2];H=+g[f+16>>2];I=+g[f+32>>2];J=+g[f+4>>2];K=+g[f+20>>2];L=+g[f+36>>2];M=+g[f+8>>2];N=+g[f+24>>2];O=+g[f+40>>2];g[G+288>>2]=m*P+n*H+o*I;g[G+288+4>>2]=m*J+n*K+o*L;g[G+288+8>>2]=m*M+n*N+o*O;g[G+288+12>>2]=0.0;g[G+288+16>>2]=p*P+q*H+r*I;g[G+288+20>>2]=p*J+q*K+r*L;g[G+288+24>>2]=p*M+q*N+r*O;g[G+288+28>>2]=0.0;g[G+288+32>>2]=s*P+t*H+u*I;g[G+288+36>>2]=s*J+t*K+u*L;g[G+288+40>>2]=s*M+t*N+u*O;k=G+288+44|0;c[k>>2]=0;c[k+4>>2]=0;c[k+8>>2]=0;c[k+12>>2]=0;c[k+16>>2]=0;k=c[h+8>>2]|0;O=+zb[c[(c[F>>2]|0)+48>>2]&15](F);c[G+64>>2]=9200;c[G+64+4>>2]=d;c[G+64+8>>2]=c[e>>2];c[G+64+8+4>>2]=c[e+4>>2];c[G+64+8+8>>2]=c[e+8>>2];c[G+64+8+12>>2]=c[e+12>>2];c[G+64+24>>2]=c[e+16>>2];c[G+64+24+4>>2]=c[e+16+4>>2];c[G+64+24+8>>2]=c[e+16+8>>2];c[G+64+24+12>>2]=c[e+16+12>>2];c[G+64+40>>2]=c[e+32>>2];c[G+64+40+4>>2]=c[e+32+4>>2];c[G+64+40+8>>2]=c[e+32+8>>2];c[G+64+40+12>>2]=c[e+32+12>>2];c[G+64+56>>2]=c[e+48>>2];c[G+64+56+4>>2]=c[e+48+4>>2];c[G+64+56+8>>2]=c[e+48+8>>2];c[G+64+56+12>>2]=c[e+48+12>>2];c[G+64+72>>2]=c[f>>2];c[G+64+72+4>>2]=c[f+4>>2];c[G+64+72+8>>2]=c[f+8>>2];c[G+64+72+12>>2]=c[f+12>>2];c[G+64+88>>2]=c[f+16>>2];c[G+64+88+4>>2]=c[f+16+4>>2];c[G+64+88+8>>2]=c[f+16+8>>2];c[G+64+88+12>>2]=c[f+16+12>>2];c[G+64+104>>2]=c[f+32>>2];c[G+64+104+4>>2]=c[f+32+4>>2];c[G+64+104+8>>2]=c[f+32+8>>2];c[G+64+104+12>>2]=c[f+32+12>>2];c[G+64+120>>2]=c[f+48>>2];c[G+64+120+4>>2]=c[f+48+4>>2];c[G+64+120+8>>2]=c[f+48+8>>2];c[G+64+120+12>>2]=c[f+48+12>>2];c[G+64+136>>2]=c[E>>2];c[G+64+136+4>>2]=c[E+4>>2];c[G+64+136+8>>2]=c[E+8>>2];c[G+64+136+12>>2]=c[E+12>>2];c[G+64+152>>2]=c[E+16>>2];c[G+64+152+4>>2]=c[E+16+4>>2];c[G+64+152+8>>2]=c[E+16+8>>2];c[G+64+152+12>>2]=c[E+16+12>>2];c[G+64+168>>2]=c[E+32>>2];c[G+64+168+4>>2]=c[E+32+4>>2];c[G+64+168+8>>2]=c[E+32+8>>2];c[G+64+168+12>>2]=c[E+32+12>>2];c[G+64+184>>2]=c[E+48>>2];c[G+64+184+4>>2]=c[E+48+4>>2];c[G+64+184+8>>2]=c[E+48+8>>2];c[G+64+184+12>>2]=c[E+48+12>>2];g[G+64+204>>2]=O;c[G+64>>2]=5988;c[G+64+212>>2]=i;c[G+64+216>>2]=k;c[G+64+220>>2]=F;c[G+64+200>>2]=c[i+4>>2];g[G+64+208>>2]=j;Vb[c[(c[d>>2]|0)+8>>2]&127](d,G+288|0,G+16|0,G);k=c[F+48>>2]|0;c[G+712>>2]=7028;c[G+712+4>>2]=k;c[G+712+8>>2]=G+64;k=c[F+52>>2]|0;if(!(a[k+60>>0]|0))Be(k,G+712|0,G+352|0,m*A+n*B+o*D+(m*x+n*y+o*z),p*A+q*B+r*D+(p*x+q*y+r*z),s*A+t*B+u*D+(s*x+t*y+u*z),G+16|0,G);else fe(k,G+712|0,G+352|0,m*A+n*B+o*D+(m*x+n*y+o*z),p*A+q*B+r*D+(p*x+q*y+r*z),s*A+t*B+u*D+(s*x+t*y+u*z),G+16|0,G,c[k+56>>2]|0);l=G;return}case 28:{c[G+712>>2]=3816;c[G+712+168>>2]=0;g[G+712+172>>2]=j;c[G+712+164>>2]=c[i+4>>2];c[G+352>>2]=9340;c[G+352+4>>2]=0;c[G+352+8>>2]=0;c[G+352+12>>2]=d;c[G+352+16>>2]=0;c[G+352+20>>2]=F;if((Bd(G+352|0,e,f,E,E,G+712|0)|0?(w=G+712+132|0,o=+g[w>>2],p=+g[G+712+136>>2],q=+g[G+712+140>>2],o*o+p*p+q*q>9.999999747378752e-05):0)?(r=+g[G+712+164>>2],r<+g[i+4>>2]):0){P=1.0/+C(+(o*o+p*p+q*q));g[w>>2]=o*P;g[G+712+136>>2]=p*P;g[G+712+140>>2]=q*P;c[G+288>>2]=c[h+8>>2];c[G+288+4>>2]=0;c[G+288+8>>2]=c[w>>2];c[G+288+8+4>>2]=c[w+4>>2];c[G+288+8+8>>2]=c[w+8>>2];c[G+288+8+12>>2]=c[w+12>>2];c[G+288+24>>2]=c[G+712+148>>2];c[G+288+24+4>>2]=c[G+712+148+4>>2];c[G+288+24+8>>2]=c[G+712+148+8>>2];c[G+288+24+12>>2]=c[G+712+148+12>>2];g[G+288+40>>2]=r;+Hb[c[(c[i>>2]|0)+12>>2]&15](i,G+288|0,1)}l=G;return}default:{p=+g[E>>2];q=+g[E+16>>2];r=+g[E+32>>2];x=+g[E+4>>2];y=+g[E+20>>2];z=+g[E+36>>2];K=+g[E+8>>2];M=+g[E+24>>2];O=+g[E+40>>2];I=-+g[E+48>>2];H=-+g[E+52>>2];D=-+g[E+56>>2];A=+g[e+48>>2];B=+g[e+52>>2];u=+g[e+56>>2];s=p*I+q*H+r*D+(p*A+q*B+r*u);t=x*I+y*H+z*D+(x*A+y*B+z*u);u=K*I+M*H+O*D+(K*A+M*B+O*u);B=+g[f+48>>2];A=+g[f+52>>2];m=+g[f+56>>2];o=p*I+q*H+r*D+(p*B+q*A+r*m);n=x*I+y*H+z*D+(x*B+y*A+z*m);m=K*I+M*H+O*D+(K*B+M*A+O*m);A=+g[f>>2];B=+g[f+16>>2];D=+g[f+32>>2];H=+g[f+4>>2];I=+g[f+20>>2];J=+g[f+36>>2];L=+g[f+8>>2];N=+g[f+24>>2];P=+g[f+40>>2];g[G+712>>2]=p*A+q*B+r*D;g[G+712+4>>2]=p*H+q*I+r*J;g[G+712+8>>2]=p*L+q*N+r*P;g[G+712+12>>2]=0.0;g[G+712+16>>2]=x*A+y*B+z*D;g[G+712+20>>2]=x*H+y*I+z*J;g[G+712+24>>2]=x*L+y*N+z*P;g[G+712+28>>2]=0.0;g[G+712+32>>2]=K*A+M*B+O*D;g[G+712+36>>2]=K*H+M*I+O*J;g[G+712+40>>2]=K*L+M*N+O*P;w=G+712+44|0;c[w>>2]=0;c[w+4>>2]=0;c[w+8>>2]=0;c[w+12>>2]=0;c[w+16>>2]=0;h=c[h+8>>2]|0;P=+zb[c[(c[F>>2]|0)+48>>2]&15](F);c[G+352>>2]=9200;c[G+352+4>>2]=d;c[G+352+8>>2]=c[e>>2];c[G+352+8+4>>2]=c[e+4>>2];c[G+352+8+8>>2]=c[e+8>>2];c[G+352+8+12>>2]=c[e+12>>2];c[G+352+24>>2]=c[e+16>>2];c[G+352+24+4>>2]=c[e+16+4>>2];c[G+352+24+8>>2]=c[e+16+8>>2];c[G+352+24+12>>2]=c[e+16+12>>2];c[G+352+40>>2]=c[e+32>>2];c[G+352+40+4>>2]=c[e+32+4>>2];c[G+352+40+8>>2]=c[e+32+8>>2];c[G+352+40+12>>2]=c[e+32+12>>2];c[G+352+56>>2]=c[e+48>>2];c[G+352+56+4>>2]=c[e+48+4>>2];c[G+352+56+8>>2]=c[e+48+8>>2];c[G+352+56+12>>2]=c[e+48+12>>2];c[G+352+72>>2]=c[f>>2];c[G+352+72+4>>2]=c[f+4>>2];c[G+352+72+8>>2]=c[f+8>>2];c[G+352+72+12>>2]=c[f+12>>2];c[G+352+88>>2]=c[f+16>>2];c[G+352+88+4>>2]=c[f+16+4>>2];c[G+352+88+8>>2]=c[f+16+8>>2];c[G+352+88+12>>2]=c[f+16+12>>2];c[G+352+104>>2]=c[f+32>>2];c[G+352+104+4>>2]=c[f+32+4>>2];c[G+352+104+8>>2]=c[f+32+8>>2];c[G+352+104+12>>2]=c[f+32+12>>2];c[G+352+120>>2]=c[f+48>>2];c[G+352+120+4>>2]=c[f+48+4>>2];c[G+352+120+8>>2]=c[f+48+8>>2];c[G+352+120+12>>2]=c[f+48+12>>2];c[G+352+136>>2]=c[E>>2];c[G+352+136+4>>2]=c[E+4>>2];c[G+352+136+8>>2]=c[E+8>>2];c[G+352+136+12>>2]=c[E+12>>2];c[G+352+152>>2]=c[E+16>>2];c[G+352+152+4>>2]=c[E+16+4>>2];c[G+352+152+8>>2]=c[E+16+8>>2];c[G+352+152+12>>2]=c[E+16+12>>2];c[G+352+168>>2]=c[E+32>>2];c[G+352+168+4>>2]=c[E+32+4>>2];c[G+352+168+8>>2]=c[E+32+8>>2];c[G+352+168+12>>2]=c[E+32+12>>2];c[G+352+184>>2]=c[E+48>>2];c[G+352+184+4>>2]=c[E+48+4>>2];c[G+352+184+8>>2]=c[E+48+8>>2];c[G+352+184+12>>2]=c[E+48+12>>2];g[G+352+204>>2]=P;c[G+352>>2]=6012;c[G+352+212>>2]=i;c[G+352+216>>2]=h;c[G+352+220>>2]=F;c[G+352+200>>2]=c[i+4>>2];g[G+352+208>>2]=j;Vb[c[(c[d>>2]|0)+8>>2]&127](d,G+712|0,G+288|0,G+64|0);g[G+16>>2]=s;g[G+16+4>>2]=t;g[G+16+8>>2]=u;g[G+16+12>>2]=0.0;if(o<s){g[G+16>>2]=o;p=o}else p=s;if(n<t){g[G+16+4>>2]=n;q=n}else q=t;if(m<u){g[G+16+8>>2]=m;r=m}else r=u;g[G>>2]=s;g[G+4>>2]=t;g[G+8>>2]=u;g[G+12>>2]=0.0;if(s<o)g[G>>2]=o;else o=s;if(t<n)g[G+4>>2]=n;else n=t;if(u<m)g[G+8>>2]=m;else m=u;g[G+16>>2]=+g[G+288>>2]+p;g[G+16+4>>2]=+g[G+288+4>>2]+q;g[G+16+8>>2]=+g[G+288+8>>2]+r;g[G>>2]=+g[G+64>>2]+o;g[G+4>>2]=+g[G+64+4>>2]+n;g[G+8>>2]=+g[G+64+8>>2]+m;Vb[c[(c[F>>2]|0)+64>>2]&127](F,G+352|0,G+16|0,G);l=G;return}}}function oc(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0,j=0,k=0,m=0.0,n=0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0,w=0,x=0,y=0,z=0.0,A=0;A=l;l=l+112|0;c[b+164>>2]=1065353216;c[b+168>>2]=1065353216;c[b+172>>2]=1065353216;g[b+176>>2]=0.0;c[b+180>>2]=0;g[b+184>>2]=999999984306749440.0;c[b+188>>2]=0;c[b+188+4>>2]=0;c[b+188+8>>2]=0;c[b+188+12>>2]=0;c[b+204>>2]=1;c[b+208>>2]=-1;c[b+212>>2]=-1;c[b+216>>2]=1;g[b+220>>2]=0.0;g[b+224>>2]=.5;g[b+228>>2]=0.0;g[b+232>>2]=0.0;c[b+236>>2]=1;c[b+240>>2]=0;g[b+244>>2]=1.0;c[b+248>>2]=0;c[b+248+4>>2]=0;c[b+248+8>>2]=0;c[b+248+12>>2]=0;c[b+4>>2]=1065353216;c[b+8>>2]=0;c[b+8+4>>2]=0;c[b+8+8>>2]=0;c[b+8+12>>2]=0;c[b+24>>2]=1065353216;c[b+28>>2]=0;c[b+28+4>>2]=0;c[b+28+8>>2]=0;c[b+28+12>>2]=0;c[b+44>>2]=1065353216;c[b+48>>2]=0;c[b+48+4>>2]=0;c[b+48+8>>2]=0;c[b+48+12>>2]=0;c[b+48+16>>2]=0;c[b>>2]=3308;a[b+280>>0]=1;c[b+276>>2]=0;c[b+268>>2]=0;c[b+272>>2]=0;c[b+284>>2]=0;a[b+408>>0]=1;c[b+404>>2]=0;c[b+396>>2]=0;c[b+400>>2]=0;a[b+428>>0]=1;c[b+424>>2]=0;c[b+416>>2]=0;c[b+420>>2]=0;a[b+448>>0]=1;c[b+444>>2]=0;c[b+436>>2]=0;c[b+440>>2]=0;a[b+496>>0]=1;c[b+492>>2]=0;c[b+484>>2]=0;c[b+488>>2]=0;a[b+516>>0]=1;c[b+512>>2]=0;c[b+504>>2]=0;c[b+508>>2]=0;c[b+684>>2]=d;a[b+704>>0]=1;c[b+700>>2]=0;c[b+692>>2]=0;c[b+696>>2]=0;a[b+724>>0]=1;c[b+720>>2]=0;c[b+712>>2]=0;c[b+716>>2]=0;a[b+744>>0]=1;c[b+740>>2]=0;c[b+732>>2]=0;c[b+736>>2]=0;a[b+764>>0]=1;c[b+760>>2]=0;c[b+752>>2]=0;c[b+756>>2]=0;a[b+784>>0]=1;c[b+780>>2]=0;c[b+772>>2]=0;c[b+776>>2]=0;a[b+804>>0]=1;c[b+800>>2]=0;c[b+792>>2]=0;c[b+796>>2]=0;a[b+824>>0]=1;c[b+820>>2]=0;c[b+812>>2]=0;c[b+816>>2]=0;a[b+844>>0]=1;c[b+840>>2]=0;c[b+832>>2]=0;c[b+836>>2]=0;a[b+864>>0]=1;c[b+860>>2]=0;c[b+852>>2]=0;c[b+856>>2]=0;a[b+884>>0]=1;c[b+880>>2]=0;c[b+872>>2]=0;c[b+876>>2]=0;a[b+964>>0]=1;c[b+960>>2]=0;c[b+952>>2]=0;c[b+956>>2]=0;a[b+984>>0]=1;c[b+980>>2]=0;c[b+972>>2]=0;c[b+976>>2]=0;c[b+928>>2]=0;c[b+932>>2]=0;c[b+936>>2]=-1;c[b+940>>2]=0;c[b+944>>2]=0;a[b+1024>>0]=1;c[b+1020>>2]=0;c[b+1012>>2]=0;c[b+1016>>2]=0;a[b+1044>>0]=1;c[b+1040>>2]=0;c[b+1032>>2]=0;c[b+1036>>2]=0;c[b+988>>2]=0;c[b+992>>2]=0;c[b+996>>2]=-1;c[b+1e3>>2]=0;c[b+1004>>2]=0;a[b+1084>>0]=1;c[b+1080>>2]=0;c[b+1072>>2]=0;c[b+1076>>2]=0;a[b+1104>>0]=1;c[b+1100>>2]=0;c[b+1092>>2]=0;c[b+1096>>2]=0;c[b+1048>>2]=0;c[b+1052>>2]=0;c[b+1056>>2]=-1;c[b+1060>>2]=0;c[b+1064>>2]=0;a[b+1124>>0]=1;c[b+1120>>2]=0;c[b+1112>>2]=0;c[b+1116>>2]=0;a[b+1144>>0]=1;c[b+1140>>2]=0;c[b+1132>>2]=0;c[b+1136>>2]=0;a[b+1248>>0]=1;c[b+1244>>2]=0;c[b+1236>>2]=0;c[b+1240>>2]=0;c[b+236>>2]=8;c[b+288>>2]=0;g[b+292>>2]=1.0;c[b+296>>2]=0;c[b+296+4>>2]=0;c[b+296+8>>2]=0;c[b+296+12>>2]=0;c[b+296+16>>2]=0;g[b+316>>2]=.20000000298023224;g[b+320>>2]=0.0;g[b+324>>2]=1.0;g[b+328>>2]=.10000000149011612;g[b+332>>2]=1.0;g[b+336>>2]=.699999988079071;g[b+340>>2]=.10000000149011612;g[b+344>>2]=1.0;g[b+348>>2]=.5;g[b+352>>2]=.5;g[b+356>>2]=.5;g[b+360>>2]=.5;g[b+364>>2]=1.0;g[b+368>>2]=1.0;c[b+372>>2]=0;c[b+376>>2]=1;c[b+380>>2]=0;c[b+384>>2]=4;c[b+388>>2]=1;a[b+472>>0]=0;a[b+473>>0]=0;g[b+476>>2]=0.0;c[b+520>>2]=0;c[b+520+4>>2]=0;c[b+520+8>>2]=0;c[b+520+12>>2]=0;c[b+536>>2]=1065353216;c[b+540>>2]=0;c[b+540+4>>2]=0;c[b+540+8>>2]=0;c[b+540+12>>2]=0;c[b+556>>2]=1065353216;c[b+560>>2]=0;c[b+560+4>>2]=0;c[b+560+8>>2]=0;c[b+560+12>>2]=0;c[b+576>>2]=1065353216;g[b+580>>2]=0.0;c[b+584>>2]=1065353216;c[b+588>>2]=0;c[b+588+4>>2]=0;c[b+588+8>>2]=0;c[b+588+12>>2]=0;c[b+604>>2]=1065353216;c[b+608>>2]=0;c[b+608+4>>2]=0;c[b+608+8>>2]=0;c[b+608+12>>2]=0;c[b+624>>2]=1065353216;g[b+628>>2]=0.0;c[b+680>>2]=0;g[b+888>>2]=0.0;a[b+924>>0]=1;c[b+892>>2]=0;c[b+892+4>>2]=0;c[b+892+8>>2]=0;c[b+892+12>>2]=0;c[b+892+16>>2]=0;c[b+892+20>>2]=0;c[b+892+24>>2]=0;c[b+892+28>>2]=0;c[b+4>>2]=1065353216;c[b+8>>2]=0;c[b+8+4>>2]=0;c[b+8+8>>2]=0;c[b+8+12>>2]=0;c[b+24>>2]=1065353216;c[b+28>>2]=0;c[b+28+4>>2]=0;c[b+28+8>>2]=0;c[b+28+12>>2]=0;c[b+44>>2]=1065353216;c[b+48>>2]=0;c[b+48+4>>2]=0;c[b+48+8>>2]=0;c[b+48+12>>2]=0;c[b+48+16>>2]=0;d=c[b+404>>2]|0;if(d|0){if(a[b+408>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+404>>2]=0}a[b+408>>0]=1;c[b+404>>2]=0;c[b+396>>2]=0;c[b+400>>2]=0;d=c[b+424>>2]|0;if(d|0){if(a[b+428>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+424>>2]=0}a[b+428>>0]=1;c[b+424>>2]=0;c[b+416>>2]=0;c[b+420>>2]=0;d=c[b+444>>2]|0;do if(d)if(a[b+448>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0);d=c[b+416>>2]|0;i=c[b+420>>2]|0;c[b+444>>2]=0;a[b+448>>0]=1;c[b+444>>2]=0;c[b+436>>2]=0;c[b+440>>2]=0;if((d|0)==(i|0)){v=14;break}else break}else{c[b+444>>2]=0;v=13;break}else v=13;while(0);if((v|0)==13){a[b+448>>0]=1;c[b+444>>2]=0;c[b+436>>2]=0;c[b+440>>2]=0;i=0;v=14}if((v|0)==14){n=i|0?i<<1:1;if((i|0)<(n|0)){if(!n){d=i;i=0}else{c[6432]=(c[6432]|0)+1;d=ec((n<<2|3)+16|0)|0;if(!d)i=0;else{c[(d+4+15&-16)+-4>>2]=d;i=d+4+15&-16}d=c[b+416>>2]|0}k=c[b+424>>2]|0;if((d|0)<=0){if(k)v=22}else{j=0;do{c[i+(j<<2)>>2]=c[k+(j<<2)>>2];j=j+1|0}while((j|0)!=(d|0));v=22}if((v|0)==22){if(a[b+428>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[k+-4>>2]|0);d=c[b+416>>2]|0}c[b+424>>2]=0}a[b+428>>0]=1;c[b+424>>2]=i;c[b+420>>2]=n;i=n}else d=i}k=c[b+424>>2]|0;c[k+(d<<2)>>2]=1;j=d+1|0;c[b+416>>2]=j;if((j|0)==(i|0)){n=i|0?i<<1:1;if((i|0)<(n|0)){if(!n){j=k;k=0}else{c[6432]=(c[6432]|0)+1;d=ec((n<<2|3)+16|0)|0;if(!d)d=0;else{c[(d+4+15&-16)+-4>>2]=d;d=d+4+15&-16}i=c[b+416>>2]|0;j=c[b+424>>2]|0;k=d}if((i|0)<=0){if(j)v=35}else{d=0;do{c[k+(d<<2)>>2]=c[j+(d<<2)>>2];d=d+1|0}while((d|0)!=(i|0));v=35}if((v|0)==35){if(a[b+428>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0);i=c[b+416>>2]|0}c[b+424>>2]=0}a[b+428>>0]=1;c[b+424>>2]=k;c[b+420>>2]=n;d=k;j=i;i=n}else{d=k;j=i}}else d=k;c[k+(j<<2)>>2]=2;j=j+1|0;c[b+416>>2]=j;if((j|0)==(i|0)){n=i|0?i<<1:1;if((i|0)<(n|0)){if(!n){j=k;k=0}else{c[6432]=(c[6432]|0)+1;d=ec((n<<2|3)+16|0)|0;if(!d)d=0;else{c[(d+4+15&-16)+-4>>2]=d;d=d+4+15&-16}i=c[b+416>>2]|0;j=c[b+424>>2]|0;k=d}if((i|0)<=0){if(j)v=48}else{d=0;do{c[k+(d<<2)>>2]=c[j+(d<<2)>>2];d=d+1|0}while((d|0)!=(i|0));v=48}if((v|0)==48){if(a[b+428>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0);i=c[b+416>>2]|0}c[b+424>>2]=0}a[b+428>>0]=1;c[b+424>>2]=k;c[b+420>>2]=n;d=k;j=i;i=n}else j=i}c[k+(j<<2)>>2]=3;j=j+1|0;c[b+416>>2]=j;if((j|0)==(i|0)){n=i|0?i<<1:1;if((i|0)<(n|0)){if(!n)d=0;else{c[6432]=(c[6432]|0)+1;d=ec((n<<2|3)+16|0)|0;if(!d)d=0;else{c[(d+4+15&-16)+-4>>2]=d;d=d+4+15&-16}i=c[b+416>>2]|0;k=c[b+424>>2]|0}if((i|0)<=0){if(k)v=61}else{j=0;do{c[d+(j<<2)>>2]=c[k+(j<<2)>>2];j=j+1|0}while((j|0)!=(i|0));v=61}if((v|0)==61){if(a[b+428>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[k+-4>>2]|0);i=c[b+416>>2]|0}c[b+424>>2]=0}a[b+428>>0]=1;c[b+424>>2]=d;c[b+420>>2]=n}}else i=j;c[d+(i<<2)>>2]=0;c[b+416>>2]=i+1;c[6432]=(c[6432]|0)+1;d=ec(39)|0;if(!d)d=0;else{c[(d+4+15&-16)+-4>>2]=d;d=d+4+15&-16}c[d+8>>2]=0;c[d>>2]=3416;c[d+4>>2]=32;c[d+16>>2]=b;c[b+192>>2]=d;g[d+12>>2]=.25;c[b+1148>>2]=1065353216;c[b+1152>>2]=0;c[b+1152+4>>2]=0;c[b+1152+8>>2]=0;c[b+1152+12>>2]=0;c[b+1168>>2]=1065353216;c[b+1172>>2]=0;c[b+1172+4>>2]=0;c[b+1172+8>>2]=0;c[b+1172+12>>2]=0;c[b+1188>>2]=1065353216;v=b+1192|0;w=v+36|0;do{c[v>>2]=0;v=v+4|0}while((v|0)<(w|0));g[b+1228>>2]=1.0;y=Qg(b)|0;g[y+4>>2]=1.0;g[y+8>>2]=1.0;g[y+12>>2]=1.0;c[y+16>>2]=1;v=c[b+192>>2]|0;z=+zb[c[(c[v>>2]|0)+48>>2]&15](v);v=A;w=v+100|0;do{c[v>>2]=0;v=v+4|0}while((v|0)<(w|0));n=c[b+712>>2]|0;if((n|0)<(e|0)){if((c[b+716>>2]|0)<(e|0)){if(!e){i=n;j=0}else{c[6432]=(c[6432]|0)+1;d=ec((e*104|3)+16|0)|0;if(!d)d=0;else{c[(d+4+15&-16)+-4>>2]=d;d=d+4+15&-16}i=c[b+712>>2]|0;j=d}if((i|0)>0){d=0;do{v=j+(d*104|0)|0;k=(c[b+720>>2]|0)+(d*104|0)|0;w=v+104|0;do{c[v>>2]=c[k>>2];v=v+4|0;k=k+4|0}while((v|0)<(w|0));d=d+1|0}while((d|0)!=(i|0))}d=c[b+720>>2]|0;if(d|0){if(a[b+724>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+720>>2]=0}a[b+724>>0]=1;c[b+720>>2]=j;c[b+716>>2]=e;d=n}else d=n;do{v=c[b+720>>2]|0;c[v+(d*104|0)>>2]=0;v=v+(d*104|0)+4|0;k=A;w=v+100|0;do{c[v>>2]=c[k>>2];v=v+4|0;k=k+4|0}while((v|0)<(w|0));d=d+1|0}while((d|0)!=(e|0))}c[b+712>>2]=e;if((e|0)>0){x=0;i=h;d=f;while(1){k=c[b+720>>2]|0;n=k+(x*104|0)|0;v=n;w=v+104|0;do{c[v>>2]=0;v=v+4|0}while((v|0)<(w|0));if(!d){o=0.0;p=0.0;q=0.0;m=0.0;d=0}else{o=+g[d>>2];p=+g[d+4>>2];q=+g[d+8>>2];m=+g[d+12>>2];d=d+16|0}h=k+(x*104|0)+8|0;g[h>>2]=o;g[k+(x*104|0)+12>>2]=p;g[k+(x*104|0)+16>>2]=q;g[k+(x*104|0)+20>>2]=m;f=k+(x*104|0)+24|0;c[f>>2]=c[h>>2];c[f+4>>2]=c[h+4>>2];c[f+8>>2]=c[h+8>>2];c[f+12>>2]=c[h+12>>2];if(!i){m=1.0;j=0}else{m=+g[i>>2];j=i+4|0}g[k+(x*104|0)+88>>2]=m>0.0?1.0/m:0.0;s=o-z;u=p-z;t=q-z;r=z+o;o=z+p;m=z+q;i=c[b+932>>2]|0;if(!i){c[6432]=(c[6432]|0)+1;i=ec(63)|0;if(!i)i=0;else{c[(i+4+15&-16)+-4>>2]=i;i=i+4+15&-16}v=i;w=v+44|0;do{c[v>>2]=0;v=v+4|0}while((v|0)<(w|0))}else c[b+932>>2]=0;c[i+32>>2]=0;c[i+36>>2]=n;c[i+40>>2]=0;g[i>>2]=s;g[i+4>>2]=u;g[i+8>>2]=t;g[i+12>>2]=0.0;g[i+16>>2]=r;g[i+20>>2]=o;g[i+24>>2]=m;g[i+28>>2]=0.0;We(b+928|0,c[b+928>>2]|0,i);c[b+940>>2]=(c[b+940>>2]|0)+1;c[k+(x*104|0)+96>>2]=i;c[k+(x*104|0)+4>>2]=y;x=x+1|0;if((x|0)==(e|0))break;else i=j}}d=c[b+928>>2]|0;if(!d){c[b+892>>2]=0;c[b+892+4>>2]=0;c[b+892+8>>2]=0;c[b+892+12>>2]=0;c[b+892+16>>2]=0;c[b+892+20>>2]=0;c[b+892+24>>2]=0;c[b+892+28>>2]=0;l=A;return}e=c[b+192>>2]|0;t=+zb[c[(c[e>>2]|0)+48>>2]&15](e);z=+g[d+4>>2]-t;u=+g[d+8>>2]-t;g[b+892>>2]=+g[d>>2]-t;g[b+896>>2]=z;g[b+900>>2]=u;g[b+904>>2]=0.0;u=t+ +g[d+20>>2];z=t+ +g[d+24>>2];g[b+908>>2]=t+ +g[d+16>>2];g[b+912>>2]=u;g[b+916>>2]=z;g[b+920>>2]=0.0;d=c[b+188>>2]|0;if(!d){l=A;return}e=c[b+684>>2]|0;f=c[e+32>>2]|0;fb[c[(c[f>>2]|0)+16>>2]&31](f,d,b+892|0,b+908|0,c[e+36>>2]|0);l=A;return}function pc(d,e,f){d=d|0;e=e|0;f=+f;var h=0.0,i=0,j=0.0,k=0,m=0.0,n=0.0,o=0,p=0.0,q=0.0,r=0.0,s=0,t=0;s=l;l=l+528|0;if((a[d+171>>0]|0)==0?+g[d+172>>2]<=0.0:0){l=s;return}a[d+168>>0]=(lb[c[(c[d>>2]|0)+48>>2]&127](d)|0)&1;m=+g[d+16>>2]-+g[d+44>>2]*f;g[d+16>>2]=m;if(m>0.0?(j=+g[d+28>>2],m>j):0)g[d+16>>2]=j;else j=m;if(j<0.0?(q=+B(+j),n=+B(+(+g[d+24>>2])),q>n):0){g[d+16>>2]=-n;j=-n}g[d+20>>2]=j*f;o=c[d+8>>2]|0;c[s>>2]=c[o+4>>2];c[s+4>>2]=c[o+4+4>>2];c[s+8>>2]=c[o+4+8>>2];c[s+12>>2]=c[o+4+12>>2];c[s+16>>2]=c[o+20>>2];c[s+16+4>>2]=c[o+20+4>>2];c[s+16+8>>2]=c[o+20+8>>2];c[s+16+12>>2]=c[o+20+12>>2];c[s+32>>2]=c[o+36>>2];c[s+32+4>>2]=c[o+36+4>>2];c[s+32+8>>2]=c[o+36+8>>2];c[s+32+12>>2]=c[o+36+12>>2];c[s+48>>2]=c[o+52>>2];c[s+48+4>>2]=c[o+52+4>>2];c[s+48+8>>2]=c[o+52+8>>2];c[s+48+12>>2]=c[o+52+12>>2];if((a[22704]|0)==0?jy(22704)|0:0){c[6123]=1065353216;c[6124]=0;c[6125]=0;c[6126]=0;c[6127]=0;c[6128]=1065353216;c[6129]=0;c[6130]=0;c[6131]=0;c[6132]=0;c[6133]=1065353216;g[6134]=0.0}o=c[d+176>>2]|0;n=+g[d+20>>2];n=+g[d+52>>2]+(n>0.0?n:0.0);p=+g[24492+(o<<4)+4>>2]*n+ +g[d+96>>2];q=n*+g[24492+(o<<4)+8>>2]+ +g[d+100>>2];g[d+112>>2]=+g[d+92>>2]+ +g[24492+(o<<4)>>2]*n;g[d+116>>2]=p;g[d+120>>2]=q;g[d+124>>2]=0.0;c[s+456>>2]=1065353216;c[s+456+4>>2]=0;c[s+456+4+4>>2]=0;c[s+456+4+8>>2]=0;c[s+456+4+12>>2]=0;c[s+456+20>>2]=1065353216;c[s+456+24>>2]=0;c[s+456+24+4>>2]=0;c[s+456+24+8>>2]=0;c[s+456+24+12>>2]=0;c[s+456+40>>2]=1065353216;o=s+456+44|0;c[o>>2]=0;c[o+4>>2]=0;c[o+8>>2]=0;c[o+12>>2]=0;c[o+16>>2]=0;c[s+392>>2]=1065353216;c[s+392+4>>2]=0;c[s+392+4+4>>2]=0;c[s+392+4+8>>2]=0;c[s+392+4+12>>2]=0;c[s+392+20>>2]=1065353216;c[s+392+24>>2]=0;c[s+392+24+4>>2]=0;c[s+392+24+8>>2]=0;c[s+392+24+12>>2]=0;c[s+392+40>>2]=1065353216;o=s+392+44|0;c[o>>2]=0;c[o+4>>2]=0;c[o+8>>2]=0;c[o+12>>2]=0;c[o+16>>2]=0;if((a[22704]|0)==0?jy(22704)|0:0){c[6123]=1065353216;c[6124]=0;c[6125]=0;c[6126]=0;c[6127]=0;c[6128]=1065353216;c[6129]=0;c[6130]=0;c[6131]=0;c[6132]=0;c[6133]=1065353216;g[6134]=0.0}i=c[d+176>>2]|0;o=c[d+12>>2]|0;n=+zb[c[(c[o>>2]|0)+48>>2]&15](o);n=n+ +g[d+56>>2];p=n*+g[24492+(i<<4)+4>>2]+ +g[d+96>>2];q=n*+g[24492+(i<<4)+8>>2]+ +g[d+100>>2];g[s+456+48>>2]=+g[24492+(i<<4)>>2]*n+ +g[d+92>>2];g[s+456+52>>2]=p;g[s+456+56>>2]=q;g[s+456+60>>2]=0.0;c[s+392+48>>2]=c[d+112>>2];c[s+392+48+4>>2]=c[d+112+4>>2];c[s+392+48+8>>2]=c[d+112+8>>2];c[s+392+48+12>>2]=c[d+112+12>>2];i=c[d+8>>2]|0;if((a[22704]|0)==0?jy(22704)|0:0){c[6123]=1065353216;c[6124]=0;c[6125]=0;c[6126]=0;c[6127]=0;c[6128]=1065353216;c[6129]=0;c[6130]=0;c[6131]=0;c[6132]=0;c[6133]=1065353216;g[6134]=0.0}k=c[d+176>>2]|0;n=-+g[24492+(k<<4)>>2];p=-+g[24492+(k<<4)+4>>2];q=-+g[24492+(k<<4)+8>>2];g[s+288+4>>2]=1.0;k=s+288+12|0;c[s+288+76>>2]=0;c[k>>2]=0;c[k+4>>2]=0;c[k+8>>2]=0;c[k+12>>2]=0;c[k+16>>2]=0;c[k+20>>2]=0;c[k+24>>2]=0;c[k+28>>2]=0;c[s+288>>2]=5064;c[s+288+80>>2]=i;g[s+288+84>>2]=n;g[s+288+88>>2]=p;g[s+288+92>>2]=q;g[s+288+96>>2]=0.0;g[s+288+100>>2]=.707099974155426;i=c[d+8>>2]|0;k=c[i+188>>2]|0;b[s+288+8>>1]=b[k+4>>1]|0;b[s+288+10>>1]=b[k+6>>1]|0;k=c[d+12>>2]|0;if(!(a[d+170>>0]|0))ud(e,k,s+456|0,s+392|0,s+288|0,0.0);else cd(i,k,s+456|0,s+392|0,s+288|0,+g[e+56>>2]);if(+g[s+288+4>>2]<1.0){if((a[22704]|0)==0?jy(22704)|0:0){c[6123]=1065353216;c[6124]=0;c[6125]=0;c[6126]=0;c[6127]=0;c[6128]=1065353216;c[6129]=0;c[6130]=0;c[6131]=0;c[6132]=0;c[6133]=1065353216;g[6134]=0.0}o=c[d+176>>2]|0;do if(+g[s+288+44>>2]*+g[24492+(o<<4)>>2]+ +g[s+288+48>>2]*+g[24492+(o<<4)+4>>2]+ +g[s+288+52>>2]*+g[24492+(o<<4)+8>>2]>0.0){j=+g[s+288+4>>2];g[d+108>>2]=+g[d+52>>2]*j;if(!(a[d+180>>0]|0)){c[d+92>>2]=c[d+112>>2];c[d+92+4>>2]=c[d+112+4>>2];c[d+92+8>>2]=c[d+112+8>>2];c[d+92+12>>2]=c[d+112+12>>2];break}else{g[d+92>>2]=(1.0-j)*+g[d+92>>2]+j*+g[d+112>>2];g[d+96>>2]=(1.0-j)*+g[d+96>>2]+j*+g[d+116>>2];g[d+100>>2]=(1.0-j)*+g[d+100>>2]+j*+g[d+120>>2];break}}while(0);g[d+16>>2]=0.0;g[d+20>>2]=0.0}else{c[d+108>>2]=c[d+52>>2];c[d+92>>2]=c[d+112>>2];c[d+92+4>>2]=c[d+112+4>>2];c[d+92+8>>2]=c[d+112+8>>2];c[d+92+12>>2]=c[d+112+12>>2]}if(!(a[d+171>>0]|0)){p=+g[d+172>>2];q=p>f?f:p;g[d+172>>2]=p-f;Od(d,e,q*+g[d+60>>2],q*+g[d+64>>2],q*+g[d+68>>2])}else Od(d,e,+g[d+60>>2],+g[d+64>>2],+g[d+68>>2]);c[s+272>>2]=c[d+112>>2];c[s+272+4>>2]=c[d+112+4>>2];c[s+272+8>>2]=c[d+112+8>>2];c[s+272+12>>2]=c[d+112+12>>2];j=+g[d+16>>2];j=(j<0.0?-j:0.0)*f;do if(j>0.0?(h=+g[d+24>>2],j>h):0){if((a[d+168>>0]|0)==0?a[d+169>>0]|0:0){h=j;break}}else h=j;while(0);if((a[22704]|0)==0?jy(22704)|0:0){c[6123]=1065353216;c[6124]=0;c[6125]=0;c[6126]=0;c[6127]=0;c[6128]=1065353216;c[6129]=0;c[6130]=0;c[6131]=0;c[6132]=0;c[6133]=1065353216;g[6134]=0.0}i=c[d+176>>2]|0;q=h+ +g[d+108>>2];n=+g[24492+(i<<4)>>2]*q;p=q*+g[24492+(i<<4)+4>>2];q=q*+g[24492+(i<<4)+8>>2];g[d+112>>2]=+g[d+112>>2]-n;g[d+116>>2]=+g[d+116>>2]-p;g[d+120>>2]=+g[d+120>>2]-q;i=c[d+8>>2]|0;if((a[22704]|0)==0?jy(22704)|0:0){c[6123]=1065353216;c[6124]=0;c[6125]=0;c[6126]=0;c[6127]=0;c[6128]=1065353216;c[6129]=0;c[6130]=0;c[6131]=0;c[6132]=0;c[6133]=1065353216;g[6134]=0.0}k=24492+(c[d+176>>2]<<4)|0;o=c[d+40>>2]|0;g[s+168+4>>2]=1.0;t=s+168+12|0;c[s+168+76>>2]=0;c[t>>2]=0;c[t+4>>2]=0;c[t+8>>2]=0;c[t+12>>2]=0;c[t+16>>2]=0;c[t+20>>2]=0;c[t+24>>2]=0;c[t+28>>2]=0;c[s+168>>2]=5064;c[s+168+80>>2]=i;c[s+168+84>>2]=c[k>>2];c[s+168+84+4>>2]=c[k+4>>2];c[s+168+84+8>>2]=c[k+8>>2];c[s+168+84+12>>2]=c[k+12>>2];c[s+168+100>>2]=o;i=c[d+8>>2]|0;o=c[i+188>>2]|0;b[s+168+8>>1]=b[o+4>>1]|0;b[s+168+10>>1]=b[o+6>>1]|0;if((a[22704]|0)==0?jy(22704)|0:0){c[6123]=1065353216;c[6124]=0;c[6125]=0;c[6126]=0;c[6127]=0;c[6128]=1065353216;c[6129]=0;c[6130]=0;c[6131]=0;c[6132]=0;c[6133]=1065353216;g[6134]=0.0}o=24492+(c[d+176>>2]<<4)|0;t=c[d+40>>2]|0;g[s+64+4>>2]=1.0;k=s+64+12|0;c[s+64+76>>2]=0;c[k>>2]=0;c[k+4>>2]=0;c[k+8>>2]=0;c[k+12>>2]=0;c[k+16>>2]=0;c[k+20>>2]=0;c[k+24>>2]=0;c[k+28>>2]=0;c[s+64>>2]=5064;c[s+64+80>>2]=i;c[s+64+84>>2]=c[o>>2];c[s+64+84+4>>2]=c[o+4>>2];c[s+64+84+8>>2]=c[o+8>>2];c[s+64+84+12>>2]=c[o+12>>2];c[s+64+100>>2]=t;i=c[(c[d+8>>2]|0)+188>>2]|0;b[s+64+8>>1]=b[i+4>>1]|0;b[s+64+10>>1]=b[i+6>>1]|0;h=+g[d+112>>2];j=+g[d+116>>2];m=+g[d+120>>2];i=0;while(1){c[s+456>>2]=1065353216;c[s+456+4>>2]=0;c[s+456+4+4>>2]=0;c[s+456+4+8>>2]=0;c[s+456+4+12>>2]=0;c[s+456+20>>2]=1065353216;c[s+456+24>>2]=0;c[s+456+24+4>>2]=0;c[s+456+24+8>>2]=0;c[s+456+24+12>>2]=0;c[s+456+40>>2]=1065353216;c[s+456+44>>2]=0;c[s+392>>2]=1065353216;c[s+392+4>>2]=0;c[s+392+4+4>>2]=0;c[s+392+4+8>>2]=0;c[s+392+4+12>>2]=0;c[s+392+20>>2]=1065353216;c[s+392+24>>2]=0;c[s+392+24+4>>2]=0;c[s+392+24+8>>2]=0;c[s+392+24+12>>2]=0;c[s+392+40>>2]=1065353216;c[s+392+44>>2]=0;c[s+288>>2]=1065353216;c[s+288+4>>2]=0;c[s+288+4+4>>2]=0;c[s+288+4+8>>2]=0;c[s+288+4+12>>2]=0;c[s+288+20>>2]=1065353216;c[s+288+24>>2]=0;c[s+288+24+4>>2]=0;c[s+288+24+8>>2]=0;c[s+288+24+12>>2]=0;c[s+288+40>>2]=1065353216;c[s+288+44>>2]=0;c[s+456+48>>2]=c[d+92>>2];c[s+456+48+4>>2]=c[d+92+4>>2];c[s+456+48+8>>2]=c[d+92+8>>2];c[s+456+48+12>>2]=c[d+92+12>>2];c[s+392+48>>2]=c[d+112>>2];c[s+392+48+4>>2]=c[d+112+4>>2];c[s+392+48+8>>2]=c[d+112+8>>2];c[s+392+48+12>>2]=c[d+112+12>>2];g[s+288+48>>2]=h-n;g[s+288+52>>2]=j-p;g[s+288+56>>2]=m-q;g[s+288+60>>2]=0.0;if(!(a[d+170>>0]|0)){ud(e,c[d+12>>2]|0,s+456|0,s+392|0,s+168|0,+g[e+56>>2]);if(!(+g[s+168+4>>2]<1.0))ud(e,c[d+12>>2]|0,s+456|0,s+288|0,s+64|0,+g[e+56>>2])}else{cd(c[d+8>>2]|0,c[d+12>>2]|0,s+456|0,s+392|0,s+168|0,+g[e+56>>2]);if(!(+g[s+168+4>>2]<1.0))cd(c[d+8>>2]|0,c[d+12>>2]|0,s+456|0,s+288|0,s+64|0,+g[e+56>>2])}m=+g[d+16>>2];m=(m<0.0?-m:0.0)*f;o=a[d+182>>0]|0;h=+g[s+168+4>>2];if(o<<24>>24!=0&h<1.0)k=1;else k=+g[s+64+4>>2]<1.0;if(!(m>0.0))break;j=+g[d+52>>2];if(i|(!(m<j)|k^1))break;if((a[d+168>>0]|0)==0?a[d+169>>0]|0:0){i=0;break}c[d+112>>2]=c[s+272>>2];c[d+112+4>>2]=c[s+272+4>>2];c[d+112+8>>2]=c[s+272+8>>2];c[d+112+12>>2]=c[s+272+12>>2];do if(!(a[22704]|0)){if(!(jy(22704)|0))break;c[6123]=1065353216;c[6124]=0;c[6125]=0;c[6126]=0;c[6127]=0;c[6128]=1065353216;c[6129]=0;c[6130]=0;c[6131]=0;c[6132]=0;c[6133]=1065353216;g[6134]=0.0}while(0);i=c[d+176>>2]|0;h=j+ +g[d+108>>2];j=h*+g[24492+(i<<4)+4>>2];m=h*+g[24492+(i<<4)+8>>2];h=+g[d+112>>2]-+g[24492+(i<<4)>>2]*h;g[d+112>>2]=h;j=+g[d+116>>2]-j;g[d+116>>2]=j;m=+g[d+120>>2]-m;g[d+120>>2]=m;i=1}if(i|h<1.0){j=+g[d+96>>2];if(!(o<<24>>24))i=d+181|0;else{h=(a[d+181>>0]|0)==0?(j-+g[s+168+64>>2])*.5:h;i=d+181|0}r=1.0-h;g[d+92>>2]=r*+g[d+92>>2]+h*+g[d+112>>2];g[d+96>>2]=r*j+h*+g[d+116>>2];g[d+100>>2]=r*+g[d+100>>2]+h*+g[d+120>>2];a[i>>0]=0;g[d+16>>2]=0.0;g[d+20>>2]=0.0;a[d+169>>0]=0}else{a[d+181>>0]=1;do if(o<<24>>24?(r=+g[d+24>>2],m>r):0){if((a[d+168>>0]|0)==0?a[d+169>>0]|0:0)break;g[d+112>>2]=n+ +g[d+112>>2];g[d+116>>2]=p+ +g[d+116>>2];g[d+120>>2]=q+ +g[d+120>>2];do if(!(a[22704]|0)){if(!(jy(22704)|0))break;c[6123]=1065353216;c[6124]=0;c[6125]=0;c[6126]=0;c[6127]=0;c[6128]=1065353216;c[6129]=0;c[6130]=0;c[6131]=0;c[6132]=0;c[6133]=1065353216;g[6134]=0.0}while(0);t=c[d+176>>2]|0;q=r+ +g[d+108>>2];f=q*+g[24492+(t<<4)+4>>2];r=q*+g[24492+(t<<4)+8>>2];g[d+112>>2]=+g[d+112>>2]-+g[24492+(t<<4)>>2]*q;g[d+116>>2]=+g[d+116>>2]-f;g[d+120>>2]=+g[d+120>>2]-r}while(0);c[d+92>>2]=c[d+112>>2];c[d+92+4>>2]=c[d+112+4>>2];c[d+92+8>>2]=c[d+112+8>>2];c[d+92+12>>2]=c[d+112+12>>2]}c[s+48>>2]=c[d+92>>2];c[s+48+4>>2]=c[d+92+4>>2];c[s+48+8>>2]=c[d+92+8>>2];c[s+48+12>>2]=c[d+92+12>>2];t=c[d+8>>2]|0;c[t+260>>2]=(c[t+260>>2]|0)+1;c[t+4>>2]=c[s>>2];c[t+4+4>>2]=c[s+4>>2];c[t+4+8>>2]=c[s+8>>2];c[t+4+12>>2]=c[s+12>>2];c[t+20>>2]=c[s+16>>2];c[t+20+4>>2]=c[s+16+4>>2];c[t+20+8>>2]=c[s+16+8>>2];c[t+20+12>>2]=c[s+16+12>>2];c[t+36>>2]=c[s+32>>2];c[t+36+4>>2]=c[s+32+4>>2];c[t+36+8>>2]=c[s+32+8>>2];c[t+36+12>>2]=c[s+32+12>>2];c[t+52>>2]=c[s+48>>2];c[t+52+4>>2]=c[s+48+4>>2];c[t+52+8>>2]=c[s+48+8>>2];c[t+52+12>>2]=c[s+48+12>>2];l=s;return}function qc(d,f,h){d=d|0;f=f|0;h=h|0;var i=0,j=0,k=0.0,m=0.0,n=0.0,o=0,p=0.0,q=0,r=0,s=0,t=0.0,u=0.0,v=0,w=0,x=0.0,y=0.0,z=0.0,A=0,B=0,C=0.0,D=0.0,E=0.0,F=0,G=0,H=0,I=0,J=0,K=0,L=0.0,M=0.0,N=0.0;K=l;l=l+96|0;H=c[d+56>>2]|0;if((h-f|0)==1){if(!(a[d+60>>0]|0)){q=(c[d+96>>2]|0)+(H<<6)|0;r=(c[d+76>>2]|0)+(f<<6)|0;s=q+64|0;do{c[q>>2]=c[r>>2];q=q+4|0;r=r+4|0}while((q|0)<(s|0))}else{I=(c[d+116>>2]|0)+(f<<4)|0;J=(c[d+136>>2]|0)+(H<<4)|0;c[J>>2]=c[I>>2];c[J+4>>2]=c[I+4>>2];c[J+8>>2]=c[I+8>>2];c[J+12>>2]=c[I+12>>2]}c[d+56>>2]=(c[d+56>>2]|0)+1;l=K;return}c[K+32>>2]=0;c[K+32+4>>2]=0;c[K+32+8>>2]=0;c[K+32+12>>2]=0;if((h|0)>(f|0)){o=(a[d+60>>0]|0)==0;if(o){i=c[d+76>>2]|0;m=0.0;k=0.0;n=0.0;j=f;do{k=k+(+g[i+(j<<6)+16>>2]+ +g[i+(j<<6)>>2])*.5;n=n+(+g[i+(j<<6)+20>>2]+ +g[i+(j<<6)+4>>2])*.5;m=m+(+g[i+(j<<6)+24>>2]+ +g[i+(j<<6)+8>>2])*.5;j=j+1|0}while((j|0)!=(h|0))}else{i=c[d+116>>2]|0;p=+g[d+36>>2];t=+g[d+40>>2];u=+g[d+44>>2];x=+g[d+4>>2];y=+g[d+8>>2];z=+g[d+12>>2];k=0.0;n=0.0;m=0.0;j=f;do{k=k+(+(e[i+(j<<4)+6>>1]|0)/p+x+(+(e[i+(j<<4)>>1]|0)/p+x))*.5;n=n+(+(e[i+(j<<4)+8>>1]|0)/t+y+(+(e[i+(j<<4)+2>>1]|0)/t+y))*.5;m=m+(+(e[i+(j<<4)+10>>1]|0)/u+z+(+(e[i+(j<<4)+4>>1]|0)/u+z))*.5;j=j+1|0}while((j|0)!=(h|0))}C=1.0/+(h-f|0);E=C*k;D=C*n;C=C*m;if(o){i=c[d+76>>2]|0;k=0.0;m=0.0;p=0.0;j=f;do{x=(+g[i+(j<<6)+16>>2]+ +g[i+(j<<6)>>2])*.5-E;y=(+g[i+(j<<6)+20>>2]+ +g[i+(j<<6)+4>>2])*.5-D;z=(+g[i+(j<<6)+24>>2]+ +g[i+(j<<6)+8>>2])*.5-C;p=p+x*x;k=y*y+k;m=z*z+m;j=j+1|0}while((j|0)!=(h|0))}else{i=c[d+116>>2]|0;n=+g[d+36>>2];t=+g[d+40>>2];u=+g[d+44>>2];x=+g[d+4>>2];y=+g[d+8>>2];z=+g[d+12>>2];k=0.0;m=0.0;p=0.0;j=f;do{N=(+(e[i+(j<<4)+6>>1]|0)/n+x+(+(e[i+(j<<4)>>1]|0)/n+x))*.5-E;M=(+(e[i+(j<<4)+8>>1]|0)/t+y+(+(e[i+(j<<4)+2>>1]|0)/t+y))*.5-D;L=(+(e[i+(j<<4)+10>>1]|0)/u+z+(+(e[i+(j<<4)+4>>1]|0)/u+z))*.5-C;p=p+N*N;k=M*M+k;m=L*L+m;j=j+1|0}while((j|0)!=(h|0))}g[K+32>>2]=p;g[K+32+4>>2]=k;g[K+32+8>>2]=m;i=K+32|0;n=+(h-f|0)}else{p=0.0;k=0.0;m=0.0;i=K+32|0;n=+(h-f|0)}L=1.0/(n+-1.0);M=L*p;g[i>>2]=M;N=L*k;g[K+32+4>>2]=N;L=L*m;g[K+32+8>>2]=L;w=+g[K+32+((M<N&1)<<2)>>2]<L?2:M<N&1;c[K+16>>2]=0;c[K+16+4>>2]=0;c[K+16+8>>2]=0;c[K+16+12>>2]=0;if((h|0)>(f|0)){if(!(a[d+60>>0]|0)){i=c[d+76>>2]|0;m=0.0;k=0.0;n=0.0;j=f;do{n=(+g[i+(j<<6)+16>>2]+ +g[i+(j<<6)>>2])*.5+n;m=(+g[i+(j<<6)+20>>2]+ +g[i+(j<<6)+4>>2])*.5+m;k=(+g[i+(j<<6)+24>>2]+ +g[i+(j<<6)+8>>2])*.5+k;j=j+1|0}while((j|0)!=(h|0))}else{i=c[d+116>>2]|0;p=+g[d+36>>2];t=+g[d+40>>2];u=+g[d+44>>2];x=+g[d+4>>2];y=+g[d+8>>2];z=+g[d+12>>2];m=0.0;k=0.0;n=0.0;j=f;do{n=(+(e[i+(j<<4)+6>>1]|0)/p+x+(+(e[i+(j<<4)>>1]|0)/p+x))*.5+n;m=(+(e[i+(j<<4)+8>>1]|0)/t+y+(+(e[i+(j<<4)+2>>1]|0)/t+y))*.5+m;k=(+(e[i+(j<<4)+10>>1]|0)/u+z+(+(e[i+(j<<4)+4>>1]|0)/u+z))*.5+k;j=j+1|0}while((j|0)!=(h|0))}g[K+16>>2]=n;g[K+16+4>>2]=m;g[K+16+8>>2]=k;i=K+16|0}else{n=0.0;m=0.0;k=0.0;i=K+16|0}g[i>>2]=1.0/+(h-f|0)*n;g[K+16+4>>2]=1.0/+(h-f|0)*m;g[K+16+8>>2]=1.0/+(h-f|0)*k;x=+g[K+16+(w<<2)>>2];if((h|0)>(f|0)){v=f;i=f;do{j=(a[d+60>>0]|0)==0;if(j){G=c[d+76>>2]|0;k=+g[G+(v<<6)+16>>2];m=+g[G+(v<<6)+20>>2];n=+g[G+(v<<6)+24>>2];p=+g[G+(v<<6)>>2];t=+g[G+(v<<6)+4>>2];u=+g[G+(v<<6)+8>>2]}else{G=c[d+116>>2]|0;L=+g[d+36>>2];M=+g[d+40>>2];N=+g[d+44>>2];p=+g[d+4>>2];t=+g[d+8>>2];u=+g[d+12>>2];k=+(e[G+(v<<4)+6>>1]|0)/L+p;m=+(e[G+(v<<4)+8>>1]|0)/M+t;n=+(e[G+(v<<4)+10>>1]|0)/N+u;p=+(e[G+(v<<4)>>1]|0)/L+p;t=+(e[G+(v<<4)+2>>1]|0)/M+t;u=+(e[G+(v<<4)+4>>1]|0)/N+u}g[K>>2]=(k+p)*.5;g[K+4>>2]=(m+t)*.5;g[K+8>>2]=(n+u)*.5;g[K+12>>2]=0.0;if(+g[K+(w<<2)>>2]>x){if(j){j=c[d+76>>2]|0;o=j+(v<<6)|0;q=K+32|0;r=o;s=q+64|0;do{c[q>>2]=c[r>>2];q=q+4|0;r=r+4|0}while((q|0)<(s|0));q=o;r=j+(i<<6)|0;s=q+64|0;do{c[q>>2]=c[r>>2];q=q+4|0;r=r+4|0}while((q|0)<(s|0));q=(c[d+76>>2]|0)+(i<<6)|0;r=K+32|0;s=q+64|0;do{c[q>>2]=c[r>>2];q=q+4|0;r=r+4|0}while((q|0)<(s|0))}else{F=c[d+116>>2]|0;G=F+(v<<4)|0;c[K+32>>2]=c[G>>2];c[K+32+4>>2]=c[G+4>>2];c[K+32+8>>2]=c[G+8>>2];c[K+32+12>>2]=c[G+12>>2];F=F+(i<<4)|0;c[G>>2]=c[F>>2];c[G+4>>2]=c[F+4>>2];c[G+8>>2]=c[F+8>>2];c[G+12>>2]=c[F+12>>2];G=(c[d+116>>2]|0)+(i<<4)|0;c[G>>2]=c[K+32>>2];c[G+4>>2]=c[K+32+4>>2];c[G+8>>2]=c[K+32+8>>2];c[G+12>>2]=c[K+32+12>>2]}i=i+1|0}v=v+1|0}while((v|0)!=(h|0))}else i=f;if(!((i|0)>(((h-f|0)/3|0)+f|0)?(i|0)<(h+-1-((h-f|0)/3|0)|0):0))i=(h-f>>1)+f|0;G=c[d+56>>2]|0;if(!(a[d+60>>0]|0)){F=(c[d+96>>2]|0)+(G<<6)|0;c[F>>2]=c[d+20>>2];c[F+4>>2]=c[d+20+4>>2];c[F+8>>2]=c[d+20+8>>2];c[F+12>>2]=c[d+20+12>>2]}else{F=c[d+136>>2]|0;M=(+g[d+24>>2]-+g[d+8>>2])*+g[d+40>>2];N=(+g[d+28>>2]-+g[d+12>>2])*+g[d+44>>2];b[F+(G<<4)>>1]=~~((+g[d+20>>2]-+g[d+4>>2])*+g[d+36>>2])&65535&-2;b[F+(G<<4)+2>>1]=~~M&65535&-2;b[F+(G<<4)+4>>1]=~~N&65535&-2}j=c[d+56>>2]|0;if(!(a[d+60>>0]|0)){F=(c[d+96>>2]|0)+(j<<6)+16|0;c[F>>2]=c[d+4>>2];c[F+4>>2]=c[d+4+4>>2];c[F+8>>2]=c[d+4+8>>2];c[F+12>>2]=c[d+4+12>>2]}else{F=c[d+136>>2]|0;L=+g[d+4>>2];M=+g[d+8>>2];N=+g[d+12>>2];M=(M-M)*+g[d+40>>2];N=(N-N)*+g[d+44>>2];b[F+(j<<4)+6>>1]=~~((L-L)*+g[d+36>>2]+1.0)&65535|1;b[F+(j<<4)+8>>1]=~~(M+1.0)&65535|1;b[F+(j<<4)+10>>1]=~~(N+1.0)&65535|1}F=c[d+56>>2]|0;if((h|0)>(f|0)){A=a[d+60>>0]|0;B=f;do{if(!(A<<24>>24)){j=c[d+76>>2]|0;k=+g[j+(B<<6)>>2];n=+g[j+(B<<6)+4>>2];p=+g[j+(B<<6)+8>>2];m=+g[j+(B<<6)+12>>2];t=+g[j+(B<<6)+16>>2];y=+g[j+(B<<6)+20>>2];u=+g[j+(B<<6)+24>>2];x=+g[j+(B<<6)+28>>2];j=c[d+96>>2]|0;if(k<+g[j+(F<<6)>>2])g[j+(F<<6)>>2]=k;if(n<+g[j+(F<<6)+4>>2])g[j+(F<<6)+4>>2]=n;if(p<+g[j+(F<<6)+8>>2])g[j+(F<<6)+8>>2]=p;if(m<+g[j+(F<<6)+12>>2])g[j+(F<<6)+12>>2]=m;if(+g[j+(F<<6)+16>>2]<t)g[j+(F<<6)+16>>2]=t;if(+g[j+(F<<6)+20>>2]<y)g[j+(F<<6)+20>>2]=y;if(+g[j+(F<<6)+24>>2]<u)g[j+(F<<6)+24>>2]=u;if(+g[j+(F<<6)+28>>2]<x)g[j+(F<<6)+28>>2]=x}else{v=c[d+116>>2]|0;p=+g[d+36>>2];y=+g[d+40>>2];E=+g[d+44>>2];t=+g[d+4>>2];z=+g[d+8>>2];L=+g[d+12>>2];u=+g[d+4>>2];C=+g[d+8>>2];M=+g[d+12>>2];x=+g[d+36>>2];D=+g[d+40>>2];N=+g[d+44>>2];j=~~((+(e[v+(B<<4)>>1]|0)/p+t-u)*x)&65535&-2;o=~~((+(e[v+(B<<4)+2>>1]|0)/y+z-C)*D)&65535&-2;q=~~((+(e[v+(B<<4)+4>>1]|0)/E+L-M)*N)&65535&-2;r=~~((+(e[v+(B<<4)+6>>1]|0)/p+t-u)*x+1.0)&65535|1;s=~~((+(e[v+(B<<4)+8>>1]|0)/y+z-C)*D+1.0)&65535|1;v=~~((+(e[v+(B<<4)+10>>1]|0)/E+L-M)*N+1.0)&65535|1;w=c[d+136>>2]|0;if((e[w+(F<<4)>>1]|0)>(j&65535))b[w+(F<<4)>>1]=j;if((e[w+(F<<4)+6>>1]|0)<(r&65535))b[w+(F<<4)+6>>1]=r;if((e[w+(F<<4)+2>>1]|0)>(o&65535))b[w+(F<<4)+2>>1]=o;if((e[w+(F<<4)+8>>1]|0)<(s&65535))b[w+(F<<4)+8>>1]=s;if((e[w+(F<<4)+4>>1]|0)>(q&65535))b[w+(F<<4)+4>>1]=q;if((e[w+(F<<4)+10>>1]|0)<(v&65535))b[w+(F<<4)+10>>1]=v}B=B+1|0}while((B|0)!=(h|0))}c[d+56>>2]=F+1;qc(d,f,i);A=c[d+56>>2]|0;qc(d,i,h);w=(c[d+56>>2]|0)-H|0;i=a[d+60>>0]|0;if(i<<24>>24!=0&(w<<4|0)>2048){s=c[d+136>>2]|0;q=c[s+(F+1<<4)+12>>2]|0;q=(q|0)>-1?1:0-q|0;v=c[s+(A<<4)+12>>2]|0;v=(v|0)>-1?1:0-v|0;if((q<<4|0)<2049){r=c[d+152>>2]|0;if((r|0)==(c[d+156>>2]|0)?(I=r|0?r<<1:1,(r|0)<(I|0)):0){if(!I){j=r;o=0}else{c[6432]=(c[6432]|0)+1;i=ec(I<<5|19)|0;if(!i)i=0;else{c[(i+4+15&-16)+-4>>2]=i;i=i+4+15&-16}j=c[d+152>>2]|0;o=i}if((j|0)>0){i=0;do{h=o+(i<<5)|0;H=(c[d+160>>2]|0)+(i<<5)|0;c[h>>2]=c[H>>2];c[h+4>>2]=c[H+4>>2];c[h+8>>2]=c[H+8>>2];c[h+12>>2]=c[H+12>>2];c[h+16>>2]=c[H+16>>2];c[h+20>>2]=c[H+20>>2];c[h+24>>2]=c[H+24>>2];c[h+28>>2]=c[H+28>>2];i=i+1|0}while((i|0)!=(j|0))}i=c[d+160>>2]|0;if(i|0){if(a[d+164>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[d+160>>2]=0}a[d+164>>0]=1;c[d+160>>2]=o;c[d+156>>2]=I;i=c[d+152>>2]|0}else i=r;c[d+152>>2]=i+1;I=(c[d+160>>2]|0)+(r<<5)|0;c[I>>2]=c[K+32>>2];c[I+4>>2]=c[K+32+4>>2];c[I+8>>2]=c[K+32+8>>2];c[I+12>>2]=c[K+32+12>>2];c[I+16>>2]=c[K+32+16>>2];c[I+20>>2]=c[K+32+20>>2];c[I+24>>2]=c[K+32+24>>2];c[I+28>>2]=c[K+32+28>>2];I=c[d+160>>2]|0;b[I+(r<<5)>>1]=b[s+(F+1<<4)>>1]|0;b[I+(r<<5)+2>>1]=b[s+(F+1<<4)+2>>1]|0;b[I+(r<<5)+4>>1]=b[s+(F+1<<4)+4>>1]|0;b[I+(r<<5)+6>>1]=b[s+(F+1<<4)+6>>1]|0;b[I+(r<<5)+8>>1]=b[s+(F+1<<4)+8>>1]|0;b[I+(r<<5)+10>>1]=b[s+(F+1<<4)+10>>1]|0;c[I+(r<<5)+12>>2]=F+1;c[I+(r<<5)+16>>2]=q}if((v<<4|0)<2049){q=c[d+152>>2]|0;if((q|0)==(c[d+156>>2]|0)?(J=q|0?q<<1:1,(q|0)<(J|0)):0){if(!J){j=q;o=0}else{c[6432]=(c[6432]|0)+1;i=ec(J<<5|19)|0;if(!i)i=0;else{c[(i+4+15&-16)+-4>>2]=i;i=i+4+15&-16}j=c[d+152>>2]|0;o=i}if((j|0)>0){i=0;do{I=o+(i<<5)|0;h=(c[d+160>>2]|0)+(i<<5)|0;c[I>>2]=c[h>>2];c[I+4>>2]=c[h+4>>2];c[I+8>>2]=c[h+8>>2];c[I+12>>2]=c[h+12>>2];c[I+16>>2]=c[h+16>>2];c[I+20>>2]=c[h+20>>2];c[I+24>>2]=c[h+24>>2];c[I+28>>2]=c[h+28>>2];i=i+1|0}while((i|0)!=(j|0))}i=c[d+160>>2]|0;if(i|0){if(a[d+164>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[d+160>>2]=0}a[d+164>>0]=1;c[d+160>>2]=o;c[d+156>>2]=J;i=c[d+152>>2]|0}else i=q;c[d+152>>2]=i+1;i=(c[d+160>>2]|0)+(q<<5)|0;c[i>>2]=c[K+32>>2];c[i+4>>2]=c[K+32+4>>2];c[i+8>>2]=c[K+32+8>>2];c[i+12>>2]=c[K+32+12>>2];c[i+16>>2]=c[K+32+16>>2];c[i+20>>2]=c[K+32+20>>2];c[i+24>>2]=c[K+32+24>>2];c[i+28>>2]=c[K+32+28>>2];i=c[d+160>>2]|0;b[i+(q<<5)>>1]=b[s+(A<<4)>>1]|0;b[i+(q<<5)+2>>1]=b[s+(A<<4)+2>>1]|0;b[i+(q<<5)+4>>1]=b[s+(A<<4)+4>>1]|0;b[i+(q<<5)+6>>1]=b[s+(A<<4)+6>>1]|0;b[i+(q<<5)+8>>1]=b[s+(A<<4)+8>>1]|0;b[i+(q<<5)+10>>1]=b[s+(A<<4)+10>>1]|0;c[i+(q<<5)+12>>2]=A;c[i+(q<<5)+16>>2]=v;i=d+152|0}else i=d+152|0;c[d+168>>2]=c[i>>2];i=a[d+60>>0]|0}if(!(i<<24>>24)){c[(c[d+96>>2]|0)+(G<<6)+32>>2]=w;l=K;return}else{c[(c[d+136>>2]|0)+(G<<4)+12>>2]=0-w;l=K;return}}function rc(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0,j=0,k=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0.0,O=0.0,P=0.0,Q=0.0,R=0.0,S=0.0,T=0.0,U=0.0,V=0.0,W=0.0,X=0.0,Y=0.0,Z=0.0,_=0.0,$=0.0,aa=0.0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0.0,ia=0.0,ja=0.0,ka=0.0,la=0.0,ma=0.0,na=0.0,oa=0.0,pa=0.0,qa=0.0,ra=0.0;ga=l;l=l+176|0;da=c[d+4>>2]|0;ea=c[e+4>>2]|0;if((c[da+68>>2]|0)==(c[b+40>>2]|0)?(c[ea+68>>2]|0)==(c[b+44>>2]|0):0)ca=b+8|0;else{i=c[b+8>>2]|0;j=c[i+8>>2]|0;if((j|0)>0){m=0;do{k=c[(c[i+16>>2]|0)+(m*12|0)+8>>2]|0;if(k|0){hb[c[c[k>>2]>>2]&511](k);ca=c[b+4>>2]|0;jb[c[(c[ca>>2]|0)+60>>2]&127](ca,k)}m=m+1|0}while((m|0)!=(j|0));i=c[b+8>>2]|0}zh(i);ca=b+8|0}a[ga+128+16>>0]=1;q=ga+128+12|0;c[q>>2]=0;c[ga+128+4>>2]=0;c[ga+128+8>>2]=0;p=c[ca>>2]|0;i=c[p+8>>2]|0;if((i|0)>0){o=0;do{j=c[(c[p+16>>2]|0)+(o*12|0)+8>>2]|0;if(j){jb[c[(c[j>>2]|0)+16>>2]&127](j,ga+128|0);i=c[ga+128+4>>2]|0;if((i|0)>0){n=0;do{m=c[(c[q>>2]|0)+(n<<2)>>2]|0;if(c[m+748>>2]|0){c[h+4>>2]=m;i=c[m+740>>2]|0;j=c[(c[h+8>>2]|0)+8>>2]|0;k=c[(c[h+12>>2]|0)+8>>2]|0;if((i|0)==(j|0))Le(m,i+4|0,k+4|0);else Le(m,k+4|0,j+4|0);c[h+4>>2]=0;i=c[ga+128+4>>2]|0}n=n+1|0}while((n|0)<(i|0))}if((i|0)<0){if((c[ga+128+8>>2]|0)<0){j=c[q>>2]|0;if(j|0){if(a[ga+128+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0)}c[q>>2]=0}a[ga+128+16>>0]=1;c[q>>2]=0;c[ga+128+8>>2]=0}do{c[(c[q>>2]|0)+(i<<2)>>2]=0;i=i+1|0}while((i|0)!=0)}c[ga+128+4>>2]=0;i=c[p+8>>2]|0}o=o+1|0}while((o|0)<(i|0));i=c[q>>2]|0;if(i|0){if(a[ga+128+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[q>>2]=0}}j=c[da+64>>2]|0;k=c[ea+64>>2]|0;s=c[b+4>>2]|0;t=c[ca>>2]|0;u=c[b+32>>2]|0;c[ga+128>>2]=6380;c[ga+128+4>>2]=0;c[ga+128+8>>2]=d;c[ga+128+12>>2]=e;c[ga+128+16>>2]=s;c[ga+128+20>>2]=f;c[ga+128+24>>2]=h;c[ga+128+28>>2]=t;c[ga+128+32>>2]=u;u=c[d+12>>2]|0;F=+g[u>>2];G=+g[u+16>>2];H=+g[u+32>>2];I=+g[u+4>>2];J=+g[u+20>>2];K=+g[u+36>>2];L=+g[u+8>>2];M=+g[u+24>>2];N=+g[u+40>>2];_=-+g[u+48>>2];$=-+g[u+52>>2];aa=-+g[u+56>>2];u=c[e+12>>2]|0;O=+g[u>>2];P=+g[u+16>>2];Q=+g[u+32>>2];R=+g[u+4>>2];S=+g[u+20>>2];T=+g[u+36>>2];U=+g[u+8>>2];V=+g[u+24>>2];W=+g[u+40>>2];X=+g[u+48>>2];Y=+g[u+52>>2];Z=+g[u+56>>2];j=c[j>>2]|0;k=c[k>>2]|0;if((j|0)!=0&(k|0)!=0){c[6432]=(c[6432]|0)+1;i=ec(1043)|0;if(!i)i=0;else{c[(i+4+15&-16)+-4>>2]=i;i=i+4+15&-16}c[i>>2]=j;c[i+4>>2]=k;w=+B(+(F*O+G*P+H*Q));C=+B(+(F*R+G*S+H*T));E=+B(+(F*U+G*V+H*W));y=+B(+(I*O+J*P+K*Q));z=+B(+(I*R+J*S+K*T));x=+B(+(I*U+J*V+K*W));D=+B(+(L*O+M*P+N*Q));A=+B(+(L*R+M*S+N*T));v=+B(+(L*U+M*V+N*W));n=i;p=i;o=i;u=1;j=128;r=i;m=128;i=124;while(1){q=u+-1|0;s=c[r+(q<<3)>>2]|0;t=c[r+(q<<3)+4>>2]|0;ra=+g[t+16>>2];qa=+g[t>>2];pa=+g[t+20>>2];oa=+g[t+4>>2];na=+g[t+24>>2];ha=+g[t+8>>2];ma=F*_+G*$+H*aa+(F*X+G*Y+H*Z)+((F*O+G*P+H*Q)*(ra+qa)*.5+(F*R+G*S+H*T)*(pa+oa)*.5+(F*U+G*V+H*W)*(na+ha)*.5);ka=I*_+J*$+K*aa+(I*X+J*Y+K*Z)+((I*O+J*P+K*Q)*(ra+qa)*.5+(I*R+J*S+K*T)*(pa+oa)*.5+(I*U+J*V+K*W)*(na+ha)*.5);ia=L*_+M*$+N*aa+(L*X+M*Y+N*Z)+((L*O+M*P+N*Q)*(ra+qa)*.5+(L*R+M*S+N*T)*(pa+oa)*.5+(L*U+M*V+N*W)*(na+ha)*.5);la=((ra-qa)*.5+0.0)*w+((pa-oa)*.5+0.0)*C+((na-ha)*.5+0.0)*E;ja=((ra-qa)*.5+0.0)*y+((pa-oa)*.5+0.0)*z+((na-ha)*.5+0.0)*x;ha=((ra-qa)*.5+0.0)*D+((pa-oa)*.5+0.0)*A+((na-ha)*.5+0.0)*v;do if(((((+g[s>>2]<=la+ma?+g[s+16>>2]>=ma-la:0)?+g[s+4>>2]<=ka+ja:0)?+g[s+20>>2]>=ka-ja:0)?+g[s+8>>2]<=ia+ha:0)?+g[s+24>>2]>=ia-ha:0){if((q|0)>(i|0)){f=m<<1;do if((m|0)<(f|0)&(j|0)<(f|0)){do if(!m){k=0;i=0;ba=52}else{c[6432]=(c[6432]|0)+1;i=ec((m<<4|3)+16|0)|0;if(!i)j=0;else{c[(i+4+15&-16)+-4>>2]=i;j=i+4+15&-16}if((m|0)>0)i=0;else{k=j;i=j;ba=52;break}do{o=r+(i<<3)|0;p=c[o+4>>2]|0;h=j+(i<<3)|0;c[h>>2]=c[o>>2];c[h+4>>2]=p;i=i+1|0}while((i|0)!=(m|0));k=j;i=j}while(0);if((ba|0)==52){ba=0;if(!r){m=i;o=i;j=f;break}}if(!n){m=i;o=i;j=f}else{c[6433]=(c[6433]|0)+1;Pc(c[n+-4>>2]|0);m=i;o=i;j=f}}else{m=p;i=n;k=r}while(0);p=m;n=i;h=j;m=f;f=f+-4|0}else{h=j;k=r;f=i}j=(c[t+40>>2]|0)!=0;if(!(c[s+40>>2]|0))if(j){j=c[t+36>>2]|0;c[k+(q<<3)>>2]=s;c[k+(q<<3)+4>>2]=j;q=c[t+40>>2]|0;c[k+(u<<3)>>2]=s;c[k+(u<<3)+4>>2]=q;q=u+1|0;j=h;i=f;break}else{Rb[c[(c[ga+128>>2]|0)+8>>2]&127](ga+128|0,s,t);j=h;i=f;break}else{i=c[s+36>>2]|0;if(j){j=c[t+36>>2]|0;c[k+(q<<3)>>2]=i;c[k+(q<<3)+4>>2]=j;i=c[t+36>>2]|0;j=u+1|0;c[k+(u<<3)>>2]=c[s+40>>2];c[k+(u<<3)+4>>2]=i;i=c[t+40>>2]|0;q=u+2|0;c[k+(j<<3)>>2]=c[s+36>>2];c[k+(j<<3)+4>>2]=i;j=c[t+40>>2]|0;c[k+(q<<3)>>2]=c[s+40>>2];c[k+(q<<3)+4>>2]=j;q=u+3|0;j=h;i=f;break}else{c[k+(q<<3)>>2]=i;c[k+(q<<3)+4>>2]=t;c[k+(u<<3)>>2]=c[s+40>>2];c[k+(u<<3)+4>>2]=t;q=u+1|0;j=h;i=f;break}}}else k=r;while(0);if(!q)break;else{u=q;r=k}}if(!((k|0)==0|(p|0)==0)){c[6433]=(c[6433]|0)+1;Pc(c[p+-4>>2]|0)}}o=c[ca>>2]|0;if((c[o+8>>2]|0)>0){p=0;do{i=c[o+16>>2]|0;j=c[i+(p*12|0)+8>>2]|0;do if(j|0){ba=c[i+(p*12|0)>>2]|0;u=c[da+24>>2]|0;t=c[u+(ba*80|0)+64>>2]|0;s=c[d+12>>2]|0;ra=+g[s>>2];S=+g[s+4>>2];R=+g[s+8>>2];oa=+g[s+16>>2];ma=+g[s+20>>2];ka=+g[s+24>>2];na=+g[s+32>>2];ja=+g[s+36>>2];X=+g[s+40>>2];ia=+g[u+(ba*80|0)>>2];ha=+g[u+(ba*80|0)+16>>2];aa=+g[u+(ba*80|0)+32>>2];$=+g[u+(ba*80|0)+4>>2];_=+g[u+(ba*80|0)+20>>2];Z=+g[u+(ba*80|0)+36>>2];la=+g[u+(ba*80|0)+8>>2];Y=+g[u+(ba*80|0)+24>>2];W=+g[u+(ba*80|0)+40>>2];qa=+g[u+(ba*80|0)+48>>2];pa=+g[u+(ba*80|0)+52>>2];T=+g[u+(ba*80|0)+56>>2];V=+g[s+48>>2]+(ra*qa+S*pa+R*T);U=+g[s+52>>2]+(oa*qa+ma*pa+ka*T);T=+g[s+56>>2]+(na*qa+ja*pa+X*T);g[ga>>2]=ra*ia+S*ha+R*aa;g[ga+4>>2]=ra*$+S*_+R*Z;g[ga+8>>2]=ra*la+S*Y+R*W;g[ga+12>>2]=0.0;g[ga+16>>2]=oa*ia+ma*ha+ka*aa;g[ga+20>>2]=oa*$+ma*_+ka*Z;g[ga+24>>2]=oa*la+ma*Y+ka*W;g[ga+28>>2]=0.0;g[ga+32>>2]=na*ia+ja*ha+X*aa;g[ga+36>>2]=na*$+ja*_+X*Z;g[ga+40>>2]=na*la+ja*Y+X*W;g[ga+44>>2]=0.0;g[ga+48>>2]=V;g[ga+52>>2]=U;g[ga+56>>2]=T;g[ga+60>>2]=0.0;Vb[c[(c[t>>2]|0)+8>>2]&127](t,ga,ga+112|0,ga+96|0);t=c[(c[o+16>>2]|0)+(p*12|0)+4>>2]|0;s=c[ea+24>>2]|0;ba=c[s+(t*80|0)+64>>2]|0;u=c[e+12>>2]|0;T=+g[u>>2];U=+g[u+4>>2];V=+g[u+8>>2];W=+g[u+16>>2];X=+g[u+20>>2];Y=+g[u+24>>2];ja=+g[u+32>>2];la=+g[u+36>>2];na=+g[u+40>>2];Z=+g[s+(t*80|0)>>2];_=+g[s+(t*80|0)+16>>2];$=+g[s+(t*80|0)+32>>2];aa=+g[s+(t*80|0)+4>>2];ha=+g[s+(t*80|0)+20>>2];ia=+g[s+(t*80|0)+36>>2];ka=+g[s+(t*80|0)+8>>2];ma=+g[s+(t*80|0)+24>>2];oa=+g[s+(t*80|0)+40>>2];R=+g[s+(t*80|0)+48>>2];S=+g[s+(t*80|0)+52>>2];ra=+g[s+(t*80|0)+56>>2];pa=+g[u+48>>2]+(T*R+U*S+V*ra);qa=+g[u+52>>2]+(W*R+X*S+Y*ra);ra=+g[u+56>>2]+(ja*R+la*S+na*ra);g[ga>>2]=T*Z+U*_+V*$;g[ga+4>>2]=T*aa+U*ha+V*ia;g[ga+8>>2]=T*ka+U*ma+V*oa;g[ga+12>>2]=0.0;g[ga+16>>2]=W*Z+X*_+Y*$;g[ga+20>>2]=W*aa+X*ha+Y*ia;g[ga+24>>2]=W*ka+X*ma+Y*oa;g[ga+28>>2]=0.0;g[ga+32>>2]=ja*Z+la*_+na*$;g[ga+36>>2]=ja*aa+la*ha+na*ia;g[ga+40>>2]=ja*ka+la*ma+na*oa;g[ga+44>>2]=0.0;g[ga+48>>2]=pa;g[ga+52>>2]=qa;g[ga+56>>2]=ra;g[ga+60>>2]=0.0;Vb[c[(c[ba>>2]|0)+8>>2]&127](ba,ga,ga+80|0,ga+64|0);if(!(+g[ga+112>>2]>+g[ga+64>>2])?!(+g[ga+96>>2]<+g[ga+80>>2]):0)i=1;else i=0;if(!(!(+g[ga+112+8>>2]>+g[ga+64+8>>2])?!(+g[ga+96+8>>2]<+g[ga+80+8>>2]):0))i=0;if(!(+g[ga+112+4>>2]>+g[ga+64+4>>2])?!(+g[ga+96+4>>2]<+g[ga+80+4>>2]|i^1):0)break;hb[c[c[j>>2]>>2]&511](j);n=c[b+4>>2]|0;jb[c[(c[n>>2]|0)+60>>2]&127](n,j);n=c[o+16>>2]|0;m=c[n+(p*12|0)>>2]|0;n=c[n+(p*12|0)+4>>2]|0;i=c[b+16>>2]|0;if((i|0)==(c[b+20>>2]|0)?(fa=i|0?i<<1:1,(i|0)<(fa|0)):0){if(!fa)j=0;else{c[6432]=(c[6432]|0)+1;i=ec((fa*12|3)+16|0)|0;if(!i)j=0;else{c[(i+4+15&-16)+-4>>2]=i;j=i+4+15&-16}i=c[b+16>>2]|0}if((i|0)>0){k=0;do{ba=j+(k*12|0)|0;u=(c[b+24>>2]|0)+(k*12|0)|0;c[ba>>2]=c[u>>2];c[ba+4>>2]=c[u+4>>2];c[ba+8>>2]=c[u+8>>2];k=k+1|0}while((k|0)!=(i|0))}i=c[b+24>>2]|0;if(i|0){if(a[b+28>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[b+24>>2]=0}a[b+28>>0]=1;c[b+24>>2]=j;c[b+20>>2]=fa;i=c[b+16>>2]|0}ba=c[b+24>>2]|0;c[ba+(i*12|0)>>2]=m;c[ba+(i*12|0)+4>>2]=n;c[ba+(i*12|0)+8>>2]=0;c[b+16>>2]=(c[b+16>>2]|0)+1}while(0);p=p+1|0}while((p|0)<(c[o+8>>2]|0));j=b+24|0;k=b+16|0}else{j=b+24|0;k=b+16|0}if((c[k>>2]|0)>0){i=0;do{e=c[ca>>2]|0;fa=c[j>>2]|0;vb[c[(c[e>>2]|0)+8>>2]&63](e,c[fa+(i*12|0)>>2]|0,c[fa+(i*12|0)+4>>2]|0)|0;i=i+1|0}while((i|0)<(c[k>>2]|0))}i=c[j>>2]|0;if(!i){a[b+28>>0]=1;c[j>>2]=0;c[k>>2]=0;b=b+20|0;c[b>>2]=0;l=ga;return}if(a[b+28>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[j>>2]=0;a[b+28>>0]=1;c[j>>2]=0;c[k>>2]=0;b=b+20|0;c[b>>2]=0;l=ga;return}function sc(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0.0,i=0.0,j=0.0,k=0.0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0.0,O=0;u=l;l=l+208|0;f=lb[c[(c[a>>2]|0)+20>>2]&127](a)|0;Tb[c[(c[f>>2]|0)+56>>2]&7](f,b,1.0);f=c[d+4>>2]|0;switch(f|0){case 31:{f=c[d+16>>2]|0;if((f|0)<=0){l=u;return}do{t=f;f=f+-1|0;s=c[d+24>>2]|0;F=+g[s+(f*80|0)>>2];C=+g[s+(f*80|0)+4>>2];z=+g[s+(f*80|0)+8>>2];E=+g[s+(f*80|0)+16>>2];B=+g[s+(f*80|0)+20>>2];x=+g[s+(f*80|0)+24>>2];D=+g[s+(f*80|0)+32>>2];A=+g[s+(f*80|0)+36>>2];v=+g[s+(f*80|0)+40>>2];N=+g[s+(f*80|0)+48>>2];M=+g[s+(f*80|0)+52>>2];k=+g[s+(f*80|0)+56>>2];s=c[s+(f*80|0)+64>>2]|0;r=c[(c[a>>2]|0)+28>>2]|0;L=+g[b>>2];K=+g[b+4>>2];J=+g[b+8>>2];I=+g[b+16>>2];H=+g[b+20>>2];G=+g[b+24>>2];y=+g[b+32>>2];w=+g[b+36>>2];h=+g[b+40>>2];i=N*L+M*K+k*J+ +g[b+48>>2];j=N*I+M*H+k*G+ +g[b+52>>2];k=N*y+M*w+k*h+ +g[b+56>>2];g[u+144>>2]=F*L+E*K+D*J;g[u+144+4>>2]=C*L+B*K+A*J;g[u+144+8>>2]=z*L+x*K+v*J;g[u+144+12>>2]=0.0;g[u+144+16>>2]=F*I+E*H+D*G;g[u+144+20>>2]=C*I+B*H+A*G;g[u+144+24>>2]=z*I+x*H+v*G;g[u+144+28>>2]=0.0;g[u+144+32>>2]=F*y+E*w+D*h;g[u+144+36>>2]=C*y+B*w+A*h;g[u+144+40>>2]=z*y+x*w+v*h;g[u+144+44>>2]=0.0;g[u+144+48>>2]=i;g[u+144+52>>2]=j;g[u+144+56>>2]=k;g[u+144+60>>2]=0.0;Vb[r&127](a,u+144|0,s,e)}while((t|0)>1);l=u;return}case 0:{c[u+144>>2]=c[d+28>>2];c[u+144+4>>2]=c[d+28+4>>2];c[u+144+8>>2]=c[d+28+8>>2];c[u+144+12>>2]=c[d+28+12>>2];L=+zb[c[(c[d>>2]|0)+48>>2]&15](d);M=+zb[c[(c[d>>2]|0)+48>>2]&15](d);N=+zb[c[(c[d>>2]|0)+48>>2]&15](d);L=L+ +g[u+144>>2];g[u+144>>2]=L;M=M+ +g[u+144+4>>2];g[u+144+4>>2]=M;N=N+ +g[u+144+8>>2];g[u+144+8>>2]=N;a=lb[c[(c[a>>2]|0)+20>>2]&127](a)|0;d=c[(c[a>>2]|0)+72>>2]|0;g[u+112>>2]=-L;g[u+112+4>>2]=-M;g[u+112+8>>2]=-N;g[u+112+12>>2]=0.0;fb[d&31](a,u+112|0,u+144|0,b,e);l=u;return}case 8:{N=+zb[c[(c[d>>2]|0)+48>>2]&15](d);a=lb[c[(c[a>>2]|0)+20>>2]&127](a)|0;ob[c[(c[a>>2]|0)+16>>2]&0](a,N,b,e);l=u;return}case 9:{f=c[d+92>>2]|0;if((f|0)<=0){l=u;return}do{t=f;f=f+-1|0;s=c[d+100>>2]|0;z=+g[s+(f<<4)>>2];A=+g[s+(f<<4)+4>>2];M=+g[s+(f<<4)+8>>2];s=lb[c[(c[a>>2]|0)+20>>2]&127](a)|0;r=c[(c[s>>2]|0)+16>>2]|0;N=+g[(c[d+120>>2]|0)+(f<<2)>>2];C=+g[b>>2];D=+g[b+4>>2];B=+g[b+8>>2];F=+g[b+16>>2];G=+g[b+20>>2];E=+g[b+24>>2];I=+g[b+32>>2];J=+g[b+36>>2];H=+g[b+40>>2];K=z*C+A*D+M*B+ +g[b+48>>2];L=z*F+A*G+M*E+ +g[b+52>>2];M=z*I+A*J+M*H+ +g[b+56>>2];g[u+144>>2]=C+D*0.0+B*0.0;g[u+144+4>>2]=C*0.0+D+B*0.0;g[u+144+8>>2]=B+(C*0.0+D*0.0);g[u+144+12>>2]=0.0;g[u+144+16>>2]=F+G*0.0+E*0.0;g[u+144+20>>2]=F*0.0+G+E*0.0;g[u+144+24>>2]=E+(F*0.0+G*0.0);g[u+144+28>>2]=0.0;g[u+144+32>>2]=I+J*0.0+H*0.0;g[u+144+36>>2]=I*0.0+J+H*0.0;g[u+144+40>>2]=H+(I*0.0+J*0.0);g[u+144+44>>2]=0.0;g[u+144+48>>2]=K;g[u+144+52>>2]=L;g[u+144+56>>2]=M;g[u+144+60>>2]=0.0;ob[r&0](s,N,u+144|0,e)}while((t|0)>1);l=u;return}case 10:{t=c[d+52>>2]|0;M=+g[d+28+(((t+2|0)%3|0)<<2)>>2];N=+g[d+28+(t<<2)>>2];a=lb[c[(c[a>>2]|0)+20>>2]&127](a)|0;nb[c[(c[a>>2]|0)+76>>2]&0](a,M,N,t,b,e);l=u;return}case 11:{M=+g[d+56>>2];N=+g[d+60>>2];d=c[d+68>>2]|0;a=lb[c[(c[a>>2]|0)+20>>2]&127](a)|0;nb[c[(c[a>>2]|0)+84>>2]&0](a,M,N,d,b,e);l=u;return}case 13:{t=c[d+52>>2]|0;M=+zb[c[(c[d>>2]|0)+92>>2]&15](d);c[u+128>>2]=c[d+28>>2];c[u+128+4>>2]=c[d+28+4>>2];c[u+128+8>>2]=c[d+28+8>>2];c[u+128+12>>2]=c[d+28+12>>2];K=+zb[c[(c[d>>2]|0)+48>>2]&15](d);L=+zb[c[(c[d>>2]|0)+48>>2]&15](d);N=+zb[c[(c[d>>2]|0)+48>>2]&15](d);g[u+128>>2]=K+ +g[u+128>>2];g[u+128+4>>2]=L+ +g[u+128+4>>2];g[u+128+8>>2]=N+ +g[u+128+8>>2];N=+g[u+128+(t<<2)>>2];a=lb[c[(c[a>>2]|0)+20>>2]&127](a)|0;nb[c[(c[a>>2]|0)+80>>2]&0](a,M,N,t,b,e);l=u;return}case 28:{N=+g[d+64>>2];a=lb[c[(c[a>>2]|0)+20>>2]&127](a)|0;Cb[c[(c[a>>2]|0)+88>>2]&0](a,d+48|0,N,b,e);l=u;return}default:{a:do if((f|0)<7){r=c[d+52>>2]|0;if(!r){if((lb[c[(c[d>>2]|0)+100>>2]&127](d)|0)<=0)break;f=0;while(1){Vb[c[(c[d>>2]|0)+104>>2]&127](d,f,u+144|0,u+112|0);L=+g[u+144>>2];z=+g[b>>2];J=+g[u+144+4>>2];A=+g[b+4>>2];H=+g[u+144+8>>2];B=+g[b+8>>2];D=+g[b+16>>2];E=+g[b+20>>2];F=+g[b+24>>2];I=+g[b+32>>2];K=+g[b+36>>2];M=+g[b+40>>2];C=+g[b+48>>2];G=+g[b+52>>2];N=+g[b+56>>2];g[u+16>>2]=L*z+J*A+H*B+C;g[u+16+4>>2]=L*D+J*E+H*F+G;g[u+16+8>>2]=L*I+J*K+H*M+N;g[u+16+12>>2]=0.0;H=+g[u+112>>2];J=+g[u+112+4>>2];L=+g[u+112+8>>2];g[u>>2]=H*z+J*A+L*B+C;g[u+4>>2]=H*D+J*E+L*F+G;g[u+8>>2]=H*I+J*K+L*M+N;g[u+12>>2]=0.0;t=lb[c[(c[a>>2]|0)+20>>2]&127](a)|0;Vb[c[(c[t>>2]|0)+8>>2]&127](t,u+16|0,u,e);f=f+1|0;if((f|0)>=(lb[c[(c[d>>2]|0)+100>>2]&127](d)|0))break a}}if((c[r+28>>2]|0)>0){s=0;do{f=c[r+36>>2]|0;q=c[f+(s*36|0)+4>>2]|0;b:do if((q|0)!=0?(t=c[f+(s*36|0)+12>>2]|0,(q|0)>0):0){m=t;h=0.0;i=0.0;j=0.0;o=c[t+(q+-1<<2)>>2]|0;f=0;while(1){p=c[m+(f<<2)>>2]|0;n=c[r+16>>2]|0;h=h+ +g[n+(p<<4)>>2];i=i+ +g[n+(p<<4)+4>>2];j=j+ +g[n+(p<<4)+8>>2];n=lb[c[(c[a>>2]|0)+20>>2]&127](a)|0;m=c[(c[n>>2]|0)+8>>2]|0;O=c[r+16>>2]|0;L=+g[O+(o<<4)>>2];z=+g[b>>2];J=+g[O+(o<<4)+4>>2];A=+g[b+4>>2];H=+g[O+(o<<4)+8>>2];B=+g[b+8>>2];D=+g[b+16>>2];E=+g[b+20>>2];F=+g[b+24>>2];I=+g[b+32>>2];K=+g[b+36>>2];M=+g[b+40>>2];C=+g[b+48>>2];G=+g[b+52>>2];N=+g[b+56>>2];g[u+144>>2]=L*z+J*A+H*B+C;g[u+144+4>>2]=L*D+J*E+H*F+G;g[u+144+8>>2]=L*I+J*K+H*M+N;g[u+144+12>>2]=0.0;H=+g[O+(p<<4)>>2];J=+g[O+(p<<4)+4>>2];L=+g[O+(p<<4)+8>>2];g[u+112>>2]=H*z+J*A+L*B+C;g[u+112+4>>2]=H*D+J*E+L*F+G;g[u+112+8>>2]=H*I+J*K+L*M+N;g[u+112+12>>2]=0.0;Vb[m&127](n,u+144|0,u+112|0,e);n=f+1|0;f=c[r+36>>2]|0;if((n|0)>=(c[f+(s*36|0)+4>>2]|0))break b;m=c[f+(s*36|0)+12>>2]|0;o=p;f=n}}else{h=0.0;i=0.0;j=0.0}while(0);k=1.0/+(q|0)*h;i=1.0/+(q|0)*i;h=1.0/+(q|0)*j;O=lb[c[(c[a>>2]|0)+20>>2]&127](a)|0;if((lb[c[(c[O>>2]|0)+48>>2]&127](O)|0)&16384|0){c[u+144>>2]=1065353216;c[u+144+4>>2]=1065353216;c[u+144+8>>2]=0;g[u+144+12>>2]=0.0;O=c[r+36>>2]|0;H=+g[O+(s*36|0)+20>>2];J=+g[O+(s*36|0)+24>>2];L=+g[O+(s*36|0)+28>>2];O=lb[c[(c[a>>2]|0)+20>>2]&127](a)|0;q=c[(c[O>>2]|0)+8>>2]|0;z=+g[b>>2];A=+g[b+4>>2];B=+g[b+8>>2];D=+g[b+16>>2];E=+g[b+20>>2];F=+g[b+24>>2];I=+g[b+32>>2];K=+g[b+36>>2];M=+g[b+40>>2];C=+g[b+48>>2];G=+g[b+52>>2];N=+g[b+56>>2];g[u+112>>2]=k*z+i*A+h*B+C;g[u+112+4>>2]=k*D+i*E+h*F+G;g[u+112+8>>2]=k*I+i*K+h*M+N;g[u+112+12>>2]=0.0;g[u+16>>2]=(k+H)*z+(i+J)*A+(h+L)*B+C;g[u+16+4>>2]=(k+H)*D+(i+J)*E+(h+L)*F+G;g[u+16+8>>2]=(k+H)*I+(i+J)*K+(h+L)*M+N;g[u+16+12>>2]=0.0;Vb[q&127](O,u+112|0,u+16|0,u+144|0)}s=s+1|0}while((s|0)<(c[r+28>>2]|0))}}while(0);f=c[d+4>>2]|0;if((f+-21|0)>>>0<9){c[u+144>>2]=1566444395;c[u+144+4>>2]=1566444395;c[u+144+8>>2]=1566444395;g[u+144+12>>2]=0.0;c[u+112>>2]=-581039253;c[u+112+4>>2]=-581039253;c[u+112+8>>2]=-581039253;g[u+112+12>>2]=0.0;f=lb[c[(c[a>>2]|0)+20>>2]&127](a)|0;c[u+16>>2]=5944;c[u+16+4>>2]=5968;c[u+16+8>>2]=f;c[u+16+12>>2]=c[e>>2];c[u+16+12+4>>2]=c[e+4>>2];c[u+16+12+8>>2]=c[e+8>>2];c[u+16+12+12>>2]=c[e+12>>2];c[u+16+28>>2]=c[b>>2];c[u+16+28+4>>2]=c[b+4>>2];c[u+16+28+8>>2]=c[b+8>>2];c[u+16+28+12>>2]=c[b+12>>2];c[u+16+44>>2]=c[b+16>>2];c[u+16+44+4>>2]=c[b+16+4>>2];c[u+16+44+8>>2]=c[b+16+8>>2];c[u+16+44+12>>2]=c[b+16+12>>2];c[u+16+60>>2]=c[b+32>>2];c[u+16+60+4>>2]=c[b+32+4>>2];c[u+16+60+8>>2]=c[b+32+8>>2];c[u+16+60+12>>2]=c[b+32+12>>2];c[u+16+76>>2]=c[b+48>>2];c[u+16+76+4>>2]=c[b+48+4>>2];c[u+16+76+8>>2]=c[b+48+8>>2];c[u+16+76+12>>2]=c[b+48+12>>2];Vb[c[(c[d>>2]|0)+64>>2]&127](d,u+16|0,u+112|0,u+144|0);f=c[d+4>>2]|0}if((f|0)!=3){l=u;return}c[u+144>>2]=1566444395;c[u+144+4>>2]=1566444395;c[u+144+8>>2]=1566444395;g[u+144+12>>2]=0.0;c[u+112>>2]=-581039253;c[u+112+4>>2]=-581039253;c[u+112+8>>2]=-581039253;g[u+112+12>>2]=0.0;O=lb[c[(c[a>>2]|0)+20>>2]&127](a)|0;c[u+16>>2]=5944;c[u+16+4>>2]=5968;c[u+16+8>>2]=O;c[u+16+12>>2]=c[e>>2];c[u+16+12+4>>2]=c[e+4>>2];c[u+16+12+8>>2]=c[e+8>>2];c[u+16+12+12>>2]=c[e+12>>2];c[u+16+28>>2]=c[b>>2];c[u+16+28+4>>2]=c[b+4>>2];c[u+16+28+8>>2]=c[b+8>>2];c[u+16+28+12>>2]=c[b+12>>2];c[u+16+44>>2]=c[b+16>>2];c[u+16+44+4>>2]=c[b+16+4>>2];c[u+16+44+8>>2]=c[b+16+8>>2];c[u+16+44+12>>2]=c[b+16+12>>2];c[u+16+60>>2]=c[b+32>>2];c[u+16+60+4>>2]=c[b+32+4>>2];c[u+16+60+8>>2]=c[b+32+8>>2];c[u+16+60+12>>2]=c[b+32+12>>2];c[u+16+76>>2]=c[b+48>>2];c[u+16+76+4>>2]=c[b+48+4>>2];c[u+16+76+8>>2]=c[b+48+8>>2];c[u+16+76+12>>2]=c[b+48+12>>2];O=c[d+92>>2]|0;Vb[c[(c[O>>2]|0)+8>>2]&127](O,u+16+4|0,u+112|0,u+144|0);l=u;return}}}function tc(b,d){b=b|0;d=d|0;var e=0,f=0,h=0.0,i=0.0,j=0.0,k=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0,r=0,s=0,t=0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,D=0.0,E=0.0,F=0.0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0.0,O=0.0,P=0,Q=0,R=0,S=0,T=0,U=0.0,V=0.0,W=0.0;T=l;l=l+144|0;R=c[d+36>>2]|0;n=+g[(+g[R+88>>2]>0.0?b+16|0:b+20|0)>>2];if(a[R+100>>0]&1){l=T;return}P=c[b+8>>2]|0;s=c[P+4>>2]|0;Q=c[P+12>>2]|0;J=c[(c[b+4>>2]|0)+684>>2]|0;N=+g[R+8>>2]-+g[Q+48>>2];p=+g[R+12>>2]-+g[Q+52>>2];O=+g[R+16>>2]-+g[Q+56>>2];F=1.0/+g[J+76>>2];E=(N*+g[Q>>2]+p*+g[Q+16>>2]+O*+g[Q+32>>2])*F/3.0;G=E<0.0?~~(1.0-E):0;K=~~((E+ +(G|0)-+(~~(E+ +(G|0))|0))*3.0);o=(E+ +(G|0)-+(~~(E+ +(G|0))|0))*3.0-+(K|0);G=~~(E+ +(G|0))-G|0;E=F*(N*+g[Q+4>>2]+p*+g[Q+20>>2]+O*+g[Q+36>>2])/3.0;I=E<0.0?~~(1.0-E):0;M=~~((E+ +(I|0)-+(~~(E+ +(I|0))|0))*3.0);u=(E+ +(I|0)-+(~~(E+ +(I|0))|0))*3.0-+(M|0);I=~~(E+ +(I|0))-I|0;O=F*(N*+g[Q+8>>2]+p*+g[Q+24>>2]+O*+g[Q+40>>2])/3.0;H=O<0.0?~~(1.0-O):0;L=~~((O+ +(H|0)-+(~~(O+ +(H|0))|0))*3.0);p=(O+ +(H|0)-+(~~(O+ +(H|0))|0))*3.0-+(L|0);H=~~(O+ +(H|0))-H|0;t=(G>>>16<<11^(G&65535)+16^(G&65535)+16<<16)+(I&65535)+((G>>>16<<11^(G&65535)+16^(G&65535)+16<<16)>>>11)|0;t=(t^I>>>16<<11^t<<16)+(H&65535)+((t^I>>>16<<11^t<<16)>>>11)|0;t=(t^H>>>16<<11^t<<16)+(s&65535)+((t^H>>>16<<11^t<<16)>>>11)|0;t=((t^s>>>16<<11^t<<16)>>>11)+(t^s>>>16<<11^t<<16)|0;t=((t<<3^t)>>>5)+(t<<3^t)<<4^((t<<3^t)>>>5)+(t<<3^t);t=(((t>>>17)+t<<25^(t>>>17)+t)>>>6)+((t>>>17)+t<<25^(t>>>17)+t)|0;q=c[J+60>>2]|0;r=c[J+68>>2]|0;d=c[r+(((t>>>0)%(q>>>0)|0)<<2)>>2]|0;c[J+96>>2]=(c[J+96>>2]|0)+1;e=(c[J+92>>2]|0)+1|0;c[J+92>>2]=e;a:do if(!d)f=9;else while(1){if(((((c[d+272>>2]|0)==(t|0)?(c[d+256>>2]|0)==(G|0):0)?(c[d+260>>2]|0)==(I|0):0)?(c[d+264>>2]|0)==(H|0):0)?(c[d+276>>2]|0)==(s|0):0)break a;d=c[d+280>>2]|0;e=e+1|0;c[J+92>>2]=e;if(!d){f=9;break}}while(0);b:do if((f|0)==9){f=c[J+84>>2]|0;c[J+84>>2]=f+1;if((f|0)>=(c[J+88>>2]|0)){c[5786]=(c[5786]|0)+1;c:do if((q|0)>0){e=r;f=0;while(1){e=e+(f<<2)|0;d=c[e>>2]|0;c[e>>2]=0;if(d|0)do{e=d;d=c[d+280>>2]|0;YG(e)}while((d|0)!=0);d=f+1|0;if((d|0)==(q|0))break c;e=c[J+68>>2]|0;f=d}}while(0);g[J+76>>2]=.25;c[J+80>>2]=0;c[J+84>>2]=0;c[J+92>>2]=1;c[J+96>>2]=1}d=Br(284)|0;Hk(d|0,0,284)|0;c[d+280>>2]=c[r+(((t>>>0)%(q>>>0)|0)<<2)>>2];c[r+(((t>>>0)%(q>>>0)|0)<<2)>>2]=d;c[d+276>>2]=s;c[d+272>>2]=t;c[d+256>>2]=G;c[d+260>>2]=I;c[d+264>>2]=H;k=+g[J+76>>2];r=T+72+4|0;s=T+72+24|0;t=T+72+44|0;h=k;e=0;while(1){j=k*+(H|0)*3.0+ +(e|0)*h;q=0;while(1){i=k*+(I|0)*3.0+ +(q|0)*h;g[T>>2]=+(G|0)*3.0*k+h*0.0;g[T+4>>2]=i;g[T+8>>2]=j;g[T+12>>2]=0.0;f=c[d+276>>2]|0;c[T+72>>2]=1065353216;c[r>>2]=0;c[r+4>>2]=0;c[r+8>>2]=0;c[r+12>>2]=0;c[T+72+20>>2]=1065353216;c[s>>2]=0;c[s+4>>2]=0;c[s+8>>2]=0;c[s+12>>2]=0;c[T+72+40>>2]=1065353216;c[t>>2]=0;c[t+4>>2]=0;c[t+8>>2]=0;c[t+12>>2]=0;c[t+16>>2]=0;if((c[f+4>>2]|0)<20)h=+Rc(T,f,T+72|0,T+16|0);else h=0.0;g[d+(q<<4)+(e<<2)>>2]=h;g[T>>2]=+(G|0)*3.0*k+ +g[J+76>>2];g[T+4>>2]=i;g[T+8>>2]=j;g[T+12>>2]=0.0;f=c[d+276>>2]|0;c[T+72>>2]=1065353216;c[r>>2]=0;c[r+4>>2]=0;c[r+8>>2]=0;c[r+12>>2]=0;c[T+72+20>>2]=1065353216;c[s>>2]=0;c[s+4>>2]=0;c[s+8>>2]=0;c[s+12>>2]=0;c[T+72+40>>2]=1065353216;c[t>>2]=0;c[t+4>>2]=0;c[t+8>>2]=0;c[t+12>>2]=0;c[t+16>>2]=0;if((c[f+4>>2]|0)<20)h=+Rc(T,f,T+72|0,T+16|0);else h=0.0;g[d+64+(q<<4)+(e<<2)>>2]=h;g[T>>2]=+(G|0)*3.0*k+ +g[J+76>>2]*2.0;g[T+4>>2]=i;g[T+8>>2]=j;g[T+12>>2]=0.0;f=c[d+276>>2]|0;c[T+72>>2]=1065353216;c[r>>2]=0;c[r+4>>2]=0;c[r+8>>2]=0;c[r+12>>2]=0;c[T+72+20>>2]=1065353216;c[s>>2]=0;c[s+4>>2]=0;c[s+8>>2]=0;c[s+12>>2]=0;c[T+72+40>>2]=1065353216;c[t>>2]=0;c[t+4>>2]=0;c[t+8>>2]=0;c[t+12>>2]=0;c[t+16>>2]=0;if((c[f+4>>2]|0)<20)h=+Rc(T,f,T+72|0,T+16|0);else h=0.0;g[d+128+(q<<4)+(e<<2)>>2]=h;g[T>>2]=+(G|0)*3.0*k+ +g[J+76>>2]*3.0;g[T+4>>2]=i;g[T+8>>2]=j;g[T+12>>2]=0.0;f=c[d+276>>2]|0;c[T+72>>2]=1065353216;c[r>>2]=0;c[r+4>>2]=0;c[r+8>>2]=0;c[r+12>>2]=0;c[T+72+20>>2]=1065353216;c[s>>2]=0;c[s+4>>2]=0;c[s+8>>2]=0;c[s+12>>2]=0;c[T+72+40>>2]=1065353216;c[t>>2]=0;c[t+4>>2]=0;c[t+8>>2]=0;c[t+12>>2]=0;c[t+16>>2]=0;if((c[f+4>>2]|0)<20)h=+Rc(T,f,T+72|0,T+16|0);else h=0.0;g[d+192+(q<<4)+(e<<2)>>2]=h;f=q+1|0;if((f|0)==4)break;h=+g[J+76>>2];q=f}e=e+1|0;if((e|0)==4)break b;h=+g[J+76>>2]}}while(0);c[d+268>>2]=c[J+80>>2];h=+g[d+(K<<6)+(M<<4)+(L<<2)>>2];D=+g[d+(K+1<<6)+(M<<4)+(L<<2)>>2];A=+g[d+(K+1<<6)+(M+1<<4)+(L<<2)>>2];B=+g[d+(K<<6)+(M+1<<4)+(L<<2)>>2];O=+g[d+(K<<6)+(M<<4)+(L+1<<2)>>2];N=+g[d+(K+1<<6)+(M<<4)+(L+1<<2)>>2];E=+g[d+(K+1<<6)+(M+1<<4)+(L+1<<2)>>2];F=+g[d+(K<<6)+(M+1<<4)+(L+1<<2)>>2];k=D-h+u*(A-B-(D-h))+p*(N-O+u*(E-F-(N-O))-(D-h+u*(A-B-(D-h))));j=B-h+o*(A-D-(B-h))+p*(F-O+o*(E-N-(F-O))-(B-h+o*(A-D-(B-h))));i=O-h+o*(N-D-(O-h))+u*(F-B+o*(E-A-(F-B))-(O-h+o*(N-D-(O-h))));m=1.0/+C(+(k*k+j*j+i*i));h=h+o*(D-h)+u*(B+o*(A-B)-(h+o*(D-h)));h=h+p*(O+o*(N-O)+u*(F+o*(E-F)-(O+o*(N-O)))-h)-n;if(!(h<0.0)){l=T;return}s=c[P+8>>2]|0;O=+g[Q>>2]*k*m+ +g[Q+4>>2]*j*m+ +g[Q+8>>2]*i*m;N=k*m*+g[Q+16>>2]+j*m*+g[Q+20>>2]+i*m*+g[Q+24>>2];F=k*m*+g[Q+32>>2]+j*m*+g[Q+36>>2]+i*m*+g[Q+40>>2];E=-(O*(+g[R+8>>2]-h*O)+N*(+g[R+12>>2]-h*N)+F*(+g[R+16>>2]-h*F));z=+g[R+88>>2];d=c[b+12>>2]|0;if(!d)p=0.0;else p=+g[d+344>>2];if(!(z+p>0.0)){l=T;return}if(!d)d=c[(c[b+8>>2]|0)+8>>2]|0;if((a[22672]|0)==0?jy(22672)|0:0){e=23148;f=e+48|0;do{c[e>>2]=0;e=e+4|0}while((e|0)<(f|0))}e=c[b+12>>2]|0;m=+g[R+8>>2];B=m-+g[d+52>>2];n=+g[R+12>>2];D=n-+g[d+56>>2];o=+g[R+16>>2];A=o-+g[d+60>>2];if(!e){Q=c[b+4>>2]|0;h=0.0;i=0.0;j=0.0;d=Q;k=+g[Q+452>>2]}else{j=+g[e+332>>2];i=+g[e+336>>2];y=+g[e+328>>2];d=c[b+4>>2]|0;k=+g[d+452>>2];h=(j*A-i*D+ +g[e+312>>2])*k;i=(+g[e+316>>2]+(i*B-A*y))*k;j=(D*y-j*B+ +g[e+320>>2])*k}W=m-+g[R+24>>2]-h;V=n-+g[R+28>>2]-i;U=o-+g[R+32>>2]-j;h=+g[d+316>>2]*+g[(c[(c[b+8>>2]|0)+8>>2]|0)+224>>2];y=1.0/k;Ch(T+72|0,p,(e|0)==0?23148:e+264|0,B,D,A);m=z+ +g[T+72>>2];w=+g[T+72+4>>2]+0.0;p=+g[T+72+8>>2]+0.0;j=+g[T+72+16>>2]+0.0;u=z+ +g[T+72+20>>2];n=+g[T+72+24>>2]+0.0;k=+g[T+72+32>>2]+0.0;v=+g[T+72+36>>2]+0.0;o=z+ +g[T+72+40>>2];x=1.0/(p*(j*v-u*k)+(m*(u*o-n*v)+w*(n*k-j*o)));r=c[b+4>>2]|0;i=z*+g[r+452>>2];h=(U-F*(W*O+V*N+U*F))*(U-F*(W*O+V*N+U*F))+((W-O*(W*O+V*N+U*F))*(W-O*(W*O+V*N+U*F))+(V-N*(W*O+V*N+U*F))*(V-N*(W*O+V*N+U*F)))<h*(W*O+V*N+U*F)*(W*O+V*N+U*F)*h?0.0:1.0-h;q=c[(c[(c[(c[b+8>>2]|0)+8>>2]|0)+204>>2]&3|0?r+328|0:r+324|0)>>2]|0;d=c[r+812>>2]|0;if((d|0)==(c[r+816>>2]|0)?(S=d|0?d<<1:1,(d|0)<(S|0)):0){if(!S)e=0;else{c[6432]=(c[6432]|0)+1;d=ec((S*104|3)+16|0)|0;if(!d)e=0;else{c[(d+4+15&-16)+-4>>2]=d;e=d+4+15&-16}d=c[r+812>>2]|0}if((d|0)>0){f=0;do{Q=e+(f*104|0)|0;P=c[r+820>>2]|0;M=P+(f*104|0)|0;c[Q>>2]=c[M>>2];c[Q+4>>2]=c[M+4>>2];c[Q+8>>2]=c[M+8>>2];c[Q+12>>2]=c[M+12>>2];c[Q+16>>2]=c[M+16>>2];c[Q+20>>2]=c[M+20>>2];c[Q+24>>2]=c[M+24>>2];Q=e+(f*104|0)+28|0;M=P+(f*104|0)+28|0;c[Q>>2]=c[M>>2];c[Q+4>>2]=c[M+4>>2];c[Q+8>>2]=c[M+8>>2];c[Q+12>>2]=c[M+12>>2];Q=P+(f*104|0)+44|0;M=e+(f*104|0)+44|0;c[M>>2]=c[Q>>2];c[M+4>>2]=c[Q+4>>2];c[M+8>>2]=c[Q+8>>2];c[M+12>>2]=c[Q+12>>2];M=P+(f*104|0)+60|0;Q=e+(f*104|0)+60|0;c[Q>>2]=c[M>>2];c[Q+4>>2]=c[M+4>>2];c[Q+8>>2]=c[M+8>>2];c[Q+12>>2]=c[M+12>>2];Q=e+(f*104|0)+76|0;P=P+(f*104|0)+76|0;c[Q>>2]=c[P>>2];c[Q+4>>2]=c[P+4>>2];c[Q+8>>2]=c[P+8>>2];c[Q+12>>2]=c[P+12>>2];c[Q+16>>2]=c[P+16>>2];c[Q+20>>2]=c[P+20>>2];c[Q+24>>2]=c[P+24>>2];f=f+1|0}while((f|0)!=(d|0))}d=c[r+820>>2]|0;if(d|0){if(a[r+824>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[r+820>>2]=0}a[r+824>>0]=1;c[r+820>>2]=e;c[r+816>>2]=S;d=c[r+812>>2]|0}Q=c[r+820>>2]|0;c[Q+(d*104|0)>>2]=s;g[Q+(d*104|0)+4>>2]=O;g[Q+(d*104|0)+8>>2]=N;g[Q+(d*104|0)+12>>2]=F;g[Q+(d*104|0)+16>>2]=0.0;g[Q+(d*104|0)+20>>2]=E;c[Q+(d*104|0)+24>>2]=R;g[Q+(d*104|0)+28>>2]=(j*v-u*k)*x*0.0+(y*(u*o-n*v)*x+(n*k-j*o)*x*0.0);g[Q+(d*104|0)+32>>2]=(w*k-m*v)*x*0.0+(y*(p*v-w*o)*x+(m*o-p*k)*x*0.0);g[Q+(d*104|0)+36>>2]=(m*u-w*j)*x*0.0+(y*(w*n-p*u)*x+(p*j-m*n)*x*0.0);g[Q+(d*104|0)+40>>2]=0.0;g[Q+(d*104|0)+44>>2]=(j*v-u*k)*x*0.0+((u*o-n*v)*x*0.0+y*(n*k-j*o)*x);g[Q+(d*104|0)+48>>2]=(w*k-m*v)*x*0.0+((p*v-w*o)*x*0.0+y*(m*o-p*k)*x);g[Q+(d*104|0)+52>>2]=(m*u-w*j)*x*0.0+((w*n-p*u)*x*0.0+y*(p*j-m*n)*x);g[Q+(d*104|0)+56>>2]=0.0;g[Q+(d*104|0)+60>>2]=y*(j*v-u*k)*x+((u*o-n*v)*x*0.0+(n*k-j*o)*x*0.0);g[Q+(d*104|0)+64>>2]=y*(w*k-m*v)*x+((p*v-w*o)*x*0.0+(m*o-p*k)*x*0.0);g[Q+(d*104|0)+68>>2]=y*(m*u-w*j)*x+((w*n-p*u)*x*0.0+(p*j-m*n)*x*0.0);g[Q+(d*104|0)+72>>2]=0.0;S=Q+(d*104|0)+76|0;g[S>>2]=B;g[Q+(d*104|0)+80>>2]=D;g[Q+(d*104|0)+84>>2]=A;g[Q+(d*104|0)+88>>2]=0.0;g[S+16>>2]=i;g[S+20>>2]=h;c[S+24>>2]=q;c[r+812>>2]=(c[r+812>>2]|0)+1;d=c[b+12>>2]|0;if(!d){l=T;return}if(c[d+204>>2]&3|0){l=T;return}if((c[d+216>>2]&-2|0)!=4)c[d+216>>2]=1;g[d+220>>2]=0.0;l=T;return}function uc(b,d){b=b|0;d=+d;var e=0,f=0.0,h=0,i=0,j=0,k=0.0,m=0.0,n=0,o=0,p=0,q=0.0,r=0,s=0,t=0,u=0.0,v=0.0,w=0.0,x=0.0,y=0,z=0.0,A=0.0,B=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0.0,O=0.0,P=0.0,Q=0.0,R=0.0;s=l;l=l+96|0;p=c[b+136>>2]|0;if(!p){l=s;return}j=c[b+8>>2]|0;if((j|0)<(p|0)){if((c[b+12>>2]|0)<(p|0)){c[6432]=(c[6432]|0)+1;e=ec((p<<4|3)+16|0)|0;if(!e)i=0;else{c[(e+4+15&-16)+-4>>2]=e;i=e+4+15&-16}e=c[b+8>>2]|0;if((e|0)>0){h=0;do{n=i+(h<<4)|0;t=(c[b+16>>2]|0)+(h<<4)|0;c[n>>2]=c[t>>2];c[n+4>>2]=c[t+4>>2];c[n+8>>2]=c[t+8>>2];c[n+12>>2]=c[t+12>>2];h=h+1|0}while((h|0)!=(e|0))}e=c[b+16>>2]|0;if(e|0){if(a[b+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}c[b+16>>2]=0}a[b+20>>0]=1;c[b+16>>2]=i;c[b+12>>2]=p;h=b+16|0}else h=b+16|0;e=j;do{t=(c[h>>2]|0)+(e<<4)|0;c[t>>2]=c[s+48>>2];c[t+4>>2]=c[s+48+4>>2];c[t+8>>2]=c[s+48+8>>2];c[t+12>>2]=c[s+48+12>>2];e=e+1|0}while((e|0)!=(p|0))}c[b+8>>2]=p;j=c[b+28>>2]|0;if((j|0)<(p|0)){if((c[b+32>>2]|0)<(p|0)){c[6432]=(c[6432]|0)+1;e=ec((p<<4|3)+16|0)|0;if(!e)i=0;else{c[(e+4+15&-16)+-4>>2]=e;i=e+4+15&-16}e=c[b+28>>2]|0;if((e|0)>0){h=0;do{t=i+(h<<4)|0;n=(c[b+36>>2]|0)+(h<<4)|0;c[t>>2]=c[n>>2];c[t+4>>2]=c[n+4>>2];c[t+8>>2]=c[n+8>>2];c[t+12>>2]=c[n+12>>2];h=h+1|0}while((h|0)!=(e|0))}e=c[b+36>>2]|0;if(e|0){if(a[b+40>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}c[b+36>>2]=0}a[b+40>>0]=1;c[b+36>>2]=i;c[b+32>>2]=p;h=b+36|0}else h=b+36|0;e=j;do{t=(c[h>>2]|0)+(e<<4)|0;c[t>>2]=c[s+48>>2];c[t+4>>2]=c[s+48+4>>2];c[t+8>>2]=c[s+48+8>>2];c[t+12>>2]=c[s+48+12>>2];e=e+1|0}while((e|0)!=(p|0))}c[b+28>>2]=p;n=c[b+48>>2]|0;if((n|0)<(p|0)){if((c[b+52>>2]|0)<(p|0)){c[6432]=(c[6432]|0)+1;e=ec((p<<2|3)+16|0)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}i=c[b+48>>2]|0;j=c[b+56>>2]|0;if((i|0)<=0)if(!j)h=b+60|0;else o=39;else{h=0;do{c[e+(h<<2)>>2]=c[j+(h<<2)>>2];h=h+1|0}while((h|0)!=(i|0));o=39}if((o|0)==39)if(!(a[b+60>>0]|0))h=b+60|0;else{c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0);h=b+60|0}a[h>>0]=1;c[b+56>>2]=e;c[b+52>>2]=p;h=p<<2}else{h=p<<2;e=c[b+56>>2]|0}Hk(e+(n<<2)|0,0,h-(n<<2)|0)|0}c[b+48>>2]=p;n=c[b+68>>2]|0;if((n|0)<(p|0)){if((c[b+72>>2]|0)<(p|0)){c[6432]=(c[6432]|0)+1;e=ec((p<<2|3)+16|0)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}i=c[b+68>>2]|0;j=c[b+76>>2]|0;if((i|0)<=0)if(!j)h=b+80|0;else o=52;else{h=0;do{c[e+(h<<2)>>2]=c[j+(h<<2)>>2];h=h+1|0}while((h|0)!=(i|0));o=52}if((o|0)==52)if(!(a[b+80>>0]|0))h=b+80|0;else{c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0);h=b+80|0}a[h>>0]=1;c[b+76>>2]=e;c[b+72>>2]=p;h=p<<2}else{h=p<<2;e=c[b+76>>2]|0}Hk(e+(n<<2)|0,0,h-(n<<2)|0)|0}c[b+68>>2]=p;e=c[b+136>>2]|0;if((e|0)<=0){l=s;return}h=c[b+76>>2]|0;i=c[b+56>>2]|0;j=0;do{g[h+(j<<2)>>2]=0.0;g[i+(j<<2)>>2]=0.0;j=j+1|0}while((j|0)!=(e|0));j=0;do{h=c[b+144>>2]|0;i=c[h+(j*284|0)+88>>2]|0;if(i){n=h+(j*284|0)+92|0;c[s+48>>2]=c[n>>2];c[s+48+4>>2]=c[n+4>>2];c[s+48+8>>2]=c[n+8>>2];c[s+48+12>>2]=c[n+12>>2];n=h+(j*284|0)+108|0;c[s+48+16>>2]=c[n>>2];c[s+48+16+4>>2]=c[n+4>>2];c[s+48+16+8>>2]=c[n+8>>2];c[s+48+16+12>>2]=c[n+12>>2];n=h+(j*284|0)+124|0;c[s+48+32>>2]=c[n>>2];c[s+48+32+4>>2]=c[n+4>>2];c[s+48+32+8>>2]=c[n+8>>2];c[s+48+32+12>>2]=c[n+12>>2];n=c[b+120>>2]|0;e=c[s+48+16+(n<<2)>>2]|0;y=c[s+48+32+(n<<2)>>2]|0;o=c[b+36>>2]|0;c[o+(j<<4)>>2]=c[s+48+(n<<2)>>2];c[o+(j<<4)+4>>2]=e;c[o+(j<<4)+8>>2]=y;g[o+(j<<4)+12>>2]=0.0;o=c[b+36>>2]|0;y=o+(j<<4)|0;z=+g[y>>2];e=h+(j*284|0)|0;f=+g[e>>2];n=o+(j<<4)+4|0;x=+g[n>>2];t=h+(j*284|0)+4|0;k=+g[t>>2];o=o+(j<<4)+8|0;u=+g[o>>2];p=h+(j*284|0)+8|0;w=+g[p>>2];m=z-f*(z*f+x*k+u*w);v=x-k*(z*f+x*k+u*w);w=u-w*(z*f+x*k+u*w);u=1.0/+C(+(m*m+v*v+w*w));g[y>>2]=m*u;g[n>>2]=v*u;g[o>>2]=w*u;k=+g[t>>2];x=+g[p>>2];f=+g[e>>2];e=c[b+16>>2]|0;g[e+(j<<4)>>2]=k*w*u-x*v*u;g[e+(j<<4)+4>>2]=x*m*u-w*u*f;g[e+(j<<4)+8>>2]=v*u*f-k*m*u;g[e+(j<<4)+12>>2]=0.0;e=c[b+16>>2]|0;p=e+(j<<4)|0;u=+g[p>>2];t=e+(j<<4)+4|0;m=+g[t>>2];e=e+(j<<4)+8|0;k=+g[e>>2];f=1.0/+C(+(u*u+m*m+k*k));g[p>>2]=u*f;g[t>>2]=m*f;g[e>>2]=k*f;e=c[b+116>>2]|0;t=c[b+36>>2]|0;f=+g[t+(j<<4)>>2];k=+g[t+(j<<4)+4>>2];m=+g[t+(j<<4)+8>>2];if(f*f+k*k+m*m>1.100000023841858)f=0.0;else{D=+g[h+(j*284|0)+16>>2];H=D-+g[e+52>>2];F=+g[h+(j*284|0)+20>>2];J=F-+g[e+56>>2];K=+g[h+(j*284|0)+24>>2];M=K-+g[e+60>>2];D=D-+g[i+52>>2];F=F-+g[i+56>>2];K=K-+g[i+60>>2];G=+g[e+332>>2];N=+g[e+336>>2];I=+g[e+328>>2];B=+g[i+332>>2];L=+g[i+336>>2];E=+g[i+328>>2];A=(m*J-k*M)*+g[e+4>>2]+(f*M-m*H)*+g[e+20>>2]+(k*H-f*J)*+g[e+36>>2];u=(m*J-k*M)*+g[e+8>>2]+(f*M-m*H)*+g[e+24>>2]+(k*H-f*J)*+g[e+40>>2];v=(m*J-k*M)*+g[e+12>>2]+(f*M-m*H)*+g[e+28>>2]+(k*H-f*J)*+g[e+44>>2];w=(F*-m-K*-k)*+g[i+4>>2]+(K*-f-D*-m)*+g[i+20>>2]+(D*-k-F*-f)*+g[i+36>>2];x=(F*-m-K*-k)*+g[i+8>>2]+(K*-f-D*-m)*+g[i+24>>2]+(D*-k-F*-f)*+g[i+40>>2];z=(F*-m-K*-k)*+g[i+12>>2]+(K*-f-D*-m)*+g[i+28>>2]+(D*-k-F*-f)*+g[i+44>>2];f=(f*(M*G-J*N+ +g[e+312>>2]-(K*B-F*L+ +g[i+312>>2]))+k*(+g[e+316>>2]+(H*N-M*I)-(+g[i+316>>2]+(D*L-K*E)))+m*(J*I-H*G+ +g[e+320>>2]-(F*E-D*B+ +g[i+320>>2])))*-.20000000298023224*(1.0/(+g[i+344>>2]+(+g[e+344>>2]+(A*A*+g[e+396>>2]+u*u*+g[e+400>>2]+v*v*+g[e+404>>2]))+(w*w*+g[i+396>>2]+x*x*+g[i+400>>2]+z*z*+g[i+404>>2])))}g[(c[b+76>>2]|0)+(j<<2)>>2]=f;e=c[b+136>>2]|0}j=j+1|0}while((j|0)<(e|0));if((e|0)<=0){l=s;return}h=c[b+144>>2]|0;i=0;p=0;while(1){e=c[h+(p*284|0)+88>>2]|0;if(e){f=+g[h+(p*284|0)+252>>2];if(f!=0.0){n=h;f=f*d}else{N=+g[h+(p*284|0)+256>>2];N=N==0.0?0.0:N;n=c[b+116>>2]|0;y=c[b+16>>2]|0;H=+g[h+(p*284|0)+16>>2];F=+g[h+(p*284|0)+20>>2];A=+g[h+(p*284|0)+24>>2];x=+g[y+(p<<4)>>2];E=+g[y+(p<<4)+4>>2];f=+g[y+(p<<4)+8>>2];P=H-+g[n+52>>2];Q=F-+g[n+56>>2];k=A-+g[n+60>>2];m=+g[n+264>>2]*(Q*f-k*E)+ +g[n+280>>2]*(k*x-P*f)+(P*E-Q*x)*+g[n+296>>2];R=(Q*f-k*E)*+g[n+268>>2]+(k*x-P*f)*+g[n+284>>2]+(P*E-Q*x)*+g[n+300>>2];O=(Q*f-k*E)*+g[n+272>>2]+(k*x-P*f)*+g[n+288>>2]+(P*E-Q*x)*+g[n+304>>2];L=H-+g[e+52>>2];J=F-+g[e+56>>2];D=A-+g[e+60>>2];w=(E*L-x*J)*+g[e+296>>2]+(+g[e+264>>2]*(f*J-E*D)+ +g[e+280>>2]*(x*D-f*L));u=(f*J-E*D)*+g[e+268>>2]+(x*D-f*L)*+g[e+284>>2]+(E*L-x*J)*+g[e+300>>2];v=(f*J-E*D)*+g[e+272>>2]+(x*D-f*L)*+g[e+288>>2]+(E*L-x*J)*+g[e+304>>2];H=H-+g[n+52>>2];F=F-+g[n+56>>2];A=A-+g[n+60>>2];I=+g[n+332>>2];z=+g[n+336>>2];G=+g[n+328>>2];M=+g[e+332>>2];B=+g[e+336>>2];K=+g[e+328>>2];f=-(1.0/(+g[n+344>>2]+(f*(Q*m-P*R)+(x*(k*R-Q*O)+E*(P*O-k*m)))+(+g[e+344>>2]+(f*(J*w-L*u)+(x*(D*u-J*v)+E*(L*v-D*w)))))*((A*I-F*z+ +g[n+312>>2]-(D*M-J*B+ +g[e+312>>2]))*x+(+g[n+316>>2]+(H*z-A*G)-(+g[e+316>>2]+(L*B-D*K)))*E+(F*G-H*I+ +g[n+320>>2]-(J*K-L*M+ +g[e+320>>2]))*f));f=N<f?N:f;n=c[b+144>>2]|0;f=f<-N?-N:f}o=c[b+56>>2]|0;y=o+(p<<2)|0;g[y>>2]=0.0;e=n+(p*284|0)+280|0;g[e>>2]=1.0;m=+g[h+(p*284|0)+276>>2]*d*+g[h+(p*284|0)+228>>2];g[y>>2]=f;k=f*.5;f=+g[(c[b+76>>2]|0)+(p<<2)>>2];if(k*k+f*f>m*m){R=m/+C(+(k*k+f*f));g[e>>2]=R*+g[e>>2];e=1}else e=i}else{o=c[b+56>>2]|0;g[o+(p<<2)>>2]=0.0;g[h+(p*284|0)+280>>2]=1.0;n=h;e=i}p=p+1|0;j=c[b+136>>2]|0;if((p|0)>=(j|0))break;else{h=n;i=e}}if(e){if((j|0)<=0){l=s;return}e=c[b+76>>2]|0;i=0;do{h=e+(i<<2)|0;if(+g[h>>2]!=0.0?(r=n+(i*284|0)+280|0,q=+g[r>>2],q<1.0):0){y=o+(i<<2)|0;g[y>>2]=q*+g[y>>2];g[h>>2]=+g[r>>2]*+g[h>>2]}i=i+1|0}while((i|0)!=(j|0))}if((j|0)<=0){l=s;return}p=n;i=o;e=0;while(1){h=c[b+116>>2]|0;j=p+(e*284|0)+16|0;k=+g[j>>2]-+g[h+52>>2];o=p+(e*284|0)+20|0;d=+g[o>>2]-+g[h+56>>2];n=p+(e*284|0)+24|0;m=+g[n>>2]-+g[h+60>>2];g[s+48>>2]=k;g[s+48+4>>2]=d;g[s+48+8>>2]=m;g[s+48+12>>2]=0.0;f=+g[i+(e<<2)>>2];if(f!=0.0){y=c[b+16>>2]|0;Q=f*+g[y+(e<<4)+4>>2];R=f*+g[y+(e<<4)+8>>2];g[s+32>>2]=+g[y+(e<<4)>>2]*f;g[s+32+4>>2]=Q;g[s+32+8>>2]=R;g[s+32+12>>2]=0.0;Vk(h,s+32|0,s+48|0)}f=+g[(c[b+76>>2]|0)+(e<<2)>>2];if(f!=0.0){y=c[(c[b+144>>2]|0)+(e*284|0)+88>>2]|0;Q=+g[o>>2]-+g[y+56>>2];P=+g[n>>2]-+g[y+60>>2];g[s+32>>2]=+g[j>>2]-+g[y+52>>2];g[s+32+4>>2]=Q;g[s+32+8>>2]=P;g[s+32+12>>2]=0.0;t=c[b+36>>2]|0;P=+g[t+(e<<4)>>2]*f;Q=f*+g[t+(e<<4)+4>>2];R=f*+g[t+(e<<4)+8>>2];g[s+16>>2]=P;g[s+16+4>>2]=Q;g[s+16+8>>2]=R;g[s+16+12>>2]=0.0;t=c[b+116>>2]|0;r=c[b+124>>2]|0;L=+g[t+4+(r<<2)>>2];M=+g[t+20+(r<<2)>>2];N=+g[t+36+(r<<2)>>2];O=(L*k+M*d+N*m)*(1.0-+g[p+(e*284|0)+244>>2]);g[s+48>>2]=k-L*O;g[s+48+4>>2]=d-M*O;g[s+48+8>>2]=m-N*O;Vk(t,s+16|0,s+48|0);g[s>>2]=-P;g[s+4>>2]=-Q;g[s+8>>2]=-R;g[s+12>>2]=0.0;Vk(y,s,s+32|0)}e=e+1|0;if((e|0)>=(c[b+136>>2]|0))break;p=c[b+144>>2]|0;i=c[b+56>>2]|0}l=s;return}function vc(b,e,f,h,i,j,k){b=b|0;e=e|0;f=f|0;h=h|0;i=i|0;j=j|0;k=k|0;var m=0.0,n=0.0,o=0.0,p=0,q=0,r=0.0,s=0.0,t=0,u=0,v=0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0;v=l;l=l+9824|0;p=j;q=p+36|0;do{c[p>>2]=0;p=p+4|0}while((p|0)<(q|0));c[v+9680>>2]=b;c[v+9680+4>>2]=f;x=+g[h>>2];K=+g[e>>2];y=+g[h+16>>2];A=+g[e+16>>2];z=+g[h+32>>2];L=+g[e+32>>2];B=+g[e+4>>2];M=+g[e+20>>2];D=+g[e+36>>2];s=+g[e+8>>2];n=+g[e+24>>2];w=+g[e+40>>2];J=+g[h+4>>2];I=+g[h+20>>2];H=+g[h+36>>2];G=+g[h+8>>2];F=+g[h+24>>2];E=+g[h+40>>2];g[v+9680+8>>2]=x*K+y*A+z*L;g[v+9680+12>>2]=x*B+y*M+z*D;g[v+9680+16>>2]=x*s+y*n+z*w;g[v+9680+20>>2]=0.0;g[v+9680+24>>2]=K*J+A*I+L*H;g[v+9680+28>>2]=B*J+M*I+D*H;g[v+9680+32>>2]=s*J+n*I+w*H;g[v+9680+36>>2]=0.0;g[v+9680+40>>2]=K*G+A*F+L*E;g[v+9680+44>>2]=B*G+M*F+D*E;g[v+9680+48>>2]=s*G+n*F+w*E;g[v+9680+52>>2]=0.0;w=+g[h+48>>2]-+g[e+48>>2];n=+g[h+52>>2]-+g[e+52>>2];s=+g[h+56>>2]-+g[e+56>>2];D=+g[e>>2];M=+g[h>>2];B=+g[e+16>>2];L=+g[h+16>>2];A=+g[e+32>>2];K=+g[h+32>>2];z=+g[e+4>>2];y=+g[e+20>>2];x=+g[e+36>>2];m=+g[e+8>>2];o=+g[e+24>>2];r=+g[e+40>>2];g[v+9680+56>>2]=D*M+B*L+A*K;g[v+9680+60>>2]=D*J+B*I+A*H;g[v+9680+64>>2]=D*G+B*F+A*E;g[v+9680+68>>2]=0.0;g[v+9680+72>>2]=M*z+L*y+K*x;g[v+9680+76>>2]=J*z+I*y+H*x;g[v+9680+80>>2]=G*z+F*y+E*x;g[v+9680+84>>2]=0.0;g[v+9680+88>>2]=M*m+L*o+K*r;g[v+9680+92>>2]=J*m+I*o+H*r;g[v+9680+96>>2]=G*m+F*o+E*r;g[v+9680+100>>2]=0.0;g[v+9680+104>>2]=w*D+n*B+s*A;g[v+9680+108>>2]=w*z+n*y+s*x;g[v+9680+112>>2]=w*m+n*o+s*r;g[v+9680+116>>2]=0.0;c[v+9680+120>>2]=k?81:80;c[v+9680+124>>2]=k?0:0;c[v+9296+364>>2]=0;c[v+9296+128>>2]=0;c[v+9296+128+4>>2]=0;c[v+9296+128+8>>2]=0;c[v+9296+128+12>>2]=0;c[v+9296+376>>2]=2;c[v+9296+368>>2]=0;g[v+9296+144>>2]=0.0;r=-+g[i+4>>2];s=-+g[i+8>>2];g[v+9808>>2]=-+g[i>>2];g[v+9808+4>>2]=r;g[v+9808+8>>2]=s;g[v+9808+12>>2]=0.0;switch(wc(v+9296|0,v+9680|0,v+9808|0)|0){case 1:{c[v+9280>>2]=0;c[v+9280+4>>2]=0;c[v+9280+8>>2]=0;c[v+9280+12>>2]=0;c[v>>2]=9;c[v+9276>>2]=0;c[v+40>>2]=0;c[v+40+4>>2]=0;c[v+40+8>>2]=0;c[v+40+12>>2]=0;c[v+40+16>>2]=0;f=0;do{k=128-f+-1|0;c[v+2108+(k*56|0)+44>>2]=0;b=c[v+9288>>2]|0;c[v+2108+(k*56|0)+48>>2]=b;if(b|0)c[b+44>>2]=v+2108+(k*56|0);c[v+9288>>2]=v+2108+(k*56|0);c[v+9292>>2]=(c[v+9292>>2]|0)+1;f=f+1|0}while((f|0)!=128);o=+g[i>>2];r=+g[i+4>>2];n=+g[i+8>>2];t=c[v+9296+372>>2]|0;do if((c[t+32>>2]|0)>>>0>1?dd(v+9296|0)|0:0){b=c[v+9280>>2]|0;if(b|0){p=c[v+9284>>2]|0;q=c[v+9292>>2]|0;do{k=b+44|0;h=b+48|0;f=c[h>>2]|0;if(f|0)c[f+44>>2]=c[k>>2];f=c[k>>2]|0;if(f|0)c[f+48>>2]=c[h>>2];if((c[v+9280>>2]|0)==(b|0))c[v+9280>>2]=c[h>>2];p=p+-1|0;c[b+44>>2]=0;c[h>>2]=c[v+9288>>2];f=c[v+9288>>2]|0;if(f|0)c[f+44>>2]=b;c[v+9288>>2]=b;q=q+1|0;b=c[v+9280>>2]|0}while((b|0)!=0);c[v+9284>>2]=p;c[v+9292>>2]=q}c[v>>2]=0;c[v+9276>>2]=0;b=c[t>>2]|0;f=c[t+12>>2]|0;M=+g[f+16>>2];E=+g[b+16>>2]-M;G=+g[f+20>>2];H=+g[b+20>>2]-G;J=+g[f+24>>2];K=+g[b+24>>2]-J;f=c[t+4>>2]|0;I=+g[f+16>>2]-M;L=+g[f+20>>2]-G;F=+g[f+24>>2]-J;k=c[t+8>>2]|0;M=+g[k+16>>2]-M;G=+g[k+20>>2]-G;J=+g[k+24>>2]-J;if(E*L*J+(H*F*M+K*I*G-E*F*G-H*I*J)-K*L*M<0.0){c[t>>2]=f;c[t+4>>2]=b;h=c[t+16>>2]|0;c[t+16>>2]=c[t+20>>2];c[t+20>>2]=h;h=f}else{h=b;b=f}h=_e(v,h,b,k,1)|0;p=_e(v,c[t+4>>2]|0,c[t>>2]|0,c[t+12>>2]|0,1)|0;q=_e(v,c[t+8>>2]|0,c[t+4>>2]|0,c[t+12>>2]|0,1)|0;i=_e(v,c[t>>2]|0,c[t+8>>2]|0,c[t+12>>2]|0,1)|0;if((c[v+9284>>2]|0)==4){f=c[v+9280>>2]|0;m=+g[f+16>>2];b=c[f+48>>2]|0;if(b){n=m*m;k=f;while(1){m=+g[b+16>>2];f=m*m<n;k=f?b:k;b=c[b+48>>2]|0;if(!b)break;else n=f?m*m:n}f=k;m=+g[k+16>>2]}s=+g[f>>2];r=+g[f+4>>2];o=+g[f+8>>2];n=+g[f+12>>2];b=c[f+20>>2]|0;k=c[f+24>>2]|0;t=c[f+28>>2]|0;a[h+52>>0]=0;c[h+32>>2]=p;a[p+52>>0]=0;c[p+32>>2]=h;a[h+53>>0]=0;c[h+36>>2]=q;a[q+52>>0]=1;c[q+32>>2]=h;a[h+54>>0]=0;c[h+40>>2]=i;a[i+52>>0]=2;c[i+32>>2]=h;a[p+53>>0]=2;c[p+36>>2]=i;a[i+54>>0]=1;c[i+40>>2]=p;a[p+54>>0]=1;c[p+40>>2]=q;a[q+53>>0]=2;c[q+36>>2]=p;a[q+54>>0]=1;c[q+40>>2]=i;a[i+53>>0]=2;c[i+36>>2]=q;c[v>>2]=0;i=f;p=b;h=k;q=t;t=0;while(1){b=c[v+9276>>2]|0;if(b>>>0>=64){u=44;break}c[v+9808>>2]=0;c[v+9808+4>>2]=0;c[v+9808+8>>2]=0;c[v+9276>>2]=b+1;t=t+1|0;a[i+55>>0]=t;f=i+4|0;k=i+8|0;mh(v+9296|0,+g[i>>2],+g[f>>2],+g[k>>2],v+60+(b<<5)|0);if(+g[i>>2]*+g[v+60+(b<<5)+16>>2]+ +g[f>>2]*+g[v+60+(b<<5)+20>>2]+ +g[k>>2]*+g[v+60+(b<<5)+24>>2]-+g[i+16>>2]>9.999999747378752e-05)k=0;else{b=7;u=43;break}do{f=Yg(v,t,v+60+(b<<5)|0,c[i+32+(k<<2)>>2]|0,d[i+52+k>>0]|0,v+9808|0)|0;k=k+1|0}while(f&k>>>0<3);if(!(f&(c[v+9808+8>>2]|0)>>>0>2)){b=4;u=43;break}k=c[v+9808>>2]|0;f=c[v+9808+4>>2]|0;a[k+53>>0]=2;c[k+36>>2]=f;a[f+54>>0]=1;c[f+40>>2]=k;f=i+44|0;k=i+48|0;b=c[k>>2]|0;if(b|0)c[b+44>>2]=c[f>>2];b=c[f>>2]|0;if(b|0)c[b+48>>2]=c[k>>2];if((c[v+9280>>2]|0)==(i|0))c[v+9280>>2]=c[k>>2];c[v+9284>>2]=(c[v+9284>>2]|0)+-1;c[i+44>>2]=0;c[k>>2]=c[v+9288>>2];b=c[v+9288>>2]|0;if(b|0)c[b+44>>2]=i;c[v+9288>>2]=i;c[v+9292>>2]=(c[v+9292>>2]|0)+1;f=c[v+9280>>2]|0;m=+g[f+16>>2];b=c[f+48>>2]|0;if(b){n=m*m;k=f;while(1){m=+g[b+16>>2];f=m*m<n;k=f?b:k;b=c[b+48>>2]|0;if(!b)break;else n=f?m*m:n}f=k;m=+g[k+16>>2]}s=+g[f>>2];r=+g[f+4>>2];o=+g[f+8>>2];n=+g[f+12>>2];k=c[f+20>>2]|0;h=c[f+24>>2]|0;b=c[f+28>>2]|0;if(t>>>0>=255){f=h;break}else{i=f;p=k;q=b}}if((u|0)==43){c[v>>2]=b;k=p;f=h;b=q}else if((u|0)==44){c[v>>2]=6;k=p;f=h;b=q}I=s*m;G=r*m;K=o*m;g[v+40>>2]=s;g[v+44>>2]=r;g[v+48>>2]=o;g[v+52>>2]=n;g[v+56>>2]=m;c[v+36>>2]=3;c[v+4>>2]=k;c[v+8>>2]=f;c[v+12>>2]=b;t=f;L=+g[t+16>>2]-I;E=+g[t+20>>2]-G;D=+g[t+24>>2]-K;i=b;J=+g[i+16>>2]-I;F=+g[i+20>>2]-G;H=+g[i+24>>2]-K;L=+C(+((L*F-E*J)*(L*F-E*J)+((E*H-D*F)*(E*H-D*F)+(D*J-L*H)*(D*J-L*H))));g[v+20>>2]=L;J=+g[i+16>>2]-I;D=+g[i+20>>2]-G;i=k;F=+g[i+16>>2]-I;E=+g[i+20>>2]-G;M=+g[i+24>>2]-K;M=+C(+((J*E-D*F)*(J*E-D*F)+((D*M-H*E)*(D*M-H*E)+(H*F-J*M)*(H*F-J*M))));g[v+24>>2]=M;J=+g[i+16>>2]-I;F=+g[i+20>>2]-G;H=+g[i+24>>2]-K;I=+g[t+16>>2]-I;G=+g[t+20>>2]-G;K=+g[t+24>>2]-K;K=+C(+((J*G-F*I)*(J*G-F*I)+((F*K-H*G)*(F*K-H*G)+(H*I-J*K)*(H*I-J*K))));g[v+20>>2]=L/(K+(L+M));g[v+24>>2]=M/(K+(L+M));g[v+28>>2]=K/(K+(L+M));if((c[v>>2]|0)!=9)if(!(c[v+36>>2]|0)){o=0.0;n=0.0;m=0.0;break}else{h=v+36|0;u=53;break}c[j>>2]=3;e=0;l=v;return e|0}else u=47}else u=47;while(0);if((u|0)==47){c[v>>2]=8;g[v+40>>2]=o;g[v+44>>2]=r;g[v+48>>2]=n;g[v+52>>2]=0.0;m=+C(+(o*o+r*r+n*n));if(m>0.0){g[v+40>>2]=1.0/m*o;g[v+44>>2]=1.0/m*r;g[v+48>>2]=1.0/m*n}else{c[v+40>>2]=1065353216;c[v+44>>2]=0;c[v+48>>2]=0}g[v+52>>2]=0.0;g[v+56>>2]=0.0;c[v+36>>2]=1;c[v+4>>2]=c[t>>2];g[v+20>>2]=1.0;h=v+36|0;u=53}if((u|0)==53){m=0.0;n=0.0;o=0.0;k=0;do{b=c[v+9680+120>>2]|0;u=c[v+9680+124>>2]|0;f=(c[v+9680>>2]|0)+(u>>1)|0;if(u&1)b=c[(c[f>>2]|0)+b>>2]|0;Rb[b&127](v+9808|0,f,c[v+4+(k<<2)>>2]|0);M=+g[v+20+(k<<2)>>2];m=m+ +g[v+9808>>2]*M;n=n+M*+g[v+9808+4>>2];o=o+M*+g[v+9808+8>>2];k=k+1|0}while(k>>>0<(c[h>>2]|0)>>>0)}c[j>>2]=1;M=m*+g[e+16>>2]+n*+g[e+20>>2]+o*+g[e+24>>2]+ +g[e+52>>2];J=m*+g[e+32>>2]+n*+g[e+36>>2]+o*+g[e+40>>2]+ +g[e+56>>2];g[j+4>>2]=m*+g[e>>2]+n*+g[e+4>>2]+o*+g[e+8>>2]+ +g[e+48>>2];g[j+8>>2]=M;g[j+12>>2]=J;g[j+16>>2]=0.0;J=+g[v+40>>2];M=+g[v+56>>2];K=+g[v+44>>2];L=+g[v+48>>2];E=m-J*M;F=n-M*K;G=o-M*L;H=E*+g[e+16>>2]+F*+g[e+20>>2]+G*+g[e+24>>2]+ +g[e+52>>2];I=E*+g[e+32>>2]+F*+g[e+36>>2]+G*+g[e+40>>2]+ +g[e+56>>2];g[j+20>>2]=E*+g[e>>2]+F*+g[e+4>>2]+G*+g[e+8>>2]+ +g[e+48>>2];g[j+24>>2]=H;g[j+28>>2]=I;g[j+32>>2]=0.0;g[j+36>>2]=-J;g[j+40>>2]=-K;g[j+44>>2]=-L;g[j+48>>2]=0.0;g[j+52>>2]=-M;e=1;l=v;return e|0}case 2:{c[j>>2]=2;e=0;l=v;return e|0}default:{e=0;l=v;return e|0}}return 0}function wc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0.0,k=0,m=0,n=0,o=0.0,p=0.0,q=0.0,r=0.0,s=0,t=0,u=0.0,v=0,w=0.0,x=0,y=0,z=0.0,A=0,B=0,D=0.0,E=0.0,F=0.0,G=0.0;B=l;l=l+176|0;c[a+348>>2]=a+220;c[a+352>>2]=a+252;c[a+356>>2]=a+284;c[a+360>>2]=a+316;c[a+364>>2]=4;c[a+368>>2]=0;c[a+376>>2]=0;y=c[b+4>>2]|0;c[a>>2]=c[b>>2];c[a+4>>2]=y;c[a+8>>2]=c[b+8>>2];c[a+8+4>>2]=c[b+8+4>>2];c[a+8+8>>2]=c[b+8+8>>2];c[a+8+12>>2]=c[b+8+12>>2];c[a+24>>2]=c[b+24>>2];c[a+24+4>>2]=c[b+24+4>>2];c[a+24+8>>2]=c[b+24+8>>2];c[a+24+12>>2]=c[b+24+12>>2];c[a+40>>2]=c[b+40>>2];c[a+40+4>>2]=c[b+40+4>>2];c[a+40+8>>2]=c[b+40+8>>2];c[a+40+12>>2]=c[b+40+12>>2];c[a+56>>2]=c[b+56>>2];c[a+56+4>>2]=c[b+56+4>>2];c[a+56+8>>2]=c[b+56+8>>2];c[a+56+12>>2]=c[b+56+12>>2];c[a+72>>2]=c[b+72>>2];c[a+72+4>>2]=c[b+72+4>>2];c[a+72+8>>2]=c[b+72+8>>2];c[a+72+12>>2]=c[b+72+12>>2];c[a+88>>2]=c[b+88>>2];c[a+88+4>>2]=c[b+88+4>>2];c[a+88+8>>2]=c[b+88+8>>2];c[a+88+12>>2]=c[b+88+12>>2];c[a+104>>2]=c[b+104>>2];c[a+104+4>>2]=c[b+104+4>>2];c[a+104+8>>2]=c[b+104+8>>2];c[a+104+12>>2]=c[b+104+12>>2];y=c[b+124>>2]|0;c[a+120>>2]=c[b+120>>2];c[a+124>>2]=y;g[a+144>>2]=0.0;c[a+180>>2]=0;c[a+128>>2]=c[d>>2];c[a+128+4>>2]=c[d+4>>2];c[a+128+8>>2]=c[d+8>>2];c[a+128+12>>2]=c[d+12>>2];e=+g[a+128>>2];f=+g[a+132>>2];h=+g[a+136>>2];if(e*e+f*f+h*h>0.0){g[a+164>>2]=0.0;c[a+364>>2]=3;c[a+148>>2]=a+316;c[a+180>>2]=1;mh(a,-e,-f,-h,a+316|0);d=a+164|0;b=a+148|0}else{g[a+164>>2]=0.0;c[a+364>>2]=3;c[a+148>>2]=a+316;c[a+180>>2]=1;mh(a,1.0,0.0,0.0,a+316|0);d=a+164|0;b=a+148|0}g[d>>2]=1.0;x=(c[b>>2]|0)+16|0;c[a+128>>2]=c[x>>2];c[a+128+4>>2]=c[x+4>>2];c[a+128+8>>2]=c[x+8>>2];c[a+128+12>>2]=c[x+12>>2];c[B+24+48>>2]=c[x>>2];c[B+24+48+4>>2]=c[x+4>>2];c[B+24+48+8>>2]=c[x+8>>2];c[B+24+48+12>>2]=c[x+12>>2];c[B+24+32>>2]=c[x>>2];c[B+24+32+4>>2]=c[x+4>>2];c[B+24+32+8>>2]=c[x+8>>2];c[B+24+32+12>>2]=c[x+12>>2];c[B+24+16>>2]=c[x>>2];c[B+24+16+4>>2]=c[x+4>>2];c[B+24+16+8>>2]=c[x+8>>2];c[B+24+16+12>>2]=c[x+12>>2];c[B+24>>2]=c[x>>2];c[B+24+4>>2]=c[x+4>>2];c[B+24+8>>2]=c[x+8>>2];c[B+24+12>>2]=c[x+12>>2];w=0.0;x=0;y=0;e=e*e+f*f+h*h;a:do{v=c[a+368>>2]|0;f=+g[a+128>>2];h=+g[a+132>>2];i=+g[a+136>>2];o=+C(+(f*f+h*h+i*i));if(o<9.999999747378752e-05){A=6;break}g[a+148+(v*36|0)+16+(c[a+148+(v*36|0)+32>>2]<<2)>>2]=0.0;d=(c[a+364>>2]|0)+-1|0;c[a+364>>2]=d;c[a+148+(v*36|0)+(c[a+148+(v*36|0)+32>>2]<<2)>>2]=c[a+348+(d<<2)>>2];d=c[a+148+(v*36|0)+32>>2]|0;c[a+148+(v*36|0)+32>>2]=d+1;mh(a,-f,-h,-i,c[a+148+(v*36|0)+(d<<2)>>2]|0);d=c[a+148+(v*36|0)+32>>2]|0;b=c[a+148+(v*36|0)+(d+-1<<2)>>2]|0;f=+g[b+16>>2];h=+g[b+20>>2];i=+g[b+24>>2];q=f-+g[B+24>>2];r=h-+g[B+24+4>>2];u=i-+g[B+24+8>>2];if(q*q+r*r+u*u<9.999999747378752e-05){A=9;break}q=f-+g[B+24+16>>2];r=h-+g[B+24+20>>2];u=i-+g[B+24+24>>2];if(q*q+r*r+u*u<9.999999747378752e-05){A=9;break}q=f-+g[B+24+32>>2];r=h-+g[B+24+36>>2];u=i-+g[B+24+40>>2];if(q*q+r*r+u*u<9.999999747378752e-05){A=9;break}q=f-+g[B+24+48>>2];r=h-+g[B+24+52>>2];u=i-+g[B+24+56>>2];if(q*q+r*r+u*u<9.999999747378752e-05){A=9;break}x=x+1&3;t=B+24+(x<<4)|0;c[t>>2]=c[b+16>>2];c[t+4>>2]=c[b+16+4>>2];c[t+8>>2]=c[b+16+8>>2];c[t+12>>2]=c[b+16+12>>2];u=(+g[a+128>>2]*f+ +g[a+132>>2]*h+ +g[a+136>>2]*i)/o;w=u>w?u:w;if(o-w-o*9.999999747378752e-05<=0.0){A=10;break}c[B>>2]=0;b:do switch(d|0){case 2:{t=c[a+148+(v*36|0)>>2]|0;s=c[a+148+(v*36|0)+4>>2]|0;e=+g[s+16>>2];f=+g[t+16>>2];h=+g[s+20>>2];i=+g[t+20>>2];o=+g[s+24>>2];p=+g[t+24>>2];if(!((e-f)*(e-f)+(h-i)*(h-i)+(o-p)*(o-p)>0.0)){A=38;break a}q=-(f*(e-f)+i*(h-i)+p*(o-p))/((e-f)*(e-f)+(h-i)*(h-i)+(o-p)*(o-p));if(q>=1.0){g[B+8>>2]=0.0;g[B+8+4>>2]=1.0;c[B>>2]=2;e=e*e+h*h+o*o;break b}if(!(q<=0.0)){g[B+8+4>>2]=q;g[B+8>>2]=1.0-q;c[B>>2]=3;e=((e-f)*q+f)*((e-f)*q+f)+((h-i)*q+i)*((h-i)*q+i)+((o-p)*q+p)*((o-p)*q+p);break b}else{g[B+8>>2]=1.0;g[B+8+4>>2]=0.0;c[B>>2]=1;e=f*f+i*i+p*p;break b}}case 3:{e=+we((c[a+148+(v*36|0)>>2]|0)+16|0,(c[a+148+(v*36|0)+4>>2]|0)+16|0,(c[a+148+(v*36|0)+8>>2]|0)+16|0,B+8|0,B);break}case 4:{m=c[a+148+(v*36|0)>>2]|0;n=c[a+148+(v*36|0)+4>>2]|0;s=c[a+148+(v*36|0)+8>>2]|0;t=c[a+148+(v*36|0)+12>>2]|0;c[B+152>>2]=m+16;c[B+152+4>>2]=n+16;c[B+152+8>>2]=s+16;c[B+152+12>>2]=t+16;h=+g[m+16>>2];i=+g[t+16>>2];e=+g[m+20>>2];o=+g[t+20>>2];f=+g[m+24>>2];p=+g[t+24>>2];g[B+104>>2]=h-i;g[B+104+4>>2]=e-o;g[B+104+8>>2]=f-p;g[B+104+12>>2]=0.0;D=+g[n+16>>2];F=+g[n+20>>2];r=+g[n+24>>2];g[B+104+16>>2]=D-i;g[B+104+20>>2]=F-o;g[B+104+24>>2]=r-p;g[B+104+28>>2]=0.0;q=+g[s+16>>2];G=+g[s+20>>2];E=+g[s+24>>2];g[B+104+32>>2]=q-i;g[B+104+36>>2]=G-o;g[B+104+40>>2]=E-p;g[B+104+44>>2]=0.0;u=(e-o)*(r-p)*(q-i)+(f-p)*(D-i)*(G-o)-(G-o)*(r-p)*(h-i)-(e-o)*(D-i)*(E-p)+(E-p)*(h-i)*(F-o)-(q-i)*(f-p)*(F-o);if(u!=u|0.0!=0.0|u==0.0|!(u*(f*((D-q)*(e-F)-(F-G)*(h-D))+(h*((F-G)*(f-r)-(r-E)*(e-F))+e*((r-E)*(h-D)-(D-q)*(f-r))))<=0.0))e=-1.0;else{c[B+92>>2]=0;c[B+92+4>>2]=0;c[B+92+8>>2]=0;c[B+88>>2]=0;r=e-o;q=f-p;f=h-i;b=c[B>>2]|0;k=0;e=-1.0;while(1){d=c[5100+(k<<2)>>2]|0;E=+g[B+104+(d<<4)+8>>2];F=+g[B+104+(d<<4)+4>>2];G=+g[B+104+(d<<4)>>2];if(u*((r*E-q*F)*i+o*(q*G-E*f)+(F*f-r*G)*p)>0.0?(z=+we(c[B+152+(k<<2)>>2]|0,c[B+152+(d<<2)>>2]|0,t+16|0,B+92|0,B+88|0),e<0.0|z<e):0){b=c[B+88>>2]|0;c[B+8+(k<<2)>>2]=c[B+92>>2];c[B+8+(d<<2)>>2]=c[B+92+4>>2];g[B+8+(c[5100+(d<<2)>>2]<<2)>>2]=0.0;c[B+8+12>>2]=c[B+92+8>>2];b=(b&2|0?1<<d:0)+(b<<1&8)+(b&1|0?1<<k:0)|0;e=z}d=k+1|0;if((d|0)==3)break;r=+g[B+104+(d<<4)+4>>2];q=+g[B+104+(d<<4)+8>>2];f=+g[B+104+(d<<4)>>2];i=+g[t+16>>2];o=+g[t+20>>2];p=+g[t+24>>2];k=d}c[B>>2]=b;if(e<0.0){c[B>>2]=15;i=+g[s+20>>2];G=+g[n+24>>2];F=+g[t+16>>2];f=+g[s+24>>2];E=+g[n+16>>2];o=+g[t+20>>2];h=+g[s+16>>2];D=+g[t+24>>2];q=+g[n+20>>2];g[B+8>>2]=(i*G*F+f*E*o-o*G*h-i*E*D+D*h*q-F*f*q)/u;e=+g[m+20>>2];p=+g[m+24>>2];r=+g[m+16>>2];g[B+8+4>>2]=(e*f*F+p*h*o-o*f*r-e*h*D+D*r*i-F*p*i)/u;g[B+8+8>>2]=(q*p*F+G*r*o-o*p*E-q*r*D+D*E*e-F*G*e)/u;g[B+8+12>>2]=1.0-((i*G*F+f*E*o-o*G*h-i*E*D+D*h*q-F*f*q)/u+(e*f*F+p*h*o-o*f*r-e*h*D+D*r*i-F*p*i)/u+(q*p*F+G*r*o-o*p*E-q*r*D+D*E*e-F*G*e)/u);e=0.0}}break}default:{}}while(0);if(!(e>=0.0)){A=38;break}c[a+148+((1-v|0)*36|0)+32>>2]=0;c[a+128>>2]=0;c[a+128+4>>2]=0;c[a+128+8>>2]=0;c[a+128+12>>2]=0;c[a+368>>2]=1-v;d=c[a+148+(v*36|0)+32>>2]|0;b=c[B>>2]|0;if(d|0){n=0;do{m=a+148+(v*36|0)+(n<<2)|0;k=c[m>>2]|0;if(!(b&1<<n)){t=c[a+364>>2]|0;c[a+364>>2]=t+1;c[a+348+(t<<2)>>2]=k}else{c[a+148+((1-v|0)*36|0)+(c[a+148+((1-v|0)*36|0)+32>>2]<<2)>>2]=k;s=c[B+8+(n<<2)>>2]|0;t=c[a+148+((1-v|0)*36|0)+32>>2]|0;c[a+148+((1-v|0)*36|0)+32>>2]=t+1;c[a+148+((1-v|0)*36|0)+16+(t<<2)>>2]=s;t=c[m>>2]|0;E=(c[j>>2]=s,+g[j>>2]);F=E*+g[t+20>>2];G=E*+g[t+24>>2];g[a+128>>2]=+g[t+16>>2]*E+ +g[a+128>>2];g[a+132>>2]=F+ +g[a+132>>2];g[a+136>>2]=G+ +g[a+136>>2]}n=n+1|0}while((n|0)!=(d|0))}if((b|0)==15)c[a+376>>2]=1;y=y+1|0;if(y>>>0>=128){A=40;break}d=c[a+376>>2]|0}while(!(d|0));if((A|0)==6){c[a+376>>2]=1;A=41}else if((A|0)==9){y=c[a+368>>2]|0;x=(c[a+148+(y*36|0)+32>>2]|0)+-1|0;c[a+148+(y*36|0)+32>>2]=x;x=c[a+148+(y*36|0)+(x<<2)>>2]|0;y=c[a+364>>2]|0;c[a+364>>2]=y+1;c[a+348+(y<<2)>>2]=x;A=41}else if((A|0)==10){y=c[a+368>>2]|0;x=(c[a+148+(y*36|0)+32>>2]|0)+-1|0;c[a+148+(y*36|0)+32>>2]=x;x=c[a+148+(y*36|0)+(x<<2)>>2]|0;y=c[a+364>>2]|0;c[a+364>>2]=y+1;c[a+348+(y<<2)>>2]=x;A=41}else if((A|0)==38){d=c[a+368>>2]|0;y=(c[a+148+(d*36|0)+32>>2]|0)+-1|0;c[a+148+(d*36|0)+32>>2]=y;y=c[a+148+(d*36|0)+(y<<2)>>2]|0;d=c[a+364>>2]|0;c[a+364>>2]=d+1;c[a+348+(d<<2)>>2]=y;d=c[a+376>>2]|0}else if((A|0)==40){c[a+376>>2]=2;c[a+372>>2]=a+148+((c[a+368>>2]|0)*36|0);a=2;l=B;return a|0}if((A|0)==41)d=c[a+376>>2]|0;c[a+372>>2]=a+148+((c[a+368>>2]|0)*36|0);switch(d|0){case 0:{F=+g[a+128>>2];G=+g[a+132>>2];e=+g[a+136>>2];e=+C(+(F*F+G*G+e*e));break}case 1:{e=0.0;break}default:{a=d;l=B;return a|0}}g[a+144>>2]=e;a=d;l=B;return a|0}function xc(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0,i=0,j=0,k=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0,I=0;s=l;l=l+144|0;n=c[b+48>>2]|0;h=c[b+52>>2]|0;if((h|0?(j=c[h+20>>2]|0,j|0):0)?(lb[c[(c[j>>2]|0)+48>>2]&127](j)|0)&1|0:0){c[s+48>>2]=1065353216;c[s+48+4>>2]=1065353216;c[s+48+8>>2]=0;g[s+48+12>>2]=0.0;k=c[b+8>>2]|0;q=c[(c[b+52>>2]|0)+20>>2]|0;p=c[(c[q>>2]|0)+8>>2]|0;y=+g[d>>2];F=+g[d+4>>2];B=+g[d+8>>2];w=+g[k+20>>2];t=+g[k+24>>2];x=+g[k+28>>2];u=+g[k+36>>2];A=+g[k+40>>2];D=+g[k+44>>2];v=+g[k+52>>2];E=+g[k+56>>2];z=+g[k+60>>2];g[s+24>>2]=y*+g[k+4>>2]+F*+g[k+8>>2]+B*+g[k+12>>2]+v;g[s+24+4>>2]=y*w+F*t+B*x+E;g[s+24+8>>2]=y*u+F*A+B*D+z;g[s+24+12>>2]=0.0;B=+g[d+16>>2];F=+g[d+20>>2];y=+g[d+24>>2];g[s>>2]=B*+g[k+4>>2]+F*+g[k+8>>2]+y*+g[k+12>>2]+v;g[s+4>>2]=B*w+F*t+y*x+E;g[s+8>>2]=B*u+F*A+y*D+z;g[s+12>>2]=0.0;Vb[p&127](q,s+24|0,s,s+48|0);q=c[(c[b+52>>2]|0)+20>>2]|0;p=c[(c[q>>2]|0)+8>>2]|0;z=+g[d+16>>2];D=+g[d+20>>2];y=+g[d+24>>2];A=+g[k+20>>2];F=+g[k+24>>2];u=+g[k+28>>2];B=+g[k+36>>2];E=+g[k+40>>2];x=+g[k+44>>2];t=+g[k+52>>2];w=+g[k+56>>2];v=+g[k+60>>2];g[s+24>>2]=z*+g[k+4>>2]+D*+g[k+8>>2]+y*+g[k+12>>2]+t;g[s+24+4>>2]=z*A+D*F+y*u+w;g[s+24+8>>2]=z*B+D*E+y*x+v;g[s+24+12>>2]=0.0;y=+g[d+32>>2];D=+g[d+36>>2];z=+g[d+40>>2];g[s>>2]=y*+g[k+4>>2]+D*+g[k+8>>2]+z*+g[k+12>>2]+t;g[s+4>>2]=y*A+D*F+z*u+w;g[s+8>>2]=y*B+D*E+z*x+v;g[s+12>>2]=0.0;Vb[p&127](q,s+24|0,s,s+48|0);q=c[(c[b+52>>2]|0)+20>>2]|0;p=c[(c[q>>2]|0)+8>>2]|0;v=+g[d+32>>2];x=+g[d+36>>2];z=+g[d+40>>2];E=+g[k+20>>2];D=+g[k+24>>2];B=+g[k+28>>2];y=+g[k+36>>2];w=+g[k+40>>2];u=+g[k+44>>2];F=+g[k+52>>2];A=+g[k+56>>2];t=+g[k+60>>2];g[s+24>>2]=v*+g[k+4>>2]+x*+g[k+8>>2]+z*+g[k+12>>2]+F;g[s+24+4>>2]=v*E+x*D+z*B+A;g[s+24+8>>2]=v*y+x*w+z*u+t;g[s+24+12>>2]=0.0;z=+g[d>>2];x=+g[d+4>>2];v=+g[d+8>>2];g[s>>2]=z*+g[k+4>>2]+x*+g[k+8>>2]+v*+g[k+12>>2]+F;g[s+4>>2]=z*E+x*D+v*B+A;g[s+8>>2]=z*y+x*w+v*u+t;g[s+12>>2]=0.0;Vb[p&127](q,s+24|0,s,s+48|0)}h=((e<<21|f)+~(f<<15)>>10^(e<<21|f)+~(f<<15))*9|0;h=(c[b+108>>2]|0)+-1&((h>>6^h)+~((h>>6^h)<<11)>>16^(h>>6^h)+~((h>>6^h)<<11));a:do if(h>>>0<(c[b+64>>2]|0)>>>0?(m=c[(c[b+72>>2]|0)+(h<<2)>>2]|0,(m|0)!=-1):0){k=c[b+132>>2]|0;j=m;while(1){if((e<<21|f|0)==(c[k+(j<<2)>>2]|0))break;h=c[(c[b+92>>2]|0)+(j<<2)>>2]|0;if((h|0)==-1)break a;else j=h}h=c[b+112>>2]|0;if(h+(j<<3)|0){q=c[h+(j<<3)+4>>2]|0;r=c[b+8>>2]|0;c[q+8>>2]=c[(c[r+192>>2]|0)+8>>2];p=c[b+4>>2]|0;o=c[p+192>>2]|0;c[s+48>>2]=0;c[s+48+4>>2]=o;c[s+48+8>>2]=p;c[s+48+12>>2]=p+4;c[s+48+16>>2]=-1;c[s+48+20>>2]=-1;c[s+24>>2]=0;c[s+24+4>>2]=q;c[s+24+8>>2]=r;c[s+24+12>>2]=r+4;c[s+24+16>>2]=e;c[s+24+20>>2]=f;r=pb[c[(c[n>>2]|0)+8>>2]&31](n,s+48|0,s+24|0,0)|0;fb[c[(c[r>>2]|0)+8>>2]&31](r,s+48|0,s+24|0,c[b+52>>2]|0,c[b+44>>2]|0);hb[c[c[r>>2]>>2]&511](r);jb[c[(c[n>>2]|0)+60>>2]&127](n,r);l=s;return}}while(0);v=+g[d+16>>2];G=+g[d>>2];w=+g[d+20>>2];t=+g[d+4>>2];x=+g[d+24>>2];u=+g[d+8>>2];y=+g[d+32>>2];A=+g[d+36>>2];D=+g[d+40>>2];z=(w-t)*(D-u)-(x-u)*(A-t);B=(x-u)*(y-G)-(v-G)*(D-u);F=(v-G)*(A-t)-(w-t)*(y-G);E=1.0/+C(+(F*F+(z*z+B*B)));g[s+48>>2]=G+E*z*.05999999865889549;g[s+48+4>>2]=t+E*B*.05999999865889549;g[s+48+8>>2]=E*F*.05999999865889549+u;g[s+48+12>>2]=0.0;g[s+48+16>>2]=E*z*.05999999865889549+v;g[s+48+20>>2]=E*B*.05999999865889549+w;g[s+48+24>>2]=E*F*.05999999865889549+x;g[s+48+28>>2]=0.0;g[s+48+32>>2]=E*z*.05999999865889549+y;g[s+48+36>>2]=E*B*.05999999865889549+A;g[s+48+40>>2]=E*F*.05999999865889549+D;g[s+48+44>>2]=0.0;g[s+48+48>>2]=G-E*z*.05999999865889549;g[s+48+52>>2]=t-E*B*.05999999865889549;g[s+48+56>>2]=u-E*F*.05999999865889549;g[s+48+60>>2]=0.0;g[s+48+64>>2]=v-E*z*.05999999865889549;g[s+48+68>>2]=w-E*B*.05999999865889549;g[s+48+72>>2]=x-E*F*.05999999865889549;g[s+48+76>>2]=0.0;g[s+48+80>>2]=y-E*z*.05999999865889549;g[s+48+84>>2]=A-E*B*.05999999865889549;g[s+48+88>>2]=D-E*F*.05999999865889549;g[s+48+92>>2]=0.0;c[6432]=(c[6432]|0)+1;h=ec(131)|0;if(!h)h=0;else{c[(h+4+15&-16)+-4>>2]=h;h=h+4+15&-16}Wf(h,s+48|0,6,16);q=c[b+8>>2]|0;c[h+8>>2]=c[(c[q+192>>2]|0)+8>>2];d=c[b+4>>2]|0;p=c[d+192>>2]|0;c[s+24>>2]=0;c[s+24+4>>2]=p;c[s+24+8>>2]=d;c[s+24+12>>2]=d+4;c[s+24+16>>2]=-1;c[s+24+20>>2]=-1;c[s>>2]=0;c[s+4>>2]=h;c[s+8>>2]=q;c[s+12>>2]=q+4;c[s+16>>2]=e;c[s+20>>2]=f;q=pb[c[(c[n>>2]|0)+8>>2]&31](n,s+24|0,s,0)|0;fb[c[(c[q>>2]|0)+8>>2]&31](q,s+24|0,s,c[b+52>>2]|0,c[b+44>>2]|0);hb[c[c[q>>2]>>2]&511](q);jb[c[(c[n>>2]|0)+60>>2]&127](n,q);q=((e<<21|f)+~(f<<15)>>10^(e<<21|f)+~(f<<15))*9|0;q=(q>>6^q)+~((q>>6^q)<<11)>>16^(q>>6^q)+~((q>>6^q)<<11);d=c[b+108>>2]|0;b:do if((q&d+-1)>>>0<(c[b+64>>2]|0)>>>0?(i=c[(c[b+72>>2]|0)+((q&d+-1)<<2)>>2]|0,(i|0)!=-1):0){j=c[b+132>>2]|0;while(1){if((e<<21|f|0)==(c[j+(i<<2)>>2]|0))break;i=c[(c[b+92>>2]|0)+(i<<2)>>2]|0;if((i|0)==-1){r=20;break b}}b=c[b+112>>2]|0;c[b+(i<<3)>>2]=e<<21|f;c[b+(i<<3)+4>>2]=h}else r=20;while(0);if((r|0)==20){p=c[b+104>>2]|0;if((p|0)==(d|0)){m=d|0?d<<1:1;if((d|0)<(m|0)){if(!m){j=d;k=0}else{c[6432]=(c[6432]|0)+1;i=ec((m<<3|3)+16|0)|0;if(!i)i=0;else{c[(i+4+15&-16)+-4>>2]=i;i=i+4+15&-16}j=c[b+104>>2]|0;k=i}if((j|0)>0){i=0;do{I=(c[b+112>>2]|0)+(i<<3)|0;H=c[I+4>>2]|0;n=k+(i<<3)|0;c[n>>2]=c[I>>2];c[n+4>>2]=H;i=i+1|0}while((i|0)!=(j|0))}i=c[b+112>>2]|0;if(i|0){if(a[b+116>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[b+112>>2]=0}a[b+116>>0]=1;c[b+112>>2]=k;c[b+108>>2]=m;i=c[b+104>>2]|0}else i=d}else i=p;I=c[b+112>>2]|0;c[I+(i<<3)>>2]=e<<21|f;c[I+(i<<3)+4>>2]=h;c[b+104>>2]=(c[b+104>>2]|0)+1;h=c[b+124>>2]|0;if((h|0)==(c[b+128>>2]|0)?(o=h|0?h<<1:1,(h|0)<(o|0)):0){if(!o)i=0;else{c[6432]=(c[6432]|0)+1;h=ec((o<<2|3)+16|0)|0;if(!h)i=0;else{c[(h+4+15&-16)+-4>>2]=h;i=h+4+15&-16}h=c[b+124>>2]|0}k=c[b+132>>2]|0;if((h|0)<=0)if(!k)h=b+136|0;else r=43;else{j=0;do{c[i+(j<<2)>>2]=c[k+(j<<2)>>2];j=j+1|0}while((j|0)!=(h|0));r=43}if((r|0)==43){if(a[b+136>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[k+-4>>2]|0)}c[b+132>>2]=0;h=b+136|0}a[h>>0]=1;c[b+132>>2]=i;c[b+128>>2]=o;h=c[b+124>>2]|0}c[(c[b+132>>2]|0)+(h<<2)>>2]=e<<21|f;c[b+124>>2]=(c[b+124>>2]|0)+1;n=c[b+108>>2]|0;if((d|0)<(n|0)){o=c[b+64>>2]|0;if((o|0)<(n|0)){if((c[b+68>>2]|0)<(n|0)){if(!n){k=o;h=0}else{c[6432]=(c[6432]|0)+1;h=ec((n<<2|3)+16|0)|0;if(!h)h=0;else{c[(h+4+15&-16)+-4>>2]=h;h=h+4+15&-16}k=c[b+64>>2]|0}j=c[b+72>>2]|0;if((k|0)<=0)if(!j)i=b+76|0;else r=59;else{i=0;do{c[h+(i<<2)>>2]=c[j+(i<<2)>>2];i=i+1|0}while((i|0)!=(k|0));r=59}if((r|0)==59)if(!(a[b+76>>0]|0))i=b+76|0;else{c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0);i=b+76|0}a[i>>0]=1;c[b+72>>2]=h;c[b+68>>2]=n;d=b+72|0}else{h=c[b+72>>2]|0;d=b+72|0}Hk(h+(o<<2)|0,0,(n<<2)-(o<<2)|0)|0;c[b+64>>2]=n;m=c[b+84>>2]|0;if((m|0)<(n|0)){if((c[b+88>>2]|0)<(n|0)){if(!n){k=m;h=0}else{c[6432]=(c[6432]|0)+1;h=ec((n<<2|3)+16|0)|0;if(!h)h=0;else{c[(h+4+15&-16)+-4>>2]=h;h=h+4+15&-16}k=c[b+84>>2]|0}j=c[b+92>>2]|0;if((k|0)<=0)if(!j)i=b+96|0;else r=73;else{i=0;do{c[h+(i<<2)>>2]=c[j+(i<<2)>>2];i=i+1|0}while((i|0)!=(k|0));r=73}if((r|0)==73)if(!(a[b+96>>0]|0))i=b+96|0;else{c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0);i=b+96|0}a[i>>0]=1;c[b+92>>2]=h;c[b+88>>2]=n}else h=c[b+92>>2]|0;Hk(h+(m<<2)|0,0,(n<<2)-(m<<2)|0)|0}c[b+84>>2]=n;if((n|0)>0){Hk(c[d>>2]|0,-1,n<<2|0)|0;Hk(c[b+92>>2]|0,-1,n<<2|0)|0}if((o|0)>0){k=c[b+132>>2]|0;h=c[d>>2]|0;i=c[b+92>>2]|0;j=0;do{I=c[k+(j<<2)>>2]|0;I=(I+~(I<<15)>>10^I+~(I<<15))*9|0;I=h+((((I>>6^I)+~((I>>6^I)<<11)>>16^(I>>6^I)+~((I>>6^I)<<11))&(c[b+108>>2]|0)+-1)<<2)|0;c[i+(j<<2)>>2]=c[I>>2];c[I>>2]=j;j=j+1|0}while((j|0)!=(o|0))}}h=q&(c[b+108>>2]|0)+-1}else h=q&d+-1;I=(c[b+72>>2]|0)+(h<<2)|0;c[(c[b+92>>2]|0)+(p<<2)>>2]=c[I>>2];c[I>>2]=p}l=s;return}function yc(b,d){b=b|0;d=d|0;var e=0,f=0,h=0,i=0,j=0,k=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;x=l;l=l+16|0;Yi(12214);j=c[b+212>>2]|0;i=c[b+180>>2]|0;if((i|0)<(j|0)){if((c[b+184>>2]|0)<(j|0)){if(!j){f=i;h=0}else{c[6432]=(c[6432]|0)+1;e=ec((j<<2|3)+16|0)|0;if(!e)e=0;else{c[(e+4+15&-16)+-4>>2]=e;e=e+4+15&-16}f=c[b+180>>2]|0;h=e}if((f|0)>0){e=0;do{c[h+(e<<2)>>2]=c[(c[b+188>>2]|0)+(e<<2)>>2];e=e+1|0}while((e|0)!=(f|0))}e=c[b+188>>2]|0;if(e|0){if(a[b+192>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}c[b+188>>2]=0}a[b+192>>0]=1;c[b+188>>2]=h;c[b+184>>2]=j;f=b+188|0}else f=b+188|0;e=i;do{c[(c[f>>2]|0)+(e<<2)>>2]=0;e=e+1|0}while((e|0)!=(j|0))}else f=b+188|0;c[b+180>>2]=j;e=0;while(1){if((e|0)>=(lb[c[(c[b>>2]|0)+104>>2]&127](b)|0))break;c[(c[f>>2]|0)+(e<<2)>>2]=c[(c[b+220>>2]|0)+(e<<2)>>2];e=e+1|0}e=c[b+180>>2]|0;if((e|0)>1)pi(b+176|0,0,e+-1|0);if(!(lb[c[(c[b>>2]|0)+104>>2]&127](b)|0))e=0;else e=c[f>>2]|0;h=c[b+196>>2]|0;t=c[b+180>>2]|0;u=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;c[h+4>>2]=d;c[h+12>>2]=e;c[h+16>>2]=t;c[h+20>>2]=u;e=c[h+32>>2]|0;if((e|0)<0){if((c[h+36>>2]|0)<0){f=c[h+40>>2]|0;if(f|0){if(a[h+44>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[h+40>>2]=0}a[h+44>>0]=1;c[h+40>>2]=0;c[h+36>>2]=0}do{c[(c[h+40>>2]|0)+(e<<2)>>2]=0;e=e+1|0}while((e|0)!=0)}c[h+32>>2]=0;e=c[h+52>>2]|0;if((e|0)<0){if((c[h+56>>2]|0)<0){f=c[h+60>>2]|0;if(f|0){if(a[h+64>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[h+60>>2]=0}a[h+64>>0]=1;c[h+60>>2]=0;c[h+56>>2]=0}do{c[(c[h+60>>2]|0)+(e<<2)>>2]=0;e=e+1|0}while((e|0)!=0)}c[h+52>>2]=0;e=c[h+72>>2]|0;if((e|0)<0){if((c[h+76>>2]|0)<0){f=c[h+80>>2]|0;if(f|0){if(a[h+84>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[h+80>>2]=0}a[h+84>>0]=1;c[h+80>>2]=0;c[h+76>>2]=0}do{c[(c[h+80>>2]|0)+(e<<2)>>2]=0;e=e+1|0}while((e|0)!=0)}c[h+72>>2]=0;u=c[b+200>>2]|0;e=c[(c[u>>2]|0)+8>>2]|0;s=c[b+8>>2]|0;t=c[b+24>>2]|0;t=lb[c[(c[t>>2]|0)+36>>2]&127](t)|0;Rb[e&127](u,s,t);t=c[b+204>>2]|0;s=c[b+24>>2]|0;u=c[b+196>>2]|0;Yi(14026);e=c[t+28>>2]|0;if((e|0)<0){if((c[t+32>>2]|0)<0){f=c[t+36>>2]|0;if(f|0){if(a[t+40>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[t+36>>2]=0}a[t+40>>0]=1;c[t+36>>2]=0;c[t+32>>2]=0}do{c[(c[t+36>>2]|0)+(e<<2)>>2]=0;e=e+1|0}while((e|0)!=0)}c[t+28>>2]=0;i=c[t+8>>2]|0;if((i|0)>0){j=c[t+16>>2]|0;k=0;do{m=j+(k<<3)|0;e=c[m>>2]|0;if((e|0)==(k|0))e=k;else{h=m;do{f=j+(e<<3)|0;c[h>>2]=c[f>>2];f=c[f>>2]|0;h=j+(f<<3)|0;e=c[h>>2]|0}while((f|0)!=(e|0));e=f}c[m>>2]=e;k=k+1|0}while((k|0)!=(i|0));if((i|0)>1){$i(t+4|0,0,i+-1|0);i=c[t+8>>2]|0}if((i|0)>0){k=c[t+16>>2]|0;f=0;while(1){m=c[k+(f<<3)>>2]|0;q=f;while(1){p=q+1|0;if((p|0)>=(i|0)){o=0;break}if((c[k+(p<<3)>>2]|0)==(m|0))q=p;else{o=1;break}}a:do if((f|0)<=(q|0)){n=c[b+16>>2]|0;e=1;j=f;while(1){h=c[n+(c[k+(j<<3)+4>>2]<<2)>>2]|0;if((c[h+208>>2]|0)==(m|0)){h=c[h+216>>2]|0;e=(h|0)!=4&(e&(h|0)!=1)}if((j|0)<(q|0))j=j+1|0;else break}if(e)while(1){e=c[n+(c[k+(f<<3)+4>>2]<<2)>>2]|0;if((c[e+208>>2]|0)==(m|0)?(c[e+216>>2]&-2|0)!=4:0)c[e+216>>2]=2;if((f|0)>=(q|0))break a;f=f+1|0}else while(1){e=c[n+(c[k+(f<<3)+4>>2]<<2)>>2]|0;if((c[e+208>>2]|0)==(m|0)?(c[e+216>>2]|0)==2:0){c[e+216>>2]=3;g[e+220>>2]=0.0}if((f|0)>=(q|0))break a;f=f+1|0}}while(0);if(o)f=p;else break}}}i=lb[c[(c[s>>2]|0)+36>>2]&127](s)|0;if((i|0)>0){k=0;do{j=Gb[c[(c[s>>2]|0)+40>>2]&31](s,k)|0;f=c[j+740>>2]|0;h=c[j+744>>2]|0;if((f|0)!=0?(c[f+216>>2]|0)!=2:0)e=93;else e=91;if(((e|0)==91?(e=0,h|0):0)?(c[h+216>>2]|0)!=2:0)e=93;if((e|0)==93){e=c[f+204>>2]|0;if((e&2|0?((e&4|0)==0?(c[f+216>>2]|0)!=2:0):0)?(c[h+204>>2]&3|0)==0:0){if((c[h+216>>2]&-2|0)!=4)c[h+216>>2]=1;g[h+220>>2]=0.0}q=c[h+204>>2]|0;if(q&2|0?((q&4|e&3|0)==0?(c[h+216>>2]|0)!=2:0):0){if((c[f+216>>2]&-2|0)!=4)c[f+216>>2]=1;g[f+220>>2]=0.0}if(a[t+64>>0]|0?vb[c[(c[s>>2]|0)+28>>2]&63](s,f,h)|0:0){e=c[t+28>>2]|0;if((e|0)==(c[t+32>>2]|0)?(r=e|0?e<<1:1,(e|0)<(r|0)):0){if(!r)f=0;else{c[6432]=(c[6432]|0)+1;e=ec((r<<2|3)+16|0)|0;if(!e)f=0;else{c[(e+4+15&-16)+-4>>2]=e;f=e+4+15&-16}e=c[t+28>>2]|0}if((e|0)>0){h=0;do{c[f+(h<<2)>>2]=c[(c[t+36>>2]|0)+(h<<2)>>2];h=h+1|0}while((h|0)!=(e|0))}h=c[t+36>>2]|0;if(h){if(a[t+40>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0);e=c[t+28>>2]|0}c[t+36>>2]=0}a[t+40>>0]=1;c[t+36>>2]=f;c[t+32>>2]=r}c[(c[t+36>>2]|0)+(e<<2)>>2]=j;c[t+28>>2]=e+1}}k=k+1|0}while((k|0)<(i|0))}e=c[2395]|0;r=(c[e+16>>2]|0)+-1|0;c[e+16>>2]=r;do if(!r){if(c[e+4>>2]|0){Va(x|0,0)|0;r=c[6431]|0;g[e+8>>2]=+g[e+8>>2]+ +(((c[x+4>>2]|0)-(c[r+4>>2]|0)+(((c[x>>2]|0)-(c[r>>2]|0)|0)*1e6|0)-(c[e+12>>2]|0)|0)>>>0)/1.0e3;if(c[e+16>>2]|0)break;e=c[2395]|0}c[2395]=c[e+20>>2]}while(0);r=c[t+8>>2]|0;Yi(14054);if(a[t+64>>0]|0){p=c[t+28>>2]|0;if((p|0)>1)li(t+24|0,0,p+-1|0);if((r|0)>0){n=1;f=0;q=0;while(1){e=c[t+16>>2]|0;o=c[e+(f<<3)>>2]|0;b:do if((f|0)<(r|0)){j=c[t+48>>2]|0;i=c[t+52>>2]|0;h=1;while(1){m=c[(c[b+16>>2]|0)+(c[e+(f<<3)+4>>2]<<2)>>2]|0;do if((j|0)==(i|0)){k=i|0?i<<1:1;if((i|0)>=(k|0)){e=i;break}if(!k){e=i;i=0}else{c[6432]=(c[6432]|0)+1;e=ec((k<<2|3)+16|0)|0;if(!e)i=0;else{c[(e+4+15&-16)+-4>>2]=e;i=e+4+15&-16}e=c[t+48>>2]|0}if((e|0)>0){j=0;do{c[i+(j<<2)>>2]=c[(c[t+56>>2]|0)+(j<<2)>>2];j=j+1|0}while((j|0)!=(e|0))}j=c[t+56>>2]|0;if(j){if(a[t+60>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0);e=c[t+48>>2]|0}c[t+56>>2]=0}a[t+60>>0]=1;c[t+56>>2]=i;c[t+52>>2]=k;i=k}else e=j;while(0);c[(c[t+56>>2]|0)+(e<<2)>>2]=m;j=e+1|0;c[t+48>>2]=j;s=c[m+216>>2]|0;h=h&((s|0)==2|(s|0)==5);f=f+1|0;if((f|0)>=(r|0)){j=f;break b}e=c[t+16>>2]|0;if((c[e+(f<<3)>>2]|0)!=(o|0)){j=f;break}}}else{j=f;h=1}while(0);if((q|0)<(p|0)?(v=c[t+36>>2]|0,w=v+(q<<2)|0,s=c[w>>2]|0,m=c[s+740>>2]|0,(c[((c[m+208>>2]|0)>-1?m:c[s+744>>2]|0)+208>>2]|0)==(o|0)):0){e=q;do{e=e+1|0;if((e|0)>=(p|0))break;s=c[v+(e<<2)>>2]|0;n=c[s+740>>2]|0}while((o|0)==(c[((c[n+208>>2]|0)>-1?n:c[s+744>>2]|0)+208>>2]|0));i=e;e=e-q|0;f=w}else{i=n;e=0;f=0}if(!h)xb[c[(c[u>>2]|0)+8>>2]&7](u,c[t+56>>2]|0,c[t+48>>2]|0,f,e,o);q=(e|0)==0?q:i;e=c[t+48>>2]|0;if((e|0)<0){if((c[t+52>>2]|0)<0){f=c[t+56>>2]|0;if(f|0){if(a[t+60>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[t+56>>2]=0}a[t+60>>0]=1;c[t+56>>2]=0;c[t+52>>2]=0}do{c[(c[t+56>>2]|0)+(e<<2)>>2]=0;e=e+1|0}while((e|0)!=0)}c[t+48>>2]=0;if((j|0)>=(r|0))break;else{n=i;f=j}}}}else{v=lb[c[(c[s>>2]|0)+44>>2]&127](s)|0;w=lb[c[(c[s>>2]|0)+36>>2]&127](s)|0;xb[c[(c[u>>2]|0)+8>>2]&7](u,c[b+16>>2]|0,c[b+8>>2]|0,v,w,-1)}e=c[2395]|0;w=(c[e+16>>2]|0)+-1|0;c[e+16>>2]=w;do if(!w){if(c[e+4>>2]|0){Va(x|0,0)|0;w=c[6431]|0;g[e+8>>2]=+g[e+8>>2]+ +(((c[x+4>>2]|0)-(c[w+4>>2]|0)+(((c[x>>2]|0)-(c[w>>2]|0)|0)*1e6|0)-(c[e+12>>2]|0)|0)>>>0)/1.0e3;if(c[e+16>>2]|0)break;e=c[2395]|0}c[2395]=c[e+20>>2]}while(0);Pg(c[b+196>>2]|0);e=c[b+200>>2]|0;Rb[c[(c[e>>2]|0)+16>>2]&127](e,d,c[b+72>>2]|0);e=c[2395]|0;b=(c[e+16>>2]|0)+-1|0;c[e+16>>2]=b;if(b|0){l=x;return}do if(c[e+4>>2]|0){Va(x|0,0)|0;b=c[6431]|0;g[e+8>>2]=+g[e+8>>2]+ +(((c[x+4>>2]|0)-(c[b+4>>2]|0)+(((c[x>>2]|0)-(c[b>>2]|0)|0)*1e6|0)-(c[e+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[e+16>>2]|0)){e=c[2395]|0;break}else{l=x;return}}while(0);c[2395]=c[e+20>>2];l=x;return}function zc(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0,i=0,j=0,k=0,m=0,n=0,o=0.0,p=0.0,q=0.0,r=0.0,s=0,t=0,u=0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0;u=l;l=l+48|0;A=1.0/+g[b+108>>2];B=1.0/+g[b+112>>2];C=1.0/+g[b+116>>2];v=+g[b+48>>2];w=A*+g[e>>2]+v;p=+g[b+52>>2];o=B*+g[e+4>>2]+p;r=+g[b+56>>2];q=C*+g[e+8>>2]+r;v=A*+g[f>>2]+v;p=B*+g[f+4>>2]+p;r=C*+g[f+8>>2]+r;C=+g[b+16>>2];w=w<C?C:w;B=+g[b+20>>2];o=o<B?B:o;A=+g[b+24>>2];q=q<A?A:q;z=+g[b+32>>2];w=z<w?z:w;y=+g[b+36>>2];o=y<o?y:o;x=+g[b+40>>2];q=x<q?x:q;v=v<C?C:v;p=p<B?B:p;r=r<A?A:r;v=z<v?z:v;p=y<p?y:p;r=x<r?x:r;m=~~(w+(w<0.0?-.5:.5))+-1|0;h=~~(v+(v<0.0?-.5:.5))+1|0;n=~~(o+(o<0.0?-.5:.5))+-1|0;i=~~(p+(p<0.0?-.5:.5))+1|0;k=~~(q+(q<0.0?-.5:.5))+-1|0;f=~~(r+(r<0.0?-.5:.5))+1|0;j=(c[b+64>>2]|0)+-1|0;e=(c[b+68>>2]|0)+-1|0;switch(c[b+104>>2]|0){case 0:{e=(f|0)<(e|0)?f:e;j=(i|0)<(j|0)?i:j;f=(k|0)>0?k:0;s=(n|0)>0?n:0;break}case 1:{e=(f|0)<(e|0)?f:e;j=(h|0)<(j|0)?h:j;f=(k|0)>0?k:0;s=(m|0)>0?m:0;break}case 2:{e=(i|0)<(e|0)?i:e;j=(h|0)<(j|0)?h:j;f=(n|0)>0?n:0;s=(m|0)>0?m:0;break}default:{f=0;s=0}}if((f|0)>=(e|0)){l=u;return}n=(s|0)<(j|0);k=f;while(1){if(n){m=(k&1|0)==0;f=k+1|0;r=+(k|0);i=s;while(1){do if(!(a[b+100>>0]|0)){if(a[b+101>>0]|0?(i+k&1|0)==0:0){t=16;break}if(!(m&(a[b+102>>0]|0)!=0)){o=+Hb[c[(c[b>>2]|0)+68>>2]&15](b,i,k);switch(c[b+104>>2]|0){case 0:{q=+(i|0)-+g[b+80>>2]*.5;p=o-+g[b+48>>2];o=r-+g[b+84>>2]*.5;t=52;break}case 1:{q=o-+g[b+52>>2];p=+(i|0)-+g[b+80>>2]*.5;o=r-+g[b+84>>2]*.5;t=52;break}case 2:{q=r-+g[b+84>>2]*.5;p=+(i|0)-+g[b+80>>2]*.5;o=o-+g[b+56>>2];t=52;break}default:{p=+g[u>>2];q=+g[u+4>>2];o=+g[u+8>>2]}}if((t|0)==52){t=0;g[u>>2]=p;g[u+4>>2]=q;g[u+8>>2]=o;g[u+12>>2]=0.0}g[u>>2]=p*+g[b+108>>2];g[u+4>>2]=q*+g[b+112>>2];g[u+8>>2]=o*+g[b+116>>2];o=+Hb[c[(c[b>>2]|0)+68>>2]&15](b,i,f);switch(c[b+104>>2]|0){case 0:{q=+(i|0)-+g[b+80>>2]*.5;p=o-+g[b+48>>2];o=+(f|0)-+g[b+84>>2]*.5;t=58;break}case 1:{q=o-+g[b+52>>2];p=+(i|0)-+g[b+80>>2]*.5;o=+(f|0)-+g[b+84>>2]*.5;t=58;break}case 2:{q=+(f|0)-+g[b+84>>2]*.5;p=+(i|0)-+g[b+80>>2]*.5;o=o-+g[b+56>>2];t=58;break}default:{p=+g[u+16>>2];q=+g[u+20>>2];o=+g[u+24>>2]}}if((t|0)==58){t=0;g[u+16>>2]=p;g[u+20>>2]=q;g[u+24>>2]=o;g[u+28>>2]=0.0}g[u+16>>2]=p*+g[b+108>>2];g[u+20>>2]=q*+g[b+112>>2];g[u+24>>2]=o*+g[b+116>>2];h=i+1|0;o=+Hb[c[(c[b>>2]|0)+68>>2]&15](b,h,k);switch(c[b+104>>2]|0){case 0:{q=+(h|0)-+g[b+80>>2]*.5;p=o-+g[b+48>>2];o=r-+g[b+84>>2]*.5;t=64;break}case 1:{q=o-+g[b+52>>2];p=+(h|0)-+g[b+80>>2]*.5;o=r-+g[b+84>>2]*.5;t=64;break}case 2:{q=r-+g[b+84>>2]*.5;p=+(h|0)-+g[b+80>>2]*.5;o=o-+g[b+56>>2];t=64;break}default:{p=+g[u+32>>2];q=+g[u+36>>2];o=+g[u+40>>2]}}if((t|0)==64){t=0;g[u+32>>2]=p;g[u+36>>2]=q;g[u+40>>2]=o;g[u+44>>2]=0.0}g[u+32>>2]=p*+g[b+108>>2];g[u+36>>2]=q*+g[b+112>>2];g[u+40>>2]=o*+g[b+116>>2];Vb[c[(c[d>>2]|0)+8>>2]&127](d,u,i,k);o=+Hb[c[(c[b>>2]|0)+68>>2]&15](b,h,k);switch(c[b+104>>2]|0){case 0:{q=+(h|0)-+g[b+80>>2]*.5;p=o-+g[b+48>>2];o=r-+g[b+84>>2]*.5;t=70;break}case 1:{q=o-+g[b+52>>2];p=+(h|0)-+g[b+80>>2]*.5;o=r-+g[b+84>>2]*.5;t=70;break}case 2:{q=r-+g[b+84>>2]*.5;p=+(h|0)-+g[b+80>>2]*.5;o=o-+g[b+56>>2];t=70;break}default:{p=+g[u>>2];q=+g[u+4>>2];o=+g[u+8>>2]}}if((t|0)==70){t=0;g[u>>2]=p;g[u+4>>2]=q;g[u+8>>2]=o;g[u+12>>2]=0.0}g[u>>2]=p*+g[b+108>>2];g[u+4>>2]=q*+g[b+112>>2];g[u+8>>2]=o*+g[b+116>>2];o=+Hb[c[(c[b>>2]|0)+68>>2]&15](b,h,f);switch(c[b+104>>2]|0){case 0:{q=+(h|0)-+g[b+80>>2]*.5;p=o-+g[b+48>>2];o=+(f|0)-+g[b+84>>2]*.5;t=76;break}case 1:{q=o-+g[b+52>>2];p=+(h|0)-+g[b+80>>2]*.5;o=+(f|0)-+g[b+84>>2]*.5;t=76;break}case 2:{q=+(f|0)-+g[b+84>>2]*.5;p=+(h|0)-+g[b+80>>2]*.5;o=o-+g[b+56>>2];t=76;break}default:{p=+g[u+32>>2];q=+g[u+36>>2];o=+g[u+40>>2]}}if((t|0)==76){t=0;g[u+32>>2]=p;g[u+36>>2]=q;g[u+40>>2]=o;g[u+44>>2]=0.0}g[u+32>>2]=p*+g[b+108>>2];g[u+36>>2]=q*+g[b+112>>2];g[u+40>>2]=o*+g[b+116>>2];Vb[c[(c[d>>2]|0)+8>>2]&127](d,u,i,k)}else t=16}else t=16;while(0);if((t|0)==16){t=0;o=+Hb[c[(c[b>>2]|0)+68>>2]&15](b,i,k);switch(c[b+104>>2]|0){case 0:{q=+(i|0)-+g[b+80>>2]*.5;p=o-+g[b+48>>2];o=r-+g[b+84>>2]*.5;t=21;break}case 1:{q=o-+g[b+52>>2];p=+(i|0)-+g[b+80>>2]*.5;o=r-+g[b+84>>2]*.5;t=21;break}case 2:{q=r-+g[b+84>>2]*.5;p=+(i|0)-+g[b+80>>2]*.5;o=o-+g[b+56>>2];t=21;break}default:{p=+g[u>>2];q=+g[u+4>>2];o=+g[u+8>>2]}}if((t|0)==21){t=0;g[u>>2]=p;g[u+4>>2]=q;g[u+8>>2]=o;g[u+12>>2]=0.0}g[u>>2]=p*+g[b+108>>2];g[u+4>>2]=q*+g[b+112>>2];g[u+8>>2]=o*+g[b+116>>2];h=i+1|0;o=+Hb[c[(c[b>>2]|0)+68>>2]&15](b,h,k);switch(c[b+104>>2]|0){case 0:{q=+(h|0)-+g[b+80>>2]*.5;p=o-+g[b+48>>2];o=r-+g[b+84>>2]*.5;t=27;break}case 1:{q=o-+g[b+52>>2];p=+(h|0)-+g[b+80>>2]*.5;o=r-+g[b+84>>2]*.5;t=27;break}case 2:{q=r-+g[b+84>>2]*.5;p=+(h|0)-+g[b+80>>2]*.5;o=o-+g[b+56>>2];t=27;break}default:{p=+g[u+16>>2];q=+g[u+20>>2];o=+g[u+24>>2]}}if((t|0)==27){t=0;g[u+16>>2]=p;g[u+20>>2]=q;g[u+24>>2]=o;g[u+28>>2]=0.0}g[u+16>>2]=p*+g[b+108>>2];g[u+20>>2]=q*+g[b+112>>2];g[u+24>>2]=o*+g[b+116>>2];o=+Hb[c[(c[b>>2]|0)+68>>2]&15](b,h,f);switch(c[b+104>>2]|0){case 0:{q=+(h|0)-+g[b+80>>2]*.5;p=o-+g[b+48>>2];o=+(f|0)-+g[b+84>>2]*.5;t=33;break}case 1:{q=o-+g[b+52>>2];p=+(h|0)-+g[b+80>>2]*.5;o=+(f|0)-+g[b+84>>2]*.5;t=33;break}case 2:{q=+(f|0)-+g[b+84>>2]*.5;p=+(h|0)-+g[b+80>>2]*.5;o=o-+g[b+56>>2];t=33;break}default:{p=+g[u+32>>2];q=+g[u+36>>2];o=+g[u+40>>2]}}if((t|0)==33){t=0;g[u+32>>2]=p;g[u+36>>2]=q;g[u+40>>2]=o;g[u+44>>2]=0.0}g[u+32>>2]=p*+g[b+108>>2];g[u+36>>2]=q*+g[b+112>>2];g[u+40>>2]=o*+g[b+116>>2];Vb[c[(c[d>>2]|0)+8>>2]&127](d,u,i,k);o=+Hb[c[(c[b>>2]|0)+68>>2]&15](b,h,f);switch(c[b+104>>2]|0){case 0:{q=+(h|0)-+g[b+80>>2]*.5;p=o-+g[b+48>>2];o=+(f|0)-+g[b+84>>2]*.5;t=39;break}case 1:{q=o-+g[b+52>>2];p=+(h|0)-+g[b+80>>2]*.5;o=+(f|0)-+g[b+84>>2]*.5;t=39;break}case 2:{q=+(f|0)-+g[b+84>>2]*.5;p=+(h|0)-+g[b+80>>2]*.5;o=o-+g[b+56>>2];t=39;break}default:{p=+g[u+16>>2];q=+g[u+20>>2];o=+g[u+24>>2]}}if((t|0)==39){t=0;g[u+16>>2]=p;g[u+20>>2]=q;g[u+24>>2]=o;g[u+28>>2]=0.0}g[u+16>>2]=p*+g[b+108>>2];g[u+20>>2]=q*+g[b+112>>2];g[u+24>>2]=o*+g[b+116>>2];o=+Hb[c[(c[b>>2]|0)+68>>2]&15](b,i,f);switch(c[b+104>>2]|0){case 0:{q=+(i|0)-+g[b+80>>2]*.5;p=o-+g[b+48>>2];o=+(f|0)-+g[b+84>>2]*.5;t=45;break}case 1:{q=o-+g[b+52>>2];p=+(i|0)-+g[b+80>>2]*.5;o=+(f|0)-+g[b+84>>2]*.5;t=45;break}case 2:{q=+(f|0)-+g[b+84>>2]*.5;p=+(i|0)-+g[b+80>>2]*.5;o=o-+g[b+56>>2];t=45;break}default:{p=+g[u+32>>2];q=+g[u+36>>2];o=+g[u+40>>2]}}if((t|0)==45){t=0;g[u+32>>2]=p;g[u+36>>2]=q;g[u+40>>2]=o;g[u+44>>2]=0.0}g[u+32>>2]=p*+g[b+108>>2];g[u+36>>2]=q*+g[b+112>>2];g[u+40>>2]=o*+g[b+116>>2];Vb[c[(c[d>>2]|0)+8>>2]&127](d,u,i,k)}if((h|0)==(j|0))break;else i=h}}else f=k+1|0;if((f|0)==(e|0))break;else k=f}l=u;return}\nfunction Wb(d,f){d=d|0;f=f|0;var h=0,i=0,k=0,m=0,n=0,o=0,p=0,q=0.0,r=0.0,s=0.0,t=0,u=0.0,v=0.0,w=0.0,x=0.0,y=0,z=0,A=0,D=0,E=0.0,F=0.0,G=0,H=0,I=0.0,J=0.0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0.0,X=0,Y=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0.0,ka=0.0,la=0;ia=l;l=l+192|0;h=c[d+52>>2]|0;if(h|0?(hb[c[c[h>>2]>>2]&511](h),i=c[d+52>>2]|0,i|0):0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[6432]=(c[6432]|0)+1;h=ec(151)|0;if(!h)h=0;else{c[(h+4+15&-16)+-4>>2]=h;h=h+4+15&-16}c[h>>2]=9504;a[h+20>>0]=1;c[h+16>>2]=0;c[h+8>>2]=0;c[h+12>>2]=0;a[h+40>>0]=1;c[h+36>>2]=0;c[h+28>>2]=0;c[h+32>>2]=0;a[h+60>>0]=1;c[h+56>>2]=0;c[h+48>>2]=0;c[h+52>>2]=0;c[d+52>>2]=h;k=0;p=0;o=0;ha=0;L=0;while(1){if((p|0)>=(lb[c[(c[d>>2]|0)+96>>2]&127](d)|0))break;do if((L|0)==(o|0)){i=o|0?o<<1:1;if((o|0)<(i|0)){if((i|0)!=0?(c[6432]=(c[6432]|0)+1,t=ec((i<<4|3)+16|0)|0,(t|0)!=0):0){c[(t+4+15&-16)+-4>>2]=t;m=t+4+15&-16}else m=0;if((o|0)<=0){if(!ha){n=o;k=m;h=m;break}}else{h=0;do{ga=m+(h<<4)|0;fa=ha+(h<<4)|0;c[ga>>2]=c[fa>>2];c[ga+4>>2]=c[fa+4>>2];c[ga+8>>2]=c[fa+8>>2];c[ga+12>>2]=c[fa+12>>2];h=h+1|0}while((h|0)!=(o|0))}c[6433]=(c[6433]|0)+1;Pc(c[ha+-4>>2]|0);n=o;k=m;h=m}else{n=o;i=o;h=ha}}else{n=L;i=o;h=ha}while(0);o=h+(L<<4)|0;c[o>>2]=c[ia+136>>2];c[o+4>>2]=c[ia+136+4>>2];c[o+8>>2]=c[ia+136+8>>2];c[o+12>>2]=c[ia+136+12>>2];Rb[c[(c[d>>2]|0)+108>>2]&127](d,p,o);p=p+1|0;o=i;ha=h;L=n+1|0}a[ia+76+16>>0]=1;ga=ia+76+12|0;c[ga>>2]=0;c[ia+76+4>>2]=0;c[ia+76+8>>2]=0;a[ia+76+36>>0]=1;fa=ia+76+32|0;c[fa>>2]=0;c[ia+76+24>>2]=0;c[ia+76+28>>2]=0;a[ia+76+56>>0]=1;ea=ia+76+52|0;c[ea>>2]=0;c[ia+76+44>>2]=0;c[ia+76+48>>2]=0;if(f){if((L|0)>0){K=0;i=0;m=0;k=0;while(1){h=K;K=K+1|0;if((K|0)<(L|0)){G=ha+(h<<4)|0;H=ha+(h<<4)+4|0;A=ha+(h<<4)+8|0;D=K;h=k;do{k=D;D=D+1|0;if((D|0)<(L|0)){y=ha+(k<<4)|0;z=ha+(k<<4)+4|0;t=ha+(k<<4)+8|0;f=D;do{F=+g[G>>2];w=+g[y>>2]-F;I=+g[H>>2];x=+g[z>>2]-I;J=+g[A>>2];E=+g[t>>2]-J;F=+g[ha+(f<<4)>>2]-F;I=+g[ha+(f<<4)+4>>2]-I;J=+g[ha+(f<<4)+8>>2]-J;q=1.0;p=0;while(1){u=(x*J-E*I)*q;v=(E*F-w*J)*q;r=(w*I-x*F)*q;a:do if(r*r+(u*u+v*v)>9.999999747378752e-05){s=1.0/+C(+(r*r+(u*u+v*v)));if((h|0)>0){k=0;do{if(u*s*+g[m+(k<<4)>>2]+v*s*+g[m+(k<<4)+4>>2]+r*s*+g[m+(k<<4)+8>>2]>.9990000128746033)break a;k=k+1|0}while((k|0)<(h|0))}q=u*s*+g[G>>2]+v*s*+g[H>>2]+r*s*+g[A>>2];k=0;do{if(u*s*+g[ha+(k<<4)>>2]+v*s*+g[ha+(k<<4)+4>>2]+r*s*+g[ha+(k<<4)+8>>2]-q+-.009999999776482582>0.0)break a;k=k+1|0}while((k|0)<(L|0));do if((h|0)==(i|0)){o=i|0?i<<1:1;if((i|0)<(o|0)){do if(!o)n=0;else{c[6432]=(c[6432]|0)+1;k=ec((o<<4|3)+16|0)|0;if(!k){n=0;break}c[(k+4+15&-16)+-4>>2]=k;n=k+4+15&-16}while(0);if((i|0)<=0){if(!m){k=i;i=o;m=n;break}}else{k=0;do{ba=n+(k<<4)|0;aa=m+(k<<4)|0;c[ba>>2]=c[aa>>2];c[ba+4>>2]=c[aa+4>>2];c[ba+8>>2]=c[aa+8>>2];c[ba+12>>2]=c[aa+12>>2];k=k+1|0}while((k|0)!=(i|0))}c[6433]=(c[6433]|0)+1;Pc(c[m+-4>>2]|0);k=i;i=o;m=n}else k=i}else k=h;while(0);g[m+(k<<4)>>2]=u*s;g[m+(k<<4)+4>>2]=v*s;g[m+(k<<4)+8>>2]=r*s;g[m+(k<<4)+12>>2]=-q;h=h+1|0}while(0);p=p+1|0;if((p|0)==2)break;else q=-1.0}f=f+1|0}while((f|0)!=(L|0))}}while((D|0)!=(L|0))}else h=k;if((K|0)==(L|0))break;else k=h}if((h|0)>0){o=0;p=0;t=0;while(1){ba=m+(t<<4)|0;c[ia+136>>2]=c[ba>>2];c[ia+136+4>>2]=c[ba+4>>2];c[ia+136+8>>2]=c[ba+8>>2];q=+g[m+(t<<4)+12>>2];q=q-+zb[c[(c[d>>2]|0)+48>>2]&15](d);do if((t|0)==(o|0)){n=o|0?o<<1:1;if((o|0)<(n|0)){if((n|0)!=0?(c[6432]=(c[6432]|0)+1,M=ec((n<<4|3)+16|0)|0,(M|0)!=0):0){c[(M+4+15&-16)+-4>>2]=M;k=M+4+15&-16}else k=0;if((o|0)<=0){if(!p){i=o;break}}else{i=0;do{ba=k+(i<<4)|0;aa=p+(i<<4)|0;c[ba>>2]=c[aa>>2];c[ba+4>>2]=c[aa+4>>2];c[ba+8>>2]=c[aa+8>>2];c[ba+12>>2]=c[aa+12>>2];i=i+1|0}while((i|0)!=(o|0))}c[6433]=(c[6433]|0)+1;Pc(c[p+-4>>2]|0);i=o}else{i=o;n=o;k=p}}else{i=t;n=o;k=p}while(0);ba=k+(i<<4)|0;c[ba>>2]=c[ia+136>>2];c[ba+4>>2]=c[ia+136+4>>2];c[ba+8>>2]=c[ia+136+8>>2];g[k+(i<<4)+12>>2]=q;t=t+1|0;if((t|0)<(h|0)){o=n;p=k}else break}if((t|0)>0){n=0;H=0;o=0;i=0;h=0;do{G=H;H=H+1|0;if((H|0)<(t|0)){D=H;do{A=D;D=D+1|0;if((D|0)<(t|0)){z=D;do{u=+g[k+(A<<4)+4>>2];q=+g[k+(z<<4)+8>>2];r=+g[k+(A<<4)+8>>2];v=+g[k+(z<<4)+4>>2];w=+g[k+(z<<4)>>2];x=+g[k+(A<<4)>>2];s=+g[k+(G<<4)+8>>2];E=+g[k+(G<<4)+4>>2];F=+g[k+(G<<4)>>2];b:do if((((v*x-u*w)*(v*x-u*w)+((u*q-r*v)*(u*q-r*v)+(r*w-q*x)*(r*w-q*x))>9.999999747378752e-05?(w*E-v*F)*(w*E-v*F)+((v*s-q*E)*(v*s-q*E)+(q*F-w*s)*(q*F-w*s))>9.999999747378752e-05:0)?(u*F-x*E)*(u*F-x*E)+((r*E-u*s)*(r*E-u*s)+(x*s-r*F)*(x*s-r*F))>9.999999747378752e-05:0)?(W=s*(v*x-u*w)+(E*(r*w-q*x)+(u*q-r*v)*F),+B(+W)>9.999999974752427e-07):0){ja=+g[k+(G<<4)+12>>2];J=+g[k+(A<<4)+12>>2];ka=+g[k+(z<<4)+12>>2];I=-1.0/W*((r*E-u*s)*ka+((u*q-r*v)*ja+(v*s-q*E)*J));r=-1.0/W*((x*s-r*F)*ka+((r*w-q*x)*ja+(q*F-w*s)*J));q=-1.0/W*((u*F-x*E)*ka+((v*x-u*w)*ja+(w*E-v*F)*J));p=0;do{if(+g[k+(p<<4)+12>>2]+(I*+g[k+(p<<4)>>2]+r*+g[k+(p<<4)+4>>2]+q*+g[k+(p<<4)+8>>2])+-.009999999776482582>0.0)break b;p=p+1|0}while((p|0)<(t|0));do if((h|0)==(o|0)){f=o|0?o<<1:1;if((o|0)>=(f|0)){y=o;break}do if(!f)p=0;else{c[6432]=(c[6432]|0)+1;n=ec((f<<4|3)+16|0)|0;if(!n){p=0;break}c[(n+4+15&-16)+-4>>2]=n;p=n+4+15&-16}while(0);if((o|0)<=0){if(!i){y=o;n=p;o=f;i=p;break}}else{n=0;do{ba=p+(n<<4)|0;aa=i+(n<<4)|0;c[ba>>2]=c[aa>>2];c[ba+4>>2]=c[aa+4>>2];c[ba+8>>2]=c[aa+8>>2];c[ba+12>>2]=c[aa+12>>2];n=n+1|0}while((n|0)!=(o|0))}c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0);y=o;n=p;o=f;i=p}else y=h;while(0);g[i+(y<<4)>>2]=I;g[i+(y<<4)+4>>2]=r;g[i+(y<<4)+8>>2]=q;g[i+(y<<4)+12>>2]=0.0;h=h+1|0}while(0);z=z+1|0}while((z|0)!=(t|0))}}while((D|0)!=(t|0))}}while((H|0)!=(t|0))}else{n=0;i=0;h=0}}else{n=0;k=0;i=0;h=0}}else{n=0;m=0;k=0;i=0;h=0}ic(ia+76|0,n,h);if(i|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}if(k|0){c[6433]=(c[6433]|0)+1;Pc(c[k+-4>>2]|0)}if(m|0){c[6433]=(c[6433]|0)+1;Pc(c[m+-4>>2]|0)}}else ic(ia+76|0,k,L);H=c[ia+76+44>>2]|0;if((H|0)>0){c[6432]=(c[6432]|0)+1;h=ec((H<<4|3)+16|0)|0;if(!h)i=0;else{c[(h+4+15&-16)+-4>>2]=h;i=h+4+15&-16}h=0;do{ba=i+(h<<4)|0;c[ba>>2]=c[ia+136>>2];c[ba+4>>2]=c[ia+136+4>>2];c[ba+8>>2]=c[ia+136+8>>2];c[ba+12>>2]=c[ia+136+12>>2];h=h+1|0}while((h|0)!=(H|0));ba=i;$=i}else{ba=0;$=0}a[ia+56+16>>0]=1;aa=ia+56+12|0;c[aa>>2]=0;_=ia+56+4|0;c[_>>2]=0;c[ia+56+8>>2]=0;k=ia+136|0;n=k+19|0;do{a[k>>0]=0;k=k+1|0}while((k|0)<(n|0));if((H|0)<0)Ta();if(H|0){vf(ia+56|0,H);h=c[aa>>2]|0;i=0;do{a[h+(i*36|0)+16>>0]=1;k=h+(i*36|0)+4|0;c[k>>2]=0;c[k+4>>2]=0;c[k+8>>2]=0;k=h+(i*36|0)+20|0;m=ia+136+3|0;n=k+16|0;do{a[k>>0]=a[m>>0]|0;k=k+1|0;m=m+1|0}while((k|0)<(n|0));i=i+1|0}while((i|0)!=(H|0))}c[_>>2]=H;o=c[ia+76+4>>2]|0;n=c[d+52>>2]|0;m=c[n+8>>2]|0;if((m|0)<(o|0)){if((c[n+12>>2]|0)<(o|0)){if(!o){i=m;k=0}else{c[6432]=(c[6432]|0)+1;h=ec((o<<4|3)+16|0)|0;if(!h)h=0;else{c[(h+4+15&-16)+-4>>2]=h;h=h+4+15&-16}i=c[n+8>>2]|0;k=h}if((i|0)>0){h=0;do{Z=k+(h<<4)|0;Y=(c[n+16>>2]|0)+(h<<4)|0;c[Z>>2]=c[Y>>2];c[Z+4>>2]=c[Y+4>>2];c[Z+8>>2]=c[Y+8>>2];c[Z+12>>2]=c[Y+12>>2];h=h+1|0}while((h|0)!=(i|0))}h=c[n+16>>2]|0;if(h|0){if(a[n+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[n+16>>2]=0}a[n+20>>0]=1;c[n+16>>2]=k;c[n+12>>2]=o;i=n+16|0}else i=n+16|0;h=m;do{Z=(c[i>>2]|0)+(h<<4)|0;c[Z>>2]=c[ia+136>>2];c[Z+4>>2]=c[ia+136+4>>2];c[Z+8>>2]=c[ia+136+8>>2];c[Z+12>>2]=c[ia+136+12>>2];h=h+1|0}while((h|0)!=(o|0))}c[n+8>>2]=o;if((o|0)>0){h=0;do{Y=(c[ga>>2]|0)+(h<<4)|0;Z=(c[(c[d+52>>2]|0)+16>>2]|0)+(h<<4)|0;c[Z>>2]=c[Y>>2];c[Z+4>>2]=c[Y+4>>2];c[Z+8>>2]=c[Y+8>>2];c[Z+12>>2]=c[Y+12>>2];h=h+1|0}while((h|0)!=(o|0))}if((H|0)>0){G=0;do{z=(c[fa>>2]|0)+((c[(c[ea>>2]|0)+(G<<2)>>2]|0)*12|0)|0;A=z;h=0;do{D=A+4|0;y=c[A+((c[D>>2]|0)*12|0)+8>>2]|0;t=c[aa>>2]|0;f=t+(G*36|0)+4|0;i=c[f>>2]|0;p=t+(G*36|0)+8|0;if((i|0)==(c[p>>2]|0)?(N=i|0?i<<1:1,(i|0)<(N|0)):0){if(!N)k=0;else{c[6432]=(c[6432]|0)+1;i=ec((N<<2|3)+16|0)|0;if(!i)k=0;else{c[(i+4+15&-16)+-4>>2]=i;k=i+4+15&-16}i=c[f>>2]|0}o=t+(G*36|0)+12|0;n=c[o>>2]|0;if((i|0)<=0)if(!n)m=t+(G*36|0)+16|0;else ca=132;else{m=0;do{c[k+(m<<2)>>2]=c[n+(m<<2)>>2];m=m+1|0}while((m|0)!=(i|0));ca=132}if((ca|0)==132){ca=0;m=t+(G*36|0)+16|0;if(a[m>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[n+-4>>2]|0)}c[o>>2]=0;i=c[f>>2]|0}a[m>>0]=1;c[o>>2]=k;c[p>>2]=N}c[(c[t+(G*36|0)+12>>2]|0)+(i<<2)>>2]=y;c[f>>2]=(c[f>>2]|0)+1;Y=c[A+8>>2]|0;Z=c[ga>>2]|0;s=+g[Z+(Y<<4)>>2]-+g[Z+(y<<4)>>2];u=+g[Z+(Y<<4)+4>>2]-+g[Z+(y<<4)+4>>2];r=+g[Z+(Y<<4)+8>>2]-+g[Z+(y<<4)+8>>2];q=1.0/+C(+(s*s+u*u+r*r));if((h|0)<2){g[ia+136+(h<<4)>>2]=s*q;g[ia+136+(h<<4)+4>>2]=u*q;g[ia+136+(h<<4)+8>>2]=r*q;g[ia+136+(h<<4)+12>>2]=0.0;h=h+1|0}Z=A+((c[D>>2]|0)*12|0)|0;A=Z+((c[Z>>2]|0)*12|0)|0}while((A|0)!=(z|0));if((h|0)==2){I=+g[ia+136+4>>2];J=+g[ia+136+24>>2];W=+g[ia+136+8>>2];ja=+g[ia+136+20>>2];F=+g[ia+136+16>>2];E=+g[ia+136>>2];Y=$+(G<<4)+4|0;Z=$+(G<<4)+8|0;g[$+(G<<4)+12>>2]=0.0;ka=1.0/+C(+((I*J-W*ja)*(I*J-W*ja)+(W*F-J*E)*(W*F-J*E)+(ja*E-I*F)*(ja*E-I*F)));g[$+(G<<4)>>2]=(I*J-W*ja)*ka;g[Y>>2]=(W*F-J*E)*ka;g[Z>>2]=(ja*E-I*F)*ka;n=c[aa>>2]|0;g[n+(G*36|0)+20>>2]=(I*J-W*ja)*ka;c[n+(G*36|0)+24>>2]=c[Y>>2];c[n+(G*36|0)+28>>2]=c[Z>>2];g[n+(G*36|0)+32>>2]=1000000015047466219876688.0e6}else{n=$+(G<<4)|0;c[n>>2]=0;c[n+4>>2]=0;c[n+8>>2]=0;c[n+12>>2]=0;n=c[aa>>2]|0}i=c[n+(G*36|0)+4>>2]|0;if((i|0)>0){k=c[(c[d+52>>2]|0)+16>>2]|0;r=+g[$+(G<<4)>>2];s=+g[$+(G<<4)+4>>2];u=+g[$+(G<<4)+8>>2];h=c[n+(G*36|0)+12>>2]|0;q=1000000015047466219876688.0e6;m=0;do{Z=c[h+(m<<2)>>2]|0;ka=+g[k+(Z<<4)>>2]*r+ +g[k+(Z<<4)+4>>2]*s+ +g[k+(Z<<4)+8>>2]*u;q=q>ka?ka:q;m=m+1|0}while((m|0)!=(i|0))}else q=1000000015047466219876688.0e6;g[n+(G*36|0)+32>>2]=-q;G=G+1|0}while((G|0)!=(H|0))}if((c[_>>2]|0)>0){k=0;h=0;o=0;i=0;n=0;do{do if((o|0)==(i|0)){i=o|0?o<<1:1;if((o|0)<(i|0)){if((i|0)!=0?(c[6432]=(c[6432]|0)+1,O=ec((i<<2|3)+16|0)|0,(O|0)!=0):0){c[(O+4+15&-16)+-4>>2]=O;m=O+4+15&-16}else m=0;if((o|0)>0){h=0;do{c[m+(h<<2)>>2]=c[n+(h<<2)>>2];h=h+1|0}while((h|0)!=(o|0));if(!k){h=m;k=m;n=m;break}}else if((n|0)==0|(k|0)==0){h=m;k=m;n=m;break}c[6433]=(c[6433]|0)+1;Pc(c[k+-4>>2]|0);h=m;k=m;n=m}else i=o}while(0);c[n+(o<<2)>>2]=o;o=o+1|0}while((o|0)<(c[_>>2]|0));N=ia+36+12|0;P=ia+36+4|0;O=ia+136+12|0;m=o;while(1){y=m+-1|0;k=c[n+(y<<2)>>2]|0;c[6432]=(c[6432]|0)+1;i=ec(23)|0;if(!i)i=0;else{c[(i+4+15&-16)+-4>>2]=i;i=i+4+15&-16}c[i>>2]=k;Z=c[aa>>2]|0;r=+g[Z+(k*36|0)+20>>2];s=+g[Z+(k*36|0)+24>>2];q=+g[Z+(k*36|0)+28>>2];c:do if((m|0)>1){t=i;f=i;o=1;p=1;k=y;D=y;while(1){A=i;d:while(1){i=c[aa>>2]|0;do{Z=k;k=k+-1|0;if((Z|0)<=0){M=t;L=A;K=p;m=D;break c}z=c[n+(k<<2)>>2]|0}while(!(r*+g[i+(z*36|0)+20>>2]+s*+g[i+(z*36|0)+24>>2]+q*+g[i+(z*36|0)+28>>2]>.9990000128746033));do if((p|0)==(o|0)){o=p|0?p<<1:1;if((p|0)<(o|0)){do if(!o)m=0;else{c[6432]=(c[6432]|0)+1;i=ec((o<<2|3)+16|0)|0;if(!i){m=0;break}c[(i+4+15&-16)+-4>>2]=i;m=i+4+15&-16}while(0);if((p|0)>0){i=0;do{c[m+(i<<2)>>2]=c[A+(i<<2)>>2];i=i+1|0}while((i|0)!=(p|0));if(!f){t=m;f=m;y=o;A=m;break}}else if((A|0)==0|(f|0)==0){t=m;f=m;y=o;A=m;break}c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0);t=m;f=m;y=o;A=m}else y=p}else y=o;while(0);c[A+(p<<2)>>2]=z;p=p+1|0;i=0;while(1){o=n+(i<<2)|0;if((c[o>>2]|0)==(z|0))break;i=i+1|0;if((i|0)>=(D|0)){o=y;continue d}}if((i|0)<(D|0))break;else o=y}m=D+-1|0;Z=n+(m<<2)|0;c[o>>2]=c[Z>>2];c[Z>>2]=z;if((D|0)>1){o=y;i=A;D=m}else{o=y;i=A;ca=162;break}}}else{t=i;f=i;o=1;p=1;k=y;m=y;ca=162}while(0);e:do if((ca|0)==162){ca=0;z=i;A=p;while(1){i=c[aa>>2]|0;do{Z=k;k=k+-1|0;if((Z|0)<=0){M=t;L=z;K=A;break e}y=c[n+(k<<2)>>2]|0}while(!(r*+g[i+(y*36|0)+20>>2]+s*+g[i+(y*36|0)+24>>2]+q*+g[i+(y*36|0)+28>>2]>.9990000128746033));do if((A|0)==(o|0)){o=A|0?A<<1:1;if((A|0)<(o|0)){do if(!o)p=0;else{c[6432]=(c[6432]|0)+1;i=ec((o<<2|3)+16|0)|0;if(!i){p=0;break}c[(i+4+15&-16)+-4>>2]=i;p=i+4+15&-16}while(0);if((A|0)>0){i=0;do{c[p+(i<<2)>>2]=c[z+(i<<2)>>2];i=i+1|0}while((i|0)!=(A|0));if(!f){t=p;f=p;i=p;break}}else if((z|0)==0|(f|0)==0){t=p;f=p;i=p;break}c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0);t=p;f=p;i=p}else{o=A;i=z}}else i=z;while(0);c[i+(A<<2)>>2]=y;z=i;A=A+1|0}}while(0);if((K|0)>1){a[ia+36+16>>0]=1;c[N>>2]=0;c[P>>2]=0;c[ia+36+8>>2]=0;q=0.0;r=0.0;s=0.0;o=0;D=0;do{k=c[L+(D<<2)>>2]|0;q=+g[i+(k*36|0)+20>>2]+q;r=+g[i+(k*36|0)+24>>2]+r;s=+g[i+(k*36|0)+28>>2]+s;A=i+(k*36|0)+4|0;if((c[A>>2]|0)>0){z=i+(k*36|0)+12|0;i=o;y=0;while(1){f=c[(c[z>>2]|0)+(y<<2)>>2]|0;Z=(c[(c[d+52>>2]|0)+16>>2]|0)+(f<<4)|0;c[ia+136>>2]=c[Z>>2];c[ia+136+4>>2]=c[Z+4>>2];c[ia+136+8>>2]=c[Z+8>>2];c[ia+136+12>>2]=c[Z+12>>2];f:do if((i|0)>0){k=c[N>>2]|0;o=0;while(1){if((c[k+(o*24|0)+20>>2]|0)==(f|0))break f;o=o+1|0;if((o|0)>=(i|0)){ca=249;break}}}else ca=249;while(0);if((ca|0)==249){ca=0;c[ia>>2]=c[ia+136>>2];c[ia+4>>2]=c[ia+136+4>>2];c[ia+8>>2]=c[ia+136+8>>2];c[ia+12>>2]=c[ia+136+12>>2];do if((i|0)==(c[ia+36+8>>2]|0)){t=i|0?i<<1:1;if((i|0)>=(t|0))break;if(!t)k=0;else{c[6432]=(c[6432]|0)+1;i=ec((t*24|3)+16|0)|0;if(!i)k=0;else{c[(i+4+15&-16)+-4>>2]=i;k=i+4+15&-16}i=c[P>>2]|0}p=c[N>>2]|0;if((i|0)<=0){if(p)ca=258}else{o=0;do{ca=k+(o*24|0)|0;Z=p+(o*24|0)|0;c[ca>>2]=c[Z>>2];c[ca+4>>2]=c[Z+4>>2];c[ca+8>>2]=c[Z+8>>2];c[ca+12>>2]=c[Z+12>>2];c[ca+16>>2]=c[Z+16>>2];c[ca+20>>2]=c[Z+20>>2];o=o+1|0}while((o|0)!=(i|0));ca=258}if((ca|0)==258){ca=0;if(a[ia+36+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[p+-4>>2]|0);i=c[P>>2]|0}c[N>>2]=0}a[ia+36+16>>0]=1;c[N>>2]=k;c[ia+36+8>>2]=t}while(0);Z=c[N>>2]|0;Y=Z+(i*24|0)|0;c[Y>>2]=c[ia>>2];c[Y+4>>2]=c[ia+4>>2];c[Y+8>>2]=c[ia+8>>2];c[Y+12>>2]=c[ia+12>>2];c[Y+16>>2]=c[ia+16>>2];c[Z+(i*24|0)+20>>2]=f;i=(c[P>>2]|0)+1|0;c[P>>2]=i}y=y+1|0;if((y|0)>=(c[A>>2]|0)){o=i;break}}}D=D+1|0;i=c[aa>>2]|0}while((D|0)!=(K|0));a[ia+16>>0]=1;c[ia+12>>2]=0;c[ia+4>>2]=0;c[ia+8>>2]=0;Z=c[L>>2]|0;c[ia+20>>2]=c[i+(Z*36|0)+20>>2];c[ia+24>>2]=c[i+(Z*36|0)+24>>2];c[ia+28>>2]=c[i+(Z*36|0)+28>>2];c[ia+32>>2]=c[i+(Z*36|0)+32>>2];v=1.0/+C(+(q*q+r*r+s*s));x=q*v;w=r*v;v=s*v;if(+B(+v)>.7071067690849304){u=1.0/+C(+(v*v+w*w));r=0.0;s=w*u;u=-(v*u)}else{u=1.0/+C(+(x*x+w*w));r=-(w*u);s=0.0;u=x*u}if((o|0)<2)if((o|0)==1){k=1;o=0;p=0;i=0;do{z=c[N>>2]|0;do if((o|0)==(p|0)){y=p|0?p<<1:1;if((p|0)>=(y|0)){f=p;break}do if(!y)t=0;else{c[6432]=(c[6432]|0)+1;k=ec((y*24|3)+16|0)|0;if(!k){p=o;t=0;break}c[(k+4+15&-16)+-4>>2]=k;p=o;t=k+4+15&-16}while(0);if((p|0)<=0){if(i|0)ca=212}else{k=0;do{ca=t+(k*24|0)|0;Z=i+(k*24|0)|0;c[ca>>2]=c[Z>>2];c[ca+4>>2]=c[Z+4>>2];c[ca+8>>2]=c[Z+8>>2];c[ca+12>>2]=c[Z+12>>2];c[ca+16>>2]=c[Z+16>>2];c[ca+20>>2]=c[Z+20>>2];k=k+1|0}while((k|0)!=(p|0));ca=212}if((ca|0)==212){ca=0;c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}f=o;k=c[P>>2]|0;p=y;i=t}else f=o;while(0);Z=i+(f*24|0)|0;c[Z>>2]=c[z>>2];c[Z+4>>2]=c[z+4>>2];c[Z+8>>2]=c[z+8>>2];c[Z+12>>2]=c[z+12>>2];c[Z+16>>2]=c[z+16>>2];c[Z+20>>2]=c[z+20>>2];o=o+1|0}while((o|0)<(k|0));ca=264}else{i=0;ca=303}else{p=c[N>>2]|0;i=o;k=0;do{if(r*+g[p+(k*24|0)>>2]+u*+g[p+(k*24|0)+4>>2]+s*+g[p+(k*24|0)+8>>2]<r*+g[p>>2]+u*+g[p+4>>2]+s*+g[p+8>>2]){c[ia+136>>2]=c[p>>2];c[ia+136+4>>2]=c[p+4>>2];c[ia+136+8>>2]=c[p+8>>2];c[ia+136+12>>2]=c[p+12>>2];c[ia+136+16>>2]=c[p+16>>2];c[ia+136+20>>2]=c[p+20>>2];i=p+(k*24|0)|0;c[p>>2]=c[i>>2];c[p+4>>2]=c[i+4>>2];c[p+8>>2]=c[i+8>>2];c[p+12>>2]=c[i+12>>2];c[p+16>>2]=c[i+16>>2];c[p+20>>2]=c[i+20>>2];i=p+(k*24|0)|0;c[i>>2]=c[ia+136>>2];c[i+4>>2]=c[ia+136+4>>2];c[i+8>>2]=c[ia+136+8>>2];c[i+12>>2]=c[ia+136+12>>2];c[i+16>>2]=c[ia+136+16>>2];c[i+20>>2]=c[ia+136+20>>2];i=o}k=k+1|0}while((k|0)<(i|0));g[p+16>>2]=-1000000015047466219876688.0e6;if((i|0)>1){q=+g[p+4>>2];k=1;do{W=+g[p+(k*24|0)>>2]-+g[p>>2];ja=+g[p+(k*24|0)+4>>2]-q;ka=+g[p+(k*24|0)+8>>2]-+g[p+8>>2];g[p+(k*24|0)+16>>2]=((r*ja-u*W)*v+(x*(u*ka-s*ja)+w*(s*W-r*ka)))/+C(+(W*W+ja*ja+ka*ka));k=k+1|0}while((k|0)!=(i|0))}c[ia+136>>2]=c[p>>2];c[ia+136+4>>2]=c[p+4>>2];c[ia+136+8>>2]=c[p+8>>2];c[ia+136+12>>2]=c[p+12>>2];df(ia+36|0,ia+136|0,1,i+-1|0);k=c[N>>2]|0;c[6432]=(c[6432]|0)+1;i=ec(43)|0;if(!i)p=0;else{c[(i+4+15&-16)+-4>>2]=i;p=i+4+15&-16}o=c[N>>2]|0;c[p>>2]=c[k>>2];c[p+4>>2]=c[k+4>>2];c[p+8>>2]=c[k+8>>2];c[p+12>>2]=c[k+12>>2];c[p+16>>2]=c[k+16>>2];c[p+20>>2]=c[k+20>>2];c[6432]=(c[6432]|0)+1;i=ec(67)|0;if(!i)i=0;else{c[(i+4+15&-16)+-4>>2]=i;i=i+4+15&-16}c[i>>2]=c[p>>2];c[i+4>>2]=c[p+4>>2];c[i+8>>2]=c[p+8>>2];c[i+12>>2]=c[p+12>>2];c[i+16>>2]=c[p+16>>2];c[i+20>>2]=c[p+20>>2];if(p|0){c[6433]=(c[6433]|0)+1;Pc(c[p+-4>>2]|0)}k=i+24|0;c[k>>2]=c[o+24>>2];c[k+4>>2]=c[o+24+4>>2];c[k+8>>2]=c[o+24+8>>2];c[k+12>>2]=c[o+24+12>>2];c[k+16>>2]=c[o+24+16>>2];c[k+20>>2]=c[o+24+20>>2];k=c[P>>2]|0;if((k|0)==2){k=2;o=2}else{t=2;o=2;p=2;z=2;do{g:do if((t|0)>1){ca=c[N>>2]|0;y=ca+(z*24|0)|0;q=+g[y>>2];r=+g[ca+(z*24|0)+4>>2];s=+g[ca+(z*24|0)+8>>2];while(1){ca=t+-2|0;f=t+-1|0;W=+g[i+(ca*24|0)>>2];ja=W-+g[i+(f*24|0)>>2];I=+g[i+(ca*24|0)+4>>2];F=I-+g[i+(f*24|0)+4>>2];ka=+g[i+(ca*24|0)+8>>2];J=ka-+g[i+(f*24|0)+8>>2];if((ja*(I-r)-F*(W-q))*v+(x*(F*(ka-s)-J*(I-r))+w*(J*(W-q)-ja*(ka-s)))>0.0)break;if((f|0)>1){t=f;o=f}else{t=1;o=f;break g}}do if((t|0)==(p|0)){f=p<<1;if((p|0)>=(f|0)){t=p;f=p;break}c[6432]=(c[6432]|0)+1;k=ec((p*48|3)+16|0)|0;if(!k)p=0;else{c[(k+4+15&-16)+-4>>2]=k;p=k+4+15&-16}if((o|0)>0){k=0;do{ca=p+(k*24|0)|0;Z=i+(k*24|0)|0;c[ca>>2]=c[Z>>2];c[ca+4>>2]=c[Z+4>>2];c[ca+8>>2]=c[Z+8>>2];c[ca+12>>2]=c[Z+12>>2];c[ca+16>>2]=c[Z+16>>2];c[ca+20>>2]=c[Z+20>>2];k=k+1|0}while((k|0)!=(o|0))}c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0);k=c[P>>2]|0;t=o;i=p}else f=p;while(0);t=i+(t*24|0)|0;c[t>>2]=c[y>>2];c[t+4>>2]=c[y+4>>2];c[t+8>>2]=c[y+8>>2];c[t+12>>2]=c[y+12>>2];c[t+16>>2]=c[y+16>>2];c[t+20>>2]=c[y+20>>2];o=o+1|0;t=o;p=f}while(0);z=z+1|0}while((z|0)!=(k|0))}ca=264}h:do if((ca|0)==264){ca=0;if((o|0)>0){p=c[ia+4>>2]|0;k=c[ia+8>>2]|0;y=a[ia+16>>0]|0;H=0;while(1){G=i+(H*24|0)+20|0;do if((p|0)==(k|0)){A=k|0?k<<1:1;if((k|0)>=(A|0)){D=y;p=k;A=k;break}do if(!A)f=0;else{c[6432]=(c[6432]|0)+1;p=ec((A<<2|3)+16|0)|0;if(!p){f=0;break}c[(p+4+15&-16)+-4>>2]=p;f=p+4+15&-16}while(0);t=c[ia+12>>2]|0;if((k|0)<=0){if(t)ca=293}else{p=0;do{c[f+(p<<2)>>2]=c[t+(p<<2)>>2];p=p+1|0}while((p|0)!=(k|0));ca=293}if((ca|0)==293){ca=0;if(y<<24>>24){c[6433]=(c[6433]|0)+1;Pc(c[t+-4>>2]|0)}c[ia+12>>2]=0;k=c[ia+4>>2]|0}c[ia+12>>2]=f;c[ia+8>>2]=A;D=1;p=k}else{D=y;A=k}while(0);c[(c[ia+12>>2]|0)+(p<<2)>>2]=c[G>>2];p=p+1|0;c[ia+4>>2]=p;k=c[P>>2]|0;i:do if((k|0)>0){z=c[N>>2]|0;t=c[G>>2]|0;f=0;while(1){y=z+(f*24|0)+20|0;f=f+1|0;if((c[y>>2]|0)==(t|0))break;if((f|0)>=(k|0))break i}c[y>>2]=-1}while(0);H=H+1|0;if((H|0)>=(o|0))break;else{k=A;y=D}}a[ia+16>>0]=D}if((k|0)<=0){ca=303;break}y=c[N>>2]|0;z=c[_>>2]|0;A=c[aa>>2]|0;G=(K|0)>0;if((z|0)>0)H=0;else{ca=303;break}while(1){D=c[y+(H*24|0)+20>>2]|0;j:do if((D|0)!=-1){if(G)f=0;else{t=0;while(1){o=c[A+(t*36|0)+4>>2]|0;if((o|0)>0){p=c[A+(t*36|0)+12>>2]|0;f=0;do{if((c[p+(f<<2)>>2]|0)==(D|0)){k=1;break h}f=f+1|0}while((f|0)<(o|0))}t=t+1|0;if((t|0)>=(z|0))break j}}do{o=0;while(1){if((c[L+(o<<2)>>2]|0)==(f|0))break;o=o+1|0;if((o|0)>=(K|0)){ca=279;break}}do if((ca|0)==279){ca=0;o=c[A+(f*36|0)+4>>2]|0;if((o|0)<=0)break;p=c[A+(f*36|0)+12>>2]|0;t=0;do{if((c[p+(t<<2)>>2]|0)==(D|0)){k=1;break h}t=t+1|0}while((t|0)<(o|0))}while(0);f=f+1|0}while((f|0)<(z|0))}while(0);H=H+1|0;if((H|0)>=(k|0)){ca=303;break}}}while(0);if((ca|0)==303){ca=0;Rg((c[d+52>>2]|0)+24|0,ia);k=0}if(i|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}i=c[ia+12>>2]|0;if(i|0){if(a[ia+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[ia+12>>2]=0}i=c[N>>2]|0;if(i|0){if(a[ia+36+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[N>>2]=0}if(k&(K|0)>0){y=0;ca=315}}else if((K|0)==1){y=0;ca=315}if((ca|0)==315)while(1){ca=0;t=c[L+(y<<2)>>2]|0;f=c[aa>>2]|0;a[ia+136+16>>0]=1;c[O>>2]=0;c[ia+136+4>>2]=0;c[ia+136+8>>2]=0;p=c[f+(t*36|0)+4>>2]|0;if((p|0)>0){c[6432]=(c[6432]|0)+1;k=ec((p<<2|3)+16|0)|0;do if(!k){o=0;i=0}else{c[(k+4+15&-16)+-4>>2]=k;i=c[O>>2]|0;if((i|0)==0|(a[ia+136+16>>0]|0)==0){o=k+4+15&-16;i=k+4+15&-16;break}c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0);o=k+4+15&-16;i=k+4+15&-16}while(0);a[ia+136+16>>0]=1;c[O>>2]=i;c[ia+136+8>>2]=p;Hk(i|0,0,p<<2|0)|0;c[ia+136+4>>2]=p;i=c[f+(t*36|0)+12>>2]|0;k=0;do{c[o+(k<<2)>>2]=c[i+(k<<2)>>2];k=k+1|0}while((k|0)!=(p|0));i=c[O>>2]|0}else{c[ia+136+4>>2]=p;i=0}c[ia+136+20>>2]=c[f+(t*36|0)+20>>2];c[ia+136+20+4>>2]=c[f+(t*36|0)+20+4>>2];c[ia+136+20+8>>2]=c[f+(t*36|0)+20+8>>2];c[ia+136+20+12>>2]=c[f+(t*36|0)+20+12>>2];Rg((c[d+52>>2]|0)+24|0,ia+136|0);if(i|0){if(a[ia+136+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[O>>2]=0}y=y+1|0;if((y|0)>=(K|0))break;else ca=315}if(!((L|0)==0|(M|0)==0)){c[6433]=(c[6433]|0)+1;Pc(c[M+-4>>2]|0)}if(!m){Z=h;break}}}else{Z=0;n=0}Y=c[d+52>>2]|0;c[Y+64>>2]=0;c[Y+64+4>>2]=0;c[Y+64+8>>2]=0;c[Y+64+12>>2]=0;h=c[Y+28>>2]|0;if((h|0)>0){y=0;G=0;i=0;k=0;K=0;A=0;f=0;m=0;H=0;t=0;o=0;D=0;L=0;z=0;X=0;while(1){p=c[Y+36>>2]|0;V=c[p+(X*36|0)+4>>2]|0;if((V|0)>0){T=X&65535;U=X|-65536;Q=y;R=A;O=t;N=L;h=0;while(1){S=h+1|0;L=c[p+(X*36|0)+12>>2]|0;t=c[L+(h<<2)>>2]&65535;L=c[L+(((S|0)==(V|0)?0:S)<<2)>>2]&65535;P=L<<16>>16>t<<16>>16?t:L;d=L<<16>>16>t<<16>>16?L:t;p=L<<16>>16>t<<16>>16?t:L;t=L<<16>>16>t<<16>>16?L:t;L=O+-1|0;k:do if((((p&65535)<<16)+(t<<16>>16)&L)>>>0<K>>>0?(da=c[k+((((p&65535)<<16)+(t<<16>>16)&L)<<2)>>2]|0,(da|0)!=-1):0){h=da;while(1){if(t<<16>>16==(b[i+(h<<2)>>1]|0)?p<<16>>16==(b[i+(h<<2)+2>>1]|0):0)break;h=c[m+(h<<2)>>2]|0;if((h|0)==-1){A=0;break k}}A=o+(h<<2)|0}else A=0;while(0);h=c[Y+16>>2]|0;v=+g[h+(p<<16>>16<<4)>>2]-+g[h+(t<<16>>16<<4)>>2];w=+g[h+(p<<16>>16<<4)+4>>2]-+g[h+(t<<16>>16<<4)+4>>2];u=+g[h+(p<<16>>16<<4)+8>>2]-+g[h+(t<<16>>16<<4)+8>>2];s=1.0/+C(+(v*v+w*w+u*u));h=c[Y+48>>2]|0;l:do if((h|0)>0){p=c[Y+56>>2]|0;t=0;while(1){q=+g[p+(t<<4)>>2];r=+g[p+(t<<4)+8>>2];do if(!(+B(+(q-v*s))>1.0e-06)){if(+B(+(+g[p+(t<<4)+4>>2]-w*s))>1.0e-06)break;if(!(+B(+(r-u*s))>1.0e-06))break l}while(0);do if(!(+B(+(v*s+q))>1.0e-06)){if(+B(+(w*s+ +g[p+(t<<4)+4>>2]))>1.0e-06)break;if(!(+B(+(u*s+r))>1.0e-06))break l}while(0);t=t+1|0;if((t|0)>=(h|0)){ca=355;break}}}else ca=355;while(0);if((ca|0)==355){ca=0;do if((h|0)==(c[Y+52>>2]|0)){y=h|0?h<<1:1;if((h|0)>=(y|0))break;if(!y)p=0;else{c[6432]=(c[6432]|0)+1;h=ec((y<<4|3)+16|0)|0;if(!h)p=0;else{c[(h+4+15&-16)+-4>>2]=h;p=h+4+15&-16}h=c[Y+48>>2]|0}if((h|0)>0){t=0;do{M=p+(t<<4)|0;la=(c[Y+56>>2]|0)+(t<<4)|0;c[M>>2]=c[la>>2];c[M+4>>2]=c[la+4>>2];c[M+8>>2]=c[la+8>>2];c[M+12>>2]=c[la+12>>2];t=t+1|0}while((t|0)!=(h|0))}h=c[Y+56>>2]|0;if(h|0){if(a[Y+60>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[Y+56>>2]=0}a[Y+60>>0]=1;c[Y+56>>2]=p;c[Y+52>>2]=y;h=c[Y+48>>2]|0}while(0);la=c[Y+56>>2]|0;g[la+(h<<4)>>2]=v*s;g[la+(h<<4)+4>>2]=w*s;g[la+(h<<4)+8>>2]=u*s;g[la+(h<<4)+12>>2]=0.0;c[Y+48>>2]=(c[Y+48>>2]|0)+1}m:do if(!A){h=((P&65535)<<16)+(d<<16>>16)&L;n:do if(h>>>0<K>>>0){p=c[k+(h<<2)>>2]|0;if((p|0)==-1)break;while(1){if(d<<16>>16==(b[i+(p<<2)>>1]|0)?P<<16>>16==(b[i+(p<<2)+2>>1]|0):0)break;p=c[m+(p<<2)>>2]|0;if((p|0)==-1)break n}y=o+(p<<2)|0;b[y>>1]=U;b[y+2>>1]=U>>>16;y=Q;A=R;t=O;L=N;break m}while(0);do if((H|0)==(O|0)){t=H|0?H<<1:1;if((H|0)>=(t|0)){t=H;break}do if(!t)y=0;else{c[6432]=(c[6432]|0)+1;p=ec((t<<2|3)+16|0)|0;if(!p){y=0;break}c[(p+4+15&-16)+-4>>2]=p;y=p+4+15&-16}while(0);if((H|0)<=0){if(!o){o=y;break}}else{p=0;do{la=y+(p<<2)|0;M=o+(p<<2)|0;M=e[M>>1]|e[M+2>>1]<<16;b[la>>1]=M;b[la+2>>1]=M>>>16;p=p+1|0}while((p|0)!=(H|0))}c[6433]=(c[6433]|0)+1;Pc(c[o+-4>>2]|0);o=y}else t=O;while(0);M=o+(H<<2)|0;b[M>>1]=U;b[M+2>>1]=U>>>16;M=H+1|0;do if((N|0)==(z|0)){z=N|0?N<<1:1;if((N|0)>=(z|0)){z=N;break}do if(!z)y=0;else{c[6432]=(c[6432]|0)+1;p=ec((z<<2|3)+16|0)|0;if(!p){y=0;break}c[(p+4+15&-16)+-4>>2]=p;y=p+4+15&-16}while(0);if((N|0)<=0){if(!i){i=y;break}}else{p=0;do{la=y+(p<<2)|0;L=i+(p<<2)|0;L=e[L>>1]|e[L+2>>1]<<16;b[la>>1]=L;b[la+2>>1]=L>>>16;p=p+1|0}while((p|0)!=(N|0))}c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0);i=y}while(0);L=i+(N<<2)|0;b[L>>1]=(P&65535)<<16|d&65535;b[L+2>>1]=((P&65535)<<16|d&65535)>>>16;L=N+1|0;if((O|0)<(t|0)){do if((K|0)<(t|0)){do if((D|0)<(t|0)){do if(!t)p=0;else{c[6432]=(c[6432]|0)+1;h=ec((t<<2|3)+16|0)|0;if(!h){p=0;break}c[(h+4+15&-16)+-4>>2]=h;p=h+4+15&-16}while(0);if((K|0)<=0){if(!k){G=p;k=p;D=t;break}}else{h=0;do{c[p+(h<<2)>>2]=c[k+(h<<2)>>2];h=h+1|0}while((h|0)!=(K|0))}c[6433]=(c[6433]|0)+1;Pc(c[k+-4>>2]|0);G=p;k=p;D=t}while(0);A=t<<2;Hk(k+(K<<2)|0,0,A-(K<<2)|0)|0;if((R|0)<(t|0)){do if((f|0)<(t|0)){do if(!t)p=0;else{c[6432]=(c[6432]|0)+1;h=ec((A|3)+16|0)|0;if(!h){p=0;break}c[(h+4+15&-16)+-4>>2]=h;p=h+4+15&-16}while(0);if((R|0)<=0){if(!m){h=p;f=t;m=p;break}}else{h=0;do{c[p+(h<<2)>>2]=c[m+(h<<2)>>2];h=h+1|0}while((h|0)!=(R|0))}c[6433]=(c[6433]|0)+1;Pc(c[m+-4>>2]|0);h=p;f=t;m=p}else h=Q;while(0);Hk(m+(R<<2)|0,0,A-(R<<2)|0)|0;y=h}else y=Q;if((t|0)>0){Hk(G|0,-1,A|0)|0;Hk(y|0,-1,A|0)|0}if((K|0)<=0){p=t;A=t;h=D;break}p=t+-1|0;h=0;do{la=k+(((e[i+(h<<2)+2>>1]<<16)+(b[i+(h<<2)>>1]|0)&p)<<2)|0;c[m+(h<<2)>>2]=c[la>>2];c[la>>2]=h;h=h+1|0}while((h|0)!=(K|0));p=t;A=t;h=D}else{y=Q;p=K;A=R;h=D}while(0);D=h;h=((P&65535)<<16)+(d<<16>>16)&t+-1}else{y=Q;p=K;A=R}K=k+(h<<2)|0;c[m+(H<<2)>>2]=c[K>>2];c[K>>2]=H;K=p;H=M}else{b[A+2>>1]=T;y=Q;A=R;t=O;L=N}while(0);if((S|0)>=(V|0))break;p=c[Y+36>>2]|0;Q=y;R=A;O=t;N=L;h=S}h=c[Y+28>>2]|0;p=L}else p=L;X=X+1|0;if((X|0)>=(h|0))break;else L=p}if((h|0)>0){z=c[Y+36>>2]|0;A=c[Y+16>>2]|0;q=0.0;D=0;do{t=c[z+(D*36|0)+4>>2]|0;f=c[z+(D*36|0)+12>>2]|0;y=c[f>>2]|0;if((t+-2|0)>=1){r=+g[Y+64>>2];s=+g[Y+68>>2];u=+g[Y+72>>2];p=1;do{da=c[f+(p<<2)>>2]|0;p=p+1|0;la=c[f+(((p|0)%(t|0)|0)<<2)>>2]|0;v=+g[A+(y<<4)>>2];w=+g[A+(da<<4)>>2];E=+g[A+(y<<4)+4>>2];F=+g[A+(da<<4)+4>>2];J=+g[A+(y<<4)+8>>2];W=+g[A+(da<<4)+8>>2];x=+g[A+(la<<4)>>2];I=+g[A+(la<<4)+4>>2];ja=+g[A+(la<<4)+8>>2];ka=+C(+(((v-w)*(E-I)-(E-F)*(v-x))*((v-w)*(E-I)-(E-F)*(v-x))+(((E-F)*(J-ja)-(J-W)*(E-I))*((E-F)*(J-ja)-(J-W)*(E-I))+((J-W)*(v-x)-(v-w)*(J-ja))*((J-W)*(v-x)-(v-w)*(J-ja)))))*.5;r=r+(v+w+x)*.3333333432674408*ka;g[Y+64>>2]=r;s=(E+F+I)*.3333333432674408*ka+s;g[Y+68>>2]=s;u=ka*(J+W+ja)*.3333333432674408+u;g[Y+72>>2]=u;q=q+ka}while((p|0)!=(t+-1|0))}D=D+1|0}while((D|0)!=(h|0));p=Y+64|0;t=1;y=i;f=k}else ca=334}else{i=0;k=0;m=0;o=0;ca=334}if((ca|0)==334){q=0.0;p=Y+64|0;t=0;y=i;f=k}u=1.0/q;v=u*+g[p>>2];g[p>>2]=v;s=u*+g[Y+68>>2];g[Y+68>>2]=s;u=u*+g[Y+72>>2];g[Y+72>>2]=u;g[Y+96>>2]=3402823466385288598117041.0e14;if(t){i=c[Y+36>>2]|0;q=3402823466385288598117041.0e14;k=0;do{r=+B(+(+g[i+(k*36|0)+32>>2]+(+g[i+(k*36|0)+20>>2]*v+ +g[i+(k*36|0)+24>>2]*s+ +g[i+(k*36|0)+28>>2]*u)));if(r<q){g[Y+96>>2]=r;q=r}k=k+1|0}while((k|0)<(h|0))}else q=3402823466385288598117041.0e14;h=c[Y+8>>2]|0;if((h|0)>0){i=c[Y+16>>2]|0;x=-3402823466385288598117041.0e14;w=-3402823466385288598117041.0e14;v=-3402823466385288598117041.0e14;u=3402823466385288598117041.0e14;s=3402823466385288598117041.0e14;r=3402823466385288598117041.0e14;k=0;do{ka=+g[i+(k<<4)>>2];u=ka<u?ka:u;x=ka>x?ka:x;ka=+g[i+(k<<4)+4>>2];s=ka<s?ka:s;w=ka>w?ka:w;ka=+g[i+(k<<4)+8>>2];r=ka<r?ka:r;v=ka>v?ka:v;k=k+1|0}while((k|0)!=(h|0))}else{x=-3402823466385288598117041.0e14;w=-3402823466385288598117041.0e14;v=-3402823466385288598117041.0e14;u=3402823466385288598117041.0e14;s=3402823466385288598117041.0e14;r=3402823466385288598117041.0e14}g[Y+100>>2]=u+x;g[Y+104>>2]=s+w;g[Y+108>>2]=r+v;g[Y+112>>2]=0.0;ja=x-u;ka=w-s;r=v-r;g[Y+116>>2]=ja;g[Y+120>>2]=ka;g[Y+124>>2]=r;g[Y+128>>2]=0.0;s=q/1.7320507764816284;p=+g[Y+116+((ja<ka&1)<<2)>>2]<r?2:ja<ka&1;r=(+g[Y+116+(p<<2)>>2]*.5-s)*.0009765625;g[Y+88>>2]=s;g[Y+84>>2]=s;g[Y+80>>2]=s;q=+g[Y+116+(p<<2)>>2]*.5;g[Y+80+(p<<2)>>2]=q;h=0;while(1){if(Lg(Y)|0){ca=440;break}q=q-r;g[Y+80+(p<<2)>>2]=q;h=h+1|0;if((h|0)>=1024){ca=439;break}}o:do if((ca|0)==439){g[Y+88>>2]=s;g[Y+84>>2]=s;g[Y+80>>2]=s}else if((ca|0)==440){r=(+g[Y+96>>2]-s)*.0009765625;i=c[Y+80+((1<<(1<<p&3)&3)<<2)>>2]|0;k=0;while(1){h=c[Y+80+((1<<p&3)<<2)>>2]|0;g[Y+80+((1<<p&3)<<2)>>2]=r+(c[j>>2]=h,+g[j>>2]);q=r+ +g[Y+80+((1<<(1<<p&3)&3)<<2)>>2];g[Y+80+((1<<(1<<p&3)&3)<<2)>>2]=q;k=k+1|0;if(!(Lg(Y)|0))break;if((k|0)>=1024)break o;else i=(g[j>>2]=q,c[j>>2]|0)}c[Y+80+((1<<p&3)<<2)>>2]=h;c[Y+80+((1<<(1<<p&3)&3)<<2)>>2]=i}while(0);if(y|0){c[6433]=(c[6433]|0)+1;Pc(c[y+-4>>2]|0)}if(o|0){c[6433]=(c[6433]|0)+1;Pc(c[o+-4>>2]|0)}if(m|0){c[6433]=(c[6433]|0)+1;Pc(c[m+-4>>2]|0)}if(f|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}if(!((n|0)==0|(Z|0)==0)){c[6433]=(c[6433]|0)+1;Pc(c[Z+-4>>2]|0)}o=c[_>>2]|0;p=c[aa>>2]|0;if((o|0)<=0){if(p|0)ca=461}else{k=0;do{n=p+(k*36|0)+4|0;m=p+(k*36|0)+12|0;i=c[m>>2]|0;h=p+(k*36|0)+16|0;if(i|0){if(a[h>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[m>>2]=0}a[h>>0]=1;c[m>>2]=0;c[n>>2]=0;c[p+(k*36|0)+8>>2]=0;k=k+1|0}while((k|0)!=(o|0));ca=461}if((ca|0)==461){if(a[ia+56+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[p+-4>>2]|0)}c[aa>>2]=0}if(!(($|0)==0|(ba|0)==0)){c[6433]=(c[6433]|0)+1;Pc(c[ba+-4>>2]|0)}h=c[ea>>2]|0;if(h|0){if(a[ia+76+56>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[ea>>2]=0}a[ia+76+56>>0]=1;c[ea>>2]=0;c[ia+76+44>>2]=0;c[ia+76+48>>2]=0;h=c[fa>>2]|0;if(h|0){if(a[ia+76+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[fa>>2]=0}a[ia+76+36>>0]=1;c[fa>>2]=0;c[ia+76+24>>2]=0;c[ia+76+28>>2]=0;h=c[ga>>2]|0;if(h|0){if(a[ia+76+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[ga>>2]=0}if(!ha){l=ia;return 1}c[6433]=(c[6433]|0)+1;Pc(c[ha+-4>>2]|0);l=ia;return 1}function Xb(b,d,e,f,h){b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0,j=0,k=0,m=0,n=0.0,o=0.0,p=0.0,q=0.0,r=0,s=0.0,t=0.0,u=0.0,v=0.0,w=0,x=0.0,y=0.0,z=0.0,A=0.0,D=0.0,G=0,H=0.0,I=0,J=0,K=0,L=0.0,M=0,N=0.0,O=0.0,P=0.0,Q=0.0,R=0.0,S=0.0,T=0,U=0,V=0,W=0.0,X=0.0,Y=0.0,Z=0.0,_=0.0,$=0.0,aa=0.0,ba=0.0,ca=0.0,da=0.0,ea=0.0,fa=0.0,ga=0.0,ha=0.0,ia=0.0,ja=0.0,ka=0.0,la=0.0,ma=0,na=0.0,oa=0.0,pa=0.0,qa=0.0,ra=0,sa=0,ta=0,ua=0,va=0;va=l;l=l+688|0;j=c[b+20>>2]|0;if(!j){j=c[b+4>>2]|0;j=vb[c[(c[j>>2]|0)+12>>2]&63](j,c[d+8>>2]|0,c[e+8>>2]|0)|0;c[b+20>>2]=j;a[b+16>>0]=1}c[h+4>>2]=j;ra=c[d+4>>2]|0;sa=c[e+4>>2]|0;k=c[ra+4>>2]|0;i=c[sa+4>>2]|0;if((k|0)==10&(i|0)==10){O=+g[j+752>>2];ma=c[ra+52>>2]|0;t=+g[ra+28+(ma<<2)>>2];N=+g[ra+28+(((ma+2|0)%3|0)<<2)>>2];ta=c[sa+52>>2]|0;o=+g[sa+28+(ta<<2)>>2];L=+g[sa+28+(((ta+2|0)%3|0)<<2)>>2];b=c[d+12>>2]|0;r=c[e+12>>2]|0;A=+g[b+(ma<<2)>>2];D=+g[b+16+(ma<<2)>>2];H=+g[b+32+(ma<<2)>>2];q=+g[r+(ta<<2)>>2];s=+g[r+16+(ta<<2)>>2];v=+g[r+32+(ta<<2)>>2];x=+g[r+48>>2]-+g[b+48>>2];y=+g[r+52>>2]-+g[b+52>>2];z=+g[r+56>>2]-+g[b+56>>2];n=1.0-(A*q+D*s+H*v)*(A*q+D*s+H*v);if(!(n==0.0)){n=(A*x+D*y+H*z-(A*q+D*s+H*v)*(q*x+s*y+v*z))/n;if(!(n<-t)){if(n>t){n=t;ua=7}}else{n=-t;ua=7}}else{n=0.0;ua=7}p=(A*q+D*s+H*v)*n-(q*x+s*y+v*z);if(p<-o){n=(A*q+D*s+H*v)*-o+(A*x+D*y+H*z);if(!(n<-t))if(n>t){n=t;o=-o}else o=-o;else{n=-t;o=-o}}else if(p>o){n=o*(A*q+D*s+H*v)+(A*x+D*y+H*z);if(!(n<-t)){if(n>t)n=t}else n=-t}else o=p;u=q*o;t=s*o;s=v*o;p=u+(x-A*n);o=t+(y-D*n);n=s+(z-H*n);q=+C(+(n*n+(p*p+o*o)));if(!(q-N-L>O)){do if(n*n+(p*p+o*o)<=1.4210854715202004e-14)if(+B(+H)>.7071067690849304){n=1.0/+C(+(D*D+H*H));g[va+280>>2]=0.0;g[va+280+4>>2]=-(H*n);n=D*n;i=2;k=va+280|0;m=va+280+4|0;break}else{n=1.0/+C(+(A*A+D*D));g[va+280>>2]=-(D*n);g[va+280+4>>2]=A*n;n=0.0;i=2;k=va+280|0;m=va+280+4|0;break}else{g[va+280>>2]=p*-(1.0/q);g[va+280+4>>2]=o*-(1.0/q);g[va+280+8>>2]=n*-(1.0/q);n=0.0;i=3;k=va+280|0;m=va+280+4|0}while(0);g[va+280+(i<<2)>>2]=n;pa=t+ +g[r+52>>2]+L*+g[m>>2];qa=s+ +g[r+56>>2]+L*+g[va+280+8>>2];g[va+264>>2]=u+ +g[r+48>>2]+L*+g[k>>2];g[va+264+4>>2]=pa;g[va+264+8>>2]=qa;g[va+264+12>>2]=0.0}if(q-N-L<O){Qb[c[(c[h>>2]|0)+16>>2]&15](h,va+280|0,va+264|0,q-N-L);j=c[h+4>>2]|0}if(!(c[j+748>>2]|0)){l=va;return}k=c[j+740>>2]|0;m=c[(c[h+8>>2]|0)+8>>2]|0;i=c[(c[h+12>>2]|0)+8>>2]|0;if((k|0)==(m|0)){Le(j,k+4|0,i+4|0);l=va;return}else{Le(j,i+4|0,m+4|0);l=va;return}}g[va+128+128>>2]=999999984306749440.0;w=c[b+8>>2]|0;I=c[b+12>>2]|0;c[va+48>>2]=9360;c[va+48+4>>2]=0;c[va+48+8>>2]=1065353216;c[va+48+12>>2]=0;g[va+48+16>>2]=0.0;c[va+48+20>>2]=I;c[va+48+24>>2]=w;c[va+48+28>>2]=ra;c[va+48+32>>2]=sa;c[va+48+36>>2]=k;c[va+48+40>>2]=i;g[va+48+44>>2]=+zb[c[(c[ra>>2]|0)+48>>2]&15](ra);g[va+48+48>>2]=+zb[c[(c[sa>>2]|0)+48>>2]&15](sa);a[va+48+52>>0]=0;c[va+48+60>>2]=-1;c[va+48+72>>2]=1;c[va+48+76>>2]=1;c[va+48+28>>2]=ra;c[va+48+32>>2]=sa;pa=+zb[c[(c[ra>>2]|0)+48>>2]&15](ra);qa=+zb[c[(c[sa>>2]|0)+48>>2]&15](sa);qa=pa+qa+ +g[(c[b+20>>2]|0)+752>>2];g[va+128+128>>2]=qa*qa;i=c[d+12>>2]|0;c[va+128>>2]=c[i>>2];c[va+128+4>>2]=c[i+4>>2];c[va+128+8>>2]=c[i+8>>2];c[va+128+12>>2]=c[i+12>>2];w=va+128+16|0;c[w>>2]=c[i+16>>2];c[w+4>>2]=c[i+16+4>>2];c[w+8>>2]=c[i+16+8>>2];c[w+12>>2]=c[i+16+12>>2];k=va+128+32|0;c[k>>2]=c[i+32>>2];c[k+4>>2]=c[i+32+4>>2];c[k+8>>2]=c[i+32+8>>2];c[k+12>>2]=c[i+32+12>>2];I=va+128+48|0;c[I>>2]=c[i+48>>2];c[I+4>>2]=c[i+48+4>>2];c[I+8>>2]=c[i+48+8>>2];c[I+12>>2]=c[i+48+12>>2];i=c[e+12>>2]|0;K=va+128+64|0;c[K>>2]=c[i>>2];c[K+4>>2]=c[i+4>>2];c[K+8>>2]=c[i+8>>2];c[K+12>>2]=c[i+12>>2];G=va+128+80|0;c[G>>2]=c[i+16>>2];c[G+4>>2]=c[i+16+4>>2];c[G+8>>2]=c[i+16+8>>2];c[G+12>>2]=c[i+16+12>>2];r=va+128+96|0;c[r>>2]=c[i+32>>2];c[r+4>>2]=c[i+32+4>>2];c[r+8>>2]=c[i+32+8>>2];c[r+12>>2]=c[i+32+12>>2];J=va+128+112|0;c[J>>2]=c[i+48>>2];c[J+4>>2]=c[i+48+4>>2];c[J+8>>2]=c[i+48+8>>2];c[J+12>>2]=c[i+48+12>>2];i=c[ra+4>>2]|0;if((i|0)<7?(m=c[sa+4>>2]|0,(m|0)<7):0){c[va+40>>2]=6204;if(!i){i=m;o=0.0}else{o=+zb[c[(c[ra>>2]|0)+48>>2]&15](ra);i=c[sa+4>>2]|0}if(!i)n=0.0;else n=+zb[c[(c[sa>>2]|0)+48>>2]&15](sa);c[va>>2]=6232;c[va+4>>2]=h;g[va+24>>2]=o;g[va+28>>2]=n;a[va+36>>0]=0;V=c[ra+52>>2]|0;a:do if(V|0){ma=c[sa+52>>2]|0;do if(!ma){if((c[sa+4>>2]|0)!=1)break a;G=va+624+16|0;a[G>>0]=1;w=va+624+12|0;c[w>>2]=0;r=va+624+4|0;c[r>>2]=0;m=va+624+8|0;c[m>>2]=0;i=c[e+12>>2]|0;pa=+g[sa+56>>2];qa=+g[sa+56+4>>2];o=+g[sa+56+8>>2];n=pa*+g[i>>2]+qa*+g[i+4>>2]+o*+g[i+8>>2]+ +g[i+48>>2];p=pa*+g[i+16>>2]+qa*+g[i+20>>2]+o*+g[i+24>>2]+ +g[i+52>>2];o=pa*+g[i+32>>2]+qa*+g[i+36>>2]+o*+g[i+40>>2]+ +g[i+56>>2];c[6432]=(c[6432]|0)+1;i=ec(35)|0;if(!i)j=0;else{c[(i+4+15&-16)+-4>>2]=i;j=i+4+15&-16}i=c[w>>2]|0;if(!i)i=0;else{c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0);i=c[r>>2]|0;c[w>>2]=0}a[G>>0]=1;c[w>>2]=j;c[m>>2]=1;g[j+(i<<4)>>2]=n;g[j+(i<<4)+4>>2]=p;g[j+(i<<4)+8>>2]=o;g[j+(i<<4)+12>>2]=0.0;i=(c[r>>2]|0)+1|0;c[r>>2]=i;ua=c[e+12>>2]|0;pa=+g[sa+56+16>>2];qa=+g[sa+56+20>>2];o=+g[sa+56+24>>2];n=pa*+g[ua>>2]+qa*+g[ua+4>>2]+o*+g[ua+8>>2]+ +g[ua+48>>2];p=pa*+g[ua+16>>2]+qa*+g[ua+20>>2]+o*+g[ua+24>>2]+ +g[ua+52>>2];o=pa*+g[ua+32>>2]+qa*+g[ua+36>>2]+o*+g[ua+40>>2]+ +g[ua+56>>2];if((i|0)==(c[m>>2]|0)?(M=i|0?i<<1:1,(i|0)<(M|0)):0){if(!M)j=0;else{c[6432]=(c[6432]|0)+1;i=ec((M<<4|3)+16|0)|0;if(!i)j=0;else{c[(i+4+15&-16)+-4>>2]=i;j=i+4+15&-16}i=c[r>>2]|0}if((i|0)>0){k=0;do{ua=j+(k<<4)|0;ta=(c[w>>2]|0)+(k<<4)|0;c[ua>>2]=c[ta>>2];c[ua+4>>2]=c[ta+4>>2];c[ua+8>>2]=c[ta+8>>2];c[ua+12>>2]=c[ta+12>>2];k=k+1|0}while((k|0)!=(i|0))}i=c[w>>2]|0;if(i|0){if(a[G>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[w>>2]=0}a[G>>0]=1;c[w>>2]=j;c[m>>2]=M;i=c[r>>2]|0}ua=c[w>>2]|0;g[ua+(i<<4)>>2]=n;g[ua+(i<<4)+4>>2]=p;g[ua+(i<<4)+8>>2]=o;g[ua+(i<<4)+12>>2]=0.0;i=(c[r>>2]|0)+1|0;c[r>>2]=i;ua=c[e+12>>2]|0;pa=+g[sa+56+32>>2];qa=+g[sa+56+36>>2];o=+g[sa+56+40>>2];n=pa*+g[ua>>2]+qa*+g[ua+4>>2]+o*+g[ua+8>>2]+ +g[ua+48>>2];p=pa*+g[ua+16>>2]+qa*+g[ua+20>>2]+o*+g[ua+24>>2]+ +g[ua+52>>2];o=pa*+g[ua+32>>2]+qa*+g[ua+36>>2]+o*+g[ua+40>>2]+ +g[ua+56>>2];if((i|0)==(c[m>>2]|0)?(T=i|0?i<<1:1,(i|0)<(T|0)):0){if(!T)j=0;else{c[6432]=(c[6432]|0)+1;i=ec((T<<4|3)+16|0)|0;if(!i)j=0;else{c[(i+4+15&-16)+-4>>2]=i;j=i+4+15&-16}i=c[r>>2]|0}if((i|0)>0){k=0;do{ua=j+(k<<4)|0;ta=(c[w>>2]|0)+(k<<4)|0;c[ua>>2]=c[ta>>2];c[ua+4>>2]=c[ta+4>>2];c[ua+8>>2]=c[ta+8>>2];c[ua+12>>2]=c[ta+12>>2];k=k+1|0}while((k|0)!=(i|0))}i=c[w>>2]|0;if(i|0){if(a[G>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[w>>2]=0}a[G>>0]=1;c[w>>2]=j;c[m>>2]=T;i=c[r>>2]|0}ua=c[w>>2]|0;g[ua+(i<<4)>>2]=n;g[ua+(i<<4)+4>>2]=p;g[ua+(i<<4)+8>>2]=o;g[ua+(i<<4)+12>>2]=0.0;c[r>>2]=(c[r>>2]|0)+1;q=+g[(c[b+20>>2]|0)+752>>2];Ac(va+48|0,va+128|0,va+40|0,c[f+20>>2]|0,0);n=+g[va+48+4>>2];o=+g[va+48+8>>2];p=+g[va+48+12>>2];if(n*n+o*o+p*p>1.1920928955078125e-07){pa=1.0/(n*n+o*o+p*p);g[va+384>>2]=n*pa;g[va+384+4>>2]=o*pa;g[va+384+8>>2]=p*pa;g[va+384+12>>2]=0.0;pa=+g[va+48+56>>2];qa=+zb[c[(c[ra>>2]|0)+48>>2]&15](ra);qa=pa-qa-+zb[c[(c[sa>>2]|0)+48>>2]&15](sa);Bc(va+384|0,c[ra+52>>2]|0,c[d+12>>2]|0,va+624|0,qa-q,q,h)}do if(a[b+16>>0]|0?(U=c[h+4>>2]|0,c[U+748>>2]|0):0){j=c[U+740>>2]|0;k=c[(c[h+8>>2]|0)+8>>2]|0;i=c[(c[h+12>>2]|0)+8>>2]|0;if((j|0)==(k|0)){Le(U,j+4|0,i+4|0);break}else{Le(U,i+4|0,k+4|0);break}}while(0);i=c[w>>2]|0;if(i|0){if(a[G>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[w>>2]=0}}else{qa=+g[(c[b+20>>2]|0)+752>>2];b:do if(!(a[f+24>>0]|0)){Ac(va+48|0,va+128|0,va,c[f+20>>2]|0,0);n=+g[va+32>>2];if(n<0.0&(a[va+36>>0]|0)!=0){o=+g[va+8>>2];p=+g[va+12>>2];q=+g[va+16>>2];i=c[va+20>>2]|0;ua=111}}else{I=c[d+12>>2]|0;G=c[e+12>>2]|0;c[6415]=(c[6415]|0)+1;ha=+g[V+64>>2];ia=+g[V+68>>2];n=+g[I+4>>2];ja=+g[V+72>>2];o=+g[I+8>>2];p=+g[I+16>>2];q=+g[I+20>>2];s=+g[I+24>>2];t=+g[I+32>>2];u=+g[I+36>>2];v=+g[I+40>>2];ka=+g[ma+64>>2];la=+g[ma+68>>2];oa=+g[ma+72>>2];na=ha*+g[I>>2]+ia*n+ja*o+ +g[I+48>>2]-(ka*+g[G>>2]+la*+g[G+4>>2]+oa*+g[G+8>>2]+ +g[G+48>>2]);pa=ha*p+ia*q+ja*s+ +g[I+52>>2]-(ka*+g[G+16>>2]+la*+g[G+20>>2]+oa*+g[G+24>>2]+ +g[G+52>>2]);oa=ha*t+ia*u+ja*v+ +g[I+56>>2]-(ka*+g[G+32>>2]+la*+g[G+36>>2]+oa*+g[G+40>>2]+ +g[G+56>>2]);k=c[V+28>>2]|0;c:do if((k|0)>0){A=o;D=p;z=q;H=0.0;L=3402823466385288598117041.0e14;j=0;o=0.0;p=0.0;q=0.0;while(1){f=c[V+36>>2]|0;ja=+g[f+(j*36|0)+20>>2];ka=+g[f+(j*36|0)+24>>2];la=+g[f+(j*36|0)+28>>2];x=ja*+g[I>>2]+ka*n+la*A;s=ja*D+ka*z+la*s;n=ja*t+ka*u+la*v;g[va+296>>2]=x;g[va+296+4>>2]=s;g[va+296+8>>2]=n;g[va+296+12>>2]=0.0;if(na*x+pa*s+oa*n<0.0){g[va+296>>2]=-x;g[va+296+4>>2]=-s;g[va+296+8>>2]=-n;x=-x;y=-s;n=-n}else y=s;c[6413]=(c[6413]|0)+1;if(ji(I,G,na,pa,oa,x,y,n,V,ma,L)|0){c[6414]=(c[6414]|0)+1;Mg(V,I,va+296|0,va+624|0,va+384|0,va+360|0,va+344|0);Mg(ma,G,va+296|0,va+380|0,va+376|0,va+328|0,va+312|0);s=+g[va+384>>2];t=+g[va+380>>2];do if(s<t){t=H;i=0}else{u=+g[va+376>>2];v=+g[va+624>>2];if(u<v){t=H;i=0;break}t=s-t<u-v?s-t:u-v;i=1}while(0);if(!i)break;if(t<L){s=t;o=x;p=y;q=n}else s=L;y=t;x=s}else{y=H;x=L}i=j+1|0;if((i|0)>=(k|0)){n=x;break c}n=+g[I+4>>2];A=+g[I+8>>2];D=+g[I+16>>2];z=+g[I+20>>2];s=+g[I+24>>2];t=+g[I+32>>2];u=+g[I+36>>2];v=+g[I+40>>2];H=y;L=x;j=i}break b}else{n=3402823466385288598117041.0e14;o=0.0;p=0.0;q=0.0}while(0);k=c[ma+28>>2]|0;d:do if((k|0)>0){A=0.0;j=0;while(1){f=c[ma+36>>2]|0;ka=+g[f+(j*36|0)+20>>2];la=+g[f+(j*36|0)+24>>2];u=+g[f+(j*36|0)+28>>2];s=ka*+g[G>>2]+la*+g[G+4>>2]+u*+g[G+8>>2];t=ka*+g[G+16>>2]+la*+g[G+20>>2]+u*+g[G+24>>2];u=ka*+g[G+32>>2]+la*+g[G+36>>2]+u*+g[G+40>>2];g[va+296>>2]=s;g[va+296+4>>2]=t;g[va+296+8>>2]=u;g[va+296+12>>2]=0.0;if(na*s+pa*t+oa*u<0.0){g[va+296>>2]=-s;g[va+296+4>>2]=-t;g[va+296+8>>2]=-u;s=-s;t=-t;u=-u}c[6413]=(c[6413]|0)+1;if(ji(I,G,na,pa,oa,s,t,u,V,ma,n)|0){c[6414]=(c[6414]|0)+1;Mg(V,I,va+296|0,va+624|0,va+384|0,va+360|0,va+344|0);Mg(ma,G,va+296|0,va+380|0,va+376|0,va+328|0,va+312|0);v=+g[va+384>>2];x=+g[va+380>>2];do if(v<x){v=A;i=0}else{y=+g[va+376>>2];z=+g[va+624>>2];if(y<z){v=A;i=0;break}v=v-x<y-z?v-x:y-z;i=1}while(0);if(!i)break;if(v<n){n=v;o=s;p=t;q=u}}else v=A;j=j+1|0;if((j|0)>=(k|0))break d;else A=v}break b}while(0);i=c[V+48>>2]|0;e:do if((i|0)>0){j=c[ma+48>>2]|0;u=0.0;w=0;k=-1;m=-1;v=0.0;y=0.0;z=0.0;A=0.0;D=0.0;W=0.0;Y=0.0;s=0.0;t=0.0;S=0.0;R=0.0;Q=0.0;N=0.0;O=0.0;P=0.0;x=0.0;H=0.0;L=0.0;f:while(1){f=c[V+56>>2]|0;ha=+g[f+(w<<4)>>2];ia=+g[f+(w<<4)+4>>2];ja=+g[f+(w<<4)+8>>2];la=ha*+g[I>>2]+ia*+g[I+4>>2]+ja*+g[I+8>>2];ka=ha*+g[I+16>>2]+ia*+g[I+20>>2]+ja*+g[I+24>>2];ja=ha*+g[I+32>>2]+ia*+g[I+36>>2]+ja*+g[I+40>>2];if((j|0)>0){X=u;r=0;ia=o;ha=p;ga=q;_=v;aa=y;ca=z;while(1){f=c[ma+56>>2]|0;ea=+g[f+(r<<4)>>2];fa=+g[f+(r<<4)+4>>2];ba=+g[f+(r<<4)+8>>2];Z=ea*+g[G>>2]+fa*+g[G+4>>2]+ba*+g[G+8>>2];$=ea*+g[G+16>>2]+fa*+g[G+20>>2]+ba*+g[G+24>>2];ba=ea*+g[G+32>>2]+fa*+g[G+36>>2]+ba*+g[G+40>>2];g[va+296>>2]=ka*ba-ja*$;g[va+296+4>>2]=ja*Z-la*ba;g[va+296+8>>2]=la*$-ka*Z;g[va+296+12>>2]=0.0;do if(!(+B(+(ka*ba-ja*$))>1.0e-06)){if(+B(+(ja*Z-la*ba))>1.0e-06){ua=75;break}if(!(+B(+(la*$-ka*Z))>1.0e-06)){o=ia;p=ha;q=ga;da=A;ea=D;fa=W}else ua=75}else ua=75;while(0);do if((ua|0)==75){ua=0;q=1.0/+C(+((ka*ba-ja*$)*(ka*ba-ja*$)+(ja*Z-la*ba)*(ja*Z-la*ba)+(la*$-ka*Z)*(la*$-ka*Z)));o=(ka*ba-ja*$)*q;g[va+296>>2]=o;p=(ja*Z-la*ba)*q;g[va+296+4>>2]=p;q=(la*$-ka*Z)*q;g[va+296+8>>2]=q;if(o*na+p*pa+oa*q<0.0){g[va+296>>2]=-o;g[va+296+4>>2]=-p;g[va+296+8>>2]=-q;o=-o;p=-p;q=-q}c[6413]=(c[6413]|0)+1;if(!(ji(I,G,na,pa,oa,o,p,q,V,ma,n)|0)){o=ia;p=ha;q=ga;da=A;ea=D;fa=W;break}c[6414]=(c[6414]|0)+1;Mg(V,I,va+296|0,va+624|0,va+384|0,va+360|0,va+344|0);Mg(ma,G,va+296|0,va+380|0,va+376|0,va+328|0,va+312|0);u=+g[va+384>>2];v=+g[va+380>>2];do if(!(u<v)){y=+g[va+376>>2];z=+g[va+624>>2];if(y<z){u=X;i=0;v=_;y=aa;z=ca;break}if(u-v<y-z){u=u-v;i=1;v=+g[va+344>>2];y=+g[va+344+4>>2];z=+g[va+344+8>>2];A=+g[va+328>>2];D=+g[va+328+4>>2];W=+g[va+328+8>>2];break}else{u=y-z;i=1;v=+g[va+360>>2];y=+g[va+360+4>>2];z=+g[va+360+8>>2];A=+g[va+312>>2];D=+g[va+312+4>>2];W=+g[va+312+8>>2];break}}else{u=X;i=0;v=_;y=aa;z=ca}while(0);if(!i)break f;if(!(u<n)){X=u;o=ia;p=ha;q=ga;_=v;aa=y;ca=z;da=A;ea=D;fa=W;break}X=u;n=u;k=w;m=r;_=v;aa=y;ca=z;da=A;ea=D;fa=W;Y=v;s=y;t=z;S=A;R=D;Q=W;N=la;O=ka;P=ja;x=Z;H=$;L=ba}while(0);r=r+1|0;j=c[ma+48>>2]|0;if((r|0)>=(j|0))break;else{ia=o;ha=p;ga=q;A=da;D=ea;W=fa}}i=c[V+48>>2]|0;u=X;v=_;y=aa;z=ca;A=da;D=ea;W=fa;X=Y}else X=Y;w=w+1|0;if((w|0)>=(i|0)){j=k;i=m;n=X;break e}else Y=X}break b}else{j=-1;i=-1;n=0.0;s=0.0;t=0.0;S=0.0;R=0.0;Q=0.0;N=0.0;O=0.0;P=0.0;x=0.0;H=0.0;L=0.0}while(0);if((i|j|0)>-1){z=S-n;D=R-s;A=Q-t;u=x*N+H*O+L*P;v=z*N+D*O+A*P;s=z*x+D*H+A*L;do if(!(1.0-u*u==0.0)){if((v-s*u)/(1.0-u*u)<-1000000015047466219876688.0e6){n=-1000000015047466219876688.0e6;ua=94;break}if((v-s*u)/(1.0-u*u)>1000000015047466219876688.0e6){n=1000000015047466219876688.0e6;ua=94}else t=(v-s*u)/(1.0-u*u)}else{n=0.0;ua=94}while(0);if((ua|0)==94)t=n;n=u*t-s;do if(n<-1000000015047466219876688.0e6){if(v-u*1000000015047466219876688.0e6<-1000000015047466219876688.0e6){s=-1000000015047466219876688.0e6;n=-1000000015047466219876688.0e6;break}if(!(v-u*1000000015047466219876688.0e6>1000000015047466219876688.0e6)){s=v-u*1000000015047466219876688.0e6;n=-1000000015047466219876688.0e6;break}s=1000000015047466219876688.0e6;n=-1000000015047466219876688.0e6}else{if(!(n>1000000015047466219876688.0e6)){s=t;break}if(v+u*1000000015047466219876688.0e6<-1000000015047466219876688.0e6){s=-1000000015047466219876688.0e6;n=1000000015047466219876688.0e6;break}if(!(v+u*1000000015047466219876688.0e6>1000000015047466219876688.0e6)){s=v+u*1000000015047466219876688.0e6;n=1000000015047466219876688.0e6;break}s=1000000015047466219876688.0e6;n=1000000015047466219876688.0e6}while(0);y=x*n;x=H*n;v=L*n;u=y+(z-N*s);t=x+(D-O*s);n=v+(A-P*s);g[va+624>>2]=u;g[va+624+4>>2]=t;g[va+624+8>>2]=n;g[va+624+12>>2]=0.0;if(u*u+t*t+n*n>1.1920928955078125e-07){s=+C(+(u*u+t*t+n*n));g[va+624>>2]=u*(1.0/s);g[va+624+4>>2]=1.0/s*t;g[va+624+8>>2]=1.0/s*n;if(u*(1.0/s)*na+1.0/s*t*pa+1.0/s*n*oa<0.0){g[va+624>>2]=-(u*(1.0/s));g[va+624+4>>2]=-(1.0/s*t);g[va+624+8>>2]=-(1.0/s*n)}g[va+384>>2]=S+y;g[va+384+4>>2]=R+x;g[va+384+8>>2]=Q+v;g[va+384+12>>2]=0.0;Qb[c[(c[h>>2]|0)+16>>2]&15](h,va+624|0,va+384|0,-s)}}if(na*o+pa*p+oa*q<0.0){n=-1000000015047466219876688.0e6;o=-o;p=-p;q=-q;i=0;ua=111}else{n=-1000000015047466219876688.0e6;i=0;ua=111}}while(0);if((ua|0)==111){V=c[ra+52>>2]|0;f=c[sa+52>>2]|0;U=c[d+12>>2]|0;T=c[e+12>>2]|0;O=n-qa;H=1.0/+C(+(o*o+p*p+q*q));N=o*H;L=p*H;H=q*H;g[va+624>>2]=N;g[va+624+4>>2]=L;g[va+624+8>>2]=H;c[va+624+12>>2]=i;j=c[f+28>>2]|0;r=c[f+36>>2]|0;if((j|0)>0){n=+g[T>>2];o=+g[T+4>>2];p=+g[T+8>>2];q=+g[T+16>>2];s=+g[T+20>>2];t=+g[T+24>>2];u=+g[T+32>>2];v=+g[T+36>>2];x=+g[T+40>>2];i=-1;D=-3402823466385288598117041.0e14;m=0;while(1){y=+g[r+(m*36|0)+20>>2];z=+g[r+(m*36|0)+24>>2];A=+g[r+(m*36|0)+28>>2];k=(y*n+z*o+A*p)*N+(y*q+z*s+A*t)*L+(y*u+z*v+A*x)*H>D;i=k?m:i;m=m+1|0;if((m|0)==(j|0)){J=i;break}else D=k?(y*n+z*o+A*p)*N+(y*q+z*s+A*t)*L+(y*u+z*v+A*x)*H:D}}else J=-1;a[va+384+16>>0]=1;M=va+384+12|0;c[M>>2]=0;K=va+384+4|0;c[K>>2]=0;c[va+384+8>>2]=0;I=c[r+(J*36|0)+4>>2]|0;g:do if((I|0)>0){G=r+(J*36|0)+12|0;i=0;k=0;j=0;while(1){d=c[(c[G>>2]|0)+(j<<2)>>2]|0;e=c[f+16>>2]|0;oa=+g[e+(d<<4)>>2];pa=+g[e+(d<<4)+4>>2];o=+g[e+(d<<4)+8>>2];n=oa*+g[T>>2]+pa*+g[T+4>>2]+o*+g[T+8>>2]+ +g[T+48>>2];p=oa*+g[T+16>>2]+pa*+g[T+20>>2]+o*+g[T+24>>2]+ +g[T+52>>2];o=oa*+g[T+32>>2]+pa*+g[T+36>>2]+o*+g[T+40>>2]+ +g[T+56>>2];if((i|0)==(k|0)){w=k|0?k<<1:1;if((k|0)<(w|0)){if(!w){i=k;k=0}else{c[6432]=(c[6432]|0)+1;i=ec((w<<4|3)+16|0)|0;if(!i)k=0;else{c[(i+4+15&-16)+-4>>2]=i;k=i+4+15&-16}i=c[K>>2]|0}r=c[M>>2]|0;if((i|0)<=0){if(r)ua=126}else{m=0;do{d=k+(m<<4)|0;ua=r+(m<<4)|0;c[d>>2]=c[ua>>2];c[d+4>>2]=c[ua+4>>2];c[d+8>>2]=c[ua+8>>2];c[d+12>>2]=c[ua+12>>2];m=m+1|0}while((m|0)!=(i|0));ua=126}if((ua|0)==126){ua=0;if(a[va+384+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[r+-4>>2]|0);i=c[K>>2]|0}c[M>>2]=0}a[va+384+16>>0]=1;c[M>>2]=k;c[va+384+8>>2]=w}else i=k}d=c[M>>2]|0;g[d+(i<<4)>>2]=n;g[d+(i<<4)+4>>2]=p;g[d+(i<<4)+8>>2]=o;g[d+(i<<4)+12>>2]=0.0;i=(c[K>>2]|0)+1|0;c[K>>2]=i;j=j+1|0;if((j|0)>=(I|0))break g;k=c[va+384+8>>2]|0}}while(0);if((J|0)>-1)Bc(va+624|0,V,U,va+384|0,O,qa,h);i=c[M>>2]|0;if(i|0){if(a[va+384+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[M>>2]=0}}if(a[b+16>>0]|0?(ta=c[h+4>>2]|0,c[ta+748>>2]|0):0){j=c[ta+740>>2]|0;k=c[(c[h+8>>2]|0)+8>>2]|0;i=c[(c[h+12>>2]|0)+8>>2]|0;if((j|0)==(k|0)){Le(ta,j+4|0,i+4|0);break}else{Le(ta,i+4|0,k+4|0);break}}}while(0);l=va;return}while(0)}Ac(va+48|0,va+128|0,h,c[f+20>>2]|0,0);if((c[b+28>>2]|0?(c[(c[h+4>>2]|0)+748>>2]|0)<(c[b+32>>2]|0):0)?(O=+g[va+48+4>>2],P=+g[va+48+8>>2],Q=+g[va+48+12>>2],O*O+P*P+Q*Q>1.1920928955078125e-07):0){D=1.0/(O*O+P*P+Q*Q);if(+B(+(Q*D))>.7071067690849304){N=1.0/+C(+(Q*D*Q*D+P*D*P*D));H=0.0;L=P*D*N;N=-(Q*D*N)}else{N=1.0/+C(+(O*D*O*D+P*D*P*D));H=-(P*D*N);L=0.0;N=O*D*N}A=+zb[c[(c[ra>>2]|0)+16>>2]&15](ra);z=+zb[c[(c[sa>>2]|0)+16>>2]&15](sa);n=.019999999552965164/(A<z?A:z);if(A<z){c[va+624>>2]=c[va+128>>2];c[va+624+4>>2]=c[va+128+4>>2];c[va+624+8>>2]=c[va+128+8>>2];c[va+624+12>>2]=c[va+128+12>>2];c[va+624+16>>2]=c[w>>2];c[va+624+16+4>>2]=c[w+4>>2];c[va+624+16+8>>2]=c[w+8>>2];c[va+624+16+12>>2]=c[w+12>>2];c[va+624+32>>2]=c[k>>2];c[va+624+32+4>>2]=c[k+4>>2];c[va+624+32+8>>2]=c[k+8>>2];c[va+624+32+12>>2]=c[k+12>>2];c[va+624+48>>2]=c[I>>2];c[va+624+48+4>>2]=c[I+4>>2];c[va+624+48+8>>2]=c[I+8>>2];c[va+624+48+12>>2]=c[I+12>>2]}else{c[va+624>>2]=c[K>>2];c[va+624+4>>2]=c[K+4>>2];c[va+624+8>>2]=c[K+8>>2];c[va+624+12>>2]=c[K+12>>2];c[va+624+16>>2]=c[G>>2];c[va+624+16+4>>2]=c[G+4>>2];c[va+624+16+8>>2]=c[G+8>>2];c[va+624+16+12>>2]=c[G+12>>2];c[va+624+32>>2]=c[r>>2];c[va+624+32+4>>2]=c[r+4>>2];c[va+624+32+8>>2]=c[r+8>>2];c[va+624+32+12>>2]=c[r+12>>2];c[va+624+48>>2]=c[J>>2];c[va+624+48+4>>2]=c[J+4>>2];c[va+624+48+8>>2]=c[J+8>>2];c[va+624+48+12>>2]=c[J+12>>2]}i=c[b+28>>2]|0;if((i|0)>0){y=H*H+N*N+L*L;x=(n>.39269909262657166?.39269909262657166:n)*.5;j=0;do{if(y>1.1920928955078125e-07){t=+F(+x)/+C(+y);u=H*t;v=N*t;t=L*t;s=+E(+x);n=+(j|0)*(6.2831854820251465/+(i|0))*.5;o=+F(+n)/+C(+(Q*D*Q*D+(O*D*O*D+P*D*P*D)));p=O*D*o;q=P*D*o;o=Q*D*o;n=+E(+n);if(A<z){la=o*(u*-o+(v*n+s*-q)-t*-p)+(p*(s*n-u*-p-v*-q-t*-o)+n*(t*-q+(u*n+s*-p)-v*-o))-q*(v*-p+(t*n+s*-o)-u*-q);oa=p*(v*-p+(t*n+s*-o)-u*-q)+(n*(u*-o+(v*n+s*-q)-t*-p)+q*(s*n-u*-p-v*-q-t*-o))-o*(t*-q+(u*n+s*-p)-v*-o);aa=q*(t*-q+(u*n+s*-p)-v*-o)+(o*(s*n-u*-p-v*-q-t*-o)+n*(v*-p+(t*n+s*-o)-u*-q))-p*(u*-o+(v*n+s*-q)-t*-p);ja=n*(s*n-u*-p-v*-q-t*-o)-p*(t*-q+(u*n+s*-p)-v*-o)-q*(u*-o+(v*n+s*-q)-t*-p)-o*(v*-p+(t*n+s*-o)-u*-q);na=la*(2.0/(ja*ja+(aa*aa+(la*la+oa*oa))));pa=oa*(2.0/(ja*ja+(aa*aa+(la*la+oa*oa))));ia=aa*(2.0/(ja*ja+(aa*aa+(la*la+oa*oa))));ua=c[d+12>>2]|0;ba=+g[ua>>2];ca=+g[ua+16>>2];da=+g[ua+32>>2];ea=+g[ua+4>>2];fa=+g[ua+20>>2];ga=+g[ua+36>>2];ha=+g[ua+8>>2];ka=+g[ua+24>>2];qa=+g[ua+40>>2];g[va+128>>2]=(1.0-(oa*pa+aa*ia))*ba+(la*pa-ja*ia)*ca+(la*ia+ja*pa)*da;g[va+128+4>>2]=(1.0-(oa*pa+aa*ia))*ea+(la*pa-ja*ia)*fa+(la*ia+ja*pa)*ga;g[va+128+8>>2]=(1.0-(oa*pa+aa*ia))*ha+(la*pa-ja*ia)*ka+(la*ia+ja*pa)*qa;g[va+128+12>>2]=0.0;g[va+128+16>>2]=(la*pa+ja*ia)*ba+(1.0-(la*na+aa*ia))*ca+(oa*ia-ja*na)*da;g[va+128+20>>2]=(la*pa+ja*ia)*ea+(1.0-(la*na+aa*ia))*fa+(oa*ia-ja*na)*ga;g[va+128+24>>2]=(la*pa+ja*ia)*ha+(1.0-(la*na+aa*ia))*ka+(oa*ia-ja*na)*qa;g[va+128+28>>2]=0.0;g[va+128+32>>2]=(la*ia-ja*pa)*ba+(oa*ia+ja*na)*ca+(1.0-(la*na+oa*pa))*da;g[va+128+36>>2]=(la*ia-ja*pa)*ea+(oa*ia+ja*na)*fa+(1.0-(la*na+oa*pa))*ga;g[va+128+40>>2]=(la*ia-ja*pa)*ha+(oa*ia+ja*na)*ka+(1.0-(la*na+oa*pa))*qa;g[va+128+44>>2]=0.0;ua=c[e+12>>2]|0;c[K>>2]=c[ua>>2];c[K+4>>2]=c[ua+4>>2];c[K+8>>2]=c[ua+8>>2];c[K+12>>2]=c[ua+12>>2];c[G>>2]=c[ua+16>>2];c[G+4>>2]=c[ua+16+4>>2];c[G+8>>2]=c[ua+16+8>>2];c[G+12>>2]=c[ua+16+12>>2];c[r>>2]=c[ua+32>>2];c[r+4>>2]=c[ua+32+4>>2];c[r+8>>2]=c[ua+32+8>>2];c[r+12>>2]=c[ua+32+12>>2];c[J>>2]=c[ua+48>>2];c[J+4>>2]=c[ua+48+4>>2];c[J+8>>2]=c[ua+48+8>>2];c[J+12>>2]=c[ua+48+12>>2]}else{ua=c[d+12>>2]|0;c[va+128>>2]=c[ua>>2];c[va+128+4>>2]=c[ua+4>>2];c[va+128+8>>2]=c[ua+8>>2];c[va+128+12>>2]=c[ua+12>>2];c[w>>2]=c[ua+16>>2];c[w+4>>2]=c[ua+16+4>>2];c[w+8>>2]=c[ua+16+8>>2];c[w+12>>2]=c[ua+16+12>>2];c[k>>2]=c[ua+32>>2];c[k+4>>2]=c[ua+32+4>>2];c[k+8>>2]=c[ua+32+8>>2];c[k+12>>2]=c[ua+32+12>>2];c[I>>2]=c[ua+48>>2];c[I+4>>2]=c[ua+48+4>>2];c[I+8>>2]=c[ua+48+8>>2];c[I+12>>2]=c[ua+48+12>>2];la=o*(u*-o+(v*n+s*-q)-t*-p)+(p*(s*n-u*-p-v*-q-t*-o)+n*(t*-q+(u*n+s*-p)-v*-o))-q*(v*-p+(t*n+s*-o)-u*-q);oa=p*(v*-p+(t*n+s*-o)-u*-q)+(n*(u*-o+(v*n+s*-q)-t*-p)+q*(s*n-u*-p-v*-q-t*-o))-o*(t*-q+(u*n+s*-p)-v*-o);aa=q*(t*-q+(u*n+s*-p)-v*-o)+(o*(s*n-u*-p-v*-q-t*-o)+n*(v*-p+(t*n+s*-o)-u*-q))-p*(u*-o+(v*n+s*-q)-t*-p);ja=n*(s*n-u*-p-v*-q-t*-o)-p*(t*-q+(u*n+s*-p)-v*-o)-q*(u*-o+(v*n+s*-q)-t*-p)-o*(v*-p+(t*n+s*-o)-u*-q);na=la*(2.0/(ja*ja+(aa*aa+(la*la+oa*oa))));pa=oa*(2.0/(ja*ja+(aa*aa+(la*la+oa*oa))));ia=aa*(2.0/(ja*ja+(aa*aa+(la*la+oa*oa))));ua=c[e+12>>2]|0;ba=+g[ua>>2];ca=+g[ua+16>>2];da=+g[ua+32>>2];ea=+g[ua+4>>2];fa=+g[ua+20>>2];ga=+g[ua+36>>2];ha=+g[ua+8>>2];ka=+g[ua+24>>2];qa=+g[ua+40>>2];g[va+128+64>>2]=(1.0-(oa*pa+aa*ia))*ba+(la*pa-ja*ia)*ca+(la*ia+ja*pa)*da;g[va+128+68>>2]=(1.0-(oa*pa+aa*ia))*ea+(la*pa-ja*ia)*fa+(la*ia+ja*pa)*ga;g[va+128+72>>2]=(1.0-(oa*pa+aa*ia))*ha+(la*pa-ja*ia)*ka+(la*ia+ja*pa)*qa;g[va+128+76>>2]=0.0;g[va+128+80>>2]=(la*pa+ja*ia)*ba+(1.0-(la*na+aa*ia))*ca+(oa*ia-ja*na)*da;g[va+128+84>>2]=(la*pa+ja*ia)*ea+(1.0-(la*na+aa*ia))*fa+(oa*ia-ja*na)*ga;g[va+128+88>>2]=(la*pa+ja*ia)*ha+(1.0-(la*na+aa*ia))*ka+(oa*ia-ja*na)*qa;g[va+128+92>>2]=0.0;g[va+128+96>>2]=(la*ia-ja*pa)*ba+(oa*ia+ja*na)*ca+(1.0-(la*na+oa*pa))*da;g[va+128+100>>2]=(la*ia-ja*pa)*ea+(oa*ia+ja*na)*fa+(1.0-(la*na+oa*pa))*ga;g[va+128+104>>2]=(la*ia-ja*pa)*ha+(oa*ia+ja*na)*ka+(1.0-(la*na+oa*pa))*qa;g[va+128+108>>2]=0.0}i=c[f+20>>2]|0;c[va+384>>2]=6260;c[va+384+32>>2]=h;c[va+384+36>>2]=c[va+128>>2];c[va+384+36+4>>2]=c[va+128+4>>2];c[va+384+36+8>>2]=c[va+128+8>>2];c[va+384+36+12>>2]=c[va+128+12>>2];c[va+384+52>>2]=c[w>>2];c[va+384+52+4>>2]=c[w+4>>2];c[va+384+52+8>>2]=c[w+8>>2];c[va+384+52+12>>2]=c[w+12>>2];c[va+384+68>>2]=c[k>>2];c[va+384+68+4>>2]=c[k+4>>2];c[va+384+68+8>>2]=c[k+8>>2];c[va+384+68+12>>2]=c[k+12>>2];c[va+384+84>>2]=c[I>>2];c[va+384+84+4>>2]=c[I+4>>2];c[va+384+84+8>>2]=c[I+8>>2];c[va+384+84+12>>2]=c[I+12>>2];c[va+384+100>>2]=c[K>>2];c[va+384+100+4>>2]=c[K+4>>2];c[va+384+100+8>>2]=c[K+8>>2];c[va+384+100+12>>2]=c[K+12>>2];c[va+384+116>>2]=c[G>>2];c[va+384+116+4>>2]=c[G+4>>2];c[va+384+116+8>>2]=c[G+8>>2];c[va+384+116+12>>2]=c[G+12>>2];c[va+384+132>>2]=c[r>>2];c[va+384+132+4>>2]=c[r+4>>2];c[va+384+132+8>>2]=c[r+8>>2];c[va+384+132+12>>2]=c[r+12>>2];c[va+384+148>>2]=c[J>>2];c[va+384+148+4>>2]=c[J+4>>2];c[va+384+148+8>>2]=c[J+8>>2];c[va+384+148+12>>2]=c[J+12>>2];c[va+384+164>>2]=c[va+624>>2];c[va+384+164+4>>2]=c[va+624+4>>2];c[va+384+164+8>>2]=c[va+624+8>>2];c[va+384+164+12>>2]=c[va+624+12>>2];c[va+384+180>>2]=c[va+624+16>>2];c[va+384+180+4>>2]=c[va+624+16+4>>2];c[va+384+180+8>>2]=c[va+624+16+8>>2];c[va+384+180+12>>2]=c[va+624+16+12>>2];c[va+384+196>>2]=c[va+624+32>>2];c[va+384+196+4>>2]=c[va+624+32+4>>2];c[va+384+196+8>>2]=c[va+624+32+8>>2];c[va+384+196+12>>2]=c[va+624+32+12>>2];c[va+384+212>>2]=c[va+624+48>>2];c[va+384+212+4>>2]=c[va+624+48+4>>2];c[va+384+212+8>>2]=c[va+624+48+8>>2];c[va+384+212+12>>2]=c[va+624+48+12>>2];a[va+384+228>>0]=A<z&1;c[va+384+232>>2]=i;Ac(va+48|0,va+128|0,va+384|0,i,0);i=c[b+28>>2]|0}j=j+1|0}while((j|0)<(i|0))}}if(!(a[b+16>>0]|0)){l=va;return}j=c[h+4>>2]|0;if(!(c[j+748>>2]|0)){l=va;return}k=c[j+740>>2]|0;m=c[(c[h+8>>2]|0)+8>>2]|0;i=c[(c[h+12>>2]|0)+8>>2]|0;if((k|0)==(m|0)){Le(j,k+4|0,i+4|0);l=va;return}else{Le(j,i+4|0,m+4|0);l=va;return}}function Yb(b){b=b|0;var d=0,e=0,f=0,h=0.0,i=0.0,k=0.0,m=0,n=0,o=0,p=0,q=0,r=0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0.0,Y=0.0,Z=0.0,_=0.0,$=0.0,aa=0.0,ba=0.0,ca=0.0,da=0.0,ea=0.0,fa=0.0,ga=0.0;W=l;l=l+176|0;ac(b);if(!(lb[c[(c[b>>2]|0)+20>>2]&127](b)|0)){l=W;return}if((c[b+328>>2]|0)<=0){l=W;return}U=W+96+32|0;V=W+96+52|0;T=0;do{R=c[(c[b+336>>2]|0)+(T<<2)>>2]|0;if(lb[c[(c[b>>2]|0)+20>>2]&127](b)|0?(M=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0,(lb[c[(c[M>>2]|0)+48>>2]&127](M)|0)&1|0):0){d=c[b+72>>2]|0;if(!(a[R+473>>0]|0))M=d;else{c[W+80>>2]=c[R+520>>2];c[W+80+4>>2]=c[R+520+4>>2];c[W+80+8>>2]=c[R+520+8>>2];c[W+80+12>>2]=c[R+520+12>>2];h=+g[R+584>>2];i=+g[R+536>>2];k=+g[R+600>>2];s=+g[R+540>>2];t=+g[R+616>>2];u=+g[R+544>>2];v=+g[R+588>>2];w=+g[R+604>>2];x=+g[R+620>>2];y=+g[R+592>>2];z=+g[R+608>>2];A=+g[R+624>>2];B=+g[R+552>>2];D=+g[R+556>>2];E=+g[R+560>>2];F=+g[R+568>>2];G=+g[R+572>>2];H=+g[R+576>>2];ga=h*i+k*s+t*u+(i*v+s*w+u*x)*0.0+(i*y+s*z+u*A)*0.0;ea=(y*B+z*D+A*E)*0.0+(h*B+k*D+t*E+(v*B+w*D+x*E)*0.0);da=(y*F+z*G+A*H)*0.0+(h*F+k*G+t*H+(v*F+w*G+x*H)*0.0);fa=1.0/+C(+(ga*ga+ea*ea+da*da));ca=(h*i+k*s+t*u)*0.0+(i*v+s*w+u*x)+(i*y+s*z+u*A)*0.0;aa=(y*B+z*D+A*E)*0.0+(v*B+w*D+x*E+(h*B+k*D+t*E)*0.0);$=(y*F+z*G+A*H)*0.0+(v*F+w*G+x*H+(h*F+k*G+t*H)*0.0);ba=1.0/+C(+(ca*ca+aa*aa+$*$));_=(h*i+k*s+t*u)*0.0+(i*v+s*w+u*x)*0.0+(i*y+s*z+u*A);Y=y*B+z*D+A*E+((h*B+k*D+t*E)*0.0+(v*B+w*D+x*E)*0.0);X=y*F+z*G+A*H+((h*F+k*G+t*H)*0.0+(v*F+w*G+x*H)*0.0);Z=1.0/+C(+(_*_+Y*Y+X*X));M=c[(c[d>>2]|0)+8>>2]|0;ea=ea*fa*10.0+ +g[W+80+4>>2];da=fa*da*10.0+ +g[W+80+8>>2];g[W+160>>2]=ga*fa*10.0+ +g[W+80>>2];g[W+160+4>>2]=ea;g[W+160+8>>2]=da;g[W+160+12>>2]=0.0;c[W+96>>2]=1065353216;c[W+96+4>>2]=0;c[W+96+8>>2]=0;g[W+96+12>>2]=0.0;Vb[M&127](d,W+80|0,W+160|0,W+96|0);M=c[(c[d>>2]|0)+8>>2]|0;aa=aa*ba*10.0+ +g[W+80+4>>2];$=ba*$*10.0+ +g[W+80+8>>2];g[W+160>>2]=ca*ba*10.0+ +g[W+80>>2];g[W+160+4>>2]=aa;g[W+160+8>>2]=$;g[W+160+12>>2]=0.0;c[W+96>>2]=0;c[W+96+4>>2]=1065353216;c[W+96+8>>2]=0;g[W+96+12>>2]=0.0;Vb[M&127](d,W+80|0,W+160|0,W+96|0);M=c[(c[d>>2]|0)+8>>2]|0;Y=Y*Z*10.0+ +g[W+80+4>>2];X=Z*X*10.0+ +g[W+80+8>>2];g[W+160>>2]=_*Z*10.0+ +g[W+80>>2];g[W+160+4>>2]=Y;g[W+160+8>>2]=X;g[W+160+12>>2]=0.0;c[W+96>>2]=0;c[W+96+4>>2]=0;c[W+96+8>>2]=1065353216;g[W+96+12>>2]=0.0;Vb[M&127](d,W+80|0,W+160|0,W+96|0);if((c[R+484>>2]|0)>0){e=0;do{M=c[R+492>>2]|0;ca=+g[M+(e<<4)>>2];da=+g[M+(e<<4)+4>>2];ga=+g[M+(e<<4)+8>>2];ea=+g[W+80>>2]+((h*i+k*s+t*u)*ca+(i*v+s*w+u*x)*da+(i*y+s*z+u*A)*ga);fa=+g[W+80+4>>2]+((h*B+k*D+t*E)*ca+(v*B+w*D+x*E)*da+(y*B+z*D+A*E)*ga);ga=(h*F+k*G+t*H)*ca+(v*F+w*G+x*H)*da+(y*F+z*G+A*H)*ga+ +g[W+80+8>>2];c[W+64>>2]=1065353216;c[W+64+4>>2]=0;c[W+64+8>>2]=1065353216;g[W+64+12>>2]=0.0;M=c[(c[d>>2]|0)+8>>2]|0;g[W+160>>2]=ea+-.10000000149011612;g[W+160+4>>2]=fa;g[W+160+8>>2]=ga;g[W+160+12>>2]=0.0;g[W+96>>2]=ea+.10000000149011612;g[W+96+4>>2]=fa+0.0;g[W+96+8>>2]=ga+0.0;g[W+96+12>>2]=0.0;Vb[M&127](d,W+160|0,W+96|0,W+64|0);M=c[(c[d>>2]|0)+8>>2]|0;g[W+160>>2]=ea;g[W+160+4>>2]=fa+-.10000000149011612;g[W+160+8>>2]=ga;g[W+160+12>>2]=0.0;g[W+96>>2]=ea+0.0;g[W+96+4>>2]=fa+.10000000149011612;g[W+96+8>>2]=ga+0.0;g[W+96+12>>2]=0.0;Vb[M&127](d,W+160|0,W+96|0,W+64|0);M=c[(c[d>>2]|0)+8>>2]|0;g[W+160>>2]=ea;g[W+160+4>>2]=fa;g[W+160+8>>2]=ga+-.10000000149011612;g[W+160+12>>2]=0.0;g[W+96>>2]=ea+0.0;g[W+96+4>>2]=fa+0.0;g[W+96+8>>2]=ga+.10000000149011612;g[W+96+12>>2]=0.0;Vb[M&127](d,W+160|0,W+96|0,W+64|0);e=e+1|0}while((e|0)<(c[R+484>>2]|0))}M=c[b+72>>2]|0}L=c[b+344>>2]|0;c[W+80>>2]=0;c[W+80+4>>2]=0;c[W+80+8>>2]=0;c[W+80+12>>2]=0;c[W+64>>2]=1065353216;c[W+64+4>>2]=1065353216;c[W+64+8>>2]=1065353216;g[W+64+12>>2]=0.0;c[W+48>>2]=1065353216;c[W+48+4>>2]=0;c[W+48+8>>2]=0;g[W+48+12>>2]=0.0;if(!(L&256)){if(L&1|0?(S=c[R+712>>2]|0,(S|0)>0):0){d=S;f=0;do{e=c[R+720>>2]|0;if(c[(c[e+(f*104|0)+4>>2]|0)+16>>2]&1){d=c[(c[M>>2]|0)+8>>2]|0;K=e+(f*104|0)+8|0;I=e+(f*104|0)+12|0;q=c[I>>2]|0;J=e+(f*104|0)+16|0;r=c[J>>2]|0;g[W+160>>2]=+g[K>>2]+-.10000000149011612;c[W+160+4>>2]=q;c[W+160+8>>2]=r;g[W+160+12>>2]=0.0;fa=+g[I>>2]+0.0;ga=+g[J>>2]+0.0;g[W+96>>2]=+g[K>>2]+.10000000149011612;g[W+96+4>>2]=fa;g[W+96+8>>2]=ga;g[W+96+12>>2]=0.0;c[W+32>>2]=1065353216;c[W+32+4>>2]=0;c[W+32+8>>2]=0;g[W+32+12>>2]=0.0;Vb[d&127](M,W+160|0,W+96|0,W+32|0);d=c[(c[M>>2]|0)+8>>2]|0;ga=+g[I>>2]+-.10000000149011612;r=c[J>>2]|0;c[W+160>>2]=c[K>>2];g[W+160+4>>2]=ga;c[W+160+8>>2]=r;g[W+160+12>>2]=0.0;ga=+g[I>>2]+.10000000149011612;fa=+g[J>>2]+0.0;g[W+96>>2]=+g[K>>2]+0.0;g[W+96+4>>2]=ga;g[W+96+8>>2]=fa;g[W+96+12>>2]=0.0;c[W+32>>2]=0;c[W+32+4>>2]=1065353216;c[W+32+8>>2]=0;g[W+32+12>>2]=0.0;Vb[d&127](M,W+160|0,W+96|0,W+32|0);d=c[(c[M>>2]|0)+8>>2]|0;r=c[I>>2]|0;fa=+g[J>>2]+-.10000000149011612;c[W+160>>2]=c[K>>2];c[W+160+4>>2]=r;g[W+160+8>>2]=fa;g[W+160+12>>2]=0.0;fa=+g[I>>2]+0.0;ga=+g[J>>2]+.10000000149011612;g[W+96>>2]=+g[K>>2]+0.0;g[W+96+4>>2]=fa;g[W+96+8>>2]=ga;g[W+96+12>>2]=0.0;c[W+32>>2]=0;c[W+32+4>>2]=0;c[W+32+8>>2]=1065353216;g[W+32+12>>2]=0.0;Vb[d&127](M,W+160|0,W+96|0,W+32|0);d=c[R+712>>2]|0}f=f+1|0}while((f|0)<(d|0))}if(L&2|0?(N=c[R+732>>2]|0,(N|0)>0):0){d=N;f=0;do{e=c[R+740>>2]|0;if(c[(c[e+(f*52|0)+4>>2]|0)+16>>2]&1){Vb[c[(c[M>>2]|0)+8>>2]&127](M,(c[e+(f*52|0)+8>>2]|0)+8|0,(c[e+(f*52|0)+12>>2]|0)+8|0,W+80|0);d=c[R+732>>2]|0}f=f+1|0}while((f|0)<(d|0))}if(L&16|0?(O=c[R+712>>2]|0,(O|0)>0):0){d=O;f=0;do{e=c[R+720>>2]|0;if(c[(c[e+(f*104|0)+4>>2]|0)+16>>2]&1){ea=+g[e+(f*104|0)+72>>2]*.5;ga=+g[e+(f*104|0)+76>>2]*.5;fa=+g[e+(f*104|0)+80>>2]*.5;K=c[(c[M>>2]|0)+8>>2]|0;d=e+(f*104|0)+8|0;I=e+(f*104|0)+12|0;ca=ga+ +g[I>>2];J=e+(f*104|0)+16|0;da=fa+ +g[J>>2];g[W+160>>2]=ea+ +g[d>>2];g[W+160+4>>2]=ca;g[W+160+8>>2]=da;g[W+160+12>>2]=0.0;Vb[K&127](M,d,W+160|0,W+64|0);K=c[(c[M>>2]|0)+8>>2]|0;ga=+g[I>>2]-ga;fa=+g[J>>2]-fa;g[W+160>>2]=+g[d>>2]-ea;g[W+160+4>>2]=ga;g[W+160+8>>2]=fa;g[W+160+12>>2]=0.0;fa=+g[W+64+4>>2]*.5;ga=+g[W+64+8>>2]*.5;g[W+96>>2]=+g[W+64>>2]*.5;g[W+96+4>>2]=fa;g[W+96+8>>2]=ga;g[W+96+12>>2]=0.0;Vb[K&127](M,d,W+160|0,W+96|0);d=c[R+712>>2]|0}f=f+1|0}while((f|0)<(d|0))}if(L&32|0){if((a[22680]|0)==0?jy(22680)|0:0){c[5800]=1065353216;c[5801]=0;c[5802]=0;c[5803]=0;c[5804]=0;c[5805]=1065353216;c[5806]=0;c[5807]=0;c[5808]=0;c[5809]=0;c[5810]=1065353216;g[5811]=0.0}if((c[R+812>>2]|0)>0){d=0;do{K=c[R+820>>2]|0;I=c[K+(d*104|0)+24>>2]|0;B=+g[I+8>>2];J=K+(d*104|0)+4|0;D=+g[J>>2];G=+g[I+12>>2];r=K+(d*104|0)+8|0;H=+g[r>>2];fa=+g[I+16>>2];I=K+(d*104|0)+12|0;da=+g[I>>2];ba=+g[K+(d*104|0)+20>>2]+(B*D+G*H+fa*da);g[W+160>>2]=B-D*ba;g[W+160+4>>2]=G-H*ba;g[W+160+8>>2]=fa-da*ba;g[W+160+12>>2]=0.0;X=+g[J>>2];Z=+g[r>>2];E=+g[I>>2];K=+g[K+(d*104|0)+4+((!(X<Z)&1)<<2)>>2]<E?!(X<Z)&1:2;F=+g[23200+(K<<4)+8>>2];Y=+g[23200+(K<<4)+4>>2];_=+g[23200+(K<<4)>>2];$=1.0/+C(+((X*Y-Z*_)*(X*Y-Z*_)+((Z*F-E*Y)*(Z*F-E*Y)+(E*_-X*F)*(E*_-X*F))));aa=E*(E*_-X*F)*$-Z*(X*Y-Z*_)*$;ca=X*(X*Y-Z*_)*$-E*(Z*F-E*Y)*$;ga=Z*(Z*F-E*Y)*$-X*(E*_-X*F)*$;ea=1.0/+C(+(ga*ga+(aa*aa+ca*ca)));K=c[(c[M>>2]|0)+8>>2]|0;g[W+96>>2]=B-D*ba-(Z*F-E*Y)*$*.5;g[W+96+4>>2]=G-H*ba-(E*_-X*F)*$*.5;g[W+96+8>>2]=fa-da*ba-(X*Y-Z*_)*$*.5;g[W+96+12>>2]=0.0;g[W+32>>2]=(Z*F-E*Y)*$*.5+(B-D*ba);g[W+32+4>>2]=(E*_-X*F)*$*.5+(G-H*ba);g[W+32+8>>2]=(X*Y-Z*_)*$*.5+(fa-da*ba);g[W+32+12>>2]=0.0;Vb[K&127](M,W+96|0,W+32|0,W+48|0);K=c[(c[M>>2]|0)+8>>2]|0;ba=+g[W+160>>2];da=+g[W+160+4>>2];fa=+g[W+160+8>>2];g[W+96>>2]=ba-ea*aa*.5;g[W+96+4>>2]=da-ea*ca*.5;g[W+96+8>>2]=fa-ea*ga*.5;g[W+96+12>>2]=0.0;g[W+32>>2]=ea*aa*.5+ba;g[W+32+4>>2]=ea*ca*.5+da;g[W+32+8>>2]=ea*ga*.5+fa;g[W+32+12>>2]=0.0;Vb[K&127](M,W+96|0,W+32|0,W+48|0);K=c[(c[M>>2]|0)+8>>2]|0;fa=+g[r>>2]*.5*3.0+ +g[W+160+4>>2];ga=+g[I>>2]*.5*3.0+ +g[W+160+8>>2];g[W+96>>2]=+g[J>>2]*.5*3.0+ +g[W+160>>2];g[W+96+4>>2]=fa;g[W+96+8>>2]=ga;g[W+96+12>>2]=0.0;c[W+32>>2]=1065353216;c[W+32+4>>2]=1065353216;c[W+32+8>>2]=0;g[W+32+12>>2]=0.0;Vb[K&127](M,W+160|0,W+96|0,W+32|0);d=d+1|0}while((d|0)<(c[R+812>>2]|0))}}if(L&4|0?(c[W+160>>2]=0,c[W+160+4>>2]=1060320051,c[W+160+8>>2]=0,g[W+160+12>>2]=0.0,P=c[R+752>>2]|0,(P|0)>0):0){d=P;f=0;do{e=c[R+760>>2]|0;if(c[(c[e+(f*44|0)+4>>2]|0)+16>>2]&1){d=c[e+(f*44|0)+8>>2]|0;_=+g[d+8>>2];ba=+g[d+12>>2];ea=+g[d+16>>2];d=c[e+(f*44|0)+12>>2]|0;$=+g[d+8>>2];ca=+g[d+12>>2];fa=+g[d+16>>2];d=c[e+(f*44|0)+16>>2]|0;aa=+g[d+8>>2];da=+g[d+12>>2];ga=+g[d+16>>2];d=c[(c[M>>2]|0)+28>>2]|0;g[W+96>>2]=(_+$+aa)*.3333333432674408+(_-(_+$+aa)*.3333333432674408)*.800000011920929;g[W+96+4>>2]=(ba+ca+da)*.3333333432674408+(ba-(ba+ca+da)*.3333333432674408)*.800000011920929;g[W+96+8>>2]=(ea+fa+ga)*.3333333432674408+(ea-(ea+fa+ga)*.3333333432674408)*.800000011920929;g[W+96+12>>2]=0.0;g[W+32>>2]=(_+$+aa)*.3333333432674408+($-(_+$+aa)*.3333333432674408)*.800000011920929;g[W+32+4>>2]=(ba+ca+da)*.3333333432674408+(ca-(ba+ca+da)*.3333333432674408)*.800000011920929;g[W+32+8>>2]=(ea+fa+ga)*.3333333432674408+(fa-(ea+fa+ga)*.3333333432674408)*.800000011920929;g[W+32+12>>2]=0.0;g[W+16>>2]=(_+$+aa)*.3333333432674408+(aa-(_+$+aa)*.3333333432674408)*.800000011920929;g[W+16+4>>2]=(ba+ca+da)*.3333333432674408+(da-(ba+ca+da)*.3333333432674408)*.800000011920929;g[W+16+8>>2]=(ea+fa+ga)*.3333333432674408+(ga-(ea+fa+ga)*.3333333432674408)*.800000011920929;g[W+16+12>>2]=0.0;wb[d&0](M,W+96|0,W+32|0,W+16|0,W+160|0,1.0);d=c[R+752>>2]|0}f=f+1|0}while((f|0)<(d|0))}if(L&8|0?(c[W+160>>2]=1050253722,c[W+160+4>>2]=1050253722,c[W+160+8>>2]=1060320051,g[W+160+12>>2]=0.0,Q=c[R+772>>2]|0,(Q|0)>0):0){d=Q;f=0;do{e=c[R+780>>2]|0;if(c[(c[e+(f*104|0)+4>>2]|0)+16>>2]&1){d=c[e+(f*104|0)+8>>2]|0;y=+g[d+8>>2];B=+g[d+12>>2];F=+g[d+16>>2];d=c[e+(f*104|0)+12>>2]|0;z=+g[d+8>>2];D=+g[d+12>>2];G=+g[d+16>>2];d=c[e+(f*104|0)+16>>2]|0;A=+g[d+8>>2];E=+g[d+12>>2];H=+g[d+16>>2];d=c[e+(f*104|0)+20>>2]|0;ea=+g[d+8>>2];fa=+g[d+12>>2];ga=+g[d+16>>2];d=c[(c[M>>2]|0)+28>>2]|0;ba=(y+z+A+ea)*.25+(y-(y+z+A+ea)*.25)*.800000011920929;ca=(B+D+E+fa)*.25+(B-(B+D+E+fa)*.25)*.800000011920929;da=(F+G+H+ga)*.25+(F-(F+G+H+ga)*.25)*.800000011920929;g[W+96>>2]=ba;g[W+96+4>>2]=ca;g[W+96+8>>2]=da;g[W+96+12>>2]=0.0;X=(y+z+A+ea)*.25+(z-(y+z+A+ea)*.25)*.800000011920929;Y=(B+D+E+fa)*.25+(D-(B+D+E+fa)*.25)*.800000011920929;Z=(F+G+H+ga)*.25+(G-(F+G+H+ga)*.25)*.800000011920929;g[W+32>>2]=X;g[W+32+4>>2]=Y;g[W+32+8>>2]=Z;g[W+32+12>>2]=0.0;_=(y+z+A+ea)*.25+(A-(y+z+A+ea)*.25)*.800000011920929;$=(B+D+E+fa)*.25+(E-(B+D+E+fa)*.25)*.800000011920929;aa=(F+G+H+ga)*.25+(H-(F+G+H+ga)*.25)*.800000011920929;g[W+16>>2]=_;g[W+16+4>>2]=$;g[W+16+8>>2]=aa;g[W+16+12>>2]=0.0;wb[d&0](M,W+96|0,W+32|0,W+16|0,W+160|0,1.0);d=c[(c[M>>2]|0)+28>>2]|0;g[W+96>>2]=ba;g[W+96+4>>2]=ca;g[W+96+8>>2]=da;g[W+96+12>>2]=0.0;g[W+32>>2]=X;g[W+32+4>>2]=Y;g[W+32+8>>2]=Z;g[W+32+12>>2]=0.0;ea=(y+z+A+ea)*.25+(ea-(y+z+A+ea)*.25)*.800000011920929;fa=(B+D+E+fa)*.25+(fa-(B+D+E+fa)*.25)*.800000011920929;ga=(F+G+H+ga)*.25+(ga-(F+G+H+ga)*.25)*.800000011920929;g[W+16>>2]=ea;g[W+16+4>>2]=fa;g[W+16+8>>2]=ga;g[W+16+12>>2]=0.0;wb[d&0](M,W+96|0,W+32|0,W+16|0,W+160|0,1.0);d=c[(c[M>>2]|0)+28>>2]|0;g[W+96>>2]=X;g[W+96+4>>2]=Y;g[W+96+8>>2]=Z;g[W+96+12>>2]=0.0;g[W+32>>2]=_;g[W+32+4>>2]=$;g[W+32+8>>2]=aa;g[W+32+12>>2]=0.0;g[W+16>>2]=ea;g[W+16+4>>2]=fa;g[W+16+8>>2]=ga;g[W+16+12>>2]=0.0;wb[d&0](M,W+96|0,W+32|0,W+16|0,W+160|0,1.0);d=c[(c[M>>2]|0)+28>>2]|0;g[W+96>>2]=_;g[W+96+4>>2]=$;g[W+96+8>>2]=aa;g[W+96+12>>2]=0.0;g[W+32>>2]=ba;g[W+32+4>>2]=ca;g[W+32+8>>2]=da;g[W+32+12>>2]=0.0;g[W+16>>2]=ea;g[W+16+4>>2]=fa;g[W+16+8>>2]=ga;g[W+16+12>>2]=0.0;wb[d&0](M,W+96|0,W+32|0,W+16|0,W+160|0,1.0);d=c[R+772>>2]|0}f=f+1|0}while((f|0)<(d|0))}}else{FG();d=c[R+1112>>2]|0;if((d|0)>0){K=0;do{if(a[(c[(c[R+1120>>2]|0)+(K<<2)>>2]|0)+377>>0]|0){da=+(sr()|0)*4.656612873077393e-10;ea=+(sr()|0)*4.656612873077393e-10;fa=+(sr()|0)*4.656612873077393e-10;ga=1.0/+C(+(fa*fa+(da*da+ea*ea)));g[W+160>>2]=da*ga*.75;g[W+160+4>>2]=ea*ga*.75;g[W+160+8>>2]=fa*ga*.75;g[W+160+12>>2]=0.0;f=c[(c[(c[R+1120>>2]|0)+(K<<2)>>2]|0)+24>>2]|0;if((f|0)>0){c[6432]=(c[6432]|0)+1;d=ec((f<<4|3)+16|0)|0;if(!d)e=0;else{c[(d+4+15&-16)+-4>>2]=d;e=d+4+15&-16}d=0;do{J=e+(d<<4)|0;c[J>>2]=c[W+96>>2];c[J+4>>2]=c[W+96+4>>2];c[J+8>>2]=c[W+96+8>>2];c[J+12>>2]=c[W+96+12>>2];d=d+1|0}while((d|0)!=(f|0));d=0;do{I=(c[(c[(c[(c[R+1120>>2]|0)+(K<<2)>>2]|0)+32>>2]|0)+(d<<2)>>2]|0)+8|0;J=e+(d<<4)|0;c[J>>2]=c[I>>2];c[J+4>>2]=c[I+4>>2];c[J+8>>2]=c[I+8>>2];c[J+12>>2]=c[I+12>>2];d=d+1|0}while((d|0)!=(f|0));J=e;I=e}else{J=0;I=0}a[W+96+16>>0]=1;c[W+96+12>>2]=0;c[W+96+4>>2]=0;c[W+96+8>>2]=0;a[W+96+36>>0]=1;c[U>>2]=0;c[W+96+24>>2]=0;c[W+96+28>>2]=0;a[W+96+56>>0]=1;c[V>>2]=0;c[W+96+44>>2]=0;c[W+96+48>>2]=0;ic(W+96|0,J,f);p=c[W+96+44>>2]|0;if((p|0)>0){n=c[U>>2]|0;r=0;do{q=c[(c[V>>2]|0)+(r<<2)>>2]|0;e=c[n+(q*12|0)+4>>2]|0;d=n+(q*12|0)+(e*12|0)+((c[n+(q*12|0)+(e*12|0)>>2]|0)*12|0)|0;if((d|0)!=(n+(q*12|0)|0)){o=c[W+96+12>>2]|0;f=c[n+(q*12|0)+(e*12|0)+8>>2]|0;m=c[n+(q*12|0)+8>>2]|0;while(1){e=c[d+8>>2]|0;wb[c[(c[M>>2]|0)+28>>2]&0](M,o+(f<<4)|0,o+(m<<4)|0,o+(e<<4)|0,W+160|0,1.0);f=d+((c[d+4>>2]|0)*12|0)|0;d=f+((c[f>>2]|0)*12|0)|0;if((d|0)==(n+(q*12|0)|0))break;else{f=m;m=e}}}r=r+1|0}while((r|0)<(p|0))}d=c[V>>2]|0;if(d|0){if(a[W+96+56>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[V>>2]=0}a[W+96+56>>0]=1;c[V>>2]=0;c[W+96+44>>2]=0;c[W+96+48>>2]=0;d=c[U>>2]|0;if(d|0){if(a[W+96+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[U>>2]=0}a[W+96+36>>0]=1;c[U>>2]=0;c[W+96+24>>2]=0;c[W+96+28>>2]=0;d=c[W+96+12>>2]|0;if(d|0){if(a[W+96+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[W+96+12>>2]=0}if(!((I|0)==0|(J|0)==0)){c[6433]=(c[6433]|0)+1;Pc(c[J+-4>>2]|0)}d=c[R+1112>>2]|0}K=K+1|0}while((K|0)<(d|0))}}if(L&64|0){if((c[R+792>>2]|0)>0){d=0;do{K=c[R+800>>2]|0;q=c[K+(d*96|0)+20>>2]|0;ca=+g[K+(d*96|0)+4>>2];da=+g[K+(d*96|0)+8>>2];ea=+g[K+(d*96|0)+12>>2];fa=ca*+g[q+20>>2]+da*+g[q+24>>2]+ea*+g[q+28>>2]+ +g[q+56>>2];ga=ca*+g[q+36>>2]+da*+g[q+40>>2]+ea*+g[q+44>>2]+ +g[q+60>>2];g[W+32>>2]=ca*+g[q+4>>2]+da*+g[q+8>>2]+ea*+g[q+12>>2]+ +g[q+52>>2];g[W+32+4>>2]=fa;g[W+32+8>>2]=ga;g[W+32+12>>2]=0.0;K=K+(d*96|0)|0;q=c[K>>2]|0;c[W+16>>2]=1065353216;c[W+16+4>>2]=0;c[W+16+8>>2]=0;g[W+16+12>>2]=0.0;J=c[(c[M>>2]|0)+8>>2]|0;ga=+g[q+8>>2];I=c[q+12>>2]|0;r=c[q+16>>2]|0;g[W+160>>2]=ga+-.25;c[W+160+4>>2]=I;c[W+160+8>>2]=r;g[W+160+12>>2]=0.0;fa=(c[j>>2]=I,+g[j>>2])+0.0;ea=(c[j>>2]=r,+g[j>>2])+0.0;g[W+96>>2]=ga+.25;g[W+96+4>>2]=fa;g[W+96+8>>2]=ea;g[W+96+12>>2]=0.0;Vb[J&127](M,W+160|0,W+96|0,W+16|0);J=c[(c[M>>2]|0)+8>>2]|0;r=c[q+8>>2]|0;ea=+g[q+12>>2];I=c[q+16>>2]|0;c[W+160>>2]=r;g[W+160+4>>2]=ea+-.25;c[W+160+8>>2]=I;g[W+160+12>>2]=0.0;fa=(c[j>>2]=r,+g[j>>2])+0.0;ga=(c[j>>2]=I,+g[j>>2])+0.0;g[W+96>>2]=fa;g[W+96+4>>2]=ea+.25;g[W+96+8>>2]=ga;g[W+96+12>>2]=0.0;Vb[J&127](M,W+160|0,W+96|0,W+16|0);J=c[(c[M>>2]|0)+8>>2]|0;I=c[q+8>>2]|0;r=c[q+12>>2]|0;ga=+g[q+16>>2];c[W+160>>2]=I;c[W+160+4>>2]=r;g[W+160+8>>2]=ga+-.25;g[W+160+12>>2]=0.0;ea=(c[j>>2]=I,+g[j>>2])+0.0;fa=(c[j>>2]=r,+g[j>>2])+0.0;g[W+96>>2]=ea;g[W+96+4>>2]=fa;g[W+96+8>>2]=ga+.25;g[W+96+12>>2]=0.0;Vb[J&127](M,W+160|0,W+96|0,W+16|0);c[W+16>>2]=0;c[W+16+4>>2]=1065353216;c[W+16+8>>2]=0;g[W+16+12>>2]=0.0;J=c[(c[M>>2]|0)+8>>2]|0;ga=+g[W+32>>2];r=c[W+32+4>>2]|0;I=c[W+32+8>>2]|0;g[W+160>>2]=ga+-.25;c[W+160+4>>2]=r;c[W+160+8>>2]=I;g[W+160+12>>2]=0.0;fa=(c[j>>2]=r,+g[j>>2])+0.0;ea=(c[j>>2]=I,+g[j>>2])+0.0;g[W+96>>2]=ga+.25;g[W+96+4>>2]=fa;g[W+96+8>>2]=ea;g[W+96+12>>2]=0.0;Vb[J&127](M,W+160|0,W+96|0,W+16|0);J=c[(c[M>>2]|0)+8>>2]|0;I=c[W+32>>2]|0;ea=+g[W+32+4>>2];r=c[W+32+8>>2]|0;c[W+160>>2]=I;g[W+160+4>>2]=ea+-.25;c[W+160+8>>2]=r;g[W+160+12>>2]=0.0;fa=(c[j>>2]=I,+g[j>>2])+0.0;ga=(c[j>>2]=r,+g[j>>2])+0.0;g[W+96>>2]=fa;g[W+96+4>>2]=ea+.25;g[W+96+8>>2]=ga;g[W+96+12>>2]=0.0;Vb[J&127](M,W+160|0,W+96|0,W+16|0);J=c[(c[M>>2]|0)+8>>2]|0;r=c[W+32>>2]|0;I=c[W+32+4>>2]|0;ga=+g[W+32+8>>2];c[W+160>>2]=r;c[W+160+4>>2]=I;g[W+160+8>>2]=ga+-.25;g[W+160+12>>2]=0.0;ea=(c[j>>2]=r,+g[j>>2])+0.0;fa=(c[j>>2]=I,+g[j>>2])+0.0;g[W+96>>2]=ea;g[W+96+4>>2]=fa;g[W+96+8>>2]=ga+.25;g[W+96+12>>2]=0.0;Vb[J&127](M,W+160|0,W+96|0,W+16|0);J=c[(c[M>>2]|0)+8>>2]|0;K=(c[K>>2]|0)+8|0;c[W+160>>2]=1065353216;c[W+160+4>>2]=1065353216;c[W+160+8>>2]=1065353216;g[W+160+12>>2]=0.0;Vb[J&127](M,K,W+32|0,W+160|0);d=d+1|0}while((d|0)<(c[R+792>>2]|0))}d=c[R+712>>2]|0;if((d|0)>0){f=0;do{e=c[R+720>>2]|0;if((c[(c[e+(f*104|0)+4>>2]|0)+16>>2]&1|0)!=0?+g[e+(f*104|0)+88>>2]<=0.0:0){J=e+(f*104|0)+8|0;c[W+32>>2]=1065353216;c[W+32+4>>2]=0;c[W+32+8>>2]=0;g[W+32+12>>2]=0.0;d=c[(c[M>>2]|0)+8>>2]|0;ga=+g[J>>2];K=e+(f*104|0)+12|0;r=c[K>>2]|0;I=e+(f*104|0)+16|0;q=c[I>>2]|0;g[W+160>>2]=ga+-.25;c[W+160+4>>2]=r;c[W+160+8>>2]=q;g[W+160+12>>2]=0.0;fa=(c[j>>2]=r,+g[j>>2])+0.0;ea=(c[j>>2]=q,+g[j>>2])+0.0;g[W+96>>2]=ga+.25;g[W+96+4>>2]=fa;g[W+96+8>>2]=ea;g[W+96+12>>2]=0.0;Vb[d&127](M,W+160|0,W+96|0,W+32|0);d=c[(c[M>>2]|0)+8>>2]|0;q=c[J>>2]|0;ea=+g[K>>2];r=c[I>>2]|0;c[W+160>>2]=q;g[W+160+4>>2]=ea+-.25;c[W+160+8>>2]=r;g[W+160+12>>2]=0.0;fa=(c[j>>2]=q,+g[j>>2])+0.0;ga=(c[j>>2]=r,+g[j>>2])+0.0;g[W+96>>2]=fa;g[W+96+4>>2]=ea+.25;g[W+96+8>>2]=ga;g[W+96+12>>2]=0.0;Vb[d&127](M,W+160|0,W+96|0,W+32|0);d=c[(c[M>>2]|0)+8>>2]|0;J=c[J>>2]|0;K=c[K>>2]|0;ga=+g[I>>2];c[W+160>>2]=J;c[W+160+4>>2]=K;g[W+160+8>>2]=ga+-.25;g[W+160+12>>2]=0.0;ea=(c[j>>2]=J,+g[j>>2])+0.0;fa=(c[j>>2]=K,+g[j>>2])+0.0;g[W+96>>2]=ea;g[W+96+4>>2]=fa;g[W+96+8>>2]=ga+.25;g[W+96+12>>2]=0.0;Vb[d&127](M,W+160|0,W+96|0,W+32|0);d=c[R+712>>2]|0}f=f+1|0}while((f|0)<(d|0))}}if(L&128|0?(c[R+692>>2]|0)>0:0){f=0;do{d=c[R+700>>2]|0;e=d+(f*60|0)+8|0;c[W+160>>2]=c[e>>2];c[W+160+4>>2]=c[e+4>>2];c[W+160+8>>2]=c[e+8>>2];c[W+160+12>>2]=c[e+12>>2];e=c[d+(f*60|0)+24>>2]|0;if((e|0)>0){h=+g[W+160+8>>2];i=+g[W+160>>2];k=+g[W+160+4>>2];m=0;do{K=c[d+(f*60|0)+28+(m<<2)>>2]|0;ga=+g[d+(f*60|0)+44+(m<<2)>>2];i=+g[K+8>>2]*ga+i;k=ga*+g[K+12>>2]+k;h=ga*+g[K+16>>2]+h;g[W+160+8>>2]=h;m=m+1|0}while((m|0)!=(e|0));g[W+160>>2]=i;g[W+160+4>>2]=k}Rb[c[(c[M>>2]|0)+40>>2]&127](M,W+160|0,c[d+(f*60|0)+4>>2]|0);f=f+1|0}while((f|0)<(c[R+692>>2]|0))}if(L&512|0){K=c[R+928>>2]|0;c[W+160>>2]=1065353216;c[W+160+4>>2]=0;c[W+160+8>>2]=1065353216;g[W+160+12>>2]=0.0;c[W+96>>2]=1065353216;c[W+96+4>>2]=1065353216;c[W+96+8>>2]=1065353216;g[W+96+12>>2]=0.0;yf(M,K,0,W+160|0,W+96|0)}if(L&1024|0){K=c[R+988>>2]|0;c[W+160>>2]=0;c[W+160+4>>2]=1065353216;c[W+160+8>>2]=0;g[W+160+12>>2]=0.0;c[W+96>>2]=1065353216;c[W+96+4>>2]=0;c[W+96+8>>2]=0;g[W+96+12>>2]=0.0;yf(M,K,0,W+160|0,W+96|0)}if(L&2048|0){K=c[R+1048>>2]|0;c[W+160>>2]=0;c[W+160+4>>2]=1065353216;c[W+160+8>>2]=1065353216;g[W+160+12>>2]=0.0;c[W+96>>2]=1065353216;c[W+96+4>>2]=0;c[W+96+8>>2]=0;g[W+96+12>>2]=0.0;yf(M,K,0,W+160|0,W+96|0)}a:do if(L&4096|0?(c[R+852>>2]|0)>0:0){e=0;while(1){d=c[(c[R+860>>2]|0)+(e<<2)>>2]|0;switch(lb[c[(c[d>>2]|0)+20>>2]&127](d)|0){case 0:{L=bi(d+4|0)|0;ga=+g[d+28>>2];fa=+g[d+32>>2];ea=+g[d+36>>2];da=ga*+g[L+16>>2]+fa*+g[L+20>>2]+ea*+g[L+24>>2]+ +g[L+52>>2];ca=ga*+g[L+32>>2]+fa*+g[L+36>>2]+ea*+g[L+40>>2]+ +g[L+56>>2];g[W+32>>2]=ga*+g[L>>2]+fa*+g[L+4>>2]+ea*+g[L+8>>2]+ +g[L+48>>2];g[W+32+4>>2]=da;g[W+32+8>>2]=ca;g[W+32+12>>2]=0.0;L=bi(d+16|0)|0;ca=+g[d+44>>2];da=+g[d+48>>2];ea=+g[d+52>>2];fa=ca*+g[L+16>>2]+da*+g[L+20>>2]+ea*+g[L+24>>2]+ +g[L+52>>2];ga=ca*+g[L+32>>2]+da*+g[L+36>>2]+ea*+g[L+40>>2]+ +g[L+56>>2];g[W+16>>2]=ca*+g[L>>2]+da*+g[L+4>>2]+ea*+g[L+8>>2]+ +g[L+48>>2];g[W+16+4>>2]=fa;g[W+16+8>>2]=ga;g[W+16+12>>2]=0.0;L=c[(c[M>>2]|0)+8>>2]|0;K=(bi(d+4|0)|0)+48|0;c[W+160>>2]=1065353216;c[W+160+4>>2]=1065353216;c[W+160+8>>2]=0;g[W+160+12>>2]=0.0;Vb[L&127](M,K,W+32|0,W+160|0);K=c[(c[M>>2]|0)+8>>2]|0;L=(bi(d+16|0)|0)+48|0;c[W+160>>2]=0;c[W+160+4>>2]=1065353216;c[W+160+8>>2]=1065353216;g[W+160+12>>2]=0.0;Vb[K&127](M,L,W+16|0,W+160|0);c[W>>2]=1065353216;c[W+4>>2]=1065353216;c[W+8>>2]=0;g[W+12>>2]=0.0;L=c[(c[M>>2]|0)+8>>2]|0;ga=+g[W+32>>2];K=c[W+32+4>>2]|0;J=c[W+32+8>>2]|0;g[W+160>>2]=ga+-.25;c[W+160+4>>2]=K;c[W+160+8>>2]=J;g[W+160+12>>2]=0.0;fa=(c[j>>2]=K,+g[j>>2])+0.0;ea=(c[j>>2]=J,+g[j>>2])+0.0;g[W+96>>2]=ga+.25;g[W+96+4>>2]=fa;g[W+96+8>>2]=ea;g[W+96+12>>2]=0.0;Vb[L&127](M,W+160|0,W+96|0,W);L=c[(c[M>>2]|0)+8>>2]|0;J=c[W+32>>2]|0;ea=+g[W+32+4>>2];K=c[W+32+8>>2]|0;c[W+160>>2]=J;g[W+160+4>>2]=ea+-.25;c[W+160+8>>2]=K;g[W+160+12>>2]=0.0;fa=(c[j>>2]=J,+g[j>>2])+0.0;ga=(c[j>>2]=K,+g[j>>2])+0.0;g[W+96>>2]=fa;g[W+96+4>>2]=ea+.25;g[W+96+8>>2]=ga;g[W+96+12>>2]=0.0;Vb[L&127](M,W+160|0,W+96|0,W);L=c[(c[M>>2]|0)+8>>2]|0;K=c[W+32>>2]|0;J=c[W+32+4>>2]|0;ga=+g[W+32+8>>2];c[W+160>>2]=K;c[W+160+4>>2]=J;g[W+160+8>>2]=ga+-.25;g[W+160+12>>2]=0.0;ea=(c[j>>2]=K,+g[j>>2])+0.0;fa=(c[j>>2]=J,+g[j>>2])+0.0;g[W+96>>2]=ea;g[W+96+4>>2]=fa;g[W+96+8>>2]=ga+.25;g[W+96+12>>2]=0.0;Vb[L&127](M,W+160|0,W+96|0,W);c[W>>2]=0;c[W+4>>2]=1065353216;c[W+8>>2]=1065353216;g[W+12>>2]=0.0;L=c[(c[M>>2]|0)+8>>2]|0;ga=+g[W+16>>2];J=c[W+16+4>>2]|0;K=c[W+16+8>>2]|0;g[W+160>>2]=ga+-.25;c[W+160+4>>2]=J;c[W+160+8>>2]=K;g[W+160+12>>2]=0.0;fa=(c[j>>2]=J,+g[j>>2])+0.0;ea=(c[j>>2]=K,+g[j>>2])+0.0;g[W+96>>2]=ga+.25;g[W+96+4>>2]=fa;g[W+96+8>>2]=ea;g[W+96+12>>2]=0.0;Vb[L&127](M,W+160|0,W+96|0,W);L=c[(c[M>>2]|0)+8>>2]|0;K=c[W+16>>2]|0;ea=+g[W+16+4>>2];J=c[W+16+8>>2]|0;c[W+160>>2]=K;g[W+160+4>>2]=ea+-.25;c[W+160+8>>2]=J;g[W+160+12>>2]=0.0;fa=(c[j>>2]=K,+g[j>>2])+0.0;ga=(c[j>>2]=J,+g[j>>2])+0.0;g[W+96>>2]=fa;g[W+96+4>>2]=ea+.25;g[W+96+8>>2]=ga;g[W+96+12>>2]=0.0;Vb[L&127](M,W+160|0,W+96|0,W);L=c[(c[M>>2]|0)+8>>2]|0;J=c[W+16>>2]|0;K=c[W+16+4>>2]|0;ga=+g[W+16+8>>2];c[W+160>>2]=J;c[W+160+4>>2]=K;g[W+160+8>>2]=ga+-.25;g[W+160+12>>2]=0.0;ea=(c[j>>2]=J,+g[j>>2])+0.0;fa=(c[j>>2]=K,+g[j>>2])+0.0;g[W+96>>2]=ea;g[W+96+4>>2]=fa;g[W+96+8>>2]=ga+.25;g[W+96+12>>2]=0.0;Vb[L&127](M,W+160|0,W+96|0,W);break}case 1:{L=(bi(d+4|0)|0)+48|0;c[W+160>>2]=c[L>>2];c[W+160+4>>2]=c[L+4>>2];c[W+160+8>>2]=c[L+8>>2];c[W+160+12>>2]=c[L+12>>2];L=(bi(d+16|0)|0)+48|0;c[W+96>>2]=c[L>>2];c[W+96+4>>2]=c[L+4>>2];c[W+96+8>>2]=c[L+8>>2];c[W+96+12>>2]=c[L+12>>2];L=bi(d+4|0)|0;aa=+g[d+28>>2];$=+g[d+32>>2];da=+g[d+36>>2];ba=+g[L>>2]*aa+ +g[L+4>>2]*$+ +g[L+8>>2]*da;ca=aa*+g[L+16>>2]+$*+g[L+20>>2]+da*+g[L+24>>2];da=aa*+g[L+32>>2]+$*+g[L+36>>2]+da*+g[L+40>>2];L=bi(d+16|0)|0;$=+g[d+44>>2];aa=+g[d+48>>2];ga=+g[d+52>>2];ea=+g[L>>2]*$+ +g[L+4>>2]*aa+ +g[L+8>>2]*ga;fa=$*+g[L+16>>2]+aa*+g[L+20>>2]+ga*+g[L+24>>2];ga=$*+g[L+32>>2]+aa*+g[L+36>>2]+ga*+g[L+40>>2];L=c[(c[M>>2]|0)+8>>2]|0;aa=ca*10.0+ +g[W+160+4>>2];$=da*10.0+ +g[W+160+8>>2];g[W+32>>2]=ba*10.0+ +g[W+160>>2];g[W+32+4>>2]=aa;g[W+32+8>>2]=$;g[W+32+12>>2]=0.0;c[W+16>>2]=1065353216;c[W+16+4>>2]=1065353216;c[W+16+8>>2]=0;g[W+16+12>>2]=0.0;Vb[L&127](M,W+160|0,W+32|0,W+16|0);L=c[(c[M>>2]|0)+8>>2]|0;$=fa*10.0+ +g[W+160+4>>2];aa=ga*10.0+ +g[W+160+8>>2];g[W+32>>2]=ea*10.0+ +g[W+160>>2];g[W+32+4>>2]=$;g[W+32+8>>2]=aa;g[W+32+12>>2]=0.0;c[W+16>>2]=1065353216;c[W+16+4>>2]=1065353216;c[W+16+8>>2]=0;g[W+16+12>>2]=0.0;Vb[L&127](M,W+160|0,W+32|0,W+16|0);L=c[(c[M>>2]|0)+8>>2]|0;ca=ca*10.0+ +g[W+96+4>>2];da=da*10.0+ +g[W+96+8>>2];g[W+32>>2]=ba*10.0+ +g[W+96>>2];g[W+32+4>>2]=ca;g[W+32+8>>2]=da;g[W+32+12>>2]=0.0;c[W+16>>2]=0;c[W+16+4>>2]=1065353216;c[W+16+8>>2]=1065353216;g[W+16+12>>2]=0.0;Vb[L&127](M,W+96|0,W+32|0,W+16|0);L=c[(c[M>>2]|0)+8>>2]|0;fa=fa*10.0+ +g[W+96+4>>2];ga=ga*10.0+ +g[W+96+8>>2];g[W+32>>2]=ea*10.0+ +g[W+96>>2];g[W+32+4>>2]=fa;g[W+32+8>>2]=ga;g[W+32+12>>2]=0.0;c[W+16>>2]=0;c[W+16+4>>2]=1065353216;c[W+16+8>>2]=1065353216;g[W+16+12>>2]=0.0;Vb[L&127](M,W+96|0,W+32|0,W+16|0);break}default:{}}e=e+1|0;if((e|0)>=(c[R+852>>2]|0))break a}}while(0)}d=c[b+72>>2]|0;if(d|0?(lb[c[(c[d>>2]|0)+48>>2]&127](d)|0)&2|0:0){if(a[b+348>>0]|0){L=c[b+72>>2]|0;M=c[R+928>>2]|0;c[W+160>>2]=1065353216;c[W+160+4>>2]=0;c[W+160+8>>2]=1065353216;g[W+160+12>>2]=0.0;c[W+96>>2]=1065353216;c[W+96+4>>2]=1065353216;c[W+96+8>>2]=1065353216;g[W+96+12>>2]=0.0;yf(L,M,0,W+160|0,W+96|0)}if(a[b+349>>0]|0){L=c[b+72>>2]|0;M=c[R+988>>2]|0;c[W+160>>2]=0;c[W+160+4>>2]=1065353216;c[W+160+8>>2]=0;g[W+160+12>>2]=0.0;c[W+96>>2]=1065353216;c[W+96+4>>2]=0;c[W+96+8>>2]=0;g[W+96+12>>2]=0.0;yf(L,M,0,W+160|0,W+96|0)}if(a[b+350>>0]|0){M=c[b+72>>2]|0;R=c[R+1048>>2]|0;c[W+160>>2]=0;c[W+160+4>>2]=1065353216;c[W+160+8>>2]=1065353216;g[W+160+12>>2]=0.0;c[W+96>>2]=1065353216;c[W+96+4>>2]=0;c[W+96+8>>2]=0;g[W+96+12>>2]=0.0;yf(M,R,0,W+160|0,W+96|0)}}T=T+1|0}while((T|0)<(c[b+328>>2]|0));l=W;return}function Zb(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0,i=0,j=0.0,k=0.0,m=0,n=0,o=0.0,p=0,q=0,r=0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,D=0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0.0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0.0,fa=0.0;da=l;l=l+80|0;if((e|0)<=0){l=da;return}aa=0;do{U=c[d+(aa<<2)>>2]|0;V=c[U+740>>2]|0;X=c[U+744>>2]|0;Z=Bj(b,V,+g[f+12>>2])|0;_=Bj(b,X,+g[f+12>>2])|0;Y=c[b+16>>2]|0;if(!(((((+g[Y+(Z*244|0)+128>>2]==0.0?+g[Y+(Z*244|0)+132>>2]==0.0:0)?+g[Y+(Z*244|0)+136>>2]==0.0:0)?+g[Y+(_*244|0)+128>>2]==0.0:0)?+g[Y+(_*244|0)+132>>2]==0.0:0)?+g[Y+(_*244|0)+136>>2]==0.0:0))ca=9;if((ca|0)==9?(ca=0,W=c[U+748>>2]|0,(W|0)>0):0){i=W;ba=0;h=1;do{S=U+4+(ba*184|0)|0;p=U+4+(ba*184|0)+80|0;if(+g[p>>2]<=+g[U+756>>2]){T=c[b+28>>2]|0;if((T|0)==(c[b+32>>2]|0)?($=T|0?T<<1:1,(T|0)<($|0)):0){if(!$){m=T;n=0}else{c[6432]=(c[6432]|0)+1;i=ec(($*152|3)+16|0)|0;if(!i)i=0;else{c[(i+4+15&-16)+-4>>2]=i;i=i+4+15&-16}m=c[b+28>>2]|0;n=i}if((m|0)>0){i=0;do{Th(n+(i*152|0)|0,(c[b+36>>2]|0)+(i*152|0)|0,152)|0;i=i+1|0}while((i|0)!=(m|0))}i=c[b+36>>2]|0;if(i|0){if(a[b+40>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[b+36>>2]=0}a[b+40>>0]=1;c[b+36>>2]=n;c[b+32>>2]=$;i=c[b+28>>2]|0}else i=T;c[b+28>>2]=i+1;R=c[b+36>>2]|0;q=(c[V+236>>2]&2|0)==0?0:V;r=(c[X+236>>2]&2|0)==0?0:X;c[R+(T*152|0)+144>>2]=Z;c[R+(T*152|0)+148>>2]=_;c[R+(T*152|0)+132>>2]=S;z=+g[U+4+(ba*184|0)+48>>2]-+g[V+52>>2];A=+g[U+4+(ba*184|0)+52>>2]-+g[V+56>>2];y=+g[U+4+(ba*184|0)+56>>2]-+g[V+60>>2];g[da+64>>2]=z;g[da+64+4>>2]=A;g[da+64+8>>2]=y;g[da+64+12>>2]=0.0;F=+g[U+4+(ba*184|0)+32>>2]-+g[X+52>>2];G=+g[U+4+(ba*184|0)+36>>2]-+g[X+56>>2];E=+g[U+4+(ba*184|0)+40>>2]-+g[X+60>>2];g[da+48>>2]=F;g[da+48+4>>2]=G;g[da+48+8>>2]=E;g[da+48+12>>2]=0.0;if(!(c[Y+(Z*244|0)+240>>2]|0)){k=0.0;s=0.0;u=0.0}else{N=+g[Y+(Z*244|0)+192>>2]+ +g[Y+(Z*244|0)+224>>2];u=+g[Y+(Z*244|0)+196>>2]+ +g[Y+(Z*244|0)+228>>2];s=+g[Y+(Z*244|0)+200>>2]+ +g[Y+(Z*244|0)+232>>2];k=+g[Y+(Z*244|0)+176>>2]+ +g[Y+(Z*244|0)+208>>2]+(u*y-s*A);s=+g[Y+(Z*244|0)+180>>2]+ +g[Y+(Z*244|0)+212>>2]+(s*z-N*y);u=+g[Y+(Z*244|0)+184>>2]+ +g[Y+(Z*244|0)+216>>2]+(N*A-u*z)}if(!(c[Y+(_*244|0)+240>>2]|0)){j=0.0;o=0.0;t=0.0}else{N=+g[Y+(_*244|0)+192>>2]+ +g[Y+(_*244|0)+224>>2];t=+g[Y+(_*244|0)+196>>2]+ +g[Y+(_*244|0)+228>>2];o=+g[Y+(_*244|0)+200>>2]+ +g[Y+(_*244|0)+232>>2];j=+g[Y+(_*244|0)+176>>2]+ +g[Y+(_*244|0)+208>>2]+(t*E-o*G);o=+g[Y+(_*244|0)+180>>2]+ +g[Y+(_*244|0)+212>>2]+(o*F-N*E);t=+g[Y+(_*244|0)+184>>2]+ +g[Y+(_*244|0)+216>>2]+(N*G-t*F)}N=k-j;M=s-o;L=u-t;Q=U+4+(ba*184|0)+64|0;I=+g[Q>>2];P=U+4+(ba*184|0)+68|0;J=+g[P>>2];O=U+4+(ba*184|0)+72|0;K=+g[O>>2];n=c[b+16>>2]|0;i=c[n+(Z*244|0)+240>>2]|0;m=c[n+(_*244|0)+240>>2]|0;if(i|0){j=((A*K-y*J)*+g[i+264>>2]+(y*I-K*z)*+g[i+268>>2]+(J*z-A*I)*+g[i+272>>2])*+g[i+544>>2];k=((A*K-y*J)*+g[i+280>>2]+(y*I-K*z)*+g[i+284>>2]+(J*z-A*I)*+g[i+288>>2])*+g[i+548>>2];o=((A*K-y*J)*+g[i+296>>2]+(y*I-K*z)*+g[i+300>>2]+(J*z-A*I)*+g[i+304>>2])*+g[i+552>>2]}else{j=0.0;k=0.0;o=0.0}g[R+(T*152|0)+64>>2]=j;g[R+(T*152|0)+68>>2]=k;g[R+(T*152|0)+72>>2]=o;g[R+(T*152|0)+76>>2]=0.0;v=+g[O>>2];w=+g[P>>2];x=+g[Q>>2];if(m|0){s=(+g[m+264>>2]*-(G*v-E*w)+ +g[m+268>>2]*-(E*x-v*F)+ +g[m+272>>2]*-(w*F-G*x))*+g[m+544>>2];t=(+g[m+280>>2]*-(G*v-E*w)+ +g[m+284>>2]*-(E*x-v*F)+ +g[m+288>>2]*-(w*F-G*x))*+g[m+548>>2];u=(+g[m+296>>2]*-(G*v-E*w)+ +g[m+300>>2]*-(E*x-v*F)+ +g[m+304>>2]*-(w*F-G*x))*+g[m+552>>2]}else{s=0.0;t=0.0;u=0.0}g[R+(T*152|0)+80>>2]=s;g[R+(T*152|0)+84>>2]=t;g[R+(T*152|0)+88>>2]=u;g[R+(T*152|0)+92>>2]=0.0;if(i|0)k=+g[i+344>>2]+((k*y-o*A)*+g[Q>>2]+(o*z-y*j)*+g[P>>2]+(A*j-k*z)*+g[O>>2]);else k=0.0;if(m|0){H=-s;j=-t;u=-u;j=+g[m+344>>2]+((E*j-G*u)*+g[Q>>2]+(F*u-E*H)*+g[P>>2]+(G*H-F*j)*+g[O>>2])}else j=0.0;g[R+(T*152|0)+108>>2]=1.0/(k+j);if(i|0){c[R+(T*152|0)+16>>2]=c[Q>>2];c[R+(T*152|0)+16+4>>2]=c[Q+4>>2];c[R+(T*152|0)+16+8>>2]=c[Q+8>>2];c[R+(T*152|0)+16+12>>2]=c[Q+12>>2];g[R+(T*152|0)>>2]=A*K-y*J;g[R+(T*152|0)+4>>2]=y*I-K*z;g[R+(T*152|0)+8>>2]=J*z-A*I;g[R+(T*152|0)+12>>2]=0.0}else{c[R+(T*152|0)>>2]=0;c[R+(T*152|0)+4>>2]=0;c[R+(T*152|0)+8>>2]=0;c[R+(T*152|0)+12>>2]=0;c[R+(T*152|0)+16>>2]=0;c[R+(T*152|0)+20>>2]=0;c[R+(T*152|0)+24>>2]=0;c[R+(T*152|0)+28>>2]=0}if(m|0){u=-+g[P>>2];H=-+g[O>>2];g[R+(T*152|0)+48>>2]=-+g[Q>>2];g[R+(T*152|0)+52>>2]=u;g[R+(T*152|0)+56>>2]=H;g[R+(T*152|0)+60>>2]=0.0;g[R+(T*152|0)+32>>2]=-(G*v-E*w);g[R+(T*152|0)+36>>2]=-(E*x-v*F);g[R+(T*152|0)+40>>2]=-(w*F-G*x);g[R+(T*152|0)+44>>2]=0.0}else{c[R+(T*152|0)+32>>2]=0;c[R+(T*152|0)+32+4>>2]=0;c[R+(T*152|0)+32+8>>2]=0;c[R+(T*152|0)+32+12>>2]=0;c[R+(T*152|0)+32+16>>2]=0;c[R+(T*152|0)+32+20>>2]=0;c[R+(T*152|0)+32+24>>2]=0;c[R+(T*152|0)+32+28>>2]=0}H=+g[p>>2]+ +g[f+56>>2];if(i|0){s=+g[i+332>>2];t=+g[i+336>>2];x=+g[i+328>>2];u=s*y-t*A+ +g[i+312>>2];t=+g[i+316>>2]+(t*z-y*x);s=A*x-s*z+ +g[i+320>>2]}else{u=0.0;t=0.0;s=0.0}if(m|0){j=+g[m+332>>2];k=+g[m+336>>2];A=+g[m+328>>2];o=j*E-k*G+ +g[m+312>>2];k=+g[m+316>>2]+(k*F-E*A);j=G*A-j*F+ +g[m+320>>2]}else{o=0.0;k=0.0;j=0.0}E=(u-o)*+g[Q>>2]+(t-k)*+g[P>>2]+(s-j)*+g[O>>2];c[R+(T*152|0)+104>>2]=c[U+4+(ba*184|0)+84>>2];E=-(E*+g[U+4+(ba*184|0)+92>>2]);E=E<=0.0?0.0:E;do if(!(c[f+64>>2]&4))g[R+(T*152|0)+100>>2]=0.0;else{j=+g[U+4+(ba*184|0)+120>>2]*+g[f+60>>2];g[R+(T*152|0)+100>>2]=j;do if(i|0){if(!(c[n+(Z*244|0)+240>>2]|0))break;G=j*+g[R+(T*152|0)+20>>2]*+g[n+(Z*244|0)+132>>2]*+g[i+352>>2]*+g[n+(Z*244|0)+116>>2];F=j*+g[R+(T*152|0)+24>>2]*+g[n+(Z*244|0)+136>>2]*+g[i+356>>2]*+g[n+(Z*244|0)+120>>2];g[n+(Z*244|0)+64>>2]=+g[n+(Z*244|0)+112>>2]*j*+g[R+(T*152|0)+16>>2]*+g[n+(Z*244|0)+128>>2]*+g[i+348>>2]+ +g[n+(Z*244|0)+64>>2];g[n+(Z*244|0)+68>>2]=G+ +g[n+(Z*244|0)+68>>2];g[n+(Z*244|0)+72>>2]=F+ +g[n+(Z*244|0)+72>>2];F=j*+g[n+(Z*244|0)+100>>2]*+g[R+(T*152|0)+68>>2];G=j*+g[n+(Z*244|0)+104>>2]*+g[R+(T*152|0)+72>>2];g[n+(Z*244|0)+80>>2]=j*+g[n+(Z*244|0)+96>>2]*+g[R+(T*152|0)+64>>2]+ +g[n+(Z*244|0)+80>>2];g[n+(Z*244|0)+84>>2]=F+ +g[n+(Z*244|0)+84>>2];g[n+(Z*244|0)+88>>2]=G+ +g[n+(Z*244|0)+88>>2]}while(0);if(!m)break;j=+g[R+(T*152|0)+100>>2];if(!(c[n+(_*244|0)+240>>2]|0))break;G=+g[R+(T*152|0)+88>>2];F=+g[R+(T*152|0)+84>>2];A=+g[R+(T*152|0)+80>>2];y=j*+g[R+(T*152|0)+52>>2]*+g[n+(_*244|0)+132>>2]*+g[m+352>>2]*+g[n+(_*244|0)+116>>2];z=j*+g[R+(T*152|0)+56>>2]*+g[n+(_*244|0)+136>>2]*+g[m+356>>2]*+g[n+(_*244|0)+120>>2];g[n+(_*244|0)+64>>2]=+g[n+(_*244|0)+112>>2]*j*+g[R+(T*152|0)+48>>2]*+g[n+(_*244|0)+128>>2]*+g[m+348>>2]+ +g[n+(_*244|0)+64>>2];g[n+(_*244|0)+68>>2]=y+ +g[n+(_*244|0)+68>>2];g[n+(_*244|0)+72>>2]=z+ +g[n+(_*244|0)+72>>2];F=F*+g[n+(_*244|0)+100>>2]*-j;G=G*+g[n+(_*244|0)+104>>2]*-j;g[n+(_*244|0)+80>>2]=+g[n+(_*244|0)+80>>2]-A*+g[n+(_*244|0)+96>>2]*-j;g[n+(_*244|0)+84>>2]=+g[n+(_*244|0)+84>>2]-F;g[n+(_*244|0)+88>>2]=+g[n+(_*244|0)+88>>2]-G}while(0);g[R+(T*152|0)+96>>2]=0.0;if(!(c[n+(Z*244|0)+240>>2]|0)){j=0.0;k=0.0;o=0.0;s=0.0;t=0.0;u=0.0}else{j=+g[n+(Z*244|0)+208>>2];k=+g[n+(Z*244|0)+212>>2];o=+g[n+(Z*244|0)+216>>2];s=+g[n+(Z*244|0)+224>>2];t=+g[n+(Z*244|0)+228>>2];u=+g[n+(Z*244|0)+232>>2]}if(!(c[n+(_*244|0)+240>>2]|0)){v=0.0;w=0.0;x=0.0;y=0.0;z=0.0;A=0.0}else{v=+g[n+(_*244|0)+208>>2];w=+g[n+(_*244|0)+212>>2];x=+g[n+(_*244|0)+216>>2];y=+g[n+(_*244|0)+224>>2];z=+g[n+(_*244|0)+228>>2];A=+g[n+(_*244|0)+232>>2]}j=E-((j+ +g[n+(Z*244|0)+176>>2])*+g[R+(T*152|0)+16>>2]+(k+ +g[n+(Z*244|0)+180>>2])*+g[R+(T*152|0)+20>>2]+(o+ +g[n+(Z*244|0)+184>>2])*+g[R+(T*152|0)+24>>2]+((s+ +g[n+(Z*244|0)+192>>2])*+g[R+(T*152|0)>>2]+(t+ +g[n+(Z*244|0)+196>>2])*+g[R+(T*152|0)+4>>2]+(u+ +g[n+(Z*244|0)+200>>2])*+g[R+(T*152|0)+8>>2])+((v+ +g[n+(_*244|0)+176>>2])*+g[R+(T*152|0)+48>>2]+(w+ +g[n+(_*244|0)+180>>2])*+g[R+(T*152|0)+52>>2]+(x+ +g[n+(_*244|0)+184>>2])*+g[R+(T*152|0)+56>>2]+((y+ +g[n+(_*244|0)+192>>2])*+g[R+(T*152|0)+32>>2]+(z+ +g[n+(_*244|0)+196>>2])*+g[R+(T*152|0)+36>>2]+(A+ +g[n+(_*244|0)+200>>2])*+g[R+(T*152|0)+40>>2])));i=(c[f+44>>2]|0)==0;k=+g[f+12>>2];if(H>0.0){o=0.0;j=j-H/k}else o=-(H*(i|H>+g[f+48>>2]?+g[f+32>>2]:+g[f+36>>2]))/k;F=+g[R+(T*152|0)+108>>2];G=o*F;F=j*F;D=i|H>+g[f+48>>2];g[R+(T*152|0)+112>>2]=D?G+F:F;g[R+(T*152|0)+128>>2]=D?0.0:G;g[R+(T*152|0)+116>>2]=0.0;g[R+(T*152|0)+120>>2]=0.0;g[R+(T*152|0)+124>>2]=1.0e10;c[R+(T*152|0)+140>>2]=c[b+68>>2];if(!q){k=0.0;t=0.0;u=0.0}else{k=+g[q+328>>2];t=+g[q+332>>2];u=+g[q+336>>2]}if(!r){j=0.0;o=0.0;s=0.0}else{j=+g[r+328>>2];o=+g[r+332>>2];s=+g[r+336>>2]}v=j-k;k=o-t;s=s-u;g[da+32>>2]=v;g[da+32+4>>2]=k;g[da+32+8>>2]=s;g[da+32+12>>2]=0.0;do if((h|0)>0?+g[U+4+(ba*184|0)+88>>2]>0.0:0){h=h+-1|0;j=+C(+(v*v+k*k+s*s));if(j>+g[f+80>>2]){g[da+32>>2]=v*(1.0/j);g[da+32+4>>2]=k*(1.0/j);g[da+32+8>>2]=s*(1.0/j);if(!(c[V+180>>2]&2)){o=v*(1.0/j);k=k*(1.0/j);j=s*(1.0/j)}else{u=+g[V+4>>2];x=+g[V+20>>2];A=+g[V+36>>2];w=+g[V+8>>2];y=+g[V+24>>2];F=+g[V+40>>2];o=+g[V+12>>2];z=+g[V+28>>2];H=+g[V+44>>2];E=(u*v*(1.0/j)+x*k*(1.0/j)+s*(1.0/j)*A)*+g[V+164>>2];G=(v*(1.0/j)*w+k*(1.0/j)*y+s*(1.0/j)*F)*+g[V+168>>2];j=(v*(1.0/j)*o+k*(1.0/j)*z+s*(1.0/j)*H)*+g[V+172>>2];g[da+32>>2]=u*E+w*G+o*j;g[da+32+4>>2]=x*E+y*G+z*j;g[da+32+8>>2]=A*E+F*G+H*j;g[da+32+12>>2]=0.0;o=u*E+w*G+o*j;k=x*E+y*G+z*j;j=A*E+F*G+H*j}if(c[X+180>>2]&2){u=+g[X+4>>2];x=+g[X+20>>2];A=+g[X+36>>2];v=+g[X+8>>2];y=+g[X+24>>2];F=+g[X+40>>2];w=+g[X+12>>2];z=+g[X+28>>2];H=+g[X+44>>2];E=(u*o+x*k+A*j)*+g[X+164>>2];G=(o*v+k*y+j*F)*+g[X+168>>2];j=(o*w+k*z+j*H)*+g[X+172>>2];g[da+32>>2]=u*E+v*G+w*j;g[da+32+4>>2]=x*E+y*G+z*j;g[da+32+8>>2]=A*E+F*G+H*j;g[da+32+12>>2]=0.0;o=u*E+v*G+w*j;k=x*E+y*G+z*j;j=A*E+F*G+H*j}if(!(+C(+(o*o+k*k+j*j))>.001))break;rd(b,da+32|0,Z,_,T,S);break}rd(b,Q,Z,_,T,S);j=+g[O>>2];if(+B(+j)>.7071067690849304){H=+g[P>>2];G=1.0/+C(+(j*j+H*H));g[da+16>>2]=0.0;g[da+16+4>>2]=-(G*j);g[da+16+8>>2]=G*H;g[da>>2]=(j*j+H*H)*G;o=+g[Q>>2];g[da+4>>2]=-(G*H*o);v=o*-(G*j);k=0.0;s=-(G*j);u=G*H;t=(j*j+H*H)*G;o=-(G*H*o)}else{t=+g[Q>>2];H=+g[P>>2];o=1.0/+C(+(t*t+H*H));g[da+16>>2]=-(H*o);g[da+16+4>>2]=o*t;g[da+16+8>>2]=0.0;g[da>>2]=-(o*t*j);g[da+4>>2]=j*-(H*o);v=(t*t+H*H)*o;k=-(H*o);s=o*t;u=0.0;t=-(o*t*j);o=j*-(H*o)}g[da+8>>2]=v;if(!(c[V+180>>2]&2))j=u;else{fa=+g[V+4>>2];x=+g[V+20>>2];A=+g[V+36>>2];ea=+g[V+8>>2];y=+g[V+24>>2];F=+g[V+40>>2];w=+g[V+12>>2];z=+g[V+28>>2];H=+g[V+44>>2];E=(fa*k+x*s+A*u)*+g[V+164>>2];G=(k*ea+s*y+u*F)*+g[V+168>>2];j=(k*w+s*z+u*H)*+g[V+172>>2];g[da+16>>2]=fa*E+ea*G+w*j;g[da+16+4>>2]=x*E+y*G+z*j;g[da+16+8>>2]=A*E+F*G+H*j;g[da+16+12>>2]=0.0;k=fa*E+ea*G+w*j;s=x*E+y*G+z*j;j=A*E+F*G+H*j}if(!(c[X+180>>2]&2))u=j;else{w=+g[X+4>>2];z=+g[X+20>>2];F=+g[X+36>>2];x=+g[X+8>>2];A=+g[X+24>>2];H=+g[X+40>>2];y=+g[X+12>>2];E=+g[X+28>>2];fa=+g[X+44>>2];G=(w*k+z*s+F*j)*+g[X+164>>2];ea=(k*x+s*A+j*H)*+g[X+168>>2];u=(k*y+s*E+j*fa)*+g[X+172>>2];g[da+16>>2]=w*G+x*ea+y*u;g[da+16+4>>2]=z*G+A*ea+E*u;g[da+16+8>>2]=F*G+H*ea+fa*u;g[da+16+12>>2]=0.0;k=w*G+x*ea+y*u;s=z*G+A*ea+E*u;u=F*G+H*ea+fa*u}do if(!V)j=v;else{if(!(c[V+180>>2]&2)){j=v;break}w=+g[V+4>>2];z=+g[V+20>>2];F=+g[V+36>>2];x=+g[V+8>>2];A=+g[V+24>>2];H=+g[V+40>>2];y=+g[V+12>>2];E=+g[V+28>>2];fa=+g[V+44>>2];G=(w*t+z*o+F*v)*+g[V+164>>2];ea=(t*x+o*A+v*H)*+g[V+168>>2];j=(t*y+o*E+v*fa)*+g[V+172>>2];g[da>>2]=w*G+x*ea+y*j;g[da+4>>2]=z*G+A*ea+E*j;g[da+8>>2]=F*G+H*ea+fa*j;g[da+12>>2]=0.0;t=w*G+x*ea+y*j;o=z*G+A*ea+E*j;j=F*G+H*ea+fa*j}while(0);do if(X){if(!(c[X+180>>2]&2))break;w=+g[X+4>>2];z=+g[X+20>>2];F=+g[X+36>>2];x=+g[X+8>>2];A=+g[X+24>>2];H=+g[X+40>>2];y=+g[X+12>>2];E=+g[X+28>>2];fa=+g[X+44>>2];G=(w*t+z*o+F*j)*+g[X+164>>2];ea=(t*x+o*A+j*H)*+g[X+168>>2];j=(t*y+o*E+j*fa)*+g[X+172>>2];g[da>>2]=w*G+x*ea+y*j;g[da+4>>2]=z*G+A*ea+E*j;g[da+8>>2]=F*G+H*ea+fa*j;g[da+12>>2]=0.0;t=w*G+x*ea+y*j;o=z*G+A*ea+E*j;j=F*G+H*ea+fa*j}while(0);if(+C(+(k*k+s*s+u*u))>.001)rd(b,da+16|0,Z,_,T,S);if(+C(+(t*t+o*o+j*j))>.001)rd(b,da,Z,_,T,S)}while(0);do if(!(c[f+64>>2]&32))ca=94;else{if(!(a[U+4+(ba*184|0)+116>>0]|0)){ca=94;break}Zc(b,U+4+(ba*184|0)+152|0,Z,_,T,S,da+64|0,da+48|0,1.0,+g[U+4+(ba*184|0)+132>>2],+g[U+4+(ba*184|0)+140>>2]);if(!(c[f+64>>2]&16))break;Zc(b,U+4+(ba*184|0)+168|0,Z,_,T,S,da+64|0,da+48|0,1.0,+g[U+4+(ba*184|0)+136>>2],+g[U+4+(ba*184|0)+144>>2])}while(0);do if((ca|0)==94){ca=0;v=+g[Q>>2];w=+g[P>>2];x=+g[O>>2];k=N-(N*I+M*J+L*K)*v;t=M-(N*I+M*J+L*K)*w;s=L-(N*I+M*J+L*K)*x;i=U+4+(ba*184|0)+152|0;g[U+4+(ba*184|0)+152>>2]=k;q=U+4+(ba*184|0)+156|0;g[q>>2]=t;r=U+4+(ba*184|0)+160|0;g[r>>2]=s;D=U+4+(ba*184|0)+164|0;g[D>>2]=0.0;if((c[f+64>>2]&64|0)==0?k*k+t*t+s*s>1.1920928955078125e-07:0){j=1.0/+C(+(k*k+t*t+s*s));g[i>>2]=k*j;g[q>>2]=j*t;g[r>>2]=j*s;do if(!V){o=k*j;k=j*t;j=j*s}else{if(!(c[V+180>>2]&1)){o=k*j;k=j*t;j=j*s;break}G=+g[V+4>>2];I=+g[V+20>>2];L=+g[V+36>>2];H=+g[V+8>>2];J=+g[V+24>>2];N=+g[V+40>>2];o=+g[V+12>>2];K=+g[V+28>>2];fa=+g[V+44>>2];M=(G*k*j+I*j*t+j*s*L)*+g[V+164>>2];ea=(k*j*H+j*t*J+j*s*N)*+g[V+168>>2];j=(k*j*o+j*t*K+j*s*fa)*+g[V+172>>2];g[i>>2]=G*M+H*ea+o*j;g[q>>2]=I*M+J*ea+K*j;g[r>>2]=L*M+N*ea+fa*j;g[D>>2]=0.0;o=G*M+H*ea+o*j;k=I*M+J*ea+K*j;j=L*M+N*ea+fa*j}while(0);do if(X|0){if(!(c[X+180>>2]&1))break;E=+g[X+4>>2];H=+g[X+20>>2];K=+g[X+36>>2];F=+g[X+8>>2];I=+g[X+24>>2];M=+g[X+40>>2];G=+g[X+12>>2];J=+g[X+28>>2];ea=+g[X+44>>2];L=(E*o+H*k+K*j)*+g[X+164>>2];N=(o*F+k*I+j*M)*+g[X+168>>2];fa=(o*G+k*J+j*ea)*+g[X+172>>2];g[i>>2]=E*L+F*N+G*fa;g[q>>2]=H*L+I*N+J*fa;g[r>>2]=K*L+M*N+ea*fa;g[D>>2]=0.0}while(0);Zc(b,i,Z,_,T,S,da+64|0,da+48|0,1.0,0.0,0.0);if(!(c[f+64>>2]&16))break;ea=+g[q>>2];o=+g[O>>2];L=+g[r>>2];M=+g[P>>2];fa=+g[Q>>2];N=+g[i>>2];i=U+4+(ba*184|0)+168|0;g[U+4+(ba*184|0)+168>>2]=ea*o-L*M;m=U+4+(ba*184|0)+172|0;n=U+4+(ba*184|0)+176|0;p=U+4+(ba*184|0)+180|0;g[p>>2]=0.0;j=1.0/+C(+((ea*o-L*M)*(ea*o-L*M)+(L*fa-o*N)*(L*fa-o*N)+(M*N-ea*fa)*(M*N-ea*fa)));k=(ea*o-L*M)*j;g[i>>2]=k;o=(L*fa-o*N)*j;g[m>>2]=o;j=(M*N-ea*fa)*j;g[n>>2]=j;do if(V){if(!(c[V+180>>2]&1))break;F=+g[V+4>>2];I=+g[V+20>>2];L=+g[V+36>>2];G=+g[V+8>>2];J=+g[V+24>>2];N=+g[V+40>>2];H=+g[V+12>>2];K=+g[V+28>>2];fa=+g[V+44>>2];M=(F*k+I*o+j*L)*+g[V+164>>2];ea=(k*G+o*J+j*N)*+g[V+168>>2];j=(k*H+o*K+j*fa)*+g[V+172>>2];g[i>>2]=F*M+G*ea+H*j;g[m>>2]=I*M+J*ea+K*j;g[n>>2]=L*M+N*ea+fa*j;g[p>>2]=0.0;k=F*M+G*ea+H*j;o=I*M+J*ea+K*j;j=L*M+N*ea+fa*j}while(0);do if(X|0){if(!(c[X+180>>2]&1))break;E=+g[X+4>>2];H=+g[X+20>>2];K=+g[X+36>>2];F=+g[X+8>>2];I=+g[X+24>>2];M=+g[X+40>>2];G=+g[X+12>>2];J=+g[X+28>>2];ea=+g[X+44>>2];L=(E*k+H*o+K*j)*+g[X+164>>2];N=(k*F+o*I+j*M)*+g[X+168>>2];fa=(k*G+o*J+j*ea)*+g[X+172>>2];g[i>>2]=E*L+F*N+G*fa;g[m>>2]=H*L+I*N+J*fa;g[n>>2]=K*L+M*N+ea*fa;g[p>>2]=0.0}while(0);Zc(b,i,Z,_,T,S,da+64|0,da+48|0,1.0,0.0,0.0);break}p=U+4+(ba*184|0)+168|0;if(+B(+x)>.7071067690849304){s=1.0/+C(+(x*x+w*w));g[i>>2]=0.0;g[q>>2]=-(s*x);g[r>>2]=s*w;o=0.0;k=-(s*x);j=s*w;t=(x*x+w*w)*s;u=-(s*w*v);s=v*-(s*x)}else{s=1.0/+C(+(v*v+w*w));g[i>>2]=-(w*s);g[q>>2]=s*v;g[r>>2]=0.0;o=-(w*s);k=s*v;j=0.0;t=-(s*v*x);u=x*-(w*s);s=(v*v+w*w)*s}g[p>>2]=t;n=U+4+(ba*184|0)+172|0;g[n>>2]=u;m=U+4+(ba*184|0)+176|0;g[m>>2]=s;do if(V){if(!(c[V+180>>2]&1))break;F=+g[V+4>>2];I=+g[V+20>>2];L=+g[V+36>>2];G=+g[V+8>>2];J=+g[V+24>>2];N=+g[V+40>>2];H=+g[V+12>>2];K=+g[V+28>>2];fa=+g[V+44>>2];M=(F*o+I*k+L*j)*+g[V+164>>2];ea=(o*G+k*J+j*N)*+g[V+168>>2];j=(o*H+k*K+j*fa)*+g[V+172>>2];g[i>>2]=F*M+G*ea+H*j;g[q>>2]=I*M+J*ea+K*j;g[r>>2]=L*M+N*ea+fa*j;g[D>>2]=0.0;o=F*M+G*ea+H*j;k=I*M+J*ea+K*j;j=L*M+N*ea+fa*j}while(0);do if(X|0){if(!(c[X+180>>2]&1))break;E=+g[X+4>>2];H=+g[X+20>>2];K=+g[X+36>>2];F=+g[X+8>>2];I=+g[X+24>>2];M=+g[X+40>>2];G=+g[X+12>>2];J=+g[X+28>>2];ea=+g[X+44>>2];L=(E*o+H*k+K*j)*+g[X+164>>2];N=(o*F+k*I+j*M)*+g[X+168>>2];fa=(o*G+k*J+j*ea)*+g[X+172>>2];g[i>>2]=E*L+F*N+G*fa;g[q>>2]=H*L+I*N+J*fa;g[r>>2]=K*L+M*N+ea*fa;g[D>>2]=0.0}while(0);Zc(b,i,Z,_,T,S,da+64|0,da+48|0,1.0,0.0,0.0);i=c[f+64>>2]|0;if(i&16){do if(V|0){if(!(c[V+180>>2]&1))break;E=+g[V+4>>2];z=+g[p>>2];H=+g[V+20>>2];A=+g[n>>2];K=+g[V+36>>2];fa=+g[m>>2];F=+g[V+8>>2];I=+g[V+24>>2];M=+g[V+40>>2];G=+g[V+12>>2];J=+g[V+28>>2];ea=+g[V+44>>2];L=(E*z+H*A+K*fa)*+g[V+164>>2];N=(z*F+A*I+fa*M)*+g[V+168>>2];fa=(z*G+A*J+fa*ea)*+g[V+172>>2];g[p>>2]=E*L+F*N+G*fa;g[n>>2]=H*L+I*N+J*fa;g[m>>2]=K*L+M*N+ea*fa;g[U+4+(ba*184|0)+180>>2]=0.0}while(0);do if(X|0){if(!(c[X+180>>2]&1))break;E=+g[X+4>>2];z=+g[p>>2];H=+g[X+20>>2];A=+g[n>>2];K=+g[X+36>>2];fa=+g[m>>2];F=+g[X+8>>2];I=+g[X+24>>2];M=+g[X+40>>2];G=+g[X+12>>2];J=+g[X+28>>2];ea=+g[X+44>>2];L=(E*z+H*A+K*fa)*+g[X+164>>2];N=(z*F+A*I+fa*M)*+g[X+168>>2];fa=(z*G+A*J+fa*ea)*+g[X+172>>2];g[p>>2]=E*L+F*N+G*fa;g[n>>2]=H*L+I*N+J*fa;g[m>>2]=K*L+M*N+ea*fa;g[U+4+(ba*184|0)+180>>2]=0.0}while(0);Zc(b,p,Z,_,T,S,da+64|0,da+48|0,1.0,0.0,0.0);i=c[f+64>>2]|0}if((i&80|0)!=80)break;a[U+4+(ba*184|0)+116>>0]=1}while(0);r=c[b+16>>2]|0;m=c[r+(Z*244|0)+240>>2]|0;n=c[r+(_*244|0)+240>>2]|0;p=c[R+(T*152|0)+140>>2]|0;q=c[b+76>>2]|0;i=c[f+64>>2]|0;do if(!(i&4))g[q+(p*152|0)+100>>2]=0.0;else{j=+g[U+4+(ba*184|0)+124>>2]*+g[f+60>>2];g[q+(p*152|0)+100>>2]=j;if(m|0){N=+g[m+344>>2];fa=j*N*+g[q+(p*152|0)+20>>2]*+g[m+352>>2]*+g[r+(Z*244|0)+116>>2];ea=j*N*+g[q+(p*152|0)+24>>2]*+g[m+356>>2]*+g[r+(Z*244|0)+120>>2];g[r+(Z*244|0)+64>>2]=+g[r+(Z*244|0)+112>>2]*j*N*+g[q+(p*152|0)+16>>2]*+g[m+348>>2]+ +g[r+(Z*244|0)+64>>2];g[r+(Z*244|0)+68>>2]=fa+ +g[r+(Z*244|0)+68>>2];g[r+(Z*244|0)+72>>2]=ea+ +g[r+(Z*244|0)+72>>2];ea=j*+g[r+(Z*244|0)+100>>2]*+g[q+(p*152|0)+68>>2];fa=j*+g[r+(Z*244|0)+104>>2]*+g[q+(p*152|0)+72>>2];g[r+(Z*244|0)+80>>2]=j*+g[r+(Z*244|0)+96>>2]*+g[q+(p*152|0)+64>>2]+ +g[r+(Z*244|0)+80>>2];g[r+(Z*244|0)+84>>2]=ea+ +g[r+(Z*244|0)+84>>2];g[r+(Z*244|0)+88>>2]=fa+ +g[r+(Z*244|0)+88>>2]}if(!n)break;j=+g[n+344>>2];k=+g[q+(p*152|0)+100>>2];if(!(c[r+(_*244|0)+240>>2]|0))break;fa=+g[q+(p*152|0)+88>>2];ea=+g[q+(p*152|0)+84>>2];N=+g[q+(p*152|0)+80>>2];L=k*j*+g[q+(p*152|0)+52>>2]*+g[n+352>>2]*+g[r+(_*244|0)+116>>2];M=k*j*+g[q+(p*152|0)+56>>2]*+g[n+356>>2]*+g[r+(_*244|0)+120>>2];g[r+(_*244|0)+64>>2]=+g[r+(_*244|0)+112>>2]*k*j*+g[q+(p*152|0)+48>>2]*+g[n+348>>2]+ +g[r+(_*244|0)+64>>2];g[r+(_*244|0)+68>>2]=L+ +g[r+(_*244|0)+68>>2];g[r+(_*244|0)+72>>2]=M+ +g[r+(_*244|0)+72>>2];ea=ea*+g[r+(_*244|0)+100>>2]*-k;fa=fa*+g[r+(_*244|0)+104>>2]*-k;g[r+(_*244|0)+80>>2]=+g[r+(_*244|0)+80>>2]-N*+g[r+(_*244|0)+96>>2]*-k;g[r+(_*244|0)+84>>2]=+g[r+(_*244|0)+84>>2]-ea;g[r+(_*244|0)+88>>2]=+g[r+(_*244|0)+88>>2]-fa}while(0);do if(i&16|0){if(!(i&4)){g[q+((p+1|0)*152|0)+100>>2]=0.0;break}k=+g[U+4+(ba*184|0)+128>>2]*+g[f+60>>2];g[q+((p+1|0)*152|0)+100>>2]=k;do if(m|0){j=+g[m+344>>2];if(!(c[r+(Z*244|0)+240>>2]|0))break;fa=k*j*+g[q+((p+1|0)*152|0)+20>>2]*+g[r+(Z*244|0)+116>>2];ea=k*j*+g[q+((p+1|0)*152|0)+24>>2]*+g[r+(Z*244|0)+120>>2];g[r+(Z*244|0)+64>>2]=+g[r+(Z*244|0)+112>>2]*k*j*+g[q+((p+1|0)*152|0)+16>>2]+ +g[r+(Z*244|0)+64>>2];g[r+(Z*244|0)+68>>2]=fa+ +g[r+(Z*244|0)+68>>2];g[r+(Z*244|0)+72>>2]=ea+ +g[r+(Z*244|0)+72>>2];ea=k*+g[r+(Z*244|0)+100>>2]*+g[q+((p+1|0)*152|0)+68>>2];fa=k*+g[r+(Z*244|0)+104>>2]*+g[q+((p+1|0)*152|0)+72>>2];g[r+(Z*244|0)+80>>2]=k*+g[r+(Z*244|0)+96>>2]*+g[q+((p+1|0)*152|0)+64>>2]+ +g[r+(Z*244|0)+80>>2];g[r+(Z*244|0)+84>>2]=ea+ +g[r+(Z*244|0)+84>>2];g[r+(Z*244|0)+88>>2]=fa+ +g[r+(Z*244|0)+88>>2]}while(0);if(!n)break;j=+g[n+344>>2];k=+g[q+((p+1|0)*152|0)+100>>2];if(!(c[r+(_*244|0)+240>>2]|0))break;fa=+g[q+((p+1|0)*152|0)+88>>2];ea=+g[q+((p+1|0)*152|0)+84>>2];N=+g[q+((p+1|0)*152|0)+80>>2];L=k*j*+g[q+((p+1|0)*152|0)+52>>2]*+g[r+(_*244|0)+116>>2];M=k*j*+g[q+((p+1|0)*152|0)+56>>2]*+g[r+(_*244|0)+120>>2];g[r+(_*244|0)+64>>2]=+g[r+(_*244|0)+112>>2]*k*j*+g[q+((p+1|0)*152|0)+48>>2]+ +g[r+(_*244|0)+64>>2];g[r+(_*244|0)+68>>2]=L+ +g[r+(_*244|0)+68>>2];g[r+(_*244|0)+72>>2]=M+ +g[r+(_*244|0)+72>>2];ea=ea*+g[r+(_*244|0)+100>>2]*-k;fa=fa*+g[r+(_*244|0)+104>>2]*-k;g[r+(_*244|0)+80>>2]=+g[r+(_*244|0)+80>>2]-N*+g[r+(_*244|0)+96>>2]*-k;g[r+(_*244|0)+84>>2]=+g[r+(_*244|0)+84>>2]-ea;g[r+(_*244|0)+88>>2]=+g[r+(_*244|0)+88>>2]-fa}while(0);i=c[U+748>>2]|0}ba=ba+1|0}while((ba|0)<(i|0))}aa=aa+1|0}while((aa|0)!=(e|0));l=da;return}function _b(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var h=0,i=0,j=0,k=0,m=0,n=0,o=0.0,p=0,q=0,r=0.0,s=0.0,t=0.0,u=0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,D=0,E=0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0.0,N=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0;Z=l;l=l+112|0;c[Z+40>>2]=0;a[Z+16>>0]=1;c[Z+12>>2]=0;c[Z+4>>2]=0;c[Z+8>>2]=0;a[Z+36>>0]=1;c[Z+32>>2]=0;c[Z+24>>2]=0;c[Z+28>>2]=0;i=e>>>0>8?e:8;if((i|0)>0){c[6432]=(c[6432]|0)+1;h=ec((i<<4|3)+16|0)|0;if(!h)j=0;else{c[(h+4+15&-16)+-4>>2]=h;j=h+4+15&-16}h=0;do{Y=j+(h<<4)|0;c[Y>>2]=c[Z+48>>2];c[Y+4>>2]=c[Z+48+4>>2];c[Y+8>>2]=c[Z+48+8>>2];c[Y+12>>2]=c[Z+48+12>>2];h=h+1|0}while((h|0)!=(i|0));Y=j;X=j}else{Y=0;X=0}do if(!e){h=0;p=0;k=0;m=0;n=0}else{i=c[Z+24>>2]|0;if((i|0)<0){h=c[Z+32>>2]|0;if((c[Z+28>>2]|0)<0){if(!((h|0)==0|(a[Z+36>>0]|0)==0)){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}a[Z+36>>0]=1;c[Z+32>>2]=0;c[Z+28>>2]=0;h=0}Hk(h+(i<<2)|0,0,O(i,-4)|0)|0}c[Z+24>>2]=0;v=3402823466385288598117041.0e14;o=-3402823466385288598117041.0e14;w=3402823466385288598117041.0e14;r=-3402823466385288598117041.0e14;x=3402823466385288598117041.0e14;t=-3402823466385288598117041.0e14;h=0;i=d;while(1){M=+g[i>>2];v=M<v?M:v;o=M>o?M:o;M=+g[i+4>>2];w=M<w?M:w;r=M>r?M:r;M=+g[i+8>>2];x=M<x?M:x;t=M>t?M:t;h=h+1|0;if((h|0)==(e|0))break;else i=i+16|0}s=o-v;H=r-w;o=t-x;I=v+s*.5;J=w+H*.5;z=x+o*.5;do if(e>>>0<3|(s<9.999999974752427e-07|H<9.999999974752427e-07|o<9.999999974752427e-07)){t=s>9.999999974752427e-07&s<3402823466385288598117041.0e14?s:3402823466385288598117041.0e14;t=H>9.999999974752427e-07&H<t?H:t;t=o>9.999999974752427e-07&o<t?o:t;if(!(t==3402823466385288598117041.0e14)){r=s<9.999999974752427e-07?t*.05000000074505806:s;s=H<9.999999974752427e-07?t*.05000000074505806:H;if(o<9.999999974752427e-07)t=t*.05000000074505806;else t=o}else{r=.009999999776482582;s=.009999999776482582;t=.009999999776482582}x=z+t;A=I+r;F=J+s;G=1.0;H=1.0;o=1.0;w=z-t;v=I-r;r=J-s;W=51}else{i=0;p=0;h=0;n=d;do{w=1.0/s*+g[n>>2];x=1.0/H*+g[n+4>>2];y=1.0/o*+g[n+8>>2];n=n+16|0;a:do if(h){j=0;while(1){d=X+(j<<4)|0;r=+g[d>>2];k=X+(j<<4)+4|0;t=+g[k>>2];m=X+(j<<4)+8|0;v=+g[m>>2];if(+B(+(r-w))<1.0000000474974513e-03&+B(+(t-x))<1.0000000474974513e-03&+B(+(v-y))<1.0000000474974513e-03)break;j=j+1|0;if(j>>>0>=h>>>0){m=j;break a}}if((w-1.0/s*I)*(w-1.0/s*I)+(x-1.0/H*J)*(x-1.0/H*J)+(y-1.0/o*z)*(y-1.0/o*z)>(r-1.0/s*I)*(r-1.0/s*I)+(t-1.0/H*J)*(t-1.0/H*J)+(v-1.0/o*z)*(v-1.0/o*z)){g[d>>2]=w;g[k>>2]=x;g[m>>2]=y;m=j}else m=j}else m=0;while(0);if((m|0)==(h|0)){g[X+(h<<4)>>2]=w;g[X+(h<<4)+4>>2]=x;g[X+(h<<4)+8>>2]=y;h=h+1|0}if((i|0)==(c[Z+28>>2]|0)?(u=i|0?i<<1:1,(i|0)<(u|0)):0){if((u|0)!=0?(c[6432]=(c[6432]|0)+1,q=ec((u<<2|3)+16|0)|0,(q|0)!=0):0){c[(q+4+15&-16)+-4>>2]=q;k=q+4+15&-16}else k=0;d=c[Z+32>>2]|0;if((i|0)<=0){if(d)W=37}else{j=0;do{c[k+(j<<2)>>2]=c[d+(j<<2)>>2];j=j+1|0}while((j|0)!=(i|0));W=37}if((W|0)==37){W=0;if(a[Z+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[Z+32>>2]=0;i=c[Z+24>>2]|0}a[Z+36>>0]=1;c[Z+32>>2]=k;c[Z+28>>2]=u}c[(c[Z+32>>2]|0)+(i<<2)>>2]=m;i=(c[Z+24>>2]|0)+1|0;c[Z+24>>2]=i;p=p+1|0}while((p|0)!=(e|0));if(!h){i=1;z=3402823466385288598117041.0e14;v=-3402823466385288598117041.0e14;y=3402823466385288598117041.0e14;t=-3402823466385288598117041.0e14;w=3402823466385288598117041.0e14;r=-3402823466385288598117041.0e14}else{A=3402823466385288598117041.0e14;z=3402823466385288598117041.0e14;F=-3402823466385288598117041.0e14;v=-3402823466385288598117041.0e14;I=3402823466385288598117041.0e14;y=3402823466385288598117041.0e14;J=-3402823466385288598117041.0e14;t=-3402823466385288598117041.0e14;L=3402823466385288598117041.0e14;w=3402823466385288598117041.0e14;M=-3402823466385288598117041.0e14;r=-3402823466385288598117041.0e14;p=0;while(1){x=+g[X+(p<<4)>>2];d=x<A;z=d?x:z;n=x>F;v=n?x:v;G=+g[X+(p<<4)+4>>2];i=G<I;y=i?G:y;k=G>J;t=k?G:t;K=+g[X+(p<<4)+8>>2];j=K<L;w=j?K:w;m=K>M;r=m?K:r;p=p+1|0;if((p|0)==(h|0))break;else{A=d?x:A;F=n?x:F;I=i?G:I;J=k?G:J;L=j?K:L;M=m?K:M}}i=h>>>0<3}x=v-z;t=t-y;A=r-w;if(!(i|(x<9.999999974752427e-07|t<9.999999974752427e-07|A<9.999999974752427e-07))){if(h|0){U=h;r=H;W=52;break}break}z=z+x*.5;y=y+t*.5;w=w+A*.5;v=x>=9.999999974752427e-07&x<3402823466385288598117041.0e14?x:3402823466385288598117041.0e14;v=t>=9.999999974752427e-07&t<v?t:v;v=A>=9.999999974752427e-07&A<v?A:v;if(!(v==3402823466385288598117041.0e14)){r=x<9.999999974752427e-07?v*.05000000074505806:x;t=t<9.999999974752427e-07?v*.05000000074505806:t;if(A<9.999999974752427e-07)v=v*.05000000074505806;else v=A}else{r=.009999999776482582;t=.009999999776482582;v=.009999999776482582}x=w+v;A=z+r;F=y+t;G=s;w=w-v;v=z-r;r=y-t;W=51}while(0);if((W|0)==51){g[X>>2]=v;g[X+4>>2]=r;g[X+8>>2]=w;g[X+16>>2]=A;g[X+20>>2]=r;g[X+24>>2]=w;g[X+32>>2]=A;g[X+36>>2]=F;g[X+40>>2]=w;g[X+48>>2]=v;g[X+52>>2]=F;g[X+56>>2]=w;g[X+64>>2]=v;g[X+68>>2]=r;g[X+72>>2]=x;g[X+80>>2]=A;g[X+84>>2]=r;g[X+88>>2]=x;g[X+96>>2]=A;g[X+100>>2]=F;g[X+104>>2]=x;g[X+112>>2]=v;g[X+116>>2]=F;g[X+120>>2]=x;U=8;s=G;r=H;W=52}if((W|0)==52){h=0;do{V=X+(h<<4)|0;g[V>>2]=s*+g[V>>2];V=X+(h<<4)+4|0;g[V>>2]=r*+g[V>>2];V=X+(h<<4)+8|0;g[V>>2]=o*+g[V>>2];h=h+1|0}while(h>>>0<U>>>0);if((U|0)>=4){o=+g[X>>2];s=+g[X+4>>2];r=+g[X+8>>2];V=U<<2;c[6432]=(c[6432]|0)+1;h=ec((V|3)+16|0)|0;if(!h)j=0;else{c[(h+4+15&-16)+-4>>2]=h;j=h+4+15&-16}c[Z+48>>2]=0;c[6432]=(c[6432]|0)+1;i=ec((V|3)+16|0)|0;if(i){c[(i+4+15&-16)+-4>>2]=i;h=c[Z+48>>2]|0;if(!h)h=i+4+15&-16;else{c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0);h=i+4+15&-16}}else h=0;c[Z+48>>2]=h;p=j;q=j;u=0;h=U;v=o;w=r;x=s;t=o;o=s;m=U;n=j;while(1){if((u|0)==(h|0)?(N=u|0?u<<1:1,(u|0)<(N|0)):0){if((N|0)!=0?(c[6432]=(c[6432]|0)+1,D=ec((N<<2|3)+16|0)|0,(D|0)!=0):0){c[(D+4+15&-16)+-4>>2]=D;j=D+4+15&-16}else j=0;i=c[Z+48>>2]|0;if((u|0)<=0){if(i|0)W=68}else{h=0;do{c[j+(h<<2)>>2]=c[i+(h<<2)>>2];h=h+1|0}while((h|0)!=(u|0));W=68}if((W|0)==68){W=0;c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0);c[Z+48>>2]=0}c[Z+48>>2]=j;k=N}else k=h;c[(c[Z+48>>2]|0)+(u<<2)>>2]=1;d=u;u=u+1|0;do if((d|0)==(m|0)){i=d|0?d<<1:1;if((d|0)<(i|0)){if((i|0)!=0?(c[6432]=(c[6432]|0)+1,E=ec((i<<2|3)+16|0)|0,(E|0)!=0):0){c[(E+4+15&-16)+-4>>2]=E;j=E+4+15&-16}else j=0;if((d|0)>0){h=0;do{c[j+(h<<2)>>2]=c[n+(h<<2)>>2];h=h+1|0}while((h|0)!=(d|0));if(!q){R=j;h=j;Q=j;break}}else if((n|0)==0|(q|0)==0){R=j;h=j;Q=j;break}c[6433]=(c[6433]|0)+1;Pc(c[q+-4>>2]|0);R=j;h=j;Q=j}else{R=p;h=q;i=d;Q=n}}else{R=p;h=q;i=m;Q=n}while(0);c[Q+(d<<2)>>2]=0;K=+g[X+(d<<4)>>2];t=K<t?K:t;L=+g[X+(d<<4)+4>>2];o=L<o?L:o;M=+g[X+(d<<4)+8>>2];r=M<r?M:r;v=v<K?K:v;x=x<L?L:x;w=w<M?M:w;if((u|0)>=(U|0))break;else{p=R;q=h;h=k;m=i;n=Q}}M=v-t;v=x-o;G=w-r;G=+C(+(M*M+v*v+G*G))*1.0000000474974513e-03;N=De(X,U,.009999999776482582,.019999999552965164,1.0,c[Z+48>>2]|0)|0;m=c[Z+48>>2]|0;P=De(X,U,-.009999999776482582,-.019999999552965164,-1.0,m)|0;n=X+(N<<4)|0;u=X+(P<<4)|0;v=+g[n>>2]-+g[u>>2];D=X+(N<<4)+4|0;E=X+(P<<4)+4|0;x=+g[D>>2]-+g[E>>2];p=X+(N<<4)+8|0;q=X+(P<<4)+8|0;w=+g[p>>2]-+g[q>>2];b:do if((N|0)!=(P|0)?!(w==0.0&x==0.0&v==0.0):0){r=+C(+((w*.019999999552965164-x*0.0)*(w*.019999999552965164-x*0.0)+(v*0.0-w)*(v*0.0-w)+(x-v*.019999999552965164)*(x-v*.019999999552965164)));o=+C(+((w-x*0.0)*(w-x*0.0)+(w*.019999999552965164+v*0.0)*(w*.019999999552965164+v*0.0)+(x*-.019999999552965164-v)*(x*-.019999999552965164-v)));if(r>o){s=(w*.019999999552965164-x*0.0)*(1.0/r);t=(v*0.0-w)*(1.0/r);o=(x-v*.019999999552965164)*(1.0/r)}else{s=(w-x*0.0)*(1.0/o);t=(w*.019999999552965164+v*0.0)*(1.0/o);o=(x*-.019999999552965164-v)*(1.0/o)}h=De(X,U,s,t,o,m)|0;if((h|0)==(N|0)|(h|0)==(P|0))k=De(X,U,-s,-t,-o,m)|0;else k=h;if(!((k|0)==(N|0)|(k|0)==(P|0))){i=X+(k<<4)|0;r=+g[i>>2]-+g[n>>2];d=X+(k<<4)+4|0;t=+g[d>>2]-+g[D>>2];j=X+(k<<4)+8|0;s=+g[j>>2]-+g[p>>2];o=1.0/+C(+((x*r-t*v)*(x*r-t*v)+((t*w-s*x)*(t*w-s*x)+(s*v-w*r)*(s*v-w*r))));h=De(X,U,(t*w-s*x)*o,(s*v-w*r)*o,(x*r-t*v)*o,m)|0;if((h|0)==(k|0)|((h|0)==(N|0)|(h|0)==(P|0)))h=De(X,U,-((t*w-s*x)*o),-((s*v-w*r)*o),-((x*r-t*v)*o),m)|0;if(!((h|0)==(k|0)|((h|0)==(N|0)|(h|0)==(P|0)))?(A=+g[n>>2],I=+g[D>>2],z=+g[p>>2],L=+g[u>>2]-A,F=+g[E>>2]-I,J=+g[q>>2]-z,K=+g[i>>2]-A,H=+g[d>>2]-I,M=+g[j>>2]-z,S=(+g[X+(h<<4)+8>>2]-z)*(L*H-F*K)+((+g[X+(h<<4)>>2]-A)*(F*M-J*H)+(+g[X+(h<<4)+4>>2]-I)*(J*K-L*M))<0.0,T=S?k:h,S=S?h:k,(N|0)!=-1):0){z=(+g[X+(N<<4)>>2]+ +g[X+(P<<4)>>2]+ +g[X+(S<<4)>>2]+ +g[X+(T<<4)>>2])*.25;A=(+g[X+(N<<4)+4>>2]+ +g[X+(P<<4)+4>>2]+ +g[X+(S<<4)+4>>2]+ +g[X+(T<<4)+4>>2])*.25;F=(+g[X+(N<<4)+8>>2]+ +g[X+(P<<4)+8>>2]+ +g[X+(S<<4)+8>>2]+ +g[X+(T<<4)+8>>2])*.25;h=sh(Z,S,T,P)|0;c[h+12>>2]=2;c[h+16>>2]=3;c[h+20>>2]=1;h=sh(Z,T,S,N)|0;c[h+12>>2]=3;c[h+16>>2]=2;c[h+20>>2]=0;h=sh(Z,N,P,T)|0;c[h+12>>2]=0;c[h+16>>2]=1;c[h+20>>2]=3;h=sh(Z,P,N,S)|0;c[h+12>>2]=1;c[h+16>>2]=0;c[h+20>>2]=2;c[Q+(T<<2)>>2]=1;c[Q+(S<<2)>>2]=1;c[Q+(P<<2)>>2]=1;c[Q+(N<<2)>>2]=1;h=c[Z+4>>2]|0;if((h|0)>0){i=c[Z+12>>2]|0;j=0;do{h=c[i+(j<<2)>>2]|0;S=c[h>>2]|0;P=c[h+4>>2]|0;T=c[h+8>>2]|0;v=+g[X+(P<<4)>>2];t=v-+g[X+(S<<4)>>2];x=+g[X+(P<<4)+4>>2];w=x-+g[X+(S<<4)+4>>2];r=+g[X+(P<<4)+8>>2];o=r-+g[X+(S<<4)+8>>2];v=+g[X+(T<<4)>>2]-v;x=+g[X+(T<<4)+4>>2]-x;r=+g[X+(T<<4)+8>>2]-r;s=+C(+((t*x-w*v)*(t*x-w*v)+((w*r-o*x)*(w*r-o*x)+(o*v-t*r)*(o*v-t*r))));if(s==0.0){y=1.0;r=0.0;o=0.0}else{y=1.0/s*(w*r-o*x);r=1.0/s*(o*v-t*r);o=1.0/s*(t*x-w*v)}S=De(X,U,y,r,o,c[Z+48>>2]|0)|0;c[h+28>>2]=S;T=c[h>>2]|0;g[h+32>>2]=(+g[X+(S<<4)>>2]-+g[X+(T<<4)>>2])*y+(+g[X+(S<<4)+4>>2]-+g[X+(T<<4)+4>>2])*r+(+g[X+(S<<4)+8>>2]-+g[X+(T<<4)+8>>2])*o;j=j+1|0;h=c[Z+4>>2]|0}while((j|0)<(h|0))}if((e+-4|0)>0){q=e+-4|0;while(1){n=c[Z+12>>2]|0;d=0;j=0;while(1){i=c[n+(d<<2)>>2]|0;do if(j){if(!i){i=j;break}if(!(+g[j+32>>2]<+g[i+32>>2]))i=j;else W=104}else W=104;while(0);if((W|0)==104)W=0;d=d+1|0;if((d|0)>=(h|0))break;else j=i}if((i|0)==0?1:!(+g[i+32>>2]>G)){i=1;break b}p=c[i+28>>2]|0;c[Q+(p<<2)>>2]=1;h=c[Z+4>>2]|0;c:do if(h|0){d=X+(p<<4)|0;m=X+(p<<4)+4|0;k=X+(p<<4)+8|0;j=n;while(1){i=h+-1|0;h=c[j+(i<<2)>>2]|0;do if(h|0){T=c[h>>2]|0;S=c[h+4>>2]|0;e=c[h+8>>2]|0;K=+g[X+(S<<4)>>2];L=+g[X+(T<<4)>>2];v=+g[X+(S<<4)+4>>2];x=+g[X+(T<<4)+4>>2];H=+g[X+(S<<4)+8>>2];I=+g[X+(T<<4)+8>>2];J=+g[X+(e<<4)>>2]-K;w=+g[X+(e<<4)+4>>2]-v;M=+g[X+(e<<4)+8>>2]-H;y=+C(+(((K-L)*w-(v-x)*J)*((K-L)*w-(v-x)*J)+(((v-x)*M-(H-I)*w)*((v-x)*M-(H-I)*w)+((H-I)*J-(K-L)*M)*((H-I)*J-(K-L)*M))));if(!((y==0.0?0.0:1.0/y*((K-L)*w-(v-x)*J))*(+g[k>>2]-I)+((+g[d>>2]-L)*(y==0.0?1.0:1.0/y*((v-x)*M-(H-I)*w))+(+g[m>>2]-x)*(y==0.0?0.0:1.0/y*((H-I)*J-(K-L)*M)))>G*.009999999776482582))break;Yd(Z,h,p)}while(0);if(!i)break;j=c[Z+12>>2]|0;h=i}i=c[Z+4>>2]|0;if(!i)break;else h=i;d:do{i=i+-1|0;d=c[Z+12>>2]|0;k=c[d+(i<<2)>>2]|0;do if(k){m=c[k>>2]|0;do if((m|0)!=(p|0)){j=c[k+4>>2]|0;if((j|0)==(p|0)){j=p;break}if((c[k+8>>2]|0)!=(p|0))break d}else j=c[k+4>>2]|0;while(0);e=c[k+8>>2]|0;K=+g[X+(j<<4)>>2];L=+g[X+(m<<4)>>2];v=+g[X+(j<<4)+4>>2];x=+g[X+(m<<4)+4>>2];H=+g[X+(j<<4)+8>>2];I=+g[X+(m<<4)+8>>2];J=+g[X+(e<<4)>>2]-K;w=+g[X+(e<<4)+4>>2]-v;M=+g[X+(e<<4)+8>>2]-H;y=+C(+(((K-L)*w-(v-x)*J)*((K-L)*w-(v-x)*J)+(((v-x)*M-(H-I)*w)*((v-x)*M-(H-I)*w)+((H-I)*J-(K-L)*M)*((H-I)*J-(K-L)*M))));if(!(y<G*G*.10000000149011612?1:(F-I)*(y==0.0?0.0:1.0/y*((K-L)*w-(v-x)*J))+((z-L)*(y==0.0?1.0:1.0/y*((v-x)*M-(H-I)*w))+(A-x)*(y==0.0?0.0:1.0/y*((H-I)*J-(K-L)*M)))>G*.009999999776482582))break;Yd(Z,c[d+(c[k+12>>2]<<2)>>2]|0,p);i=c[Z+4>>2]|0;h=i}while(0)}while((i|0)!=0);if(!h)break;d=c[Z+12>>2]|0;do{h=h+-1|0;j=c[d+(h<<2)>>2]|0;do if(j|0){if((c[j+28>>2]|0)>-1)break c;T=c[j>>2]|0;S=c[j+4>>2]|0;e=c[j+8>>2]|0;v=+g[X+(S<<4)>>2];t=v-+g[X+(T<<4)>>2];x=+g[X+(S<<4)+4>>2];w=x-+g[X+(T<<4)+4>>2];r=+g[X+(S<<4)+8>>2];o=r-+g[X+(T<<4)+8>>2];v=+g[X+(e<<4)>>2]-v;x=+g[X+(e<<4)+4>>2]-x;r=+g[X+(e<<4)+8>>2]-r;s=+C(+((t*x-w*v)*(t*x-w*v)+((w*r-o*x)*(w*r-o*x)+(o*v-t*r)*(o*v-t*r))));if(s==0.0){y=1.0;r=0.0;o=0.0}else{y=1.0/s*(w*r-o*x);r=1.0/s*(o*v-t*r);o=1.0/s*(t*x-w*v)}i=De(X,U,y,r,o,c[Z+48>>2]|0)|0;c[j+28>>2]=i;if(!(c[Q+(i<<2)>>2]|0)){e=c[j>>2]|0;g[j+32>>2]=(+g[X+(i<<4)>>2]-+g[X+(e<<4)>>2])*y+(+g[X+(i<<4)+4>>2]-+g[X+(e<<4)+4>>2])*r+(+g[X+(i<<4)+8>>2]-+g[X+(e<<4)+8>>2])*o;break}else{c[j+28>>2]=-1;break}}while(0)}while((h|0)!=0)}while(0);if((q|0)<=1){i=1;break b}h=c[Z+4>>2]|0;q=q+-1|0}}else i=1}else i=0}else i=0}else i=0;while(0);h=c[Z+48>>2]|0;if(h|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0);c[Z+48>>2]=0}if(!((Q|0)==0|(R|0)==0)){c[6433]=(c[6433]|0)+1;Pc(c[R+-4>>2]|0)}if(i){h=c[Z+4>>2]|0;if((h|0)>0){i=c[Z+12>>2]|0;n=0;j=0;D=0;q=0;d=0;k=0;while(1){p=c[i+(D<<2)>>2]|0;if(!p)m=q;else{do if((k|0)==(q|0)){m=q|0?q<<1:1;if((q|0)>=(m|0)){m=q;break}do if(!m)i=0;else{c[6432]=(c[6432]|0)+1;h=ec((m<<2|3)+16|0)|0;if(!h){i=0;break}c[(h+4+15&-16)+-4>>2]=h;i=h+4+15&-16}while(0);if((q|0)>0){h=0;do{c[i+(h<<2)>>2]=c[d+(h<<2)>>2];h=h+1|0}while((h|0)!=(q|0));if(!n){n=i;j=i;d=i;break}}else if((d|0)==0|(n|0)==0){n=i;j=i;d=i;break}c[6433]=(c[6433]|0)+1;Pc(c[n+-4>>2]|0);n=i;j=i;d=i}else m=q;while(0);c[d+(k<<2)>>2]=c[p>>2];u=k+1|0;q=(c[(c[Z+12>>2]|0)+(D<<2)>>2]|0)+4|0;do if((u|0)==(m|0)){p=m|0?m<<1:1;if((m|0)>=(p|0))break;do if(!p)i=0;else{c[6432]=(c[6432]|0)+1;h=ec((p<<2|3)+16|0)|0;if(!h){i=0;break}c[(h+4+15&-16)+-4>>2]=h;i=h+4+15&-16}while(0);if((m|0)>0){h=0;do{c[i+(h<<2)>>2]=c[d+(h<<2)>>2];h=h+1|0}while((h|0)!=(m|0));if(!n){n=i;j=i;m=p;d=i;break}}else if((d|0)==0|(n|0)==0){n=i;j=i;m=p;d=i;break}c[6433]=(c[6433]|0)+1;Pc(c[n+-4>>2]|0);n=i;j=i;m=p;d=i}while(0);c[d+(u<<2)>>2]=c[q>>2];u=k+2|0;q=(c[(c[Z+12>>2]|0)+(D<<2)>>2]|0)+8|0;do if((u|0)==(m|0)){p=m|0?m<<1:1;if((m|0)>=(p|0))break;do if(!p)i=0;else{c[6432]=(c[6432]|0)+1;h=ec((p<<2|3)+16|0)|0;if(!h){i=0;break}c[(h+4+15&-16)+-4>>2]=h;i=h+4+15&-16}while(0);if((m|0)>0){h=0;do{c[i+(h<<2)>>2]=c[d+(h<<2)>>2];h=h+1|0}while((h|0)!=(m|0));if(!n){j=i;n=i;m=p;d=i;break}}else if((d|0)==0|(n|0)==0){j=i;n=i;m=p;d=i;break}c[6433]=(c[6433]|0)+1;Pc(c[n+-4>>2]|0);j=i;n=i;m=p;d=i}while(0);c[d+(u<<2)>>2]=c[q>>2];i=c[Z+12>>2]|0;h=c[i+(D<<2)>>2]|0;c[i+(c[h+24>>2]<<2)>>2]=0;if(h|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}h=c[Z+4>>2]|0;k=k+3|0}D=D+1|0;if((D|0)>=(h|0))break;else q=m}c[Z+44>>2]=(k|0)/3|0;if((k|0)>0){c[6432]=(c[6432]|0)+1;h=ec((k<<2|3)+16|0)|0;if(!h)i=0;else{c[(h+4+15&-16)+-4>>2]=h;i=h+4+15&-16}Hk(i|0,0,k<<2|0)|0;h=0;do{c[i+(h<<2)>>2]=c[d+(h<<2)>>2];h=h+1|0}while((h|0)!=(k|0));m=j;S=i;h=i;R=k}else{m=j;S=0;h=0;R=k}}else{c[Z+44>>2]=0;m=0;S=0;h=0;d=0;R=0}i=c[Z+4>>2]|0;if((i|0)<0){if((c[Z+8>>2]|0)<0){j=c[Z+12>>2]|0;if(j|0){if(a[Z+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0)}c[Z+12>>2]=0}a[Z+16>>0]=1;c[Z+12>>2]=0;c[Z+8>>2]=0}do{c[(c[Z+12>>2]|0)+(i<<2)>>2]=0;i=i+1|0}while((i|0)!=0)}c[Z+4>>2]=0;if(!((d|0)==0|(m|0)==0)){c[6433]=(c[6433]|0)+1;Pc(c[m+-4>>2]|0)}Q=c[Z+44>>2]|0;k=(U|0)>0;if(k){c[6432]=(c[6432]|0)+1;i=ec((U<<4|3)+16|0)|0;if(!i)j=0;else{c[(i+4+15&-16)+-4>>2]=i;j=i+4+15&-16}i=0;do{e=j+(i<<4)|0;c[e>>2]=c[Z+48>>2];c[e+4>>2]=c[Z+48+4>>2];c[e+8>>2]=c[Z+48+8>>2];c[e+12>>2]=c[Z+48+12>>2];i=i+1|0}while((i|0)!=(U|0));P=j;N=j}else{P=0;N=0}j=c[Z+24>>2]|0;do if((j|0)>0){c[6432]=(c[6432]|0)+1;i=ec((j<<2|3)+16|0)|0;if(!i)d=0;else{c[(i+4+15&-16)+-4>>2]=i;d=i+4+15&-16}Hk(d|0,0,j<<2|0)|0;if((c[Z+24>>2]|0)<=0){E=d;D=d;break}i=c[Z+32>>2]|0;j=0;do{c[d+(j<<2)>>2]=c[i+(j<<2)>>2];j=j+1|0}while((j|0)<(c[Z+24>>2]|0));E=d;D=d}else{E=0;D=0}while(0);if(k){c[6432]=(c[6432]|0)+1;i=ec((V|3)+16|0)|0;if(!i)i=0;else{c[(i+4+15&-16)+-4>>2]=i;i=i+4+15&-16}Hk(i|0,0,V|0)|0;u=i;q=i}else{u=0;q=0}Hk(u|0,0,V|0)|0;if((Q|0)<=0)if(!q)p=0;else{i=0;W=221}else{n=c[Z+32>>2]|0;p=0;i=0;do{d=h+(p<<2)|0;k=c[d>>2]|0;m=q+(k<<2)|0;j=c[m>>2]|0;if(!j){c[d>>2]=i;c[N+(i<<4)>>2]=c[Y+(k<<4)>>2];c[N+(i<<4)+4>>2]=c[Y+(k<<4)+4>>2];c[N+(i<<4)+8>>2]=c[Y+(k<<4)+8>>2];j=c[Z+24>>2]|0;if((j|0)>0){d=0;do{if((c[D+(d<<2)>>2]|0)==(k|0))c[n+(d<<2)>>2]=i;d=d+1|0}while((d|0)!=(j|0))}i=i+1|0;c[m>>2]=i}else c[d>>2]=j+-1;p=p+1|0}while((p|0)!=(Q*3|0));W=221}do if((W|0)==221){if(!u){p=i;break}c[6433]=(c[6433]|0)+1;Pc(c[u+-4>>2]|0);p=i}while(0);if(!((D|0)==0|(E|0)==0)){c[6433]=(c[6433]|0)+1;Pc(c[E+-4>>2]|0)}if((p|0)>0){c[6432]=(c[6432]|0)+1;i=ec((p<<4|3)+16|0)|0;if(!i)j=0;else{c[(i+4+15&-16)+-4>>2]=i;j=i+4+15&-16}i=0;do{W=j+(i<<4)|0;c[W>>2]=c[Z+48>>2];c[W+4>>2]=c[Z+48+4>>2];c[W+8>>2]=c[Z+48+8>>2];c[W+12>>2]=c[Z+48+12>>2];i=i+1|0}while((i|0)!=(p|0));d=j;k=j}else{d=0;k=0}if((Q|0)>0){c[6432]=(c[6432]|0)+1;i=ec((Q*12|3)+16|0)|0;if(!i)j=0;else{c[(i+4+15&-16)+-4>>2]=i;j=i+4+15&-16}i=c[Z+40>>2]|0;if(i|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[Z+40>>2]=j;Hk(j|0,0,Q*12|0)|0}Th(d|0,P|0,p<<4|0)|0;Th(c[Z+40>>2]|0,S|0,Q*12|0)|0;do if(R){if(!h){h=0;break}c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0);h=0}while(0);if((N|0)==0|(P|0)==0){m=Q;n=Q*3|0;break}c[6433]=(c[6433]|0)+1;Pc(c[P+-4>>2]|0);m=Q;n=Q*3|0;break}}}h=0;p=0;k=0;m=0;n=0}while(0);if(!((X|0)==0|(Y|0)==0)){c[6433]=(c[6433]|0)+1;Pc(c[Y+-4>>2]|0)}if(h|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[6432]=(c[6432]|0)+1;h=ec(1271)|0;if(!h)D=0;else{c[(h+4+15&-16)+-4>>2]=h;D=h+4+15&-16}oc(D,b,p,k,0);if((m|0)>0){d=0;do{j=d*3|0;b=c[Z+40>>2]|0;h=c[b+(j<<2)>>2]|0;i=c[b+(j+1<<2)>>2]|0;j=c[b+(j+2<<2)>>2]|0;if((h|0)<(i|0))Df(D,h,i,0,0);if((i|0)<(j|0))Df(D,i,j,0,0);if((j|0)<(h|0))Df(D,j,h,0,0);Mf(D,h,i,j,0);d=d+1|0}while((d|0)!=(m|0))}if(p)if(!k)u=0;else{c[6433]=(c[6433]|0)+1;Pc(c[k+-4>>2]|0);u=0}else u=k;if(n|0){h=c[Z+40>>2]|0;if(h|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0);c[Z+40>>2]=0}c[Z+40>>2]=0}if(f){i=c[D+732>>2]|0;if((i|0)>0){m=D+740|0;k=0;h=243703;do{j=c[m>>2]|0;d=j+(k*52|0)|0;h=(O(h,1664525)|0)+1013904223|0;n=Z+48|0;p=d;q=n+52|0;do{c[n>>2]=c[p>>2];n=n+4|0;p=p+4|0}while((n|0)<(q|0));n=d;p=j+(((h>>>0)%(i>>>0)|0)*52|0)|0;q=n+52|0;do{c[n>>2]=c[p>>2];n=n+4|0;p=p+4|0}while((n|0)<(q|0));n=j+(((h>>>0)%(i>>>0)|0)*52|0)|0;p=Z+48|0;q=n+52|0;do{c[n>>2]=c[p>>2];n=n+4|0;p=p+4|0}while((n|0)<(q|0));k=k+1|0}while((k|0)!=(i|0))}else h=243703;d=c[D+752>>2]|0;if((d|0)>0){m=D+760|0;k=0;do{i=c[m>>2]|0;j=i+(k*44|0)|0;h=(O(h,1664525)|0)+1013904223|0;i=i+(((h>>>0)%(d>>>0)|0)*44|0)|0;n=Z+48|0;p=j;q=n+44|0;do{c[n>>2]=c[p>>2];n=n+4|0;p=p+4|0}while((n|0)<(q|0));n=j;p=i;q=n+44|0;do{c[n>>2]=c[p>>2];n=n+4|0;p=p+4|0}while((n|0)<(q|0));n=i;p=Z+48|0;q=n+44|0;do{c[n>>2]=c[p>>2];n=n+4|0;p=p+4|0}while((n|0)<(q|0));k=k+1|0}while((k|0)!=(d|0))}}h=c[Z+32>>2]|0;if(h|0){if(a[Z+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[Z+32>>2]=0}a[Z+36>>0]=1;c[Z+32>>2]=0;c[Z+24>>2]=0;c[Z+28>>2]=0;h=c[Z+12>>2]|0;if(h|0){if(a[Z+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[Z+12>>2]=0}h=c[Z+40>>2]|0;if(h|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0);c[Z+40>>2]=0}c[Z+40>>2]=0;if(!u){l=Z;return D|0}c[6433]=(c[6433]|0)+1;Pc(c[u+-4>>2]|0);l=Z;return D|0}function $b(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,h=0,i=0,j=0,k=0,m=0.0,n=0.0,o=0.0,p=0,q=0,r=0,s=0,t=0,u=0,v=0.0,w=0,x=0.0,y=0.0,z=0.0,A=0.0,C=0.0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0.0,M=0.0,N=0.0,P=0.0;K=l;l=l+16|0;f=c[b+1112>>2]|0;a:do if((f|0)>0)while(1){k=c[c[b+1120>>2]>>2]|0;f=c[k+348>>2]|0;if(f|0){Kg(b+1048|0,f)|0;h=c[b+1052>>2]|0;if(h|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[b+1052>>2]=f;c[b+1060>>2]=(c[b+1060>>2]|0)+-1}f=c[k+52>>2]|0;if(f|0){if(a[k+56>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[k+52>>2]=0}a[k+56>>0]=1;c[k+52>>2]=0;c[k+44>>2]=0;c[k+48>>2]=0;f=c[k+32>>2]|0;if(f|0){if(a[k+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[k+32>>2]=0}a[k+36>>0]=1;c[k+32>>2]=0;c[k+24>>2]=0;c[k+28>>2]=0;f=c[k+12>>2]|0;if(f|0){if(a[k+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[k+12>>2]=0}a[k+16>>0]=1;c[k+12>>2]=0;c[k+4>>2]=0;c[k+8>>2]=0;c[6433]=(c[6433]|0)+1;Pc(c[k+-4>>2]|0);f=c[b+1112>>2]|0;if((f|0)<=0){k=f;break a}j=c[b+1120>>2]|0;h=0;do{i=j+(h<<2)|0;if((c[i>>2]|0)==(k|0)){J=24;break}h=h+1|0}while((h|0)<(f|0));if((J|0)==24){J=0;if((h|0)<(f|0)){c[i>>2]=c[j+(f+-1<<2)>>2];c[(c[b+1120>>2]|0)+(f+-1<<2)>>2]=k;c[b+1112>>2]=f+-1;f=f+-1|0}}if((f|0)<=0){k=f;break}}else k=f;while(0);f=c[b+712>>2]|0;f=(f|0)>(d|0)?d:f;if((k|0)<(f|0)){if((c[b+1116>>2]|0)<(f|0)){if(f){c[6432]=(c[6432]|0)+1;h=ec((f<<2|3)+16|0)|0;if(!h)j=0;else{c[(h+4+15&-16)+-4>>2]=h;j=h+4+15&-16}h=c[b+1112>>2]|0;if((h|0)>0){i=0;do{c[j+(i<<2)>>2]=c[(c[b+1120>>2]|0)+(i<<2)>>2];i=i+1|0}while((i|0)!=(h|0));i=b+1120|0}else i=b+1120|0}else{i=b+1120|0;j=0}h=c[i>>2]|0;if(h|0){if(a[b+1124>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[i>>2]=0}a[b+1124>>0]=1;c[i>>2]=j;c[b+1116>>2]=f}else i=b+1120|0;h=k;do{c[(c[i>>2]|0)+(h<<2)>>2]=0;h=h+1|0}while((h|0)!=(f|0))}c[b+1112>>2]=f;if((f|0)>0){h=0;do{c[6432]=(c[6432]|0)+1;f=ec(403)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}a[f+16>>0]=1;c[f+12>>2]=0;c[f+4>>2]=0;c[f+8>>2]=0;a[f+36>>0]=1;c[f+32>>2]=0;c[f+24>>2]=0;c[f+28>>2]=0;a[f+56>>0]=1;c[f+52>>2]=0;c[f+44>>2]=0;c[f+48>>2]=0;i=f+348|0;c[i>>2]=0;c[i+4>>2]=0;c[i+8>>2]=0;c[i+12>>2]=0;c[i+16>>2]=0;g[f+368>>2]=100.0;g[f+372>>2]=.009999999776482582;a[f+376>>0]=0;c[(c[b+1120>>2]|0)+(h<<2)>>2]=f;i=c[b+1120>>2]|0;a[(c[i+(h<<2)>>2]|0)+377>>0]=1;h=h+1|0;f=c[b+1112>>2]|0}while((h|0)<(f|0));if((f|0)>0){h=c[b+712>>2]|0;if((h|0)>0){m=0.0;n=0.0;o=0.0;k=f;p=0;while(1){d=c[b+720>>2]|0;v=m+ +g[d+(p*104|0)+8>>2];x=n+ +g[d+(p*104|0)+12>>2];y=o+ +g[d+(p*104|0)+16>>2];k=c[i+(((p*29873|0)%(k|0)|0)<<2)>>2]|0;d=d+(p*104|0)|0;i=c[k+24>>2]|0;if((i|0)==(c[k+28>>2]|0)?(q=i|0?i<<1:1,(i|0)<(q|0)):0){if(!q){h=i;i=0}else{c[6432]=(c[6432]|0)+1;h=ec((q<<2|3)+16|0)|0;if(!h)i=0;else{c[(h+4+15&-16)+-4>>2]=h;i=h+4+15&-16}h=c[k+24>>2]|0}if((h|0)>0){j=0;do{c[i+(j<<2)>>2]=c[(c[k+32>>2]|0)+(j<<2)>>2];j=j+1|0}while((j|0)!=(h|0))}j=c[k+32>>2]|0;if(j){if(a[k+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0);h=c[k+24>>2]|0}c[k+32>>2]=0}a[k+36>>0]=1;c[k+32>>2]=i;c[k+28>>2]=q;i=h;h=c[b+712>>2]|0}c[(c[k+32>>2]|0)+(i<<2)>>2]=d;c[k+24>>2]=i+1;j=p+1|0;if((j|0)>=(h|0))break;m=v;n=x;o=y;k=c[b+1112>>2]|0;i=c[b+1120>>2]|0;p=j}m=1.0/+(h|0);if((f|0)>=0)if(!f){n=v*m;o=x*m;m=y*m;i=0;J=70}else{n=v*m;o=x*m;m=y*m;J=68}else{G=0;F=0;E=b+720|0}}else{n=1.0/+(h|0)*0.0;o=1.0/+(h|0)*0.0;m=1.0/+(h|0)*0.0;J=68}if((J|0)==68){c[6432]=(c[6432]|0)+1;h=ec((f<<4|3)+16|0)|0;if(!h){i=0;J=70}else{c[(h+4+15&-16)+-4>>2]=h;i=h+4+15&-16;J=70}}if((J|0)==70){h=0;do{g[i+(h<<4)>>2]=n;g[i+(h<<4)+4>>2]=o;g[i+(h<<4)+8>>2]=m;g[i+(h<<4)+12>>2]=0.0;h=h+1|0}while((h|0)!=(f|0));G=i;F=i;E=b+720|0}s=F+4|0;t=F+8|0;u=0;do{A=+(u|0)*.0625;A=2.0-(A>1.0?1.0:A);k=0;d=0;while(1){h=c[(c[b+1120>>2]|0)+(d<<2)>>2]|0;j=c[h+24>>2]|0;if((j|0)>0){h=c[h+32>>2]|0;m=0.0;n=0.0;o=0.0;i=0;do{r=c[h+(i<<2)>>2]|0;m=m+ +g[r+8>>2];n=n+ +g[r+12>>2];o=o+ +g[r+16>>2];i=i+1|0}while((i|0)!=(j|0))}else{o=0.0;n=0.0;m=0.0}if(!j)r=k;else{q=F+(d<<4)|0;x=+g[q>>2];r=F+(d<<4)+4|0;y=+g[r>>2];h=F+(d<<4)+8|0;z=+g[h>>2];v=x+A*(m*(1.0/+(j|0))-x);n=y+A*(n*(1.0/+(j|0))-y);m=z+A*(o*(1.0/+(j|0))-z);g[q>>2]=v;g[r>>2]=n;g[h>>2]=m;g[F+(d<<4)+12>>2]=0.0;j=c[(c[b+1120>>2]|0)+(d<<2)>>2]|0;h=c[j+24>>2]|0;if((h|0)<0){if((c[j+28>>2]|0)<0){i=c[j+32>>2]|0;if(i|0){if(a[j+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[j+32>>2]=0}a[j+36>>0]=1;c[j+32>>2]=0;c[j+28>>2]=0}do{c[(c[j+32>>2]|0)+(h<<2)>>2]=0;h=h+1|0}while((h|0)!=0)}c[j+24>>2]=0;r=k|(v-x)*(v-x)+(n-y)*(n-y)+(m-z)*(m-z)>1.1920928955078125e-07}d=d+1|0;if((d|0)>=(f|0))break;else k=r}u=u+1|0;h=c[b+712>>2]|0;b:do if((h|0)>0){if((f|0)>1)q=0;else{p=0;while(1){k=c[c[b+1120>>2]>>2]|0;d=(c[E>>2]|0)+(p*104|0)|0;i=c[k+24>>2]|0;if((i|0)==(c[k+28>>2]|0)?(w=i|0?i<<1:1,(i|0)<(w|0)):0){if(!w){h=i;i=0}else{c[6432]=(c[6432]|0)+1;h=ec((w<<2|3)+16|0)|0;if(!h)i=0;else{c[(h+4+15&-16)+-4>>2]=h;i=h+4+15&-16}h=c[k+24>>2]|0}if((h|0)>0){j=0;do{c[i+(j<<2)>>2]=c[(c[k+32>>2]|0)+(j<<2)>>2];j=j+1|0}while((j|0)!=(h|0))}j=c[k+32>>2]|0;if(j){if(a[k+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0);h=c[k+24>>2]|0}c[k+32>>2]=0}a[k+36>>0]=1;c[k+32>>2]=i;c[k+28>>2]=w;i=h;h=c[b+712>>2]|0}c[(c[k+32>>2]|0)+(i<<2)>>2]=d;c[k+24>>2]=i+1;p=p+1|0;if((p|0)>=(h|0))break b}}do{d=c[E>>2]|0;o=+g[d+(q*104|0)+8>>2];v=+g[d+(q*104|0)+12>>2];x=+g[d+(q*104|0)+16>>2];j=1;k=0;n=+B(+(+g[F>>2]-o))+ +B(+(+g[s>>2]-v))+ +B(+(+g[t>>2]-x));while(1){m=+B(+(+g[F+(j<<4)>>2]-o))+ +B(+(+g[F+(j<<4)+4>>2]-v))+ +B(+(+g[F+(j<<4)+8>>2]-x));i=m<n;k=i?j:k;j=j+1|0;if((j|0)==(f|0))break;else n=i?m:n}p=c[(c[b+1120>>2]|0)+(k<<2)>>2]|0;k=d+(q*104|0)|0;i=c[p+24>>2]|0;if((i|0)==(c[p+28>>2]|0)?(D=i|0?i<<1:1,(i|0)<(D|0)):0){if(!D){h=i;i=0}else{c[6432]=(c[6432]|0)+1;h=ec((D<<2|3)+16|0)|0;if(!h)i=0;else{c[(h+4+15&-16)+-4>>2]=h;i=h+4+15&-16}h=c[p+24>>2]|0}if((h|0)>0){j=0;do{c[i+(j<<2)>>2]=c[(c[p+32>>2]|0)+(j<<2)>>2];j=j+1|0}while((j|0)!=(h|0))}j=c[p+32>>2]|0;if(j){if(a[p+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0);h=c[p+24>>2]|0}c[p+32>>2]=0}a[p+36>>0]=1;c[p+32>>2]=i;c[p+28>>2]=D;i=h;h=c[b+712>>2]|0}c[(c[p+32>>2]|0)+(i<<2)>>2]=k;c[p+24>>2]=i+1;q=q+1|0}while((q|0)<(h|0))}while(0)}while((u|0)<(e|0)&r);if((h|0)>0){h=h<<2;c[6432]=(c[6432]|0)+1;f=ec((h|3)+16|0)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}Hk(f|0,-1,h|0)|0;w=f;u=f}else{w=0;u=0}f=c[b+1112>>2]|0;if((f|0)>0){d=c[b+1120>>2]|0;k=0;do{j=c[d+(k<<2)>>2]|0;if((c[j+24>>2]|0)>0){h=c[E>>2]|0;f=c[j+32>>2]|0;i=0;do{c[u+((((c[f+(i<<2)>>2]|0)-h|0)/104|0)<<2)>>2]=k;i=i+1|0}while((i|0)<(c[j+24>>2]|0));f=c[b+1112>>2]|0}k=k+1|0}while((k|0)<(f|0))}if((c[b+752>>2]|0)>0){r=0;do{e=c[b+760>>2]|0;f=c[E>>2]|0;h=((c[e+(r*44|0)+8>>2]|0)-f|0)/104|0;c[K>>2]=h;c[K+4>>2]=((c[e+(r*44|0)+12>>2]|0)-f|0)/104|0;c[K+8>>2]=((c[e+(r*44|0)+16>>2]|0)-f|0)/104|0;f=0;while(1){d=c[u+(h<<2)>>2]|0;q=1;do{h=c[K+(((q+f|0)%3|0)<<2)>>2]|0;c:do if((c[u+(h<<2)>>2]|0)!=(d|0)){p=c[(c[b+1120>>2]|0)+(d<<2)>>2]|0;k=(c[E>>2]|0)+(h*104|0)|0;h=c[p+24>>2]|0;d:do if((h|0)>0){j=c[p+32>>2]|0;i=0;while(1){if((c[j+(i<<2)>>2]|0)==(k|0))break;i=i+1|0;if((i|0)>=(h|0))break d}if((i|0)!=(h|0))break c}while(0);if((h|0)==(c[p+28>>2]|0)?(H=h|0?h<<1:1,(h|0)<(H|0)):0){if(!H)i=0;else{c[6432]=(c[6432]|0)+1;h=ec((H<<2|3)+16|0)|0;if(!h)i=0;else{c[(h+4+15&-16)+-4>>2]=h;i=h+4+15&-16}h=c[p+24>>2]|0}if((h|0)>0){j=0;do{c[i+(j<<2)>>2]=c[(c[p+32>>2]|0)+(j<<2)>>2];j=j+1|0}while((j|0)!=(h|0))}j=c[p+32>>2]|0;if(j){if(a[p+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[j+-4>>2]|0);h=c[p+24>>2]|0}c[p+32>>2]=0}a[p+36>>0]=1;c[p+32>>2]=i;c[p+28>>2]=H}c[(c[p+32>>2]|0)+(h<<2)>>2]=k;c[p+24>>2]=h+1}while(0);q=q+1|0}while((q|0)!=3);f=f+1|0;if((f|0)>=3)break;h=c[K+(f<<2)>>2]|0}r=r+1|0}while((r|0)<(c[b+752>>2]|0));f=c[b+1112>>2]|0}if((f|0)>1){c[6432]=(c[6432]|0)+1;f=ec(403)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}a[f+16>>0]=1;c[f+12>>2]=0;c[f+4>>2]=0;c[f+8>>2]=0;p=f+36|0;a[p>>0]=1;r=f+32|0;c[r>>2]=0;s=f+24|0;c[s>>2]=0;q=f+28|0;c[q>>2]=0;a[f+56>>0]=1;c[f+52>>2]=0;c[f+44>>2]=0;c[f+48>>2]=0;t=f+348|0;c[t>>2]=0;c[t+4>>2]=0;c[t+8>>2]=0;c[t+12>>2]=0;c[t+16>>2]=0;g[f+368>>2]=100.0;g[f+372>>2]=.009999999776482582;a[f+376>>0]=0;t=f;a[f+377>>0]=0;j=c[b+712>>2]|0;if((j|0)>0){c[6432]=(c[6432]|0)+1;f=ec((j<<2|3)+16|0)|0;if(!f)i=0;else{c[(f+4+15&-16)+-4>>2]=f;i=f+4+15&-16}f=c[s>>2]|0;if((f|0)>0){h=0;do{c[i+(h<<2)>>2]=c[(c[r>>2]|0)+(h<<2)>>2];h=h+1|0}while((h|0)!=(f|0))}f=c[r>>2]|0;if(f|0){if(a[p>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[r>>2]=0}a[p>>0]=1;c[r>>2]=i;c[q>>2]=j;f=c[b+712>>2]|0;if((f|0)>0){i=c[s>>2]|0;h=j;d=0;do{k=(c[E>>2]|0)+(d*104|0)|0;do if((i|0)==(h|0)){j=h|0?h<<1:1;if((h|0)>=(j|0)){i=h;break}if(!j){f=h;h=0}else{c[6432]=(c[6432]|0)+1;f=ec((j<<2|3)+16|0)|0;if(!f)h=0;else{c[(f+4+15&-16)+-4>>2]=f;h=f+4+15&-16}f=c[s>>2]|0}if((f|0)>0){i=0;do{c[h+(i<<2)>>2]=c[(c[r>>2]|0)+(i<<2)>>2];i=i+1|0}while((i|0)!=(f|0))}i=c[r>>2]|0;if(i){if(a[p>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0);f=c[s>>2]|0}c[r>>2]=0}a[p>>0]=1;c[r>>2]=h;c[q>>2]=j;i=f;f=c[b+712>>2]|0;h=j}while(0);c[(c[r>>2]|0)+(i<<2)>>2]=k;i=i+1|0;c[s>>2]=i;d=d+1|0}while((d|0)<(f|0))}}f=c[b+1112>>2]|0;if((f|0)==(c[b+1116>>2]|0)?(I=f|0?f<<1:1,(f|0)<(I|0)):0){if(!I)h=0;else{c[6432]=(c[6432]|0)+1;f=ec((I<<2|3)+16|0)|0;if(!f)h=0;else{c[(f+4+15&-16)+-4>>2]=f;h=f+4+15&-16}f=c[b+1112>>2]|0}if((f|0)>0){i=0;do{c[h+(i<<2)>>2]=c[(c[b+1120>>2]|0)+(i<<2)>>2];i=i+1|0}while((i|0)!=(f|0))}i=c[b+1120>>2]|0;if(i){if(a[b+1124>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0);f=c[b+1112>>2]|0}c[b+1120>>2]=0}a[b+1124>>0]=1;c[b+1120>>2]=h;c[b+1116>>2]=I}c[(c[b+1120>>2]|0)+(f<<2)>>2]=t;I=f+1|0;c[b+1112>>2]=I;E=c[b+1120>>2]|0;f=E+(f<<2)|0;H=c[E>>2]|0;c[E>>2]=c[f>>2];c[f>>2]=H;f=I}if((f|0)>0){h=0;do{d=c[(c[b+1120>>2]|0)+(h<<2)>>2]|0;e:do if(!(c[d+24>>2]|0)){h=h+-1|0;f=c[d+348>>2]|0;if(f|0){Kg(b+1048|0,f)|0;i=c[b+1052>>2]|0;if(i|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[b+1052>>2]=f;c[b+1060>>2]=(c[b+1060>>2]|0)+-1}f=c[d+52>>2]|0;if(f|0){if(a[d+56>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[d+52>>2]=0}a[d+56>>0]=1;c[d+52>>2]=0;c[d+44>>2]=0;c[d+48>>2]=0;f=c[d+32>>2]|0;if(f|0){if(a[d+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[d+32>>2]=0}a[d+36>>0]=1;c[d+32>>2]=0;c[d+24>>2]=0;c[d+28>>2]=0;f=c[d+12>>2]|0;if(f|0){if(a[d+16>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[d+12>>2]=0}a[d+16>>0]=1;c[d+12>>2]=0;c[d+4>>2]=0;c[d+8>>2]=0;c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0);f=c[b+1112>>2]|0;if((f|0)>0){k=c[b+1120>>2]|0;i=0;while(1){j=k+(i<<2)|0;if((c[j>>2]|0)==(d|0))break;i=i+1|0;if((i|0)>=(f|0))break e}if((i|0)>=(f|0))break;c[j>>2]=c[k+(f+-1<<2)>>2];c[(c[b+1120>>2]|0)+(f+-1<<2)>>2]=d;c[b+1112>>2]=f+-1;f=f+-1|0}}while(0);h=h+1|0}while((h|0)<(f|0))}if(!((u|0)==0|(w|0)==0)){c[6433]=(c[6433]|0)+1;Pc(c[w+-4>>2]|0)}if(!((F|0)==0|(G|0)==0)){c[6433]=(c[6433]|0)+1;Pc(c[G+-4>>2]|0)}}else J=234}else J=234;f:do if((J|0)==234){k=c[b+772>>2]|0;if(k|0){if((f|0)<(k|0)){if((c[b+1116>>2]|0)<(k|0)){c[6432]=(c[6432]|0)+1;h=ec((k<<2|3)+16|0)|0;if(!h)j=0;else{c[(h+4+15&-16)+-4>>2]=h;j=h+4+15&-16}h=c[b+1112>>2]|0;if((h|0)>0){i=0;do{c[j+(i<<2)>>2]=c[(c[b+1120>>2]|0)+(i<<2)>>2];i=i+1|0}while((i|0)!=(h|0))}h=c[b+1120>>2]|0;if(h|0){if(a[b+1124>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[b+1120>>2]=0}a[b+1124>>0]=1;c[b+1120>>2]=j;c[b+1116>>2]=k;h=b+1120|0}else h=b+1120|0;do{c[(c[h>>2]|0)+(f<<2)>>2]=0;f=f+1|0}while((f|0)!=(k|0))}c[b+1112>>2]=k;if((k|0)>0){h=0;do{c[6432]=(c[6432]|0)+1;f=ec(403)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}a[f+16>>0]=1;c[f+12>>2]=0;c[f+4>>2]=0;c[f+8>>2]=0;a[f+36>>0]=1;c[f+32>>2]=0;c[f+24>>2]=0;c[f+28>>2]=0;a[f+56>>0]=1;c[f+52>>2]=0;c[f+44>>2]=0;c[f+48>>2]=0;I=f+348|0;c[I>>2]=0;c[I+4>>2]=0;c[I+8>>2]=0;c[I+12>>2]=0;c[I+16>>2]=0;g[f+368>>2]=100.0;g[f+372>>2]=.009999999776482582;a[f+376>>0]=0;c[(c[b+1120>>2]|0)+(h<<2)>>2]=f;a[(c[(c[b+1120>>2]|0)+(h<<2)>>2]|0)+377>>0]=1;h=h+1|0}while((h|0)<(c[b+1112>>2]|0))}if((c[b+772>>2]|0)<=0)break;d=0;while(1){p=0;do{j=c[(c[b+1120>>2]|0)+(d<<2)>>2]|0;k=(c[b+780>>2]|0)+(d*104|0)+8+(p<<2)|0;f=c[j+24>>2]|0;if((f|0)==(c[j+28>>2]|0)?(r=f|0?f<<1:1,(f|0)<(r|0)):0){if(!r)h=0;else{c[6432]=(c[6432]|0)+1;f=ec((r<<2|3)+16|0)|0;if(!f)h=0;else{c[(f+4+15&-16)+-4>>2]=f;h=f+4+15&-16}f=c[j+24>>2]|0}if((f|0)>0){i=0;do{c[h+(i<<2)>>2]=c[(c[j+32>>2]|0)+(i<<2)>>2];i=i+1|0}while((i|0)!=(f|0))}i=c[j+32>>2]|0;if(i){if(a[j+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0);f=c[j+24>>2]|0}c[j+32>>2]=0}a[j+36>>0]=1;c[j+32>>2]=h;c[j+28>>2]=r}c[(c[j+32>>2]|0)+(f<<2)>>2]=c[k>>2];c[j+24>>2]=f+1;p=p+1|0}while((p|0)!=4);d=d+1|0;if((d|0)>=(c[b+772>>2]|0))break f}}d=c[b+752>>2]|0;if((f|0)<(d|0)){if((c[b+1116>>2]|0)<(d|0)){if(d){c[6432]=(c[6432]|0)+1;h=ec((d<<2|3)+16|0)|0;if(!h)k=0;else{c[(h+4+15&-16)+-4>>2]=h;k=h+4+15&-16}h=c[b+1112>>2]|0;if((h|0)>0){i=0;do{c[k+(i<<2)>>2]=c[(c[b+1120>>2]|0)+(i<<2)>>2];i=i+1|0}while((i|0)!=(h|0));j=b+1120|0;i=k}else{j=b+1120|0;i=k}}else{j=b+1120|0;i=0}h=c[j>>2]|0;if(h|0){if(a[b+1124>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[h+-4>>2]|0)}c[j>>2]=0}a[b+1124>>0]=1;c[j>>2]=i;c[b+1116>>2]=d}do{c[(c[b+1120>>2]|0)+(f<<2)>>2]=0;f=f+1|0}while((f|0)!=(d|0))}c[b+1112>>2]=d;if((d|0)>0){h=0;do{c[6432]=(c[6432]|0)+1;f=ec(403)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}a[f+16>>0]=1;c[f+12>>2]=0;c[f+4>>2]=0;c[f+8>>2]=0;a[f+36>>0]=1;c[f+32>>2]=0;c[f+24>>2]=0;c[f+28>>2]=0;a[f+56>>0]=1;c[f+52>>2]=0;c[f+44>>2]=0;c[f+48>>2]=0;I=f+348|0;c[I>>2]=0;c[I+4>>2]=0;c[I+8>>2]=0;c[I+12>>2]=0;c[I+16>>2]=0;g[f+368>>2]=100.0;g[f+372>>2]=.009999999776482582;a[f+376>>0]=0;c[(c[b+1120>>2]|0)+(h<<2)>>2]=f;a[(c[(c[b+1120>>2]|0)+(h<<2)>>2]|0)+377>>0]=1;h=h+1|0}while((h|0)<(c[b+1112>>2]|0))}if((c[b+752>>2]|0)>0){d=0;do{p=0;do{j=c[(c[b+1120>>2]|0)+(d<<2)>>2]|0;k=(c[b+760>>2]|0)+(d*44|0)+8+(p<<2)|0;f=c[j+24>>2]|0;if((f|0)==(c[j+28>>2]|0)?(s=f|0?f<<1:1,(f|0)<(s|0)):0){if(!s)h=0;else{c[6432]=(c[6432]|0)+1;f=ec((s<<2|3)+16|0)|0;if(!f)h=0;else{c[(f+4+15&-16)+-4>>2]=f;h=f+4+15&-16}f=c[j+24>>2]|0}if((f|0)>0){i=0;do{c[h+(i<<2)>>2]=c[(c[j+32>>2]|0)+(i<<2)>>2];i=i+1|0}while((i|0)!=(f|0))}i=c[j+32>>2]|0;if(i){if(a[j+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0);f=c[j+24>>2]|0}c[j+32>>2]=0}a[j+36>>0]=1;c[j+32>>2]=h;c[j+28>>2]=s}c[(c[j+32>>2]|0)+(f<<2)>>2]=c[k>>2];c[j+24>>2]=f+1;p=p+1|0}while((p|0)!=3);d=d+1|0}while((d|0)<(c[b+752>>2]|0))}}while(0);f=c[b+1112>>2]|0;if(!f){b=0;l=K;return b|0}if((f|0)>0){q=0;do{p=c[(c[b+1120>>2]|0)+(q<<2)>>2]|0;g[p+128>>2]=0.0;d=c[p+24>>2]|0;k=c[p+4>>2]|0;if((d|0)>(k|0)){if((c[p+8>>2]|0)<(d|0)){if(!d){j=k;f=0}else{c[6432]=(c[6432]|0)+1;f=ec((d<<2|3)+16|0)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}j=c[p+4>>2]|0}i=c[p+12>>2]|0;if((j|0)<=0)if(!i)h=p+16|0;else J=324;else{h=0;do{c[f+(h<<2)>>2]=c[i+(h<<2)>>2];h=h+1|0}while((h|0)!=(j|0));J=324}if((J|0)==324){J=0;if(!(a[p+16>>0]|0))h=p+16|0;else{c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0);h=p+16|0}}a[h>>0]=1;c[p+12>>2]=f;c[p+8>>2]=d}else f=c[p+12>>2]|0;Hk(f+(k<<2)|0,0,d-k<<2|0)|0;k=c[p+24>>2]|0}else k=d;c[p+4>>2]=d;j=(k|0)>0;if(j){h=c[p+32>>2]|0;i=c[p+12>>2]|0;f=0;do{m=+g[(c[h+(f<<2)>>2]|0)+88>>2];if(m==0.0){a[p+376>>0]=1;m=999999984306749440.0}else m=1.0/m;g[i+(f<<2)>>2]=m;n=m+ +g[p+128>>2];g[p+128>>2]=n;f=f+1|0}while((f|0)!=(k|0));g[p+128>>2]=1.0/n;m=0.0;o=0.0;v=0.0;f=0;do{I=c[h+(f<<2)>>2]|0;C=+g[i+(f<<2)>>2];m=m+ +g[I+8>>2]*C;o=o+C*+g[I+12>>2];v=v+C*+g[I+16>>2];f=f+1|0}while((f|0)!=(k|0));n=1.0/n}else{n=1.0/+g[p+128>>2];g[p+128>>2]=n;v=0.0;o=0.0;m=0.0}C=m*n;A=o*n;z=v*n;g[p+228>>2]=C;g[p+232>>2]=A;g[p+236>>2]=z;g[p+240>>2]=0.0;f=p+316|0;h=f+36|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0));f=p+132|0;h=f+48|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(h|0));if(j){f=c[p+32>>2]|0;h=c[p+12>>2]|0;m=0.0;x=0.0;y=0.0;n=0.0;o=0.0;v=0.0;i=0;do{I=c[f+(i<<2)>>2]|0;P=+g[I+8>>2]-C;M=+g[I+12>>2]-A;N=+g[I+16>>2]-z;L=+g[h+(i<<2)>>2];m=m+L*(M*M+N*N);g[p+132>>2]=m;x=L*(P*P+N*N)+x;g[p+152>>2]=x;y=(P*P+M*M)*L+y;g[p+172>>2]=y;n=n-M*P*L;g[p+136>>2]=n;o=o-N*P*L;g[p+140>>2]=o;v=v-N*M*L;g[p+156>>2]=v;i=i+1|0}while((i|0)!=(k|0));f=p+136|0;h=p+140|0;i=p+156|0;j=p+152|0}else{y=0.0;x=0.0;v=0.0;o=0.0;n=0.0;m=0.0;f=p+136|0;h=p+140|0;i=p+156|0;j=p+152|0}L=x*y-v*v;M=v*o-y*n;N=v*n-x*o;P=1.0/(L*m+n*M+N*o);g[p+132>>2]=L*P;g[f>>2]=(v*o-y*n)*P;g[h>>2]=(v*n-x*o)*P;g[p+144>>2]=0.0;g[p+148>>2]=M*P;g[j>>2]=(y*m-o*o)*P;g[i>>2]=(n*o-v*m)*P;g[p+160>>2]=0.0;g[p+164>>2]=N*P;g[p+168>>2]=(o*n-v*m)*P;g[p+172>>2]=(x*m-n*n)*P;g[p+176>>2]=0.0;c[p+60>>2]=1065353216;c[p+64>>2]=0;c[p+64+4>>2]=0;c[p+64+8>>2]=0;c[p+64+12>>2]=0;c[p+80>>2]=1065353216;c[p+84>>2]=0;c[p+84+4>>2]=0;c[p+84+8>>2]=0;c[p+84+12>>2]=0;c[p+100>>2]=1065353216;c[p+104>>2]=0;c[p+108>>2]=c[p+228>>2];c[p+108+4>>2]=c[p+228+4>>2];c[p+108+8>>2]=c[p+228+8>>2];c[p+108+12>>2]=c[p+228+12>>2];k=c[p+24>>2]|0;j=c[p+44>>2]|0;if((j|0)<(k|0)){if((c[p+48>>2]|0)<(k|0)){if(!k){h=j;i=0}else{c[6432]=(c[6432]|0)+1;f=ec((k<<4|3)+16|0)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}h=c[p+44>>2]|0;i=f}if((h|0)>0){f=0;do{I=i+(f<<4)|0;H=(c[p+52>>2]|0)+(f<<4)|0;c[I>>2]=c[H>>2];c[I+4>>2]=c[H+4>>2];c[I+8>>2]=c[H+8>>2];c[I+12>>2]=c[H+12>>2];f=f+1|0}while((f|0)!=(h|0))}f=c[p+52>>2]|0;if(f|0){if(a[p+56>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[p+52>>2]=0}a[p+56>>0]=1;c[p+52>>2]=i;c[p+48>>2]=k;h=p+52|0}else h=p+52|0;f=j;do{I=(c[h>>2]|0)+(f<<4)|0;c[I>>2]=c[K>>2];c[I+4>>2]=c[K+4>>2];c[I+8>>2]=c[K+8>>2];c[I+12>>2]=c[K+12>>2];f=f+1|0}while((f|0)!=(k|0))}c[p+44>>2]=k;if((k|0)>0){f=0;do{H=c[(c[p+32>>2]|0)+(f<<2)>>2]|0;N=+g[H+12>>2]-+g[p+232>>2];P=+g[H+16>>2]-+g[p+236>>2];I=c[p+52>>2]|0;g[I+(f<<4)>>2]=+g[H+8>>2]-+g[p+228>>2];g[I+(f<<4)+4>>2]=N;g[I+(f<<4)+8>>2]=P;g[I+(f<<4)+12>>2]=0.0;f=f+1|0}while((f|0)<(c[p+44>>2]|0))}q=q+1|0}while((q|0)<(c[b+1112>>2]|0))}Hc(b);f=c[b+1112>>2]|0;d=O(f,f)|0;k=c[b+1132>>2]|0;if((d|0)>(k|0)){if((c[b+1136>>2]|0)<(d|0)){if(!d){j=k;f=0}else{c[6432]=(c[6432]|0)+1;f=ec(d+19|0)|0;if(!f)f=0;else{c[(f+4+15&-16)+-4>>2]=f;f=f+4+15&-16}j=c[b+1132>>2]|0}i=c[b+1140>>2]|0;if((j|0)<=0)if(!i)h=b+1144|0;else J=372;else{h=0;do{a[f+h>>0]=a[i+h>>0]|0;h=h+1|0}while((h|0)!=(j|0));J=372}if((J|0)==372)if(!(a[b+1144>>0]|0))h=b+1144|0;else{c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0);h=b+1144|0}a[h>>0]=1;c[b+1140>>2]=f;c[b+1136>>2]=d}else f=c[b+1140>>2]|0;Hk(f+k|0,0,d-k|0)|0;f=c[b+1112>>2]|0}c[b+1132>>2]=d;if((f|0)<=0){b=f;l=K;return b|0}w=c[b+1120>>2]|0;q=c[b+1140>>2]|0;t=0;do{r=c[w+(t<<2)>>2]|0;c[r+380>>2]=t;s=c[r+24>>2]|0;u=0;do{h=c[w+(u<<2)>>2]|0;g:do if((s|0)>0){i=c[h+24>>2]|0;d=0;while(1){if((i|0)>0){k=c[(c[r+32>>2]|0)+(d<<2)>>2]|0;j=c[h+32>>2]|0;p=0;do{if((k|0)==(c[j+(p<<2)>>2]|0)){h=1;break g}p=p+1|0}while((p|0)<(i|0))}d=d+1|0;if((d|0)>=(s|0)){h=0;break}}}else h=0;while(0);a[q+((O(f,u)|0)+t)>>0]=h;u=u+1|0}while((u|0)!=(f|0));t=t+1|0}while((t|0)!=(f|0));l=K;return f|0}function ac(b){b=b|0;var d=0,e=0.0,f=0.0,h=0.0,i=0.0,k=0,m=0,n=0,o=0,p=0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0,D=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0.0,$=0.0,aa=0.0,ba=0.0,ca=0.0,da=0.0,ea=0.0,fa=0.0,ga=0.0,ha=0.0,ia=0.0,ja=0.0,ka=0.0,la=0,ma=0,na=0;Z=l;l=l+176|0;Yi(12426);Qd(b);a:do if(lb[c[(c[b>>2]|0)+20>>2]&127](b)|0?(Y=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0,(lb[c[(c[Y>>2]|0)+48>>2]&127](Y)|0)&6144|0):0){G=Z+112+44|0;S=Z+112+4|0;T=Z+112+8|0;U=Z+112+16|0;V=Z+112+20|0;O=Z+112+24|0;P=Z+112+32|0;Q=Z+112+36|0;R=Z+112+40|0;W=Z+112+48|0;X=Z+112+52|0;Y=Z+112+56|0;N=Z+112+48|0;I=Z+112+16|0;D=Z+112+32|0;M=Z+112+48|0;H=Z+112+16|0;C=Z+112+32|0;L=Z+112+48|0;d=lb[c[(c[b>>2]|0)+104>>2]&127](b)|0;b:while(1){K=d+-1|0;if((d|0)<=0)break a;p=Gb[c[(c[b>>2]|0)+108>>2]&31](b,K)|0;d=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;d=((lb[c[(c[d>>2]|0)+48>>2]&127](d)|0)&2048|0)!=0;o=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;o=((lb[c[(c[o>>2]|0)+48>>2]&127](o)|0)&4096|0)!=0;B=+g[p+40>>2];if(B<=0.0){d=K;continue}switch(c[p+4>>2]|0){case 3:{c[Z+112>>2]=1065353216;c[Z+112+4>>2]=0;c[Z+112+4+4>>2]=0;c[Z+112+4+8>>2]=0;c[Z+112+4+12>>2]=0;c[Z+112+20>>2]=1065353216;c[Z+112+24>>2]=0;c[Z+112+24+4>>2]=0;c[Z+112+24+8>>2]=0;c[Z+112+24+12>>2]=0;c[Z+112+40>>2]=1065353216;c[G>>2]=0;c[G+4>>2]=0;c[G+8>>2]=0;c[G+12>>2]=0;c[G+16>>2]=0;A=+g[p+300>>2];z=+g[p+304>>2];y=+g[p+308>>2];o=c[p+28>>2]|0;x=A*+g[o+20>>2]+z*+g[o+24>>2]+y*+g[o+28>>2]+ +g[o+56>>2];w=A*+g[o+36>>2]+z*+g[o+40>>2]+y*+g[o+44>>2]+ +g[o+60>>2];g[Z+112+48>>2]=A*+g[o+4>>2]+z*+g[o+8>>2]+y*+g[o+12>>2]+ +g[o+52>>2];g[Z+112+52>>2]=x;g[Z+112+56>>2]=w;g[Z+112+60>>2]=0.0;o=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;Tb[c[(c[o>>2]|0)+56>>2]&7](o,Z+112|0,B);w=+g[p+316>>2];x=+g[p+320>>2];y=+g[p+324>>2];p=c[p+32>>2]|0;z=w*+g[p+20>>2]+x*+g[p+24>>2]+y*+g[p+28>>2]+ +g[p+56>>2];A=w*+g[p+36>>2]+x*+g[p+40>>2]+y*+g[p+44>>2]+ +g[p+60>>2];g[Z+112+48>>2]=w*+g[p+4>>2]+x*+g[p+8>>2]+y*+g[p+12>>2]+ +g[p+52>>2];g[Z+112+52>>2]=z;g[Z+112+56>>2]=A;g[Z+112+60>>2]=0.0;if(d){p=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;Tb[c[(c[p>>2]|0)+56>>2]&7](p,Z+112|0,B)}d=K;continue b}case 4:{n=c[p+28>>2]|0;e=+g[p+552>>2];da=+g[n+4>>2];f=+g[p+552+16>>2];ca=+g[n+8>>2];h=+g[p+552+32>>2];ba=+g[n+12>>2];i=+g[p+552+4>>2];q=+g[p+552+20>>2];r=+g[p+552+36>>2];s=+g[p+552+8>>2];u=+g[p+552+24>>2];w=+g[p+552+40>>2];aa=+g[n+20>>2];$=+g[n+24>>2];_=+g[n+28>>2];t=+g[n+36>>2];v=+g[n+40>>2];x=+g[n+44>>2];fa=+g[p+552+48>>2];ea=+g[p+552+52>>2];A=+g[p+552+56>>2];y=+g[n+52>>2]+(da*fa+ca*ea+ba*A);z=aa*fa+$*ea+_*A+ +g[n+56>>2];A=t*fa+v*ea+x*A+ +g[n+60>>2];g[Z+112>>2]=e*da+f*ca+h*ba;g[Z+112+4>>2]=da*i+ca*q+ba*r;g[Z+112+8>>2]=da*s+ca*u+ba*w;g[Z+112+12>>2]=0.0;g[Z+112+16>>2]=e*aa+f*$+h*_;g[Z+112+20>>2]=i*aa+q*$+r*_;g[Z+112+24>>2]=s*aa+u*$+w*_;g[Z+112+28>>2]=0.0;g[Z+112+32>>2]=e*t+f*v+h*x;g[Z+112+36>>2]=i*t+q*v+r*x;g[Z+112+40>>2]=s*t+u*v+w*x;g[Z+112+44>>2]=0.0;g[Z+112+48>>2]=y;g[Z+112+52>>2]=z;g[Z+112+56>>2]=A;g[Z+112+60>>2]=0.0;if(d){n=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;Tb[c[(c[n>>2]|0)+56>>2]&7](n,Z+112|0,B);n=c[p+32>>2]|0;u=+g[p+616>>2];h=+g[n+4>>2];v=+g[p+616+16>>2];i=+g[n+8>>2];w=+g[p+616+32>>2];q=+g[n+12>>2];x=+g[p+616+4>>2];y=+g[p+616+20>>2];z=+g[p+616+36>>2];A=+g[p+616+8>>2];$=+g[p+616+24>>2];ba=+g[p+616+40>>2];r=+g[n+20>>2];s=+g[n+24>>2];t=+g[n+28>>2];_=+g[n+36>>2];aa=+g[n+40>>2];ca=+g[n+44>>2];e=+g[p+616+48>>2];f=+g[p+616+52>>2];fa=+g[p+616+56>>2];da=+g[n+52>>2]+(h*e+i*f+q*fa);ea=r*e+s*f+t*fa+ +g[n+56>>2];fa=_*e+aa*f+ca*fa+ +g[n+60>>2];g[Z+112>>2]=u*h+v*i+w*q;g[Z+112+4>>2]=h*x+i*y+q*z;g[Z+112+8>>2]=h*A+i*$+q*ba;g[Z+112+12>>2]=0.0;g[Z+112+16>>2]=u*r+v*s+w*t;g[Z+112+20>>2]=x*r+y*s+z*t;g[Z+112+24>>2]=A*r+$*s+ba*t;g[Z+112+28>>2]=0.0;g[Z+112+32>>2]=u*_+v*aa+w*ca;g[Z+112+36>>2]=x*_+y*aa+z*ca;g[Z+112+40>>2]=A*_+$*aa+ba*ca;g[Z+112+44>>2]=0.0;g[Z+112+48>>2]=da;g[Z+112+52>>2]=ea;g[Z+112+56>>2]=fa;g[Z+112+60>>2]=0.0;n=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;Tb[c[(c[n>>2]|0)+56>>2]&7](n,Z+112|0,B)}else{n=c[p+32>>2]|0;u=+g[p+616>>2];h=+g[n+4>>2];v=+g[p+616+16>>2];i=+g[n+8>>2];w=+g[p+616+32>>2];q=+g[n+12>>2];x=+g[p+616+4>>2];y=+g[p+616+20>>2];z=+g[p+616+36>>2];A=+g[p+616+8>>2];$=+g[p+616+24>>2];ba=+g[p+616+40>>2];r=+g[n+20>>2];s=+g[n+24>>2];t=+g[n+28>>2];_=+g[n+36>>2];aa=+g[n+40>>2];ca=+g[n+44>>2];e=+g[p+616+48>>2];f=+g[p+616+52>>2];fa=+g[p+616+56>>2];da=+g[n+52>>2]+(h*e+i*f+q*fa);ea=r*e+s*f+t*fa+ +g[n+56>>2];fa=_*e+aa*f+ca*fa+ +g[n+60>>2];g[Z+112>>2]=u*h+v*i+w*q;g[Z+112+4>>2]=h*x+i*y+q*z;g[Z+112+8>>2]=h*A+i*$+q*ba;g[Z+112+12>>2]=0.0;g[Z+112+16>>2]=u*r+v*s+w*t;g[Z+112+20>>2]=x*r+y*s+z*t;g[Z+112+24>>2]=A*r+$*s+ba*t;g[Z+112+28>>2]=0.0;g[Z+112+32>>2]=u*_+v*aa+w*ca;g[Z+112+36>>2]=x*_+y*aa+z*ca;g[Z+112+40>>2]=A*_+$*aa+ba*ca;g[Z+112+44>>2]=0.0;g[Z+112+48>>2]=da;g[Z+112+52>>2]=ea;g[Z+112+56>>2]=fa;g[Z+112+60>>2]=0.0}h=+g[p+688>>2];f=+g[p+688+4>>2];e=+Vg(h-f,6.2831854820251465);if(!(e<-3.1415927410125732))if(e>3.1415927410125732)i=e+-6.2831854820251465;else i=e;else i=e+6.2831854820251465;e=+Vg(h+f,6.2831854820251465);if(!(e<-3.1415927410125732)){if(e>3.1415927410125732)e=e+-6.2831854820251465}else e=e+6.2831854820251465;if(!(i==e)?(J=i>e,o):0){c[Z+96>>2]=c[Z+112+8>>2];c[Z+96+4>>2]=c[Z+112+24>>2];c[Z+96+8>>2]=c[Z+112+40>>2];g[Z+96+12>>2]=0.0;c[Z+80>>2]=c[Z+112>>2];c[Z+80+4>>2]=c[Z+112+16>>2];c[Z+80+8>>2]=c[Z+112+32>>2];g[Z+80+12>>2]=0.0;p=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;o=c[(c[p>>2]|0)+60>>2]|0;c[Z+64>>2]=0;c[Z+64+4>>2]=0;c[Z+64+8>>2]=0;c[Z+64+12>>2]=0;sb[o&0](p,Z+112+48|0,Z+96|0,Z+80|0,B,B,J?0.0:i,J?6.2831854820251465:e,Z+64|0,J^1,10.0)}d=K;continue b}case 5:{n=c[p+28>>2]|0;u=+g[p+300>>2];h=+g[n+4>>2];v=+g[p+300+16>>2];i=+g[n+8>>2];w=+g[p+300+32>>2];q=+g[n+12>>2];x=+g[p+300+4>>2];y=+g[p+300+20>>2];z=+g[p+300+36>>2];A=+g[p+300+8>>2];$=+g[p+300+24>>2];ba=+g[p+300+40>>2];r=+g[n+20>>2];s=+g[n+24>>2];t=+g[n+28>>2];_=+g[n+36>>2];aa=+g[n+40>>2];ca=+g[n+44>>2];e=+g[p+300+48>>2];f=+g[p+300+52>>2];fa=+g[p+300+56>>2];da=+g[n+52>>2]+(h*e+i*f+q*fa);ea=r*e+s*f+t*fa+ +g[n+56>>2];fa=_*e+aa*f+ca*fa+ +g[n+60>>2];g[Z+112>>2]=u*h+v*i+w*q;g[S>>2]=h*x+i*y+q*z;g[T>>2]=h*A+i*$+q*ba;g[Z+112+12>>2]=0.0;g[U>>2]=u*r+v*s+w*t;g[V>>2]=x*r+y*s+z*t;g[O>>2]=A*r+$*s+ba*t;g[Z+112+28>>2]=0.0;g[P>>2]=u*_+v*aa+w*ca;g[Q>>2]=x*_+y*aa+z*ca;g[R>>2]=A*_+$*aa+ba*ca;g[Z+112+44>>2]=0.0;g[W>>2]=da;g[X>>2]=ea;g[Y>>2]=fa;g[Z+112+60>>2]=0.0;if(d){n=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;Tb[c[(c[n>>2]|0)+56>>2]&7](n,Z+112|0,B);n=c[p+32>>2]|0;u=+g[p+364>>2];h=+g[n+4>>2];v=+g[p+364+16>>2];i=+g[n+8>>2];w=+g[p+364+32>>2];q=+g[n+12>>2];x=+g[p+364+4>>2];y=+g[p+364+20>>2];z=+g[p+364+36>>2];A=+g[p+364+8>>2];$=+g[p+364+24>>2];ba=+g[p+364+40>>2];r=+g[n+20>>2];s=+g[n+24>>2];t=+g[n+28>>2];_=+g[n+36>>2];aa=+g[n+40>>2];ca=+g[n+44>>2];e=+g[p+364+48>>2];f=+g[p+364+52>>2];fa=+g[p+364+56>>2];da=+g[n+52>>2]+(h*e+i*f+q*fa);ea=r*e+s*f+t*fa+ +g[n+56>>2];fa=_*e+aa*f+ca*fa+ +g[n+60>>2];g[Z+112>>2]=u*h+v*i+w*q;g[S>>2]=h*x+i*y+q*z;g[T>>2]=h*A+i*$+q*ba;g[Z+112+12>>2]=0.0;g[U>>2]=u*r+v*s+w*t;g[V>>2]=x*r+y*s+z*t;g[O>>2]=A*r+$*s+ba*t;g[Z+112+28>>2]=0.0;g[P>>2]=u*_+v*aa+w*ca;g[Q>>2]=x*_+y*aa+z*ca;g[R>>2]=A*_+$*aa+ba*ca;g[Z+112+44>>2]=0.0;g[W>>2]=da;g[X>>2]=ea;g[Y>>2]=fa;g[Z+112+60>>2]=0.0;n=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;Tb[c[(c[n>>2]|0)+56>>2]&7](n,Z+112|0,B)}else{n=c[p+32>>2]|0;u=+g[p+364>>2];h=+g[n+4>>2];v=+g[p+364+16>>2];i=+g[n+8>>2];w=+g[p+364+32>>2];q=+g[n+12>>2];x=+g[p+364+4>>2];y=+g[p+364+20>>2];z=+g[p+364+36>>2];A=+g[p+364+8>>2];$=+g[p+364+24>>2];ba=+g[p+364+40>>2];r=+g[n+20>>2];s=+g[n+24>>2];t=+g[n+28>>2];_=+g[n+36>>2];aa=+g[n+40>>2];ca=+g[n+44>>2];e=+g[p+364+48>>2];f=+g[p+364+52>>2];fa=+g[p+364+56>>2];da=+g[n+52>>2]+(h*e+i*f+q*fa);ea=r*e+s*f+t*fa+ +g[n+56>>2];fa=_*e+aa*f+ca*fa+ +g[n+60>>2];g[Z+112>>2]=u*h+v*i+w*q;g[S>>2]=h*x+i*y+q*z;g[T>>2]=h*A+i*$+q*ba;g[Z+112+12>>2]=0.0;g[U>>2]=u*r+v*s+w*t;g[V>>2]=x*r+y*s+z*t;g[O>>2]=A*r+$*s+ba*t;g[Z+112+28>>2]=0.0;g[P>>2]=u*_+v*aa+w*ca;g[Q>>2]=x*_+y*aa+z*ca;g[R>>2]=A*_+$*aa+ba*ca;g[Z+112+44>>2]=0.0;g[W>>2]=da;g[X>>2]=ea;g[Y>>2]=fa;g[Z+112+60>>2]=0.0}if(o){lk(Z+96|0,p,6.0868353843688965,B);ba=+g[Z+96>>2];ca=+g[Z+96+4>>2];da=+g[Z+96+8>>2];ea=ba*+g[U>>2]+ca*+g[V>>2]+da*+g[O>>2]+ +g[X>>2];fa=ba*+g[P>>2]+ca*+g[Q>>2]+da*+g[R>>2]+ +g[Y>>2];g[Z+96>>2]=ba*+g[Z+112>>2]+ca*+g[S>>2]+da*+g[T>>2]+ +g[W>>2];g[Z+96+4>>2]=ea;g[Z+96+8>>2]=fa;g[Z+96+12>>2]=0.0;d=0;do{lk(Z+80|0,p,+(d|0)*6.283185005187988*.03125,B);ba=+g[Z+80>>2];ca=+g[Z+80+4>>2];da=+g[Z+80+8>>2];ea=ba*+g[U>>2]+ca*+g[V>>2]+da*+g[O>>2]+ +g[X>>2];fa=ba*+g[P>>2]+ca*+g[Q>>2]+da*+g[R>>2]+ +g[Y>>2];g[Z+80>>2]=ba*+g[Z+112>>2]+ca*+g[S>>2]+da*+g[T>>2]+ +g[W>>2];g[Z+80+4>>2]=ea;g[Z+80+8>>2]=fa;g[Z+80+12>>2]=0.0;o=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;n=c[(c[o>>2]|0)+8>>2]|0;c[Z+64>>2]=0;c[Z+64+4>>2]=0;c[Z+64+8>>2]=0;c[Z+64+12>>2]=0;Vb[n&127](o,Z+96|0,Z+80|0,Z+64|0);if(!(d&3)){o=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;n=c[(c[o>>2]|0)+8>>2]|0;c[Z+64>>2]=0;c[Z+64+4>>2]=0;c[Z+64+8>>2]=0;c[Z+64+12>>2]=0;Vb[n&127](o,N,Z+80|0,Z+64|0)}c[Z+96>>2]=c[Z+80>>2];c[Z+96+4>>2]=c[Z+80+4>>2];c[Z+96+8>>2]=c[Z+80+8>>2];c[Z+96+12>>2]=c[Z+80+12>>2];d=d+1|0}while((d|0)!=32);z=+g[p+452>>2];A=+g[p+512>>2];d=c[p+32>>2]|0;if(+g[d+344>>2]>0.0){ia=+g[p+364>>2];$=+g[d+4>>2];ha=+g[p+364+16>>2];aa=+g[d+8>>2];v=+g[p+364+32>>2];x=+g[d+12>>2];ka=+g[p+364+4>>2];ja=+g[p+364+20>>2];u=+g[p+364+36>>2];ga=+g[p+364+8>>2];_=+g[p+364+24>>2];w=+g[p+364+40>>2];ba=+g[d+20>>2];da=+g[d+24>>2];y=+g[d+28>>2];t=+g[d+36>>2];s=+g[d+40>>2];fa=+g[d+44>>2];ca=+g[p+364+48>>2];ea=+g[p+364+52>>2];e=+g[p+364+56>>2];f=t*ca+s*ea;h=ga*t+_*s+w*fa;i=$*ka+aa*ja+x*u;q=ia*$+ha*aa+v*x;r=ka*t+ja*s+u*fa;s=ia*t+ha*s+v*fa;t=ga*ba+_*da+w*y;u=ka*ba+ja*da+u*y;v=ia*ba+ha*da+v*y;w=$*ga+aa*_+x*w;x=$*ca+aa*ea+x*e;y=ba*ca+da*ea+y*e;d=d+4|0;e=fa*e}else{d=c[p+28>>2]|0;aa=+g[p+300>>2];ea=+g[d+4>>2];ba=+g[p+300+16>>2];fa=+g[d+8>>2];v=+g[p+300+32>>2];x=+g[d+12>>2];_=+g[p+300+4>>2];$=+g[p+300+20>>2];u=+g[p+300+36>>2];ca=+g[p+300+8>>2];da=+g[p+300+24>>2];w=+g[p+300+40>>2];ga=+g[d+20>>2];ia=+g[d+24>>2];y=+g[d+28>>2];t=+g[d+36>>2];s=+g[d+40>>2];ka=+g[d+44>>2];ha=+g[p+300+48>>2];ja=+g[p+300+52>>2];e=+g[p+300+56>>2];f=t*ha+s*ja;h=ca*t+da*s+w*ka;i=ea*_+fa*$+x*u;q=aa*ea+ba*fa+v*x;r=_*t+$*s+u*ka;s=aa*t+ba*s+v*ka;t=ca*ga+da*ia+w*y;u=_*ga+$*ia+u*y;v=aa*ga+ba*ia+v*y;w=ea*ca+fa*da+x*w;x=ea*ha+fa*ja+x*e;y=ga*ha+ia*ja+y*e;d=d+4|0;e=ka*e}ia=x+ +g[d+48>>2];ja=y+ +g[d+52>>2];ka=e+f+ +g[d+56>>2];g[Z+112>>2]=q;g[S>>2]=i;g[T>>2]=w;g[Z+112+12>>2]=0.0;g[U>>2]=v;g[V>>2]=u;g[O>>2]=t;g[Z+112+28>>2]=0.0;g[P>>2]=s;g[Q>>2]=r;g[R>>2]=h;g[Z+112+44>>2]=0.0;g[W>>2]=ia;g[X>>2]=ja;g[Y>>2]=ka;g[Z+112+60>>2]=0.0;c[Z+80>>2]=c[N>>2];c[Z+80+4>>2]=c[N+4>>2];c[Z+80+8>>2]=c[N+8>>2];c[Z+80+12>>2]=c[N+12>>2];g[Z+64>>2]=q;g[Z+64+4>>2]=v;g[Z+64+8>>2]=s;g[Z+64+12>>2]=0.0;g[Z+48>>2]=i;g[Z+48+4>>2]=u;g[Z+48+8>>2]=r;g[Z+48+12>>2]=0.0;p=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;o=c[(c[p>>2]|0)+60>>2]|0;c[Z+32>>2]=0;c[Z+32+4>>2]=0;c[Z+32+8>>2]=0;c[Z+32+12>>2]=0;sb[o&0](p,Z+80|0,Z+64|0,Z+48|0,B,B,-A-z,z-A,Z+32|0,1,10.0)}d=K;continue b}case 6:case 9:{c[Z+112>>2]=c[p+1064>>2];c[Z+112+4>>2]=c[p+1064+4>>2];c[Z+112+8>>2]=c[p+1064+8>>2];c[Z+112+12>>2]=c[p+1064+12>>2];m=p+1064+16|0;c[I>>2]=c[m>>2];c[I+4>>2]=c[m+4>>2];c[I+8>>2]=c[m+8>>2];c[I+12>>2]=c[m+12>>2];k=p+1064+32|0;c[D>>2]=c[k>>2];c[D+4>>2]=c[k+4>>2];c[D+8>>2]=c[k+8>>2];c[D+12>>2]=c[k+12>>2];n=p+1064+48|0;c[M>>2]=c[n>>2];c[M+4>>2]=c[n+4>>2];c[M+8>>2]=c[n+8>>2];c[M+12>>2]=c[n+12>>2];if(d){d=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;Tb[c[(c[d>>2]|0)+56>>2]&7](d,Z+112|0,B);c[Z+112>>2]=c[p+1128>>2];c[Z+112+4>>2]=c[p+1128+4>>2];c[Z+112+8>>2]=c[p+1128+8>>2];c[Z+112+12>>2]=c[p+1128+12>>2];c[I>>2]=c[p+1128+16>>2];c[I+4>>2]=c[p+1128+16+4>>2];c[I+8>>2]=c[p+1128+16+8>>2];c[I+12>>2]=c[p+1128+16+12>>2];c[D>>2]=c[p+1128+32>>2];c[D+4>>2]=c[p+1128+32+4>>2];c[D+8>>2]=c[p+1128+32+8>>2];c[D+12>>2]=c[p+1128+32+12>>2];c[M>>2]=c[p+1128+48>>2];c[M+4>>2]=c[p+1128+48+4>>2];c[M+8>>2]=c[p+1128+48+8>>2];c[M+12>>2]=c[p+1128+48+12>>2];d=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;Tb[c[(c[d>>2]|0)+56>>2]&7](d,Z+112|0,B)}else{c[Z+112>>2]=c[p+1128>>2];c[Z+112+4>>2]=c[p+1128+4>>2];c[Z+112+8>>2]=c[p+1128+8>>2];c[Z+112+12>>2]=c[p+1128+12>>2];c[I>>2]=c[p+1128+16>>2];c[I+4>>2]=c[p+1128+16+4>>2];c[I+8>>2]=c[p+1128+16+8>>2];c[I+12>>2]=c[p+1128+16+12>>2];c[D>>2]=c[p+1128+32>>2];c[D+4>>2]=c[p+1128+32+4>>2];c[D+8>>2]=c[p+1128+32+8>>2];c[D+12>>2]=c[p+1128+32+12>>2];c[M>>2]=c[p+1128+48>>2];c[M+4>>2]=c[p+1128+48+4>>2];c[M+8>>2]=c[p+1128+48+8>>2];c[M+12>>2]=c[p+1128+48+12>>2]}if(o){c[Z+112>>2]=c[p+1064>>2];c[Z+112+4>>2]=c[p+1064+4>>2];c[Z+112+8>>2]=c[p+1064+8>>2];c[Z+112+12>>2]=c[p+1064+12>>2];c[I>>2]=c[m>>2];c[I+4>>2]=c[m+4>>2];c[I+8>>2]=c[m+8>>2];c[I+12>>2]=c[m+12>>2];c[D>>2]=c[k>>2];c[D+4>>2]=c[k+4>>2];c[D+8>>2]=c[k+8>>2];c[D+12>>2]=c[k+12>>2];c[M>>2]=c[n>>2];c[M+4>>2]=c[n+4>>2];c[M+8>>2]=c[n+8>>2];c[M+12>>2]=c[n+12>>2];d=p+1128+48|0;c[Z+96>>2]=c[Z+112+8>>2];c[Z+96+4>>2]=c[Z+112+24>>2];c[Z+96+8>>2]=c[Z+112+40>>2];g[Z+96+12>>2]=0.0;c[Z+80>>2]=c[Z+112>>2];c[Z+80+4>>2]=c[Z+112+16>>2];c[Z+80+8>>2]=c[Z+112+32>>2];g[Z+80+12>>2]=0.0;ga=+g[p+932>>2];e=+g[p+932+4>>2];ja=+g[p+996>>2];ia=+g[p+996+4>>2];ma=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;la=c[(c[ma>>2]|0)+64>>2]|0;c[Z+64>>2]=0;c[Z+64+4>>2]=0;c[Z+64+8>>2]=0;c[Z+64+12>>2]=0;Mb[la&0](ma,d,Z+96|0,Z+80|0,B*.8999999761581421,ga,e,ja,ia,Z+64|0,10.0,1);ma=c[Z+112+4>>2]|0;la=c[Z+112+20>>2]|0;o=c[Z+112+36>>2]|0;c[Z+80>>2]=ma;c[Z+80+4>>2]=la;c[Z+80+8>>2]=o;g[Z+80+12>>2]=0.0;ia=+g[p+1196>>2];ja=+g[p+1200>>2];e=+E(+ia);ia=+F(+ia);ga=+E(+ja);ja=+F(+ja);ha=(c[j>>2]=ma,+g[j>>2]);ka=(c[j>>2]=la,+g[j>>2]);f=(c[j>>2]=o,+g[j>>2]);g[Z+64>>2]=e*ga*ha+e*ja*ka-ia*f;g[Z+64+4>>2]=ga*ka-ja*ha;g[Z+64+8>>2]=ia*ga*ha+ia*ja*ka+e*f;c[Z+112>>2]=c[p+1128>>2];c[Z+112+4>>2]=c[p+1128+4>>2];c[Z+112+8>>2]=c[p+1128+8>>2];c[Z+112+12>>2]=c[p+1128+12>>2];c[I>>2]=c[p+1128+16>>2];c[I+4>>2]=c[p+1128+16+4>>2];c[I+8>>2]=c[p+1128+16+8>>2];c[I+12>>2]=c[p+1128+16+12>>2];c[D>>2]=c[p+1128+32>>2];c[D+4>>2]=c[p+1128+32+4>>2];c[D+8>>2]=c[p+1128+32+8>>2];c[D+12>>2]=c[p+1128+32+12>>2];c[M>>2]=c[d>>2];c[M+4>>2]=c[d+4>>2];c[M+8>>2]=c[d+8>>2];c[M+12>>2]=c[d+12>>2];f=-+g[Z+112+16>>2];e=-+g[Z+112+32>>2];g[Z+48>>2]=-+g[Z+112>>2];g[Z+48+4>>2]=f;g[Z+48+8>>2]=e;g[Z+48+12>>2]=0.0;e=+g[p+868>>2];f=+g[p+868+4>>2];if(!(e>f)){if(e<f){ma=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;la=c[(c[ma>>2]|0)+60>>2]|0;c[Z+32>>2]=0;c[Z+32+4>>2]=0;c[Z+32+8>>2]=0;c[Z+32+12>>2]=0;sb[la&0](ma,d,Z+48|0,Z+64|0,B,B,e,f,Z+32|0,1,10.0)}}else{ma=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;la=c[(c[ma>>2]|0)+60>>2]|0;c[Z+32>>2]=0;c[Z+32+4>>2]=0;c[Z+32+8>>2]=0;c[Z+32+12>>2]=0;sb[la&0](ma,d,Z+48|0,Z+64|0,B,B,-3.1415927410125732,3.1415927410125732,Z+32|0,0,10.0)}c[Z+112>>2]=c[p+1064>>2];c[Z+112+4>>2]=c[p+1064+4>>2];c[Z+112+8>>2]=c[p+1064+8>>2];c[Z+112+12>>2]=c[p+1064+12>>2];c[I>>2]=c[m>>2];c[I+4>>2]=c[m+4>>2];c[I+8>>2]=c[m+8>>2];c[I+12>>2]=c[m+12>>2];c[D>>2]=c[k>>2];c[D+4>>2]=c[k+4>>2];c[D+8>>2]=c[k+8>>2];c[D+12>>2]=c[k+12>>2];c[M>>2]=c[n>>2];c[M+4>>2]=c[n+4>>2];c[M+8>>2]=c[n+8>>2];c[M+12>>2]=c[n+12>>2];c[Z+32>>2]=c[p+680>>2];c[Z+32+4>>2]=c[p+680+4>>2];c[Z+32+8>>2]=c[p+680+8>>2];c[Z+32+12>>2]=c[p+680+12>>2];c[Z+16>>2]=c[p+680+16>>2];c[Z+16+4>>2]=c[p+680+16+4>>2];c[Z+16+8>>2]=c[p+680+16+8>>2];c[Z+16+12>>2]=c[p+680+16+12>>2];ma=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;la=c[(c[ma>>2]|0)+72>>2]|0;c[Z>>2]=0;c[Z+4>>2]=0;c[Z+8>>2]=0;c[Z+12>>2]=0;fb[la&31](ma,Z+32|0,Z+16|0,Z+112|0,Z)}d=K;continue b}case 7:{c[Z+112>>2]=c[p+824>>2];c[Z+112+4>>2]=c[p+824+4>>2];c[Z+112+8>>2]=c[p+824+8>>2];c[Z+112+12>>2]=c[p+824+12>>2];c[H>>2]=c[p+824+16>>2];c[H+4>>2]=c[p+824+16+4>>2];c[H+8>>2]=c[p+824+16+8>>2];c[H+12>>2]=c[p+824+16+12>>2];c[C>>2]=c[p+824+32>>2];c[C+4>>2]=c[p+824+32+4>>2];c[C+8>>2]=c[p+824+32+8>>2];c[C+12>>2]=c[p+824+32+12>>2];c[L>>2]=c[p+824+48>>2];c[L+4>>2]=c[p+824+48+4>>2];c[L+8>>2]=c[p+824+48+8>>2];c[L+12>>2]=c[p+824+48+12>>2];if(d){ma=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;Tb[c[(c[ma>>2]|0)+56>>2]&7](ma,Z+112|0,B);c[Z+112>>2]=c[p+888>>2];c[Z+112+4>>2]=c[p+888+4>>2];c[Z+112+8>>2]=c[p+888+8>>2];c[Z+112+12>>2]=c[p+888+12>>2];c[H>>2]=c[p+888+16>>2];c[H+4>>2]=c[p+888+16+4>>2];c[H+8>>2]=c[p+888+16+8>>2];c[H+12>>2]=c[p+888+16+12>>2];c[C>>2]=c[p+888+32>>2];c[C+4>>2]=c[p+888+32+4>>2];c[C+8>>2]=c[p+888+32+8>>2];c[C+12>>2]=c[p+888+32+12>>2];c[L>>2]=c[p+888+48>>2];c[L+4>>2]=c[p+888+48+4>>2];c[L+8>>2]=c[p+888+48+8>>2];c[L+12>>2]=c[p+888+48+12>>2];ma=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;Tb[c[(c[ma>>2]|0)+56>>2]&7](ma,Z+112|0,B)}else{c[Z+112>>2]=c[p+888>>2];c[Z+112+4>>2]=c[p+888+4>>2];c[Z+112+8>>2]=c[p+888+8>>2];c[Z+112+12>>2]=c[p+888+12>>2];c[H>>2]=c[p+888+16>>2];c[H+4>>2]=c[p+888+16+4>>2];c[H+8>>2]=c[p+888+16+8>>2];c[H+12>>2]=c[p+888+16+12>>2];c[C>>2]=c[p+888+32>>2];c[C+4>>2]=c[p+888+32+4>>2];c[C+8>>2]=c[p+888+32+8>>2];c[C+12>>2]=c[p+888+32+12>>2];c[L>>2]=c[p+888+48>>2];c[L+4>>2]=c[p+888+48+4>>2];c[L+8>>2]=c[p+888+48+8>>2];c[L+12>>2]=c[p+888+48+12>>2]}if(o){d=a[p+180>>0]|0?p+824|0:p+888|0;k=c[d>>2]|0;o=c[d+4>>2]|0;m=c[d+16>>2]|0;la=c[d+20>>2]|0;n=c[d+32>>2]|0;ma=c[d+36>>2]|0;_=+g[d+48>>2];ca=+g[d+52>>2];ga=+g[d+56>>2];ja=+g[p+184>>2];ba=(c[j>>2]=k,+g[j>>2]);aa=(c[j>>2]=o,+g[j>>2])*0.0;$=+g[d+8>>2]*0.0;fa=(c[j>>2]=m,+g[j>>2]);ea=(c[j>>2]=la,+g[j>>2])*0.0;da=+g[d+24>>2]*0.0;ka=(c[j>>2]=n,+g[j>>2]);ia=(c[j>>2]=ma,+g[j>>2])*0.0;ha=+g[d+40>>2]*0.0;g[Z+96>>2]=_+($+(aa+ba*ja));g[Z+96+4>>2]=ca+(da+(ea+fa*ja));g[Z+96+8>>2]=ga+(ha+(ia+ka*ja));g[Z+96+12>>2]=0.0;ja=+g[p+188>>2];g[Z+80>>2]=_+($+(aa+ba*ja));g[Z+80+4>>2]=ca+(da+(ea+fa*ja));g[Z+80+8>>2]=ga+(ha+(ia+ka*ja));g[Z+80+12>>2]=0.0;d=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;na=c[(c[d>>2]|0)+8>>2]|0;c[Z+64>>2]=0;c[Z+64+4>>2]=0;c[Z+64+8>>2]=0;c[Z+64+12>>2]=0;Vb[na&127](d,Z+96|0,Z+80|0,Z+64|0);c[Z+64>>2]=k;c[Z+64+4>>2]=m;c[Z+64+8>>2]=n;g[Z+64+12>>2]=0.0;c[Z+48>>2]=o;c[Z+48+4>>2]=la;c[Z+48+8>>2]=ma;g[Z+48+12>>2]=0.0;ja=+g[p+192>>2];ka=+g[p+196>>2];ma=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0;la=c[(c[ma>>2]|0)+60>>2]|0;c[Z+32>>2]=0;c[Z+32+4>>2]=0;c[Z+32+8>>2]=0;c[Z+32+12>>2]=0;sb[la&0](ma,p+888+48|0,Z+64|0,Z+48|0,B,B,ja,ka,Z+32|0,1,10.0)}d=K;continue b}default:{d=K;continue b}}}}while(0);if((((lb[c[(c[b>>2]|0)+20>>2]&127](b)|0?(na=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0,(lb[c[(c[na>>2]|0)+48>>2]&127](na)|0)&16387|0):0)?lb[c[(c[b>>2]|0)+20>>2]&127](b)|0:0)?(na=lb[c[(c[b>>2]|0)+20>>2]&127](b)|0,lb[c[(c[na>>2]|0)+48>>2]&127](na)|0):0)?(c[b+280>>2]|0)>0:0){d=0;do{na=c[(c[b+288>>2]|0)+(d<<2)>>2]|0;jb[c[(c[na>>2]|0)+12>>2]&127](na,c[b+72>>2]|0);d=d+1|0}while((d|0)<(c[b+280>>2]|0))}d=c[2395]|0;na=(c[d+16>>2]|0)+-1|0;c[d+16>>2]=na;if(na|0){l=Z;return}do if(c[d+4>>2]|0){Va(Z+112|0,0)|0;na=c[6431]|0;g[d+8>>2]=+g[d+8>>2]+ +(((c[Z+112+4>>2]|0)-(c[na+4>>2]|0)+(((c[Z+112>>2]|0)-(c[na>>2]|0)|0)*1e6|0)-(c[d+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[d+16>>2]|0)){d=c[2395]|0;break}else{l=Z;return}}while(0);c[2395]=c[d+20>>2];l=Z;return}function bc(b,e,f){b=b|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0;A=l;l=l+80|0;Ze(b,e,f)|0;a[A+16>>0]=1;c[A+12>>2]=0;c[A+4>>2]=0;c[A+8>>2]=0;a[A+36>>0]=1;c[A+32>>2]=0;c[A+24>>2]=0;c[A+28>>2]=0;a[A+56>>0]=1;c[A+52>>2]=0;c[A+44>>2]=0;c[A+48>>2]=0;a[A+76>>0]=1;c[A+72>>2]=0;c[A+64>>2]=0;c[A+68>>2]=0;y=c[b+872>>2]|0;c[e+292>>2]=y;if(y){y=Gb[c[(c[f>>2]|0)+28>>2]&31](f,b+868|0)|0;c[e+260>>2]=y;if(y|0){g=c[e+292>>2]|0;m=vb[c[(c[f>>2]|0)+16>>2]&63](f,4,g)|0;if((g|0)>0){j=0;k=c[m+8>>2]|0;while(1){h=c[(c[b+880>>2]|0)+(j<<2)>>2]|0;if(!h)i=0;else i=Gb[c[(c[f>>2]|0)+28>>2]&31](f,h)|0;c[k>>2]=i;if(!(Gb[c[(c[f>>2]|0)+24>>2]&31](f,h)|0)){y=vb[c[(c[f>>2]|0)+16>>2]&63](f,16,1)|0;t=c[y+8>>2]|0;c[t+12>>2]=c[h+16>>2];c[t+4>>2]=c[h+8>>2];c[t>>2]=c[h+4>>2];c[t+8>>2]=c[h+12>>2];fb[c[(c[f>>2]|0)+20>>2]&31](f,y,10822,1414349395,h)}j=j+1|0;if((j|0)>=(g|0)){g=f;break}else k=k+4|0}}else g=f;fb[c[(c[g>>2]|0)+20>>2]&31](f,m,10822,1497453121,b+868|0)}}else c[e+260>>2]=0;y=c[b+712>>2]|0;c[e+296>>2]=y;if(y){y=Gb[c[(c[f>>2]|0)+28>>2]&31](f,b+708|0)|0;c[e+264>>2]=y;if(y|0){q=c[e+296>>2]|0;r=vb[c[(c[f>>2]|0)+16>>2]&63](f,100,q)|0;if((q|0)>0){s=0;t=c[r+8>>2]|0;while(1){g=c[b+720>>2]|0;c[t+52>>2]=c[g+(s*104|0)+56>>2];c[t+56>>2]=c[g+(s*104|0)+60>>2];c[t+60>>2]=c[g+(s*104|0)+64>>2];c[t+64>>2]=c[g+(s*104|0)+68>>2];c[t+88>>2]=c[g+(s*104|0)+92>>2];c[t+92>>2]=(a[g+(s*104|0)+100>>0]<<7&255)<<24>>24>>7<<24>>24;c[t+84>>2]=c[g+(s*104|0)+88>>2];h=c[g+(s*104|0)+4>>2]|0;if(!h)h=0;else{h=Gb[c[(c[f>>2]|0)+28>>2]&31](f,h)|0;g=c[b+720>>2]|0}c[t>>2]=h;c[t+68>>2]=c[g+(s*104|0)+72>>2];c[t+72>>2]=c[g+(s*104|0)+76>>2];c[t+76>>2]=c[g+(s*104|0)+80>>2];c[t+80>>2]=c[g+(s*104|0)+84>>2];c[t+4>>2]=c[g+(s*104|0)+8>>2];c[t+8>>2]=c[g+(s*104|0)+12>>2];c[t+12>>2]=c[g+(s*104|0)+16>>2];c[t+16>>2]=c[g+(s*104|0)+20>>2];c[t+20>>2]=c[g+(s*104|0)+24>>2];c[t+24>>2]=c[g+(s*104|0)+28>>2];c[t+28>>2]=c[g+(s*104|0)+32>>2];c[t+32>>2]=c[g+(s*104|0)+36>>2];c[t+36>>2]=c[g+(s*104|0)+40>>2];c[t+40>>2]=c[g+(s*104|0)+44>>2];c[t+44>>2]=c[g+(s*104|0)+48>>2];c[t+48>>2]=c[g+(s*104|0)+52>>2];m=(c[b+720>>2]|0)+(s*104|0)|0;p=(m+~(m<<15)>>10^m+~(m<<15))*9|0;p=(p>>6^p)+~((p>>6^p)<<11)>>16^(p>>6^p)+~((p>>6^p)<<11);k=c[A+48>>2]|0;a:do if((p&k+-1)>>>0<(c[A+4>>2]|0)>>>0?(x=c[(c[A+12>>2]|0)+((p&k+-1)<<2)>>2]|0,(x|0)!=-1):0){h=c[A+72>>2]|0;i=c[A+32>>2]|0;g=x;while(1){if((m|0)==(c[h+(g<<3)>>2]|0))break;g=c[i+(g<<2)>>2]|0;if((g|0)==-1){z=27;break a}}i=c[A+52>>2]|0;h=s}else z=27;while(0);if((z|0)==27){z=0;o=c[A+44>>2]|0;if((o|0)==(k|0)){g=k|0?k<<1:1;if((k|0)<(g|0)){if((g|0)!=0?(c[6432]=(c[6432]|0)+1,u=ec((g<<2|3)+16|0)|0,(u|0)!=0):0){c[(u+4+15&-16)+-4>>2]=u;j=u+4+15&-16}else j=0;i=c[A+52>>2]|0;if((k|0)<=0)if(!i)h=k;else z=35;else{h=0;do{c[j+(h<<2)>>2]=c[i+(h<<2)>>2];h=h+1|0}while((h|0)!=(k|0));z=35}if((z|0)==35){z=0;if(a[A+56>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}c[A+52>>2]=0;h=c[A+44>>2]|0}a[A+56>>0]=1;c[A+52>>2]=j;c[A+48>>2]=g}else{g=k;h=k}}else{g=k;h=o}c[(c[A+52>>2]|0)+(h<<2)>>2]=s;c[A+44>>2]=h+1;h=c[A+64>>2]|0;if((h|0)==(c[A+68>>2]|0)?(w=h|0?h<<1:1,(h|0)<(w|0)):0){if((w|0)!=0?(c[6432]=(c[6432]|0)+1,v=ec((w<<3|3)+16|0)|0,(v|0)!=0):0){c[(v+4+15&-16)+-4>>2]=v;i=v+4+15&-16}else i=0;if((h|0)>0){g=0;do{j=(c[A+72>>2]|0)+(g<<3)|0;n=c[j+4>>2]|0;y=i+(g<<3)|0;c[y>>2]=c[j>>2];c[y+4>>2]=n;g=g+1|0}while((g|0)!=(h|0))}g=c[A+72>>2]|0;if(g|0){if(a[A+76>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[g+-4>>2]|0)}c[A+72>>2]=0}a[A+76>>0]=1;c[A+72>>2]=i;c[A+68>>2]=w;h=c[A+64>>2]|0;g=c[A+48>>2]|0}c[(c[A+72>>2]|0)+(h<<3)>>2]=m;c[A+64>>2]=h+1;if((k|0)<(g|0)){n=c[A+4>>2]|0;do if((n|0)<(g|0)){if((c[A+8>>2]|0)<(g|0)){do if(!g)h=0;else{c[6432]=(c[6432]|0)+1;h=ec((g<<2|3)+16|0)|0;if(!h){h=0;break}c[(h+4+15&-16)+-4>>2]=h;h=h+4+15&-16}while(0);i=c[A+12>>2]|0;if((n|0)>0){j=0;do{c[h+(j<<2)>>2]=c[i+(j<<2)>>2];j=j+1|0}while((j|0)!=(n|0));if(a[A+16>>0]|0)z=62}else if(!((i|0)==0|(a[A+16>>0]|0)==0))z=62;if((z|0)==62){z=0;c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}a[A+16>>0]=1;c[A+12>>2]=h;c[A+8>>2]=g}else h=c[A+12>>2]|0;m=g<<2;Hk(h+(n<<2)|0,0,m-(n<<2)|0)|0;c[A+4>>2]=g;k=c[A+24>>2]|0;if((k|0)<(g|0)){if((c[A+28>>2]|0)<(g|0)){do if(!g)h=0;else{c[6432]=(c[6432]|0)+1;h=ec((m|3)+16|0)|0;if(!h){h=0;break}c[(h+4+15&-16)+-4>>2]=h;h=h+4+15&-16}while(0);i=c[A+32>>2]|0;if((k|0)>0){j=0;do{c[h+(j<<2)>>2]=c[i+(j<<2)>>2];j=j+1|0}while((j|0)!=(k|0));if(a[A+36>>0]|0)z=74}else if(!((i|0)==0|(a[A+36>>0]|0)==0))z=74;if((z|0)==74){z=0;c[6433]=(c[6433]|0)+1;Pc(c[i+-4>>2]|0)}a[A+36>>0]=1;c[A+32>>2]=h;c[A+28>>2]=g}else h=c[A+32>>2]|0;Hk(h+(k<<2)|0,0,m-(k<<2)|0)|0}c[A+24>>2]=g;if((g|0)>0){Hk(c[A+12>>2]|0,-1,m|0)|0;Hk(c[A+32>>2]|0,-1,m|0)|0}if((n|0)<=0){g=c[A+48>>2]|0;break}h=c[A+72>>2]|0;i=c[A+12>>2]|0;j=c[A+32>>2]|0;g=c[A+48>>2]|0;k=0;do{y=c[h+(k<<3)>>2]|0;y=(y+~(y<<15)>>10^y+~(y<<15))*9|0;y=i+((((y>>6^y)+~((y>>6^y)<<11)>>16^(y>>6^y)+~((y>>6^y)<<11))&g+-1)<<2)|0;c[j+(k<<2)>>2]=c[y>>2];c[y>>2]=k;k=k+1|0}while((k|0)!=(n|0))}while(0);g=p&g+-1}else g=p&k+-1;i=c[A+12>>2]|0;c[(c[A+32>>2]|0)+(o<<2)>>2]=c[i+(g<<2)>>2];h=o}c[i+(g<<2)>>2]=h;s=s+1|0;if((s|0)>=(q|0))break;else t=t+100|0}}fb[c[(c[f>>2]|0)+20>>2]&31](f,r,10843,1145979475,b+708|0)}}else c[e+264>>2]=0;y=c[b+732>>2]|0;c[e+300>>2]=y;if(y){y=Gb[c[(c[f>>2]|0)+28>>2]&31](f,c[b+740>>2]|0)|0;c[e+268>>2]=y;if(y|0){j=c[e+300>>2]|0;n=vb[c[(c[f>>2]|0)+16>>2]&63](f,20,j)|0;if((j|0)>0){g=c[b+740>>2]|0;i=g;k=0;m=c[n+8>>2]|0;while(1){c[m+16>>2]=(a[i+(k*52|0)+20>>0]<<7&255)<<24>>24>>7<<24>>24;h=c[i+(k*52|0)+4>>2]|0;if(!h)h=0;else{h=Gb[c[(c[f>>2]|0)+28>>2]&31](f,h)|0;g=c[b+740>>2]|0;i=g}c[m>>2]=h;h=c[i+(k*52|0)+8>>2]|0;if(!h)h=-1;else h=(h-(c[b+720>>2]|0)|0)/104|0;c[m+4>>2]=h;h=c[i+(k*52|0)+12>>2]|0;if(!h)h=-1;else h=(h-(c[b+720>>2]|0)|0)/104|0;c[m+8>>2]=h;c[m+12>>2]=c[i+(k*52|0)+16>>2];k=k+1|0;if((k|0)>=(j|0))break;else m=m+20|0}}else g=c[b+740>>2]|0;fb[c[(c[f>>2]|0)+20>>2]&31](f,n,10860,1497453121,g)}}else c[e+268>>2]=0;y=c[b+752>>2]|0;c[e+304>>2]=y;if(y){y=Gb[c[(c[f>>2]|0)+28>>2]&31](f,c[b+760>>2]|0)|0;c[e+272>>2]=y;if(y|0){j=c[e+304>>2]|0;n=vb[c[(c[f>>2]|0)+16>>2]&63](f,36,j)|0;if((j|0)>0){g=c[b+760>>2]|0;i=g;k=0;m=c[n+8>>2]|0;while(1){h=c[i+(k*44|0)+4>>2]|0;if(!h)h=0;else{h=Gb[c[(c[f>>2]|0)+28>>2]&31](f,h)|0;g=c[b+760>>2]|0;i=g}c[m+16>>2]=h;c[m>>2]=c[i+(k*44|0)+20>>2];c[m+4>>2]=c[i+(k*44|0)+24>>2];c[m+8>>2]=c[i+(k*44|0)+28>>2];c[m+12>>2]=c[i+(k*44|0)+32>>2];h=c[i+(k*44|0)+8>>2]|0;if(!h)h=-1;else h=(h-(c[b+720>>2]|0)|0)/104|0;c[m+20>>2]=h;h=c[i+(k*44|0)+12>>2]|0;if(!h)h=-1;else h=(h-(c[b+720>>2]|0)|0)/104|0;c[m+24>>2]=h;h=c[i+(k*44|0)+16>>2]|0;if(!h)h=-1;else h=(h-(c[b+720>>2]|0)|0)/104|0;c[m+28>>2]=h;c[m+32>>2]=c[i+(k*44|0)+36>>2];k=k+1|0;if((k|0)>=(j|0))break;else m=m+36|0}}else g=c[b+760>>2]|0;fb[c[(c[f>>2]|0)+20>>2]&31](f,n,10877,1497453121,g)}}else c[e+272>>2]=0;y=c[b+772>>2]|0;c[e+308>>2]=y;if(y){y=Gb[c[(c[f>>2]|0)+28>>2]&31](f,c[b+780>>2]|0)|0;c[e+276>>2]=y;if(y|0){j=c[e+308>>2]|0;n=vb[c[(c[f>>2]|0)+16>>2]&63](f,100,j)|0;if((j|0)>0){g=c[b+780>>2]|0;i=g;k=0;m=c[n+8>>2]|0;while(1){c[m>>2]=c[i+(k*104|0)+32>>2];c[m+4>>2]=c[i+(k*104|0)+36>>2];c[m+8>>2]=c[i+(k*104|0)+40>>2];c[m+12>>2]=c[i+(k*104|0)+44>>2];h=c[i+8>>2]|0;if(!h)h=-1;else h=(h-(c[b+720>>2]|0)|0)/104|0;c[m+68>>2]=h;c[m+16>>2]=c[i+(k*104|0)+48>>2];c[m+20>>2]=c[i+(k*104|0)+52>>2];c[m+24>>2]=c[i+(k*104|0)+56>>2];c[m+28>>2]=c[i+(k*104|0)+60>>2];h=c[i+116>>2]|0;if(!h)h=-1;else h=(h-(c[b+720>>2]|0)|0)/104|0;c[m+72>>2]=h;c[m+32>>2]=c[i+(k*104|0)+64>>2];c[m+36>>2]=c[i+(k*104|0)+68>>2];c[m+40>>2]=c[i+(k*104|0)+72>>2];c[m+44>>2]=c[i+(k*104|0)+76>>2];h=c[i+224>>2]|0;if(!h)h=-1;else h=(h-(c[b+720>>2]|0)|0)/104|0;c[m+76>>2]=h;c[m+48>>2]=c[i+(k*104|0)+80>>2];c[m+52>>2]=c[i+(k*104|0)+84>>2];c[m+56>>2]=c[i+(k*104|0)+88>>2];c[m+60>>2]=c[i+(k*104|0)+92>>2];h=c[i+332>>2]|0;if(!h)h=-1;else h=(h-(c[b+720>>2]|0)|0)/104|0;c[m+80>>2]=h;c[m+88>>2]=c[i+(k*104|0)+96>>2];c[m+92>>2]=c[i+(k*104|0)+100>>2];h=c[i+(k*104|0)+4>>2]|0;if(!h)h=0;else{h=Gb[c[(c[f>>2]|0)+28>>2]&31](f,h)|0;g=c[b+780>>2]|0;i=g}c[m+64>>2]=h;c[m+84>>2]=c[i+(k*104|0)+24>>2];k=k+1|0;if((k|0)>=(j|0))break;else m=m+100|0}}else g=c[b+780>>2]|0;fb[c[(c[f>>2]|0)+20>>2]&31](f,n,10894,1497453121,g)}}else c[e+276>>2]=0;y=c[b+792>>2]|0;c[e+312>>2]=y;if(y){y=Gb[c[(c[f>>2]|0)+28>>2]&31](f,c[b+800>>2]|0)|0;c[e+280>>2]=y;if(!y)y=f;else{i=c[e+312>>2]|0;j=vb[c[(c[f>>2]|0)+16>>2]&63](f,92,i)|0;if((i|0)>0){k=0;m=c[j+8>>2]|0;while(1){h=c[b+800>>2]|0;c[m>>2]=c[h+(k*96|0)+28>>2];c[m+4>>2]=c[h+(k*96|0)+32>>2];c[m+8>>2]=c[h+(k*96|0)+36>>2];c[m+12>>2]=c[h+(k*96|0)+40>>2];c[m+16>>2]=c[h+(k*96|0)+44>>2];c[m+20>>2]=c[h+(k*96|0)+48>>2];c[m+24>>2]=c[h+(k*96|0)+52>>2];c[m+28>>2]=c[h+(k*96|0)+56>>2];c[m+32>>2]=c[h+(k*96|0)+60>>2];c[m+36>>2]=c[h+(k*96|0)+64>>2];c[m+40>>2]=c[h+(k*96|0)+68>>2];c[m+44>>2]=c[h+(k*96|0)+72>>2];c[m+48>>2]=c[h+(k*96|0)+76>>2];c[m+52>>2]=c[h+(k*96|0)+80>>2];c[m+56>>2]=c[h+(k*96|0)+84>>2];c[m+60>>2]=c[h+(k*96|0)+88>>2];c[m+88>>2]=c[h+(k*96|0)+92>>2];h=c[b+800>>2]|0;c[m+64>>2]=c[h+(k*96|0)+4>>2];c[m+68>>2]=c[h+(k*96|0)+8>>2];c[m+72>>2]=c[h+(k*96|0)+12>>2];c[m+76>>2]=c[h+(k*96|0)+16>>2];g=c[h+(k*96|0)>>2]|0;if(!g)g=-1;else g=(g-(c[b+720>>2]|0)|0)/104|0;c[m+84>>2]=g;g=c[h+(k*96|0)+20>>2]|0;if(!g)g=0;else g=Gb[c[(c[f>>2]|0)+28>>2]&31](f,g)|0;c[m+80>>2]=g;k=k+1|0;if((k|0)>=(i|0))break;else m=m+92|0}}fb[c[(c[f>>2]|0)+20>>2]&31](f,j,10912,1497453121,c[b+800>>2]|0);y=f}}else{c[e+280>>2]=0;y=f}c[e+352>>2]=c[b+316>>2];c[e+328>>2]=c[b+292>>2];c[e+344>>2]=c[b+308>>2];c[e+324>>2]=c[b+288>>2];c[e+340>>2]=c[b+304>>2];c[e+336>>2]=c[b+300>>2];c[e+412>>2]=c[b+376>>2];c[e+416>>2]=c[b+380>>2];c[e+420>>2]=c[b+384>>2];c[e+408>>2]=c[b+372>>2];n=c[b+364>>2]|0;c[e+332>>2]=c[b+296>>2];c[e+356>>2]=c[b+320>>2];c[e+424>>2]=c[b+388>>2];c[e+348>>2]=c[b+312>>2];c[e+360>>2]=c[b+324>>2];c[e+364>>2]=c[b+328>>2];c[e+368>>2]=c[b+332>>2];c[e+372>>2]=c[b+336>>2];c[e+404>>2]=c[b+368>>2];c[e+400>>2]=n;c[e+376>>2]=c[b+340>>2];c[e+380>>2]=c[b+344>>2];c[e+384>>2]=c[b+348>>2];c[e+388>>2]=c[b+352>>2];c[e+392>>2]=c[b+356>>2];c[e+396>>2]=c[b+360>>2];c[e+256>>2]=Gb[c[(c[y>>2]|0)+28>>2]&31](f,b+472|0)|0;n=vb[c[(c[f>>2]|0)+16>>2]&63](f,192,1)|0;m=c[n+8>>2]|0;c[m+96>>2]=c[b+632>>2];c[m+100>>2]=c[b+636>>2];c[m+104>>2]=c[b+640>>2];c[m+108>>2]=c[b+644>>2];c[m+112>>2]=c[b+648>>2];c[m+116>>2]=c[b+652>>2];c[m+120>>2]=c[b+656>>2];c[m+124>>2]=c[b+660>>2];c[m+128>>2]=c[b+664>>2];c[m+132>>2]=c[b+668>>2];c[m+136>>2]=c[b+672>>2];c[m+140>>2]=c[b+676>>2];c[m+180>>2]=d[b+473>>0];c[m+176>>2]=d[b+472>>0];c[m+144>>2]=c[b+520>>2];c[m+148>>2]=c[b+524>>2];c[m+152>>2]=c[b+528>>2];c[m+156>>2]=c[b+532>>2];x=c[b+484>>2]|0;c[m+168>>2]=x;if(x){x=Gb[c[(c[y>>2]|0)+28>>2]&31](f,c[b+492>>2]|0)|0;h=c[m+168>>2]|0;c[m+160>>2]=x;if(h|0){k=vb[c[(c[f>>2]|0)+16>>2]&63](f,16,h)|0;if((h|0)>0){g=c[b+492>>2]|0;i=0;j=c[k+8>>2]|0;while(1){c[j>>2]=c[g+(i<<4)>>2];c[j+4>>2]=c[g+(i<<4)+4>>2];c[j+8>>2]=c[g+(i<<4)+8>>2];c[j+12>>2]=c[g+(i<<4)+12>>2];i=i+1|0;if((i|0)==(h|0))break;else j=j+16|0}}else g=c[b+492>>2]|0;fb[c[(c[f>>2]|0)+20>>2]&31](f,k,19426,1497453121,g)}}else c[m+160>>2]=0;c[m+184>>2]=c[b+476>>2];c[m>>2]=c[b+536>>2];c[m+4>>2]=c[b+540>>2];c[m+8>>2]=c[b+544>>2];c[m+12>>2]=c[b+548>>2];c[m+16>>2]=c[b+552>>2];c[m+20>>2]=c[b+556>>2];c[m+24>>2]=c[b+560>>2];c[m+28>>2]=c[b+564>>2];c[m+32>>2]=c[b+568>>2];c[m+36>>2]=c[b+572>>2];c[m+40>>2]=c[b+576>>2];c[m+44>>2]=c[b+580>>2];c[m+48>>2]=c[b+584>>2];c[m+52>>2]=c[b+588>>2];c[m+56>>2]=c[b+592>>2];c[m+60>>2]=c[b+596>>2];c[m+64>>2]=c[b+600>>2];c[m+68>>2]=c[b+604>>2];c[m+72>>2]=c[b+608>>2];c[m+76>>2]=c[b+612>>2];c[m+80>>2]=c[b+616>>2];c[m+84>>2]=c[b+620>>2];c[m+88>>2]=c[b+624>>2];c[m+92>>2]=c[b+628>>2];x=c[b+504>>2]|0;c[m+172>>2]=x;if(x){x=Gb[c[(c[y>>2]|0)+28>>2]&31](f,c[b+512>>2]|0)|0;j=c[m+172>>2]|0;c[m+164>>2]=x;if(!j)z=147;else{k=vb[c[(c[f>>2]|0)+16>>2]&63](f,4,j)|0;if((j|0)>0){g=c[b+512>>2]|0;h=0;i=c[k+8>>2]|0;while(1){c[i>>2]=c[g+(h<<2)>>2];h=h+1|0;if((h|0)==(j|0))break;else i=i+4|0}}else g=c[b+512>>2]|0;fb[c[(c[f>>2]|0)+20>>2]&31](f,k,10932,1497453121,g);x=f}}else{c[m+164>>2]=0;z=147}if((z|0)==147)x=f;fb[c[(c[x>>2]|0)+20>>2]&31](f,n,10938,1497453121,b+472|0);z=c[b+1112>>2]|0;c[e+316>>2]=z;if(z){z=Gb[c[(c[y>>2]|0)+28>>2]&31](f,c[c[b+1120>>2]>>2]|0)|0;t=c[e+316>>2]|0;c[e+284>>2]=z;if(t|0){u=vb[c[(c[f>>2]|0)+16>>2]&63](f,348,t)|0;if((t|0)>0){v=0;w=c[u+8>>2]|0;while(1){g=c[(c[b+1120>>2]|0)+(v<<2)>>2]|0;z=w+320|0;c[z>>2]=c[g+360>>2];c[w+256>>2]=c[g+332>>2];c[w+260>>2]=c[g+336>>2];c[w+264>>2]=c[g+340>>2];c[w+268>>2]=c[g+344>>2];c[w+344>>2]=c[g+380>>2];c[w+340>>2]=d[g+377>>0];c[w+160>>2]=c[g+228>>2];c[w+164>>2]=c[g+232>>2];c[w+168>>2]=c[g+236>>2];c[w+172>>2]=c[g+240>>2];c[w+336>>2]=d[g+376>>0];c[w+208>>2]=c[g+276>>2];c[w+212>>2]=c[g+280>>2];c[w+216>>2]=c[g+284>>2];c[w+220>>2]=c[g+288>>2];c[w+224>>2]=c[g+292>>2];c[w+228>>2]=c[g+296>>2];c[w+232>>2]=c[g+300>>2];c[w+236>>2]=c[g+304>>2];g=c[(c[b+1120>>2]|0)+(v<<2)>>2]|0;c[w>>2]=c[g+60>>2];c[w+4>>2]=c[g+64>>2];c[w+8>>2]=c[g+68>>2];c[w+12>>2]=c[g+72>>2];c[w+16>>2]=c[g+76>>2];c[w+20>>2]=c[g+80>>2];c[w+24>>2]=c[g+84>>2];c[w+28>>2]=c[g+88>>2];c[w+32>>2]=c[g+92>>2];c[w+36>>2]=c[g+96>>2];c[w+40>>2]=c[g+100>>2];c[w+44>>2]=c[g+104>>2];c[w+48>>2]=c[g+108>>2];c[w+52>>2]=c[g+112>>2];c[w+56>>2]=c[g+116>>2];c[w+60>>2]=c[g+120>>2];c[w+296>>2]=c[g+124>>2];g=c[(c[b+1120>>2]|0)+(v<<2)>>2]|0;c[w+300>>2]=c[g+128>>2];c[w+112>>2]=c[g+180>>2];c[w+116>>2]=c[g+184>>2];c[w+120>>2]=c[g+188>>2];c[w+124>>2]=c[g+192>>2];c[w+128>>2]=c[g+196>>2];c[w+132>>2]=c[g+200>>2];c[w+136>>2]=c[g+204>>2];c[w+140>>2]=c[g+208>>2];c[w+144>>2]=c[g+212>>2];c[w+148>>2]=c[g+216>>2];c[w+152>>2]=c[g+220>>2];c[w+156>>2]=c[g+224>>2];h=w+316|0;c[h>>2]=c[g+356>>2];c[w+64>>2]=c[g+132>>2];c[w+68>>2]=c[g+136>>2];c[w+72>>2]=c[g+140>>2];c[w+76>>2]=c[g+144>>2];c[w+80>>2]=c[g+148>>2];c[w+84>>2]=c[g+152>>2];c[w+88>>2]=c[g+156>>2];c[w+92>>2]=c[g+160>>2];c[w+96>>2]=c[g+164>>2];c[w+100>>2]=c[g+168>>2];c[w+104>>2]=c[g+172>>2];c[w+108>>2]=c[g+176>>2];g=c[(c[b+1120>>2]|0)+(v<<2)>>2]|0;c[w+240>>2]=c[g+316>>2];c[w+244>>2]=c[g+320>>2];c[w+248>>2]=c[g+324>>2];c[w+252>>2]=c[g+328>>2];c[w+324>>2]=c[g+364>>2];c[w+328>>2]=c[g+368>>2];c[w+312>>2]=c[g+352>>2];c[h>>2]=c[g+356>>2];c[z>>2]=c[g+360>>2];c[w+332>>2]=c[g+372>>2];z=c[g+44>>2]|0;h=w+284|0;c[h>>2]=z;n=w+292|0;c[n>>2]=c[g+4>>2];o=w+288|0;c[o>>2]=c[g+24>>2];c[w+304>>2]=c[g+308>>2];c[w+176>>2]=c[g+244>>2];c[w+180>>2]=c[g+248>>2];c[w+184>>2]=c[g+252>>2];c[w+188>>2]=c[g+256>>2];c[w+192>>2]=c[g+260>>2];c[w+196>>2]=c[g+264>>2];c[w+200>>2]=c[g+268>>2];c[w+204>>2]=c[g+272>>2];g=c[(c[b+1120>>2]|0)+(v<<2)>>2]|0;c[w+308>>2]=c[g+312>>2];if(z){z=Gb[c[(c[y>>2]|0)+28>>2]&31](f,c[g+52>>2]|0)|0;c[w+272>>2]=z;if(z|0){h=c[h>>2]|0;m=vb[c[(c[f>>2]|0)+16>>2]&63](f,16,h)|0;if((h|0)>0){g=c[(c[b+1120>>2]|0)+(v<<2)>>2]|0;i=c[g+52>>2]|0;j=0;k=c[m+8>>2]|0;while(1){c[k>>2]=c[i+(j<<4)>>2];c[k+4>>2]=c[i+(j<<4)+4>>2];c[k+8>>2]=c[i+(j<<4)+8>>2];c[k+12>>2]=c[i+(j<<4)+12>>2];j=j+1|0;if((j|0)==(h|0))break;else k=k+16|0}}else g=c[(c[b+1120>>2]|0)+(v<<2)>>2]|0;fb[c[(c[x>>2]|0)+20>>2]&31](f,m,19426,1497453121,c[g+52>>2]|0)}}else c[w+272>>2]=0;if(c[n>>2]|0){z=Gb[c[(c[y>>2]|0)+28>>2]&31](f,c[(c[(c[b+1120>>2]|0)+(v<<2)>>2]|0)+12>>2]|0)|0;c[w+280>>2]=z;if(z|0){h=c[n>>2]|0;m=vb[c[(c[f>>2]|0)+16>>2]&63](f,4,h)|0;if((h|0)>0){g=c[(c[b+1120>>2]|0)+(v<<2)>>2]|0;i=c[g+12>>2]|0;j=0;k=c[m+8>>2]|0;while(1){c[k>>2]=c[i+(j<<2)>>2];j=j+1|0;if((j|0)==(h|0))break;else k=k+4|0}}else g=c[(c[b+1120>>2]|0)+(v<<2)>>2]|0;fb[c[(c[x>>2]|0)+20>>2]&31](f,m,10932,1497453121,c[g+12>>2]|0)}}else c[w+280>>2]=0;if(c[o>>2]|0){z=Gb[c[(c[y>>2]|0)+28>>2]&31](f,(c[(c[b+1120>>2]|0)+(v<<2)>>2]|0)+20|0)|0;c[w+276>>2]=z;if(z|0){j=c[n>>2]|0;s=vb[c[(c[f>>2]|0)+16>>2]&63](f,4,j)|0;if((j|0)>0){g=c[(c[b+1120>>2]|0)+(v<<2)>>2]|0;k=c[g+32>>2]|0;m=c[A+12>>2]|0;n=c[A+72>>2]|0;o=c[A+52>>2]|0;p=c[A+32>>2]|0;q=0;r=c[s+8>>2]|0;while(1){i=c[k+(q<<2)>>2]|0;h=(i+~(i<<15)>>10^i+~(i<<15))*9|0;h=c[m+((((h>>6^h)+~((h>>6^h)<<11)>>16^(h>>6^h)+~((h>>6^h)<<11))&(c[A+48>>2]|0)+-1)<<2)>>2]|0;if((i|0)!=(c[n+(h<<3)>>2]|0))do h=c[p+(h<<2)>>2]|0;while((i|0)!=(c[n+(h<<3)>>2]|0));c[r>>2]=c[o+(h<<2)>>2];q=q+1|0;if((q|0)==(j|0))break;else r=r+4|0}}else g=c[(c[b+1120>>2]|0)+(v<<2)>>2]|0;fb[c[(c[x>>2]|0)+20>>2]&31](f,s,10975,1497453121,g+20|0)}}else c[w+276>>2]=0;v=v+1|0;if((v|0)>=(t|0))break;else w=w+348|0}}fb[c[(c[x>>2]|0)+20>>2]&31](f,u,10955,1497453121,c[c[b+1120>>2]>>2]|0)}}else c[e+284>>2]=0;z=c[b+852>>2]|0;c[e+320>>2]=z;if(!z){c[e+288>>2]=0;Ui(A);l=A;return 10999}z=Gb[c[(c[y>>2]|0)+28>>2]&31](f,c[b+860>>2]|0)|0;c[e+288>>2]=z;if(!z){Ui(A);l=A;return 10999}i=c[b+852>>2]|0;j=vb[c[(c[f>>2]|0)+16>>2]&63](f,104,i)|0;if((i|0)>0){k=0;n=c[j+8>>2]|0;while(1){g=c[(c[b+860>>2]|0)+(k<<2)>>2]|0;c[n+96>>2]=lb[c[(c[g>>2]|0)+20>>2]&127](g)|0;g=(c[b+860>>2]|0)+(k<<2)|0;h=c[g>>2]|0;c[n+8>>2]=c[h+28>>2];c[n+12>>2]=c[h+32>>2];c[n+16>>2]=c[h+36>>2];c[n+20>>2]=c[h+40>>2];c[n+24>>2]=c[h+44>>2];c[n+28>>2]=c[h+48>>2];c[n+32>>2]=c[h+52>>2];c[n+36>>2]=c[h+56>>2];c[n+40>>2]=c[h+60>>2];c[n+44>>2]=c[h+64>>2];c[n+48>>2]=c[h+68>>2];c[n+52>>2]=d[h+152>>0];h=n+56|0;c[n>>2]=0;m=n+4|0;c[m>>2]=0;c[h>>2]=0;c[h+4>>2]=0;c[h+8>>2]=0;c[h+12>>2]=0;c[h+16>>2]=0;c[h+20>>2]=0;c[h+24>>2]=0;c[h+28>>2]=0;g=c[g>>2]|0;h=c[g+4>>2]|0;if(h){c[n+88>>2]=1;c[n>>2]=Gb[c[(c[y>>2]|0)+28>>2]&31](f,h)|0;g=c[(c[b+860>>2]|0)+(k<<2)>>2]|0}if(c[g+12>>2]|0){c[n+88>>2]=3;c[n>>2]=Gb[c[(c[y>>2]|0)+28>>2]&31](f,c[(c[(c[b+860>>2]|0)+(k<<2)>>2]|0)+12>>2]|0)|0}g=c[(c[b+860>>2]|0)+(k<<2)>>2]|0;h=c[g+8>>2]|0;if(h){c[n+88>>2]=2;c[n>>2]=Gb[c[(c[y>>2]|0)+28>>2]&31](f,h)|0;g=c[(c[b+860>>2]|0)+(k<<2)>>2]|0}h=c[g+16>>2]|0;if(h){c[n+92>>2]=1;c[m>>2]=Gb[c[(c[y>>2]|0)+28>>2]&31](f,h)|0;g=c[(c[b+860>>2]|0)+(k<<2)>>2]|0}h=c[g+24>>2]|0;if(h){c[n+92>>2]=3;c[m>>2]=Gb[c[(c[y>>2]|0)+28>>2]&31](f,h)|0;g=c[(c[b+860>>2]|0)+(k<<2)>>2]|0}g=c[g+20>>2]|0;if(g|0){c[n+92>>2]=2;c[m>>2]=Gb[c[(c[y>>2]|0)+28>>2]&31](f,g)|0}k=k+1|0;if((k|0)>=(i|0))break;else n=n+104|0}}fb[c[(c[x>>2]|0)+20>>2]&31](f,j,10979,1497453121,c[b+860>>2]|0);Ui(A);l=A;return 10999}function cc(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,P=0;K=l;l=l+144|0;a:do switch(d-b|0){case 0:{c[e>>2]=0;c[e+4>>2]=0;c[e+8>>2]=0;c[e+12>>2]=0;l=K;return}case 2:{f=c[(c[a+92>>2]|0)+(b<<2)>>2]|0;i=c[f+88>>2]|0;j=c[f+200>>2]|0;h=c[f+92>>2]|0;g=c[f+204>>2]|0;if((i|0)==(j|0)&(h|0)==(g|0))if((c[f+96>>2]|0)==(c[f+208>>2]|0))break a;else g=h;g=h-g|0;if(!(g|i-j)){J=(c[f+96>>2]|0)>(c[f+208>>2]|0);j=J?f+112|0:f;c[j>>2]=j;c[j+4>>2]=j;k=j;g=j;h=j;i=j;f=J?f:f+112|0}else{c[f>>2]=f+112;c[f+4>>2]=f+112;c[f+112>>2]=f;c[f+116>>2]=f;J=(i-j|0)<0|(i-j|0)==0&(g|0)<0;k=(g|0)<0|(i-j|0)<0&(g|0)==0?f:f+112|0;g=(g|0)<0|(i-j|0)<0&(g|0)==0?f+112|0:f;h=J?f+112|0:f;i=J?f:f+112|0;j=f;f=f+112|0}c[e>>2]=i;c[e+4>>2]=h;c[e+8>>2]=k;c[e+12>>2]=g;a=Pf(a,j,f)|0;c[a>>2]=a;c[a+4>>2]=a;c[j+8>>2]=a;a=c[a+8>>2]|0;c[a>>2]=a;c[a+4>>2]=a;c[f+8>>2]=a;l=K;return}case 1:{f=c[(c[a+92>>2]|0)+(b<<2)>>2]|0;break}default:{n=((d-b|0)/2|0)+b|0;h=c[a+92>>2]|0;m=c[h+(n+-1<<2)>>2]|0;i=c[m+88>>2]|0;j=c[m+92>>2]|0;m=c[m+96>>2]|0;b:do if((n|0)<(d|0)){f=n;do{g=c[h+(f<<2)>>2]|0;if((c[g+88>>2]|0)!=(i|0))break b;if((c[g+92>>2]|0)!=(j|0))break b;if((c[g+96>>2]|0)!=(m|0))break b;f=f+1|0}while((f|0)<(d|0))}else f=n;while(0);cc(a,b,n,e);c[K+96>>2]=0;c[K+96+4>>2]=0;c[K+96+8>>2]=0;c[K+96+12>>2]=0;cc(a,f,d,K+96|0);m=c[K+96+4>>2]|0;c:do if(m|0){B=c[e+4>>2]|0;if(!B){c[e>>2]=c[K+96>>2];c[e+4>>2]=c[K+96+4>>2];c[e+8>>2]=c[K+96+8>>2];c[e+12>>2]=c[K+96+12>>2];break}c[a+100>>2]=(c[a+100>>2]|0)+-1;g=c[e+12>>2]|0;i=c[K+96+8>>2]|0;j=c[g+88>>2]|0;do if((j|0)==(c[i+88>>2]|0)?(k=c[g+92>>2]|0,(k|0)==(c[i+92>>2]|0)):0){f=c[i+4>>2]|0;if((f|0)==(i|0)){f=c[i+8>>2]|0;if(f){i=c[f+12>>2]|0;j=c[i+88>>2]|0;k=c[i+92>>2]|0}f=g;G=i;h=g;g=i;n=j+1|0;d=c[i+96>>2]|0;break}j=c[i>>2]|0;c[f>>2]=j;c[j+4>>2]=f;if((i|0)==(c[K+96>>2]|0)){g=c[j+88>>2]|0;h=c[f+88>>2]|0;do if((g|0)<(h|0))g=j;else{if((g|0)==(h|0)?(c[j+92>>2]|0)<(c[f+92>>2]|0):0){g=j;break}g=f}while(0);c[K+96>>2]=g}if((i|0)==(m|0)){g=c[j+88>>2]|0;h=c[f+88>>2]|0;do if((g|0)>(h|0))f=j;else if((g|0)==(h|0)?(c[j+92>>2]|0)>(c[f+92>>2]|0):0){f=j;break}while(0);c[K+96+4>>2]=f;H=36}else{f=m;H=36}}else{f=m;H=36}while(0);if((H|0)==36){w=c[e>>2]|0;x=c[K+96>>2]|0;y=0;A=1;o=B;g=0;h=f;i=0;while(1){j=c[h+88>>2]|0;d=c[o+88>>2]|0;k=O(j-d|0,A)|0;d:do if((k|0)<=0){if((k|0)<0){v=(y|0)!=0;n=c[o+92>>2]|0;u=c[h+92>>2]|0;m=k;k=o;while(1){s=c[(v?h+4|0:h)>>2]|0;r=(s|0)==(h|0);t=h+88|0;q=m;while(1){m=k+88|0;p=u-n|0;if(!r?(C=c[s+88>>2]|0,E=O(C-j|0,A)|0,D=c[s+92>>2]|0,F=D-u|0,(F|0)>-1):0){if(!E)break;if((E|0)<0?(O(F,q)|0)<=(O(E,p)|0):0)break}o=c[(v?k+4|0:k)>>2]|0;if((o|0)==(k|0))break d;G=c[o+88>>2]|0;b=O(G-(c[m>>2]|0)|0,A)|0;d=c[o+92>>2]|0;n=d-n|0;j=c[t>>2]|0;m=q;q=O(j-G|0,A)|0;if(!((n|0)>0&(q|0)<0))break d;if(!b){n=d;k=o;continue}if((b|0)>=0)break d;if((O(n,m)|0)>=(O(b,p)|0))break d;else{n=d;k=o}}j=C;u=D;m=O(C-(c[m>>2]|0)|0,A)|0;h=s}}j=c[o+92>>2]|0;n=(y|0)!=0;e:do if(n){m=o;while(1){k=c[m>>2]|0;if((k|0)==(o|0))break e;if((c[k+88>>2]|0)!=(d|0))break e;G=j;j=c[k+92>>2]|0;if((j|0)>(G|0))break;else m=k}}else{m=o;while(1){k=c[m+4>>2]|0;if((k|0)==(o|0))break e;if((c[k+88>>2]|0)!=(d|0))break e;G=j;j=c[k+92>>2]|0;if((j|0)>(G|0))break;else m=k}}while(0);k=c[h+92>>2]|0;if(n){n=h;while(1){j=c[n+4>>2]|0;if((j|0)==(h|0)){k=m;h=n;break d}if((c[j+88>>2]|0)!=(d|0)){k=m;h=n;break d}G=k;k=c[j+92>>2]|0;if((k|0)<(G|0)){k=m;h=n;break}else n=j}}else{n=h;while(1){j=c[n>>2]|0;if((j|0)==(h|0)){k=m;h=n;break d}if((c[j+88>>2]|0)!=(d|0)){k=m;h=n;break d}G=k;k=c[j+92>>2]|0;if((k|0)<(G|0)){k=m;h=n;break}else n=j}}}else{u=(y|0)!=0;s=d;t=c[h+92>>2]|0;r=k;while(1){q=h+88|0;j=c[o+92>>2]|0;d=t-j|0;k=c[(u?o:o+4|0)>>2]|0;f:do if((k|0)!=(o|0))if(u){p=s;n=r;while(1){m=p;p=c[k+88>>2]|0;m=O(p-m|0,A)|0;b=j;j=c[k+92>>2]|0;b=j-b|0;if((b|0)>=1){b=d;k=o;break f}if(m|0){if((m|0)>=0){b=d;k=o;break f}if((O(b,n)|0)>(O(m,d)|0)){b=d;k=o;break f}}n=O((c[q>>2]|0)-p|0,A)|0;d=t-j|0;m=c[k>>2]|0;if((m|0)==(k|0)){b=d;break}else{o=k;k=m}}}else{p=s;n=r;while(1){m=p;p=c[k+88>>2]|0;m=O(p-m|0,A)|0;b=j;j=c[k+92>>2]|0;b=j-b|0;if((b|0)>=1){b=d;k=o;break f}if(m|0){if((m|0)>=0){b=d;k=o;break f}if((O(b,n)|0)>(O(m,d)|0)){b=d;k=o;break f}}n=O((c[q>>2]|0)-p|0,A)|0;d=t-j|0;m=c[k+4>>2]|0;if((m|0)==(k|0)){b=d;break}else{o=k;k=m}}}else{n=r;b=d;k=o}while(0);d=c[(u?h:h+4|0)>>2]|0;if((d|0)==(h|0))break d;r=c[d+88>>2]|0;j=O(r-(c[q>>2]|0)|0,A)|0;m=t;t=c[d+92>>2]|0;m=t-m|0;s=c[k+88>>2]|0;r=O(r-s|0,A)|0;if(!((m|0)<0&(r|0)>0))break d;if(!j){o=k;h=d;continue}if((j|0)>=0)break d;if((O(m,n)|0)>=(O(j,b)|0))break;else{o=k;h=d}}}while(0);j=(y|0)==0;i=j?h:i;g=j?k:g;h=j?x:h;o=j?w:k;y=y+1|0;if((y|0)==2)break;else A=j?-1:A}c[o+4>>2]=h;c[h>>2]=o;c[g>>2]=i;c[i+4>>2]=g;if((c[x+88>>2]|0)<(c[w+88>>2]|0))c[e>>2]=x;if((c[f+88>>2]|0)>=(c[B+88>>2]|0))c[e+4>>2]=f;c[e+12>>2]=c[K+96+12>>2];h=g;F=i;A=c[i+88>>2]|0;p=c[g+88>>2]|0;B=c[i+92>>2]|0;C=c[g+92>>2]|0;D=c[i+96>>2]|0;q=c[g+96>>2]|0;s=((B-C|0)<0)<<31>>31;E=0-(A-p)|0;t=St(0,0,E|0,((E|0)<0)<<31>>31|0)|0;t=Xr(D-q|0,((D-q|0)<0)<<31>>31|0,t|0,z|0)|0;u=z;v=Xr(D-q|0,((D-q|0)<0)<<31>>31|0,B-C|0,s|0)|0;w=z;d=Xr(A-p|0,((A-p|0)<0)<<31>>31|0,E|0,((E|0)<0)<<31>>31|0)|0;y=z;x=Xr(B-C|0,s|0,B-C|0,s|0)|0;x=St(d|0,y|0,x|0,z|0)|0;y=z;d=c[g+8>>2]|0;c[K+120>>2]=0;if(!d)p=0;else{b=St(0,0,B-C|0,s|0)|0;o=z;r=d;f=0;do{m=c[r+12>>2]|0;j=c[m+88>>2]|0;k=c[m+92>>2]|0;m=c[m+96>>2]|0;n=Xr(k-C|0,((k-C|0)<0)<<31>>31|0,E|0,((E|0)<0)<<31>>31|0)|0;G=z;e=Xr(j-p|0,((j-p|0)<0)<<31>>31|0,b|0,o|0)|0;g:do if((n|0)==(e|0)&(G|0)==(z|0)?(e=Xr(j-p|0,((j-p|0)<0)<<31>>31|0,t|0,u|0)|0,n=z,G=Xr(k-C|0,((k-C|0)<0)<<31>>31|0,v|0,w|0)|0,n=xv(G|0,z|0,e|0,n|0)|0,e=z,G=Xr(m-q|0,((m-q|0)<0)<<31>>31|0,x|0,y|0)|0,G=xv(n|0,e|0,G|0,z|0)|0,e=z,(e|0)>0|(e|0)==0&G>>>0>0):0){do if(f|0){n=(c[f+4>>2]|0)==(r|0);if((c[f>>2]|0)!=(r|0))if(n)break;else break g;if(!n)break g;e=c[f+12>>2]|0;L=c[(c[r+8>>2]|0)+12>>2]|0;G=c[L+88>>2]|0;n=c[L+92>>2]|0;L=c[L+96>>2]|0;M=(c[e+96>>2]|0)-L|0;n=(O(m-L|0,(c[e+92>>2]|0)-n|0)|0)-(O(M,k-n|0)|0)|0;G=(O(M,j-G|0)|0)-(O(m-L|0,(c[e+88>>2]|0)-G|0)|0)|0;n=Xr(n|0,((n|0)<0)<<31>>31|0,B-C|0,s|0)|0;e=z;G=Xr(G|0,((G|0)<0)<<31>>31|0,E|0,((E|0)<0)<<31>>31|0)|0;G=xv(n|0,e|0,G|0,z|0)|0;e=z;if((e|0)>0|(e|0)==0&G>>>0>0)break g}while(0);f=r}while(0);r=c[r>>2]|0}while((r|0)!=(d|0));c[K+120>>2]=f;p=f}n=c[i+8>>2]|0;c[K+72>>2]=0;if(!n)f=0;else{d=St(0,0,B-C|0,s|0)|0;b=z;o=n;f=0;do{m=c[o+12>>2]|0;j=c[m+88>>2]|0;k=c[m+92>>2]|0;m=c[m+96>>2]|0;G=Xr(k-B|0,((k-B|0)<0)<<31>>31|0,E|0,((E|0)<0)<<31>>31|0)|0;M=z;L=Xr(j-A|0,((j-A|0)<0)<<31>>31|0,d|0,b|0)|0;do if((G|0)==(L|0)&(M|0)==(z|0)?(L=Xr(j-A|0,((j-A|0)<0)<<31>>31|0,t|0,u|0)|0,G=z,M=Xr(k-B|0,((k-B|0)<0)<<31>>31|0,v|0,w|0)|0,G=xv(M|0,z|0,L|0,G|0)|0,L=z,M=Xr(m-D|0,((m-D|0)<0)<<31>>31|0,x|0,y|0)|0,M=xv(G|0,L|0,M|0,z|0)|0,L=z,(L|0)>0|(L|0)==0&M>>>0>0):0){if(f|0){if((c[f>>2]|0)!=(o|0))break;if((c[f+4>>2]|0)==(o|0)?(L=c[f+12>>2]|0,e=c[(c[o+8>>2]|0)+12>>2]|0,M=c[e+88>>2]|0,G=c[e+92>>2]|0,e=c[e+96>>2]|0,r=(c[L+96>>2]|0)-e|0,G=(O(m-e|0,(c[L+92>>2]|0)-G|0)|0)-(O(r,k-G|0)|0)|0,M=(O(r,j-M|0)|0)-(O(m-e|0,(c[L+88>>2]|0)-M|0)|0)|0,G=Xr(G|0,((G|0)<0)<<31>>31|0,B-C|0,s|0)|0,L=z,M=Xr(M|0,((M|0)<0)<<31>>31|0,E|0,((E|0)<0)<<31>>31|0)|0,M=xv(G|0,L|0,M|0,z|0)|0,L=z,!((L|0)>0|(L|0)==0&M>>>0>0)):0)break}f=o}while(0);o=c[o>>2]|0}while((o|0)!=(n|0));c[K+72>>2]=f}if((p|0)!=0|(f|0)!=0){hc(a,g,i,K+120|0,K+72|0);f=c[K+120>>2]|0;if(f){h=c[f+12>>2]|0;g=h}f=c[K+72>>2]|0;if(!f){f=g;g=F}else{M=c[f+12>>2]|0;i=M;f=g;g=M}}else{f=g;g=F}G=i;n=c[i+88>>2]|0;d=(c[i+96>>2]|0)+1|0;k=c[i+92>>2]|0}w=G;x=f;i=0;E=0;e=1;j=0;m=0;A=0;B=0;C=n;D=d;v=0;n=0;while(1){y=c[x+88>>2]|0;t=(c[w+88>>2]|0)-y|0;M=c[x+92>>2]|0;F=(c[w+92>>2]|0)-M|0;s=c[x+96>>2]|0;q=(c[w+96>>2]|0)-s|0;c[K+120>>2]=t;c[K+120+4>>2]=F;c[K+120+8>>2]=q;c[K+120+12>>2]=-1;y=C-y|0;M=k-M|0;s=D-s|0;r=(O(q,M)|0)-(O(F,s)|0)|0;s=(O(t,s)|0)-(O(q,y)|0)|0;M=(O(F,y)|0)-(O(t,M)|0)|0;c[K+72>>2]=r;c[K+72+4>>2]=((r|0)<0)<<31>>31;c[K+72+8>>2]=s;c[K+72+8+4>>2]=((s|0)<0)<<31>>31;c[K+72+16>>2]=M;c[K+72+16+4>>2]=((M|0)<0)<<31>>31;y=Xr(F|0,((F|0)<0)<<31>>31|0,M|0,((M|0)<0)<<31>>31|0)|0;L=z;u=Xr(q|0,((q|0)<0)<<31>>31|0,s|0,((s|0)<0)<<31>>31|0)|0;u=St(y|0,L|0,u|0,z|0)|0;L=z;q=Xr(r|0,((r|0)<0)<<31>>31|0,q|0,((q|0)<0)<<31>>31|0)|0;y=z;M=Xr(t|0,((t|0)<0)<<31>>31|0,M|0,((M|0)<0)<<31>>31|0)|0;M=St(q|0,y|0,M|0,z|0)|0;y=z;s=Xr(t|0,((t|0)<0)<<31>>31|0,s|0,((s|0)<0)<<31>>31|0)|0;t=z;F=Xr(r|0,((r|0)<0)<<31>>31|0,F|0,((F|0)<0)<<31>>31|0)|0;F=St(s|0,t|0,F|0,z|0)|0;c[K+48>>2]=u;c[K+48+4>>2]=L;c[K+48+8>>2]=M;c[K+48+8+4>>2]=y;c[K+48+16>>2]=F;c[K+48+16+4>>2]=z;c[K+24>>2]=0;c[K+24+4>>2]=0;c[K+24+8>>2]=0;c[K+24+12>>2]=0;c[K+24+16>>2]=0;F=nd(a,0,x,K+120|0,K+72|0,K+48|0,K+24|0)|0;c[K>>2]=0;c[K+4>>2]=0;c[K+8>>2]=0;c[K+12>>2]=0;c[K+16>>2]=0;y=nd(a,1,w,K+120|0,K+72|0,K+48|0,K)|0;do if((F|0)!=0|(y|0)!=0){d=F|0?-1:1;do if((F|0)!=0&(y|0)!=0){u=c[K+24+16>>2]|0;d=c[K+16>>2]|0;if((u|0)!=(d|0)){d=u-d|0;break}if(!u)d=0;else{M=c[K+24>>2]|0;s=c[K+24+4>>2]|0;o=c[K+8>>2]|0;N=c[K+8+4>>2]|0;b=Xr(o|0,0,M|0,0)|0;d=z;M=Xr(N|0,0,M|0,0)|0;L=z;o=Xr(o|0,0,s|0,0)|0;p=z;s=Xr(N|0,0,s|0,0)|0;N=z;o=xv(M|0,0,o|0,0)|0;M=z;N=xv(L|0,0,s|0,N|0)|0;p=xv(N|0,z|0,p|0,0)|0;M=xv(p|0,z|0,M|0,0)|0;p=z;d=xv(0,o|0,b|0,d|0)|0;b=z;o=xv(M|0,p|0,(b>>>0<o>>>0|(b|0)==(o|0)&d>>>0<0)&1|0,0)|0;p=z;M=c[K+24+8>>2]|0;N=c[K+24+8+4>>2]|0;s=c[K>>2]|0;L=c[K+4>>2]|0;r=Xr(s|0,0,M|0,0)|0;q=z;M=Xr(L|0,0,M|0,0)|0;P=z;s=Xr(s|0,0,N|0,0)|0;t=z;N=Xr(L|0,0,N|0,0)|0;L=z;s=xv(M|0,0,s|0,0)|0;M=z;L=xv(P|0,0,N|0,L|0)|0;t=xv(L|0,z|0,t|0,0)|0;M=xv(t|0,z|0,M|0,0)|0;t=z;q=xv(0,s|0,r|0,q|0)|0;r=z;s=xv(M|0,t|0,(r>>>0<s>>>0|(r|0)==(s|0)&q>>>0<0)&1|0,0)|0;t=z;if(p>>>0<t>>>0|(p|0)==(t|0)&o>>>0<s>>>0)d=-1;else d=p>>>0>t>>>0|(p|0)==(t|0)&o>>>0>s>>>0?1:b>>>0<r>>>0|(b|0)==(r|0)&d>>>0<q>>>0?-1:(b>>>0>r>>>0|(b|0)==(r|0)&d>>>0>q>>>0)&1;d=O(d,u)|0}}while(0);do if(!e)if((d|0)>-1)if((c[K+16>>2]|0)<0&((c[K+8>>2]|0)==0?(c[K+8+4>>2]|0)==0:0)){u=A;b=B;break}else{H=133;break}else if((c[K+24+16>>2]|0)<0&((c[K+24+8>>2]|0)==0?(c[K+24+8+4>>2]|0)==0:0)){u=A;b=B;break}else{H=133;break}else H=133;while(0);if((H|0)==133){H=0;o=Pf(a,x,w)|0;if(!A)j=o;else c[A+4>>2]=o;c[o>>2]=A;b=c[o+8>>2]|0;if(!B)m=b;else c[B>>2]=b;c[b+4>>2]=B;u=o}c[K+116>>2]=F;c[K+112>>2]=y;if(!d){hc(a,h,g,K+116|0,K+112|0);s=c[K+112>>2]|0}else s=y;if((d|0)>-1&(s|0)!=0){r=(n|0)!=0;if(r?(I=c[n>>2]|0,(I|0)!=(y|0)):0){p=I;do{q=p;p=c[p>>2]|0;o=c[q+8>>2]|0;if((p|0)==(q|0))k=0;else{c[p+4>>2]=c[q+4>>2];c[c[q+4>>2]>>2]=p;k=p}c[(c[o+12>>2]|0)+8>>2]=k;k=c[o>>2]|0;if((k|0)==(o|0))k=0;else{c[k+4>>2]=c[o+4>>2];c[c[o+4>>2]>>2]=k}c[(c[q+12>>2]|0)+8>>2]=k;c[q+4>>2]=0;c[q+4+4>>2]=0;c[q+4+8>>2]=0;c[q+4+12>>2]=0;c[q>>2]=c[a+56>>2];c[a+56>>2]=q;c[o+4>>2]=0;c[o+4+4>>2]=0;c[o+4+8>>2]=0;c[o+4+12>>2]=0;c[o>>2]=c[a+56>>2];c[a+56>>2]=o;c[a+116>>2]=(c[a+116>>2]|0)+-1}while((p|0)!=(y|0))}if(!b){n=s;k=r?E:y}else{if(r)k=E;else{n=c[y+4>>2]|0;k=m}c[n>>2]=m;c[m+4>>2]=n;c[b>>2]=y;c[y+4>>2]=b;n=c[K+112>>2]|0;m=0}P=g;g=c[n+12>>2]|0;s=k;y=0;b=c[P+88>>2]|0;o=c[P+96>>2]|0;k=c[P+92>>2]|0;n=c[n+8>>2]|0}else{s=E;y=b;b=C;o=D}r=c[K+116>>2]|0;if((d|0)<1&(r|0)!=0){q=(v|0)!=0;if(q?(J=c[v+4>>2]|0,(J|0)!=(F|0)):0){b=J;do{p=b+4|0;o=b;b=c[p>>2]|0;k=c[o>>2]|0;d=c[o+8>>2]|0;if((k|0)==(o|0))k=0;else{c[k+4>>2]=b;c[c[p>>2]>>2]=k}c[(c[d+12>>2]|0)+8>>2]=k;k=c[d>>2]|0;if((k|0)==(d|0))k=0;else{c[k+4>>2]=c[d+4>>2];c[c[d+4>>2]>>2]=k}c[(c[o+12>>2]|0)+8>>2]=k;c[p>>2]=0;c[p+4>>2]=0;c[p+8>>2]=0;c[p+12>>2]=0;c[o>>2]=c[a+56>>2];c[a+56>>2]=o;c[d+4>>2]=0;c[d+4+4>>2]=0;c[d+4+8>>2]=0;c[d+4+12>>2]=0;c[d>>2]=c[a+56>>2];c[a+56>>2]=d;c[a+116>>2]=(c[a+116>>2]|0)+-1}while((b|0)!=(F|0))}if(!u){d=r;i=q?i:F}else{if(q)k=v;else{k=c[F>>2]|0;i=j}c[j>>2]=k;c[k+4>>2]=j;c[F>>2]=u;c[u+4>>2]=F;d=c[K+116>>2]|0;j=0}k=h;h=c[d+12>>2]|0;u=0;w=c[k+88>>2]|0;x=c[k+96>>2]|0;k=c[k+92>>2]|0;v=c[d+8>>2]|0}else{w=b;x=o}if((h|0)==(f|0)&(g|0)==(G|0)){if(v){r=v+4|0;d=c[r>>2]|0;if((d|0)!=(i|0))do{q=d+4|0;p=d;d=c[q>>2]|0;b=c[p>>2]|0;o=c[p+8>>2]|0;if((b|0)==(p|0))b=0;else{c[b+4>>2]=d;c[c[q>>2]>>2]=b}c[(c[o+12>>2]|0)+8>>2]=b;b=c[o>>2]|0;if((b|0)==(o|0))b=0;else{c[b+4>>2]=c[o+4>>2];c[c[o+4>>2]>>2]=b}c[(c[p+12>>2]|0)+8>>2]=b;c[q>>2]=0;c[q+4>>2]=0;c[q+8>>2]=0;c[q+12>>2]=0;c[p>>2]=c[a+56>>2];c[a+56>>2]=p;c[o+4>>2]=0;c[o+4+4>>2]=0;c[o+4+8>>2]=0;c[o+4+12>>2]=0;c[o>>2]=c[a+56>>2];c[a+56>>2]=o;c[a+116>>2]=(c[a+116>>2]|0)+-1}while((d|0)!=(i|0));if(u|0){c[j>>2]=v;c[r>>2]=j;c[i>>2]=u;c[u+4>>2]=i}}else{c[j>>2]=u;c[u+4>>2]=j;c[h+8>>2]=u}if(!n){c[y>>2]=m;c[m+4>>2]=y;c[G+8>>2]=y;r=0;t=e;q=u;p=y;o=w;b=x;d=v;n=0;break}d=c[n>>2]|0;if((d|0)!=(s|0))do{p=d;d=c[d>>2]|0;o=c[p+8>>2]|0;if((d|0)==(p|0))b=0;else{c[d+4>>2]=c[p+4>>2];c[c[p+4>>2]>>2]=d;b=d}c[(c[o+12>>2]|0)+8>>2]=b;b=c[o>>2]|0;if((b|0)==(o|0))b=0;else{c[b+4>>2]=c[o+4>>2];c[c[o+4>>2]>>2]=b}c[(c[p+12>>2]|0)+8>>2]=b;c[p+4>>2]=0;c[p+4+4>>2]=0;c[p+4+8>>2]=0;c[p+4+12>>2]=0;c[p>>2]=c[a+56>>2];c[a+56>>2]=p;c[o+4>>2]=0;c[o+4+4>>2]=0;c[o+4+8>>2]=0;c[o+4+12>>2]=0;c[o>>2]=c[a+56>>2];c[a+56>>2]=o;c[a+116>>2]=(c[a+116>>2]|0)+-1}while((d|0)!=(s|0));if(!y){r=0;t=e;q=u;p=0;o=w;b=x;d=v}else{c[n>>2]=m;c[m+4>>2]=n;c[y>>2]=s;c[s+4>>2]=y;r=0;t=e;q=u;p=y;o=w;b=x;d=v}}else{r=1;t=0;q=u;p=y;o=w;b=x;d=v}}else{r=Pf(a,x,w)|0;c[r>>2]=r;c[r+4>>2]=r;c[x+8>>2]=r;r=c[r+8>>2]|0;c[r>>2]=r;c[r+4>>2]=r;c[w+8>>2]=r;r=0;s=E;t=e;q=A;p=B;o=C;b=D;d=v}while(0);if(!r)break c;w=g;x=h;E=s;e=t;A=q;B=p;C=o;D=b;v=d}}while(0);l=K;return}}while(0);c[f+8>>2]=0;c[f>>2]=f;c[f+4>>2]=f;c[e>>2]=f;c[e+4>>2]=f;c[e+8>>2]=f;c[e+12>>2]=f;l=K;return}function dc(b,d){b=b|0;d=+d;var e=0,f=0,h=0,i=0.0,k=0.0,m=0.0,n=0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0,z=0.0,A=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0,J=0,K=0,L=0,M=0,N=0.0,O=0.0,P=0.0,Q=0,R=0,S=0.0,T=0.0,U=0.0,V=0,W=0,X=0.0,Y=0.0,Z=0,_=0.0,$=0.0,aa=0.0,ba=0.0,ca=0.0,da=0.0,ea=0,fa=0,ga=0,ha=0.0,ia=0.0,ja=0.0,ka=0.0,la=0.0,ma=0.0,na=0.0,oa=0.0,pa=0.0;ea=l;l=l+240|0;e=c[b+24>>2]|0;if((e|0)<=0){l=ea;return}Z=ea+128+76|0;V=ea+80+16|0;W=ea+80+32|0;J=0;do{I=c[(c[b+32>>2]|0)+(J<<2)>>2]|0;switch(c[I+216>>2]|0){case 2:case 5:break;default:{if(a[I+924>>0]|0){a[I+924>>0]=0;f=c[I+732>>2]|0;if((f|0)>0){h=c[I+740>>2]|0;e=0;do{n=c[h+(e*52|0)+8>>2]|0;y=c[h+(e*52|0)+12>>2]|0;F=+g[n+8>>2]-+g[y+8>>2];G=+g[n+12>>2]-+g[y+12>>2];H=+g[n+16>>2]-+g[y+16>>2];H=+C(+(F*F+G*G+H*H));g[h+(e*52|0)+16>>2]=H;g[h+(e*52|0)+28>>2]=H*H;e=e+1|0}while((e|0)!=(f|0));e=0;do{g[h+(e*52|0)+24>>2]=(+g[(c[h+(e*52|0)+8>>2]|0)+88>>2]+ +g[(c[h+(e*52|0)+12>>2]|0)+88>>2])/+g[(c[h+(e*52|0)+4>>2]|0)+4>>2];e=e+1|0}while((e|0)!=(f|0))}Hf(I);kl(I+988|0);if(c[I+388>>2]&16|0)Jg(I)}m=+g[I+368>>2]*d;g[I+452>>2]=m;g[I+456>>2]=1.0/m;g[I+460>>2]=m*3.0;e=c[I+192>>2]|0;m=+zb[c[(c[e>>2]|0)+48>>2]&15](e);g[I+464>>2]=m;g[I+468>>2]=m*.25;e=c[I+684>>2]|0;m=+g[I+452>>2];i=+g[e+40>>2]*m;k=m*+g[e+44>>2];m=m*+g[e+48>>2];e=c[I+712>>2]|0;if((e|0)>0){f=c[I+720>>2]|0;h=0;do{if(+g[f+(h*104|0)+88>>2]>0.0){y=f+(h*104|0)+40|0;g[y>>2]=i+ +g[y>>2];y=f+(h*104|0)+44|0;g[y>>2]=k+ +g[y>>2];y=f+(h*104|0)+48|0;g[y>>2]=m+ +g[y>>2]}h=h+1|0}while((h|0)!=(e|0))}Yi(11177);G=+g[I+308>>2];H=+g[I+312>>2];n=+g[I+304>>2]>0.0?1:+g[I+300>>2]>0.0;y=c[I+712>>2]|0;if(G!=0.0|H>0.0){if((y|0)>0){e=c[I+720>>2]|0;k=+g[e+8>>2];m=+g[e+12>>2];o=+g[e+16>>2];e=c[I+752>>2]|0;if((e|0)>0){f=c[I+760>>2]|0;h=0;i=0.0;do{fa=c[f+(h*44|0)+8>>2]|0;ga=c[f+(h*44|0)+12>>2]|0;E=+g[ga+8>>2]-k;x=+g[ga+12>>2]-m;A=+g[ga+16>>2]-o;ga=c[f+(h*44|0)+16>>2]|0;D=+g[ga+8>>2]-k;z=+g[ga+12>>2]-m;F=+g[ga+16>>2]-o;i=i+((+g[fa+16>>2]-o)*(E*z-x*D)+((+g[fa+8>>2]-k)*(x*F-A*z)+(+g[fa+12>>2]-m)*(A*D-E*F)));h=h+1|0}while((h|0)!=(e|0))}else i=0.0;i=i/6.0}else i=0.0;F=G*(1.0/+B(+i));E=H*(+g[I+476>>2]-i)}else{E=0.0;F=0.0}a:do if((y|0)>0){if(!n){e=c[I+720>>2]|0;f=0;while(1){if(+g[e+(f*104|0)+88>>2]>0.0){if(G!=0.0){z=F*+g[e+(f*104|0)+92>>2];A=z*+g[e+(f*104|0)+76>>2];D=z*+g[e+(f*104|0)+80>>2];ga=e+(f*104|0)+56|0;g[ga>>2]=+g[e+(f*104|0)+72>>2]*z+ +g[ga>>2];ga=e+(f*104|0)+60|0;g[ga>>2]=A+ +g[ga>>2];ga=e+(f*104|0)+64|0;g[ga>>2]=D+ +g[ga>>2]}if(H>0.0){z=E*+g[e+(f*104|0)+92>>2];A=z*+g[e+(f*104|0)+76>>2];D=z*+g[e+(f*104|0)+80>>2];ga=e+(f*104|0)+56|0;g[ga>>2]=+g[e+(f*104|0)+72>>2]*z+ +g[ga>>2];ga=e+(f*104|0)+60|0;g[ga>>2]=A+ +g[ga>>2];ga=e+(f*104|0)+64|0;g[ga>>2]=D+ +g[ga>>2]}}f=f+1|0;if((f|0)==(y|0))break a}}e=c[I+720>>2]|0;f=0;do{x=+g[e+(f*104|0)+88>>2];if(x>0.0){z=+g[I+452>>2];p=+g[I+304>>2];o=+g[I+300>>2];b:do if((p>0.0|o>0.0?(R=c[c[I+684>>2]>>2]|0,(c[I+288>>2]|0)<4):0)?(S=+g[e+(f*104|0)+40>>2],_=S-+g[I+1212>>2],T=+g[e+(f*104|0)+44>>2],ca=T-+g[I+1216>>2],U=+g[e+(f*104|0)+48>>2],ba=U-+g[I+1220>>2],X=+C(+(_*_+ca*ca+ba*ba)),_*_+ca*ca+ba*ba>1.1920928955078125e-07):0){u=_*(1.0/X);A=ca*(1.0/X);D=ba*(1.0/X);s=+g[e+(f*104|0)+72>>2];t=+g[e+(f*104|0)+76>>2];w=+g[e+(f*104|0)+80>>2];switch(c[I+288>>2]|0){case 2:break;case 1:case 3:case 0:{i=_*s+ca*t+ba*w<0.0?-1.0:1.0;if(!(ba*w*i+(_*s*i+ca*t*i)>0.0))break b;v=-((c[j>>2]=R,+g[j>>2])*(_*_+ca*ca+ba*ba)*(ba*w*i+(_*s*i+ca*t*i))*+g[e+(f*104|0)+92>>2]*.5);m=u*o*v+(s*i*p*v+0.0);k=A*o*v+(t*i*p*v+0.0);i=D*o*v+(w*i*p*v+0.0);if(z*x*i*z*x*i+(z*x*m*z*x*m+z*x*k*z*x*k)>S*S+T*T+U*U){D=1.0/+C(+(i*i+(m*m+k*k)));ga=e+(f*104|0)+56|0;g[ga>>2]=+g[ga>>2]-1.0/(z*x)*m*D*(U*i*D+(S*m*D+T*k*D));ga=e+(f*104|0)+60|0;g[ga>>2]=+g[ga>>2]-1.0/(z*x)*k*D*(U*i*D+(S*m*D+T*k*D));ga=e+(f*104|0)+64|0;g[ga>>2]=+g[ga>>2]-1.0/(z*x)*i*D*(U*i*D+(S*m*D+T*k*D));break b}else{ga=e+(f*104|0)+56|0;g[ga>>2]=m+ +g[ga>>2];ga=e+(f*104|0)+60|0;g[ga>>2]=k+ +g[ga>>2];ga=e+(f*104|0)+64|0;g[ga>>2]=i+ +g[ga>>2];break b}}default:break b}r=_*s+ca*t+ba*w<0.0?-1.0:1.0;k=D*w*r+(u*s*r+A*t*r);m=+g[e+(f*104|0)+92>>2]*.5;i=(c[j>>2]=R,+g[j>>2]);v=k*o*.5*i*(_*_+ca*ca+ba*ba)*m;if(k>0.0&k<.9847999811172485){o=p*.5*i*X*m*+C(+(1.0-k*k));p=(D*(u*w*r-D*s*r)-A*(A*s*r-u*t*r))*o;q=(u*(A*s*r-u*t*r)-D*(D*t*r-A*w*r))*o;o=(A*(D*t*r-A*w*r)-u*(u*w*r-D*s*r))*o}else{p=0.0;q=0.0;o=0.0}i=z*x*-(D*v)*z*x*-(D*v)+(x*-(u*v)*z*x*-(u*v)*z+z*x*-(A*v)*z*x*-(A*v));if(i>0.0?i>=S*S+T*T+U*U:0){i=+C(+(S*S+T*T+U*U))/+C(+i)*.800000011920929;m=i*-(u*v);k=i*-(D*v);i=i*-(A*v)}else{m=-(u*v);k=-(D*v);i=-(A*v)}n=e+(f*104|0)+56|0;fa=e+(f*104|0)+60|0;A=i+ +g[fa>>2];ga=e+(f*104|0)+64|0;D=k+ +g[ga>>2];g[n>>2]=p+(m+ +g[n>>2]);g[fa>>2]=q+A;g[ga>>2]=o+D}while(0);if(G!=0.0){z=F*+g[e+(f*104|0)+92>>2];A=z*+g[e+(f*104|0)+76>>2];D=z*+g[e+(f*104|0)+80>>2];ga=e+(f*104|0)+56|0;g[ga>>2]=+g[e+(f*104|0)+72>>2]*z+ +g[ga>>2];ga=e+(f*104|0)+60|0;g[ga>>2]=A+ +g[ga>>2];ga=e+(f*104|0)+64|0;g[ga>>2]=D+ +g[ga>>2]}if(H>0.0){z=E*+g[e+(f*104|0)+92>>2];A=z*+g[e+(f*104|0)+76>>2];D=z*+g[e+(f*104|0)+80>>2];ga=e+(f*104|0)+56|0;g[ga>>2]=+g[e+(f*104|0)+72>>2]*z+ +g[ga>>2];ga=e+(f*104|0)+60|0;g[ga>>2]=A+ +g[ga>>2];ga=e+(f*104|0)+64|0;g[ga>>2]=D+ +g[ga>>2]}}f=f+1|0}while((f|0)!=(y|0))}while(0);h=c[I+752>>2]|0;if((h|0)>0){n=0;do{v=+g[I+452>>2];r=+g[I+304>>2];p=+g[I+300>>2];c:do if((r>0.0|p>0.0?(K=c[I+288>>2]|0,(K|0)>3):0)?(L=c[I+760>>2]|0,M=c[L+(n*44|0)+8>>2]|0,fa=c[L+(n*44|0)+12>>2]|0,N=+g[M+40>>2],O=+g[M+44>>2],P=+g[M+48>>2],ga=c[L+(n*44|0)+16>>2]|0,Q=c[c[I+684>>2]>>2]|0,$=(N+ +g[fa+40>>2]+ +g[ga+40>>2])*.3333333432674408-+g[I+1212>>2],da=(O+ +g[fa+44>>2]+ +g[ga+44>>2])*.3333333432674408-+g[I+1216>>2],aa=(P+ +g[fa+48>>2]+ +g[ga+48>>2])*.3333333432674408-+g[I+1220>>2],Y=+C(+($*$+da*da+aa*aa)),$*$+da*da+aa*aa>1.1920928955078125e-07):0){s=$*(1.0/Y);w=da*(1.0/Y);x=aa*(1.0/Y);q=+g[L+(n*44|0)+20>>2];t=+g[L+(n*44|0)+24>>2];u=+g[L+(n*44|0)+28>>2];switch(K|0){case 5:break;case 4:case 6:{i=$*q+da*t+aa*u<0.0?-1.0:1.0;if(!(aa*u*i+($*q*i+da*t*i)>0.0))break c;k=-((c[j>>2]=Q,+g[j>>2])*($*$+da*da+aa*aa)*(aa*u*i+($*q*i+da*t*i))*+g[L+(n*44|0)+36>>2]);s=(s*p*k+(q*i*r*k+0.0))*.3333333432674408;q=(w*p*k+(t*i*r*k+0.0))*.3333333432674408;p=(x*p*k+(u*i*r*k+0.0))*.3333333432674408;f=M;k=N;m=O;o=P;e=0;while(1){i=v*+g[f+88>>2];if(p*i*p*i+(s*i*s*i+q*i*q*i)>k*k+m*m+o*o){G=1.0/+C(+(p*p+(s*s+q*q)));H=o*p*G+(k*s*G+m*q*G);ga=f+56|0;g[ga>>2]=+g[ga>>2]-1.0/i*s*G*H;ga=f+60|0;g[ga>>2]=+g[ga>>2]-1.0/i*q*G*H;ga=f+64|0;g[ga>>2]=+g[ga>>2]-1.0/i*p*G*H}else{ga=f+56|0;g[ga>>2]=s+ +g[ga>>2];ga=f+60|0;g[ga>>2]=q+ +g[ga>>2];ga=f+64|0;g[ga>>2]=p+ +g[ga>>2]}e=e+1|0;if((e|0)==3)break c;ga=c[L+(n*44|0)+8+(e<<2)>>2]|0;f=ga;k=+g[ga+40>>2];m=+g[ga+44>>2];o=+g[ga+48>>2]}}default:break c}o=$*q+da*t+aa*u<0.0?-1.0:1.0;k=x*u*o+(s*q*o+w*t*o);m=+g[L+(n*44|0)+36>>2]*.5;i=(c[j>>2]=Q,+g[j>>2]);p=k*($*$+da*da+aa*aa)*p*.5*i*m;if(k>0.0&k<.9847999811172485){A=Y*r*.5*i*m*+C(+(1.0-k*k));D=(x*(s*u*o-x*q*o)-w*(w*q*o-s*t*o))*A*.3333333432674408;E=(s*(w*q*o-s*t*o)-x*(x*t*o-w*u*o))*A*.3333333432674408;A=(w*(x*t*o-w*u*o)-s*(s*u*o-x*q*o))*A*.3333333432674408}else{D=0.0;E=0.0;A=0.0}f=M;i=s*p*-.3333333432674408;z=w*p*-.3333333432674408;o=x*p*-.3333333432674408;m=x*p*-.3333333432674408;v=w*p*-.3333333432674408;u=s*p*-.3333333432674408;e=0;while(1){k=+g[f+88>>2];if(k>0.0){r=+g[I+452>>2];s=i*k*r;t=z*k*r;r=o*k*r;k=+g[f+40>>2];p=+g[f+44>>2];q=+g[f+48>>2];if(r*r+(s*s+t*t)>0.0?r*r+(s*s+t*t)>=k*k+p*p+q*q:0){p=+C(+(k*k+p*p+q*q))/+C(+(r*r+(s*s+t*t)))*.800000011920929;i=i*p;k=z*p;o=o*p;p=i;q=k;m=o}else{p=u;q=v;k=z}y=f+56|0;fa=f+60|0;G=q+ +g[fa>>2];ga=f+64|0;H=m+ +g[ga>>2];g[y>>2]=D+(p+ +g[y>>2]);g[fa>>2]=E+G;g[ga>>2]=A+H}else{p=u;k=z;q=v}e=e+1|0;if((e|0)==3)break c;f=c[L+(n*44|0)+8+(e<<2)>>2]|0;z=k;v=q;u=p}}while(0);n=n+1|0}while((n|0)!=(h|0))}e=c[2395]|0;ga=(c[e+16>>2]|0)+-1|0;c[e+16>>2]=ga;do if(!ga){if(c[e+4>>2]|0){Va(ea+128|0,0)|0;ga=c[6431]|0;g[e+8>>2]=+g[e+8>>2]+ +(((c[ea+128+4>>2]|0)-(c[ga+4>>2]|0)+(((c[ea+128>>2]|0)-(c[ga>>2]|0)|0)*1e6|0)-(c[e+12>>2]|0)|0)>>>0)/1.0e3;if(c[e+16>>2]|0)break;e=c[2395]|0}c[2395]=c[e+20>>2]}while(0);e=c[I+712>>2]|0;if((e|0)>0){f=0;do{fa=c[I+720>>2]|0;y=fa+(f*104|0)+8|0;ga=fa+(f*104|0)+24|0;c[ga>>2]=c[y>>2];c[ga+4>>2]=c[y+4>>2];c[ga+8>>2]=c[y+8>>2];c[ga+12>>2]=c[y+12>>2];ga=fa+(f*104|0)+56|0;G=+g[fa+(f*104|0)+88>>2];H=+g[I+452>>2];E=+g[ga>>2]*G*H;F=G*+g[fa+(f*104|0)+60>>2]*H;G=H*G*+g[fa+(f*104|0)+64>>2];H=+g[(c[I+684>>2]|0)+12>>2]/H;E=E>H?H:E;F=F>H?H:F;G=G>H?H:G;n=fa+(f*104|0)+40|0;E=(E<-H?-H:E)+ +g[n>>2];g[n>>2]=E;n=fa+(f*104|0)+44|0;F=(F<-H?-H:F)+ +g[n>>2];g[n>>2]=F;n=fa+(f*104|0)+48|0;G=(G<-H?-H:G)+ +g[n>>2];g[n>>2]=G;H=+g[I+452>>2];g[y>>2]=E*H+ +g[y>>2];y=fa+(f*104|0)+12|0;g[y>>2]=H*F+ +g[y>>2];fa=fa+(f*104|0)+16|0;g[fa>>2]=G*H+ +g[fa>>2];c[ga>>2]=0;c[ga+4>>2]=0;c[ga+8>>2]=0;c[ga+12>>2]=0;f=f+1|0}while((f|0)!=(e|0))}Hc(I);e=c[I+928>>2]|0;if(e){ga=c[I+192>>2]|0;F=+zb[c[(c[ga>>2]|0)+48>>2]&15](ga);H=+g[e+4>>2]-F;G=+g[e+8>>2]-F;g[I+892>>2]=+g[e>>2]-F;g[I+896>>2]=H;g[I+900>>2]=G;g[I+904>>2]=0.0;G=F+ +g[e+20>>2];H=F+ +g[e+24>>2];g[I+908>>2]=F+ +g[e+16>>2];g[I+912>>2]=G;g[I+916>>2]=H;g[I+920>>2]=0.0;e=c[I+188>>2]|0;if(e|0){ga=c[I+684>>2]|0;fa=c[ga+32>>2]|0;fb[c[(c[fa>>2]|0)+16>>2]&31](fa,e,I+892|0,I+908|0,c[ga+36>>2]|0)}}else{c[I+892>>2]=0;c[I+892+4>>2]=0;c[I+892+8>>2]=0;c[I+892+12>>2]=0;c[I+892+16>>2]=0;c[I+892+20>>2]=0;c[I+892+24>>2]=0;c[I+892+28>>2]=0}e=c[I+712>>2]|0;if((e|0)>0){f=0;do{fa=c[I+720>>2]|0;G=+g[I+464>>2];E=+g[fa+(f*104|0)+8>>2];H=+g[fa+(f*104|0)+12>>2];F=+g[fa+(f*104|0)+16>>2];g[ea>>2]=E-G;g[ea+4>>2]=H-G;g[ea+8>>2]=F-G;g[ea+12>>2]=0.0;g[ea+16>>2]=G+E;g[ea+20>>2]=G+H;g[ea+24>>2]=G+F;g[ea+28>>2]=0.0;ga=c[fa+(f*104|0)+96>>2]|0;F=+g[I+460>>2];G=F*+g[fa+(f*104|0)+44>>2];H=F*+g[fa+(f*104|0)+48>>2];g[ea+128>>2]=+g[fa+(f*104|0)+40>>2]*F;g[ea+128+4>>2]=G;g[ea+128+8>>2]=H;g[ea+128+12>>2]=0.0;Ug(I+928|0,ga,ea,ea+128|0,+g[I+468>>2])|0;f=f+1|0}while((f|0)!=(e|0))}if(c[I+988>>2]|0?(c[I+752>>2]|0)>0:0){e=0;do{ga=c[I+760>>2]|0;n=c[ga+(e*44|0)+8>>2]|0;y=c[ga+(e*44|0)+12>>2]|0;fa=c[ga+(e*44|0)+16>>2]|0;E=(+g[n+40>>2]+ +g[y+40>>2]+ +g[fa+40>>2])*.3333333432674408;F=(+g[n+44>>2]+ +g[y+44>>2]+ +g[fa+44>>2])*.3333333432674408;G=(+g[n+48>>2]+ +g[y+48>>2]+ +g[fa+48>>2])*.3333333432674408;x=+g[I+464>>2];u=+g[n+8>>2];w=+g[n+12>>2];A=+g[n+16>>2];H=+g[n+20>>2];D=+g[y+8>>2];p=D<u?D:u;z=+g[y+12>>2];q=z<w?z:w;v=+g[y+16>>2];r=v<A?v:A;t=+g[y+20>>2];s=t<H?t:H;u=u<D?D:u;w=w<z?z:w;A=A<v?v:A;H=H<t?t:H;t=+g[fa+8>>2];v=+g[fa+12>>2];z=+g[fa+16>>2];D=+g[fa+20>>2];g[ea>>2]=(t<p?t:p)-x;g[ea+4>>2]=(v<q?v:q)-x;g[ea+8>>2]=(z<r?z:r)-x;g[ea+12>>2]=D<s?D:s;g[ea+16>>2]=x+(u<t?t:u);g[ea+20>>2]=x+(w<v?v:w);g[ea+24>>2]=x+(A<z?z:A);g[ea+28>>2]=H<D?D:H;ga=c[ga+(e*44|0)+40>>2]|0;H=+g[I+460>>2];g[ea+128>>2]=E*H;g[ea+128+4>>2]=F*H;g[ea+128+8>>2]=G*H;g[ea+128+12>>2]=0.0;Ug(I+988|0,ga,ea,ea+128|0,+g[I+468>>2])|0;e=e+1|0}while((e|0)<(c[I+752>>2]|0))}do if(a[I+473>>0]|0){y=c[I+712>>2]|0;if((y|0)>0){e=c[I+720>>2]|0;f=c[I+512>>2]|0;k=0.0;m=0.0;i=0.0;h=0;do{H=+g[f+(h<<2)>>2];i=i+ +g[e+(h*104|0)+8>>2]*H;k=k+H*+g[e+(h*104|0)+12>>2];m=m+H*+g[e+(h*104|0)+16>>2];h=h+1|0}while((h|0)!=(y|0))}else{i=0.0;k=0.0;m=0.0}g[I+520>>2]=i;g[I+524>>2]=k;g[I+528>>2]=m;g[I+532>>2]=0.0;h=ea+128+4|0;n=h+44|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(n|0));g[ea+128>>2]=1.1920928955078125e-07;g[ea+128+20>>2]=2.384185791015625e-07;g[ea+128+40>>2]=3.5762786865234375e-07;if((y|0)>0){e=c[I+512>>2]|0;f=c[I+720>>2]|0;h=c[I+492>>2]|0;o=1.1920928955078125e-07;p=0.0;q=0.0;r=0.0;s=2.384185791015625e-07;t=0.0;u=0.0;v=0.0;w=3.5762786865234375e-07;n=0;do{G=+g[e+(n<<2)>>2];A=(+g[f+(n*104|0)+8>>2]-i)*G;D=(+g[f+(n*104|0)+12>>2]-k)*G;G=G*(+g[f+(n*104|0)+16>>2]-m);E=+g[h+(n<<4)>>2];F=+g[h+(n<<4)+4>>2];H=+g[h+(n<<4)+8>>2];o=A*E+o;p=A*F+p;q=A*H+q;r=D*E+r;s=D*F+s;t=D*H+t;u=G*E+u;v=G*F+v;w=G*H+w;n=n+1|0}while((n|0)!=(y|0));g[ea+128>>2]=o;g[ea+128+4>>2]=p;g[ea+128+8>>2]=q;g[ea+128+16>>2]=r;g[ea+128+20>>2]=s;g[ea+128+24>>2]=t;g[ea+128+32>>2]=u;g[ea+128+36>>2]=v;g[ea+128+40>>2]=w}if((a[22664]|0)==0?jy(22664)|0:0){g[5784]=9.999999747378752e-05;c[5785]=16}Vc(ea+128|0,ea+80|0,ea+32|0);c[I+536>>2]=c[ea+80>>2];c[I+536+4>>2]=c[ea+80+4>>2];c[I+536+8>>2]=c[ea+80+8>>2];c[I+536+12>>2]=c[ea+80+12>>2];c[I+552>>2]=c[V>>2];c[I+552+4>>2]=c[V+4>>2];c[I+552+8>>2]=c[V+8>>2];c[I+552+12>>2]=c[V+12>>2];c[I+568>>2]=c[W>>2];c[I+568+4>>2]=c[W+4>>2];c[I+568+8>>2]=c[W+8>>2];c[I+568+12>>2]=c[W+12>>2];ja=+g[ea+80>>2];w=+g[V>>2];D=+g[W>>2];ia=+g[ea+80+4>>2];x=+g[ea+80+20>>2];F=+g[ea+80+36>>2];ha=+g[ea+80+8>>2];z=+g[ea+80+24>>2];H=+g[ea+80+40>>2];s=+g[I+632>>2];t=+g[I+636>>2];u=+g[I+640>>2];pa=+g[I+648>>2];oa=+g[I+652>>2];r=+g[I+656>>2];E=+g[I+664>>2];G=+g[I+668>>2];i=+g[I+672>>2];na=+g[ea+128>>2];ma=+g[ea+128+16>>2];q=+g[ea+128+32>>2];o=(ja*s+ia*t+ha*u)*na+(w*s+x*t+z*u)*ma+(D*s+F*t+H*u)*q;la=+g[ea+128+4>>2];ka=+g[ea+128+20>>2];p=+g[ea+128+36>>2];m=(ja*s+ia*t+ha*u)*la+(w*s+x*t+z*u)*ka+(D*s+F*t+H*u)*p;v=+g[ea+128+8>>2];A=+g[ea+128+24>>2];k=+g[ea+128+40>>2];u=(ja*s+ia*t+ha*u)*v+(w*s+x*t+z*u)*A+(D*s+F*t+H*u)*k;t=(ja*pa+ia*oa+ha*r)*na+(w*pa+x*oa+z*r)*ma+(D*pa+F*oa+H*r)*q;s=(ja*pa+ia*oa+ha*r)*la+(w*pa+x*oa+z*r)*ka+(D*pa+F*oa+H*r)*p;r=(ja*pa+ia*oa+ha*r)*v+(w*pa+x*oa+z*r)*A+(D*pa+F*oa+H*r)*k;q=na*(ja*E+ia*G+ha*i)+ma*(w*E+x*G+z*i)+(D*E+F*G+H*i)*q;p=(ja*E+ia*G+ha*i)*la+(w*E+x*G+z*i)*ka+(D*E+F*G+H*i)*p;k=(ja*E+ia*G+ha*i)*v+(w*E+x*G+z*i)*A+(D*E+F*G+H*i)*k;g[I+584>>2]=o;g[I+588>>2]=m;g[I+592>>2]=u;g[I+596>>2]=0.0;g[I+600>>2]=t;g[I+604>>2]=s;g[I+608>>2]=r;g[I+612>>2]=0.0;g[I+616>>2]=q;g[I+620>>2]=p;g[I+624>>2]=k;g[I+628>>2]=0.0;i=+g[I+364>>2];if(i>1.0){pa=1.0/(u*(p*t-s*q)+(o*(s*k-r*p)+m*(r*q-k*t)))<1.0?1.0:1.0/(u*(p*t-s*q)+(o*(s*k-r*p)+m*(r*q-k*t)))>i?i:1.0/(u*(p*t-s*q)+(o*(s*k-r*p)+m*(r*q-k*t)));g[I+584>>2]=o*pa;g[I+588>>2]=m*pa;g[I+592>>2]=u*pa;g[I+596>>2]=0.0;g[I+600>>2]=t*pa;g[I+604>>2]=s*pa;g[I+608>>2]=r*pa;g[I+612>>2]=0.0;g[I+616>>2]=q*pa;g[I+620>>2]=p*pa;g[I+624>>2]=pa*k;g[I+628>>2]=0.0}if(a[I+473>>0]|0){if(!(+g[I+320>>2]>0.0))break;i=+g[I+536>>2];p=+g[I+540>>2];q=+g[I+544>>2];r=+g[I+552>>2];s=+g[I+556>>2];t=+g[I+560>>2];k=+g[I+568>>2];m=+g[I+572>>2];o=+g[I+576>>2];e=c[I+712>>2]|0;if((e|0)<=0)break;h=0;do{f=c[I+720>>2]|0;if(+g[f+(h*104|0)+88>>2]>0.0){y=c[I+492>>2]|0;ka=+g[y+(h<<4)>>2];la=+g[y+(h<<4)+4>>2];ma=+g[y+(h<<4)+8>>2];ja=+g[I+320>>2];y=f+(h*104|0)+8|0;na=+g[y>>2];fa=f+(h*104|0)+12|0;oa=+g[fa>>2];ga=f+(h*104|0)+16|0;pa=+g[ga>>2];oa=oa+ja*(r*ka+s*la+t*ma+ +g[I+524>>2]-oa);pa=pa+ja*(k*ka+m*la+o*ma+ +g[I+528>>2]-pa);g[y>>2]=na+ja*(+g[I+520>>2]+(i*ka+p*la+q*ma)-na);g[fa>>2]=oa;g[ga>>2]=pa;g[f+(h*104|0)+20>>2]=0.0}h=h+1|0}while((h|0)!=(e|0))}}while(0);h=ea+128|0;n=h+104|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(n|0));e=c[I+812>>2]|0;if((e|0)<0){if((c[I+816>>2]|0)<0){f=c[I+820>>2]|0;if(f|0){if(a[I+824>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[I+820>>2]=0}a[I+824>>0]=1;c[I+820>>2]=0;c[I+816>>2]=0}do{ga=c[I+820>>2]|0;fa=ga+(e*104|0)|0;c[fa>>2]=c[ea+128>>2];c[fa+4>>2]=c[ea+128+4>>2];c[fa+8>>2]=c[ea+128+8>>2];c[fa+12>>2]=c[ea+128+12>>2];c[fa+16>>2]=c[ea+128+16>>2];c[fa+20>>2]=c[ea+128+20>>2];c[fa+24>>2]=c[ea+128+24>>2];fa=ga+(e*104|0)+28|0;c[fa>>2]=c[ea+128+28>>2];c[fa+4>>2]=c[ea+128+28+4>>2];c[fa+8>>2]=c[ea+128+28+8>>2];c[fa+12>>2]=c[ea+128+28+12>>2];fa=ga+(e*104|0)+44|0;c[fa>>2]=c[ea+128+44>>2];c[fa+4>>2]=c[ea+128+44+4>>2];c[fa+8>>2]=c[ea+128+44+8>>2];c[fa+12>>2]=c[ea+128+44+12>>2];fa=ga+(e*104|0)+60|0;c[fa>>2]=c[ea+128+60>>2];c[fa+4>>2]=c[ea+128+60+4>>2];c[fa+8>>2]=c[ea+128+60+8>>2];c[fa+12>>2]=c[ea+128+60+12>>2];ga=ga+(e*104|0)+76|0;c[ga>>2]=c[Z>>2];c[ga+4>>2]=c[Z+4>>2];c[ga+8>>2]=c[Z+8>>2];c[ga+12>>2]=c[Z+12>>2];c[ga+16>>2]=c[Z+16>>2];c[ga+20>>2]=c[Z+20>>2];c[ga+24>>2]=c[Z+24>>2];e=e+1|0}while((e|0)!=0)}c[I+812>>2]=0;h=ea+128|0;n=h+56|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(n|0));e=c[I+832>>2]|0;if((e|0)<0){if((c[I+836>>2]|0)<0){f=c[I+840>>2]|0;if(f|0){if(a[I+844>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[f+-4>>2]|0)}c[I+840>>2]=0}a[I+844>>0]=1;c[I+840>>2]=0;c[I+836>>2]=0}do{h=(c[I+840>>2]|0)+(e*56|0)|0;f=ea+128|0;n=h+56|0;do{c[h>>2]=c[f>>2];h=h+4|0;f=f+4|0}while((h|0)<(n|0));e=e+1|0}while((e|0)!=0)}c[I+832>>2]=0;Sf(I+928|0,1);Sf(I+988|0,1);Sf(I+1048|0,1);e=c[b+24>>2]|0}}J=J+1|0}while((J|0)<(e|0));l=ea;return}\nfunction hk(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;f=c[e+16>>2]|0;if(!f){if(!(eo(e)|0)){f=c[e+16>>2]|0;g=5}}else g=5;a:do if((g|0)==5){g=c[e+20>>2]|0;if((f-g|0)>>>0<d>>>0){vb[c[e+36>>2]&63](e,b,d)|0;break}b:do if((a[e+75>>0]|0)>-1){h=d;while(1){if(!h){f=d;break b}f=h+-1|0;if((a[b+f>>0]|0)==10)break;else h=f}if((vb[c[e+36>>2]&63](e,b,h)|0)>>>0<h>>>0)break a;g=c[e+20>>2]|0;f=d-h|0;b=b+h|0}else f=d;while(0);Th(g|0,b|0,f|0)|0;c[e+20>>2]=(c[e+20>>2]|0)+f}while(0);return}function ik(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0;e=l;l=l+16|0;Rb[c[(c[b>>2]|0)+68>>2]&127](e,b,d);c[a>>2]=c[e>>2];c[a+4>>2]=c[e+4>>2];c[a+8>>2]=c[e+8>>2];c[a+12>>2]=c[e+12>>2];i=+g[d>>2];h=+g[d+4>>2];f=+g[d+8>>2];k=i*i+h*h+f*f<1.4210854715202004e-14?-1.0:i;j=i*i+h*h+f*f<1.4210854715202004e-14?-1.0:h;f=i*i+h*h+f*f<1.4210854715202004e-14?-1.0:f;h=1.0/+C(+(f*f+(k*k+j*j)));i=+zb[c[(c[b>>2]|0)+48>>2]&15](b);g[a>>2]=+g[a>>2]+i*h*k;g[a+4>>2]=i*h*j+ +g[a+4>>2];g[a+8>>2]=i*h*f+ +g[a+8>>2];l=e;return}function jk(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;d=l;l=l+48|0;e=aF(b,0)|0;g[d+32>>2]=+Io(c,e);g[d+28>>2]=+ho(c,e);g[d+24>>2]=+go(c,e);e=aF(b,1)|0;g[d+20>>2]=+Io(c,e);g[d+16>>2]=+ho(c,e);g[d+12>>2]=+go(c,e);b=aF(b,2)|0;g[d+8>>2]=+Io(c,b);g[d+4>>2]=+ho(c,b);g[d>>2]=+go(c,b);Xp(a,d+32|0,d+28|0,d+24|0,d+20|0,d+16|0,d+12|0,d+8|0,d+4|0,d);l=d;return}function kk(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=c[b+188>>2]|0;if(d|0){g=c[a+68>>2]|0;g=lb[c[(c[g>>2]|0)+36>>2]&127](g)|0;Rb[c[(c[g>>2]|0)+40>>2]&127](g,d,c[a+24>>2]|0);g=c[a+68>>2]|0;Rb[c[(c[g>>2]|0)+12>>2]&127](g,d,c[a+24>>2]|0);c[b+188>>2]=0}f=c[a+8>>2]|0;if((f|0)<=0)return;g=c[a+16>>2]|0;d=0;while(1){e=g+(d<<2)|0;if((c[e>>2]|0)==(b|0))break;d=d+1|0;if((d|0)>=(f|0)){h=9;break}}if((h|0)==9)return;if((d|0)>=(f|0))return;c[e>>2]=c[g+(f+-1<<2)>>2];c[(c[a+16>>2]|0)+(f+-1<<2)>>2]=b;c[a+8>>2]=f+-1;return}function lk(a,b,c,d){a=a|0;b=b|0;c=+c;d=+d;var e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0;i=+E(+c);h=+F(+c);c=+g[b+444>>2];if(+B(+i)>1.1920928955078125e-07){e=+g[b+448>>2];c=+C(+((h*h/(i*i)+1.0)/(1.0/(e*e)+h*h/(i*i)/(c*c))));e=h*h;f=i*i}else{e=h*h;f=i*i}j=c*.5;f=+F(+j)/+C(+(f+0.0+e));j=+E(+j);k=j*d+i*f*0.0-h*f*-0.0;e=j*0.0-h*f*d-f*0.0*0.0;c=j*0.0+f*0.0*0.0-i*f*d;d=-(f*0.0*d)-i*f*0.0-h*f*-0.0;g[a>>2]=h*f*e+(j*k+d*-(f*0.0))-c*-(i*f);g[a+4>>2]=c*-(f*0.0)+(j*e+d*-(i*f))-h*f*k;g[a+8>>2]=k*-(i*f)+(h*f*d+j*c)-e*-(f*0.0);g[a+12>>2]=0.0;return}function mk(b,d){b=b|0;d=d|0;var e=0,f=0,h=0;g[b+16>>2]=0.0;g[b+20>>2]=0.0;a[b+168>>0]=0;a[b+169>>0]=0;g[b+172>>2]=0.0;c[b+60>>2]=0;c[b+60+4>>2]=0;c[b+60+8>>2]=0;c[b+60+12>>2]=0;b=c[(c[b+8>>2]|0)+284>>2]|0;if((c[(lb[c[(c[b>>2]|0)+28>>2]&127](b)|0)+4>>2]|0)<=0)return;do{f=c[b>>2]|0;h=c[f+12>>2]|0;f=c[c[(lb[c[f+28>>2]&127](b)|0)+12>>2]>>2]|0;e=c[(c[(lb[c[(c[b>>2]|0)+28>>2]&127](b)|0)+12>>2]|0)+4>>2]|0;pb[h&31](b,f,e,c[d+24>>2]|0)|0}while((c[(lb[c[(c[b>>2]|0)+28>>2]&127](b)|0)+4>>2]|0)>0);return}function nk(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;c[6135]=(c[6135]|0)+-1;jb[c[(c[a>>2]|0)+20>>2]&127](a,b);e=c[b+768>>2]|0;d=(c[a+12>>2]|0)+-1|0;g=c[a+20>>2]|0;f=c[g+(e<<2)>>2]|0;c[g+(e<<2)>>2]=c[g+(d<<2)>>2];c[(c[a+20>>2]|0)+(d<<2)>>2]=f;c[(c[(c[a+20>>2]|0)+(e<<2)>>2]|0)+768>>2]=e;c[a+12>>2]=d;a=c[a+68>>2]|0;if(!b)return;g=c[a+16>>2]|0;if(g>>>0<=b>>>0?(g+(O(c[a>>2]|0,c[a+4>>2]|0)|0)|0)>>>0>b>>>0:0){c[b>>2]=c[a+12>>2];c[a+12>>2]=b;c[a+8>>2]=(c[a+8>>2]|0)+1;return}c[6433]=(c[6433]|0)+1;Pc(c[b+-4>>2]|0);return}function ok(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;k=c[b+8>>2]|0;if((k|0)<=0)return;i=c[b+16>>2]|0;j=0;b=0;do{g=c[i+(j<<2)>>2]|0;if(!(c[g+204>>2]&3)){h=c[a+16>>2]|0;e=h+(b<<3)|0;d=c[e>>2]|0;if((d|0)==(b|0))d=b;else{f=d;do{d=h+(f<<3)|0;c[e>>2]=c[d>>2];d=c[d>>2]|0;e=h+(d<<3)|0;f=c[e>>2]|0}while((d|0)!=(f|0))}c[g+208>>2]=d;c[h+(b<<3)+4>>2]=j;c[g+212>>2]=-1;b=b+1|0}else{c[g+208>>2]=-1;c[g+212>>2]=-2}j=j+1|0}while((j|0)!=(k|0));return}function pk(a,b,d,f){a=a|0;b=b|0;d=d|0;f=f|0;var g=0,h=0,i=0;while(1){g=c[a+12>>2]|0;if(!(((e[f>>1]|0)>=(e[a>>1]|0)?(e[d>>1]|0)<=(e[a+6>>1]|0):0)&(e[d+4>>1]|0)<=(e[a+10>>1]|0)&(e[f+4>>1]|0)>=(e[a+4>>1]|0)&(e[d+2>>1]|0)<=(e[a+8>>1]|0)&(e[f+2>>1]|0)>=(e[a+2>>1]|0))){h=6;break}if((g|0)>-1)break;i=a+16|0;pk(i,b,d,f);g=c[a+28>>2]|0;a=i+(((g|0)>-1?1:0-g|0)<<4)|0}if((h|0)==6)return;Rb[c[(c[b>>2]|0)+8>>2]&127](b,g>>>21,g&2097151);return}function qk(b,d,e){b=b|0;d=d|0;e=e|0;var f=0;f=Nr()|0;Gd(f,b,d,e);c[f>>2]=4612;c[f+4>>2]=9;a[f+1309>>0]=0;g[f+1316>>2]=0.0;g[f+1340>>2]=0.0;g[f+1364>>2]=1.0;a[f+1310>>0]=0;g[f+1320>>2]=0.0;g[f+1344>>2]=0.0;g[f+1368>>2]=1.0;a[f+1311>>0]=0;g[f+1324>>2]=0.0;g[f+1348>>2]=0.0;g[f+1372>>2]=1.0;a[f+1312>>0]=0;g[f+1328>>2]=0.0;g[f+1352>>2]=0.0;g[f+1376>>2]=1.0;a[f+1313>>0]=0;g[f+1332>>2]=0.0;g[f+1356>>2]=0.0;g[f+1380>>2]=1.0;a[f+1314>>0]=0;g[f+1336>>2]=0.0;g[f+1360>>2]=0.0;g[f+1384>>2]=1.0;return f|0}function rk(a,b){a=a|0;b=+b;var d=0,e=0;d=l;l=l+16|0;Te(a,b);Yi(11809);a=c[a+452>>2]|0;gb[c[(c[a>>2]|0)+24>>2]&31](a,b);a=c[2395]|0;e=(c[a+16>>2]|0)+-1|0;c[a+16>>2]=e;if(e|0){l=d;return}do if(c[a+4>>2]|0){Va(d|0,0)|0;e=c[6431]|0;g[a+8>>2]=+g[a+8>>2]+ +(((c[d+4>>2]|0)-(c[e+4>>2]|0)+(((c[d>>2]|0)-(c[e>>2]|0)|0)*1e6|0)-(c[a+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[a+16>>2]|0)){a=c[2395]|0;break}else{l=d;return}}while(0);c[2395]=c[a+20>>2];l=d;return}function sk(b,d){b=b|0;d=d|0;a[b+148>>0]=0;if((((Md(b,d)|0?(a[b+148>>0]=1,Md(b,d)|0):0)?(a[b+148>>0]=1,Md(b,d)|0):0)?(a[b+148>>0]=1,Md(b,d)|0):0)?(a[b+148>>0]=1,Md(b,d)|0):0)a[b+148>>0]=1;d=(c[b+8>>2]|0)+52|0;c[b+92>>2]=c[d>>2];c[b+92+4>>2]=c[d+4>>2];c[b+92+8>>2]=c[d+8>>2];c[b+92+12>>2]=c[d+12>>2];fp(b+112|0,d|0,16)|0;return}function tk(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0;h=+g[a+56>>2];k=+g[a+72>>2]-h;j=+g[a+60>>2];i=+g[a+76>>2]-j;l=+g[a+64>>2];m=+g[a+80>>2]-l;h=+g[a+88>>2]-h;j=+g[a+92>>2]-j;l=+g[a+96>>2]-l;g[d+12>>2]=0.0;f=1.0/+C(+((k*j-i*h)*(k*j-i*h)+((i*l-m*j)*(i*l-m*j)+(m*h-k*l)*(m*h-k*l))));g[d>>2]=(i*l-m*j)*f;g[d+4>>2]=(m*h-k*l)*f;g[d+8>>2]=(k*j-i*h)*f;c[e>>2]=c[a+56>>2];c[e+4>>2]=c[a+56+4>>2];c[e+8>>2]=c[a+56+8>>2];c[e+12>>2]=c[a+56+12>>2];return}function uk(b,d){b=b|0;d=d|0;var e=0,f=0,g=0;g=l;l=l+224|0;e=g+80|0;f=e+40|0;do{c[e>>2]=0;e=e+4|0}while((e|0)<(f|0));c[g+120>>2]=c[d>>2];if((Oc(0,b,g+120|0,g,g+80|0)|0)>=0){d=c[2397]|0;if((a[9662]|0)<1)c[2397]=d&-33;if(!(c[2409]|0)){e=c[2408]|0;c[2408]=g+136;c[2404]=g+136;c[2402]=g+136;c[2409]=80;c[2401]=g+136+80;Oc(9588,b,g+120|0,g,g+80|0)|0;if(e|0){vb[c[9624>>2]&63](9588,0,0)|0;c[2408]=e;c[2409]=0;c[2401]=0;c[2404]=0;c[2402]=0}}else Oc(9588,b,g+120|0,g,g+80|0)|0;c[2397]=c[2397]|d&32}l=g;return}function vk(b,d){b=b|0;d=d|0;do if(b){if(d>>>0<128){a[b>>0]=d;b=1;break}if(!(c[6444]|0))if((d&-128|0)==57216){a[b>>0]=d;b=1;break}else{c[6577]=84;b=-1;break}if(d>>>0<2048){a[b>>0]=d>>>6|192;a[b+1>>0]=d&63|128;b=2;break}if(d>>>0<55296|(d&-8192|0)==57344){a[b>>0]=d>>>12|224;a[b+1>>0]=d>>>6&63|128;a[b+2>>0]=d&63|128;b=3;break}if((d+-65536|0)>>>0<1048576){a[b>>0]=d>>>18|240;a[b+1>>0]=d>>>12&63|128;a[b+2>>0]=d>>>6&63|128;a[b+3>>0]=d&63|128;b=4;break}else{c[6577]=84;b=-1;break}}else b=1;while(0);return b|0}function wk(b){b=b|0;var d=0,e=0,f=0;c[b>>2]=6288;d=c[b+12>>2]|0;if((d|0)>0){f=0;do{e=c[(c[b+20>>2]|0)+(f<<2)>>2]|0;if(e|0){hb[c[c[e>>2]>>2]&511](e);e=c[b+4>>2]|0;jb[c[(c[e>>2]|0)+60>>2]&127](e,c[(c[b+20>>2]|0)+(f<<2)>>2]|0)}f=f+1|0}while((f|0)!=(d|0))}d=c[b+20>>2]|0;if(!d){a[b+24>>0]=1;c[b+20>>2]=0;c[b+12>>2]=0;b=b+16|0;c[b>>2]=0;return}if(a[b+24>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+20>>2]=0;a[b+24>>0]=1;c[b+20>>2]=0;c[b+12>>2]=0;b=b+16|0;c[b>>2]=0;return}function xk(a,b,c){a=a|0;b=b|0;c=c|0;var d=0.0,e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0;h=+g[a+56>>2];f=+g[a+72>>2]-h;k=+g[a+60>>2];j=+g[a+76>>2]-k;e=+g[a+64>>2];i=+g[a+80>>2]-e;h=+g[a+88>>2]-h;k=+g[a+92>>2]-k;e=+g[a+96>>2]-e;g[c+12>>2]=0.0;d=1.0/+C(+((f*k-j*h)*(f*k-j*h)+((j*e-i*k)*(j*e-i*k)+(i*h-f*e)*(i*h-f*e))));g[c>>2]=(j*e-i*k)*d;g[c+4>>2]=(i*h-f*e)*d;g[c+8>>2]=(f*k-j*h)*d;if(!b)return;g[c>>2]=-((j*e-i*k)*d);g[c+4>>2]=-((i*h-f*e)*d);g[c+8>>2]=-((f*k-j*h)*d);return}function yk(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;g=c[a+720>>2]|0;h=c[a+752>>2]|0;if((h|0)<=0){e=0;return e|0}a=c[a+760>>2]|0;f=0;while(1){i=c[a+(f*44|0)+8>>2]|0;if(((i|0)==(g+(e*104|0)|0)|((i|0)==(g+(b*104|0)|0)|(i|0)==(g+(d*104|0)|0))?(i=c[a+(f*44|0)+12>>2]|0,(i|0)==(g+(e*104|0)|0)|((i|0)==(g+(b*104|0)|0)|(i|0)==(g+(d*104|0)|0))):0)?(i=c[a+(f*44|0)+16>>2]|0,(i|0)==(g+(e*104|0)|0)|((i|0)==(g+(b*104|0)|0)|(i|0)==(g+(d*104|0)|0))):0){a=1;f=7;break}f=f+1|0;if((f|0)>=(h|0)){a=0;f=7;break}}if((f|0)==7)return a|0;return 0}function zk(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0,j=0;i=c[a+96>>2]|0;j=c[a+104>>2]|0;f=+g[j+(((b|0)%(i|0)|0)<<4)+4>>2]*+g[a+16>>2];h=+g[j+(((b|0)%(i|0)|0)<<4)+8>>2]*+g[a+20>>2];g[d>>2]=+g[j+(((b|0)%(i|0)|0)<<4)>>2]*+g[a+12>>2];g[d+4>>2]=f;g[d+8>>2]=h;g[d+12>>2]=0.0;d=c[a+104>>2]|0;h=+g[d+(((b+1|0)%(i|0)|0)<<4)+4>>2]*+g[a+16>>2];f=+g[d+(((b+1|0)%(i|0)|0)<<4)+8>>2]*+g[a+20>>2];g[e>>2]=+g[d+(((b+1|0)%(i|0)|0)<<4)>>2]*+g[a+12>>2];g[e+4>>2]=h;g[e+8>>2]=f;g[e+12>>2]=0.0;return}function Ak(a,b){a=a|0;b=b|0;var d=0,e=0,f=0.0,h=0,i=0;e=l;l=l+32|0;d=c[a+184>>2]|0;if(+g[d+4>>2]==0.0){a=0;l=e;return a|0}b=c[b>>2]|0;if(!(Gb[c[(c[d>>2]|0)+8>>2]&31](d,c[b+188>>2]|0)|0)){a=1;l=e;return a|0}h=c[a+192>>2]|0;i=c[b+192>>2]|0;d=c[a+184>>2]|0;f=+g[a+188>>2];c[e>>2]=0;c[e+4>>2]=i;c[e+8>>2]=b;c[e+12>>2]=b+4;c[e+16>>2]=-1;c[e+20>>2]=-1;nc(h,a+36|0,a+100|0,e,d,f);a=1;l=e;return a|0}function Bk(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0;e=l;l=l+16|0;k=+g[d>>2];j=+g[d+4>>2];i=+g[d+8>>2];h=k*+g[b+56>>2]+j*+g[b+60>>2]+i*+g[b+64>>2];f=k*+g[b+72>>2]+j*+g[b+76>>2]+i*+g[b+80>>2];i=k*+g[b+88>>2]+j*+g[b+92>>2]+i*+g[b+96>>2];g[e>>2]=h;g[e+4>>2]=f;g[e+8>>2]=i;g[e+12>>2]=0.0;b=b+56+((+g[e+((h<f&1)<<2)>>2]<i?2:h<f&1)<<4)|0;c[a>>2]=c[b>>2];c[a+4>>2]=c[b+4>>2];c[a+8>>2]=c[b+8>>2];c[a+12>>2]=c[b+12>>2];l=e;return}function Ck(a,b){a=a|0;b=b|0;var d=0;d=l;l=l+16|0;c[d>>2]=c[b>>2];c[d+4>>2]=c[b+4>>2];c[d+8>>2]=c[b+8>>2];c[d+12>>2]=c[b+12>>2];a=c[a+8>>2]|0;c[a+260>>2]=(c[a+260>>2]|0)+1;c[a+4>>2]=1065353216;c[a+8>>2]=0;c[a+8+4>>2]=0;c[a+8+8>>2]=0;c[a+8+12>>2]=0;c[a+24>>2]=1065353216;c[a+28>>2]=0;c[a+28+4>>2]=0;c[a+28+8>>2]=0;c[a+28+12>>2]=0;c[a+44>>2]=1065353216;c[a+48>>2]=0;c[a+52>>2]=c[d>>2];c[a+52+4>>2]=c[d+4>>2];c[a+52+8>>2]=c[d+8>>2];c[a+52+12>>2]=c[d+12>>2];l=d;return}function Dk(a){a=a|0;var b=0,d=0;b=l;l=l+16|0;Yi(15077);d=c[a+68>>2]|0;jb[c[(c[d>>2]|0)+32>>2]&127](d,c[a+24>>2]|0);a=c[2395]|0;d=(c[a+16>>2]|0)+-1|0;c[a+16>>2]=d;if(d|0){l=b;return}do if(c[a+4>>2]|0){Va(b|0,0)|0;d=c[6431]|0;g[a+8>>2]=+g[a+8>>2]+ +(((c[b+4>>2]|0)-(c[d+4>>2]|0)+(((c[b>>2]|0)-(c[d>>2]|0)|0)*1e6|0)-(c[a+12>>2]|0)|0)>>>0)/1.0e3;if(!(c[a+16>>2]|0)){a=c[2395]|0;break}else{l=b;return}}while(0);c[2395]=c[a+20>>2];l=b;return}function Ek(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0;do switch(b|0){case 0:{f=0;b=1;break}case 1:{f=0;b=2;break}case 2:{f=1;b=3;break}case 3:{f=2;break}case 4:{f=0;break}case 5:{f=1;break}case 6:{f=2;break}case 7:{f=3;break}case 8:{f=4;b=5;break}case 9:{f=4;b=6;break}case 10:{f=5;b=7;break}case 11:{f=6;b=7;break}default:{f=0;b=0}}while(0);Rb[c[(c[a>>2]|0)+108>>2]&127](a,f,d);Rb[c[(c[a>>2]|0)+108>>2]&127](a,b,e);return}function Fk(a,b){a=a|0;b=b|0;var d=0.0,e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0.0;k=+zb[c[(c[a>>2]|0)+48>>2]&15](a);h=+zb[c[(c[a>>2]|0)+48>>2]&15](a);d=+zb[c[(c[a>>2]|0)+48>>2]&15](a);m=(k+ +g[a+28>>2])/+g[a+12>>2];j=(h+ +g[a+32>>2])/+g[a+16>>2];f=(d+ +g[a+36>>2])/+g[a+20>>2];l=+B(+(+g[b>>2]));i=+B(+(+g[b+4>>2]));e=+B(+(+g[b+8>>2]));g[a+12>>2]=l;g[a+16>>2]=i;g[a+20>>2]=e;g[a+24>>2]=0.0;g[a+28>>2]=m*l-k;g[a+32>>2]=j*i-h;g[a+36>>2]=f*e-d;g[a+40>>2]=0.0;return}function Gk(b,d){b=b|0;d=d|0;var e=0,f=0,h=0.0,i=0,j=0;if(a[b+527>>0]|0){c[d>>2]=0;c[d+4>>2]=0;return}c[d>>2]=3;c[d+4>>2]=3;j=c[b+28>>2]|0;i=c[b+32>>2]|0;kc(b,j+4|0,i+4|0,j+264|0,i+264|0);if((a[b+526>>0]|0?(e=c[d>>2]|0,c[d>>2]=e+1,f=c[d+4>>2]|0,c[d+4>>2]=f+-1,h=+g[b+456>>2],+g[b+444>>2]<h):0)?+g[b+448>>2]<h:0){c[d>>2]=e+2;c[d+4>>2]=f+-2}if(!(a[b+525>>0]|0))return;c[d>>2]=(c[d>>2]|0)+1;c[d+4>>2]=(c[d+4>>2]|0)+-1;return}function Hk(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0;f=b+e|0;d=d&255;if((e|0)>=67){while(b&3){a[b>>0]=d;b=b+1|0}g=d|d<<8|d<<16|d<<24;while((b|0)<=((f&-4)-64|0)){c[b>>2]=g;c[b+4>>2]=g;c[b+8>>2]=g;c[b+12>>2]=g;c[b+16>>2]=g;c[b+20>>2]=g;c[b+24>>2]=g;c[b+28>>2]=g;c[b+32>>2]=g;c[b+36>>2]=g;c[b+40>>2]=g;c[b+44>>2]=g;c[b+48>>2]=g;c[b+52>>2]=g;c[b+56>>2]=g;c[b+60>>2]=g;b=b+64|0}while((b|0)<(f&-4|0)){c[b>>2]=g;b=b+4|0}}while((b|0)<(f|0)){a[b>>0]=d;b=b+1|0}return f-e|0}function Ik(a,b,c,d,e,f,h,i,j,k){a=+a;b=+b;c=+c;d=+d;e=+e;f=+f;h=+h;i=+i;j=+j;k=k|0;if(!(((h-d)*b-(i-e)*a)*f+(((i-e)*c-(j-f)*b)*d+((j-f)*a-(h-d)*c)*e)<0.0)){k=0;return k|0}do if(!((h-d)*d+(i-e)*e+(j-f)*f>0.0))if((h-d)*h+(i-e)*i+(j-f)*j<0.0){d=h*h+i*i+j*j;break}else{d=((h*h+i*i+j*j)*(d*d+e*e+f*f)-(h*d+i*e+j*f)*(h*d+i*e+j*f))/((h-d)*(h-d)+(i-e)*(i-e)+(j-f)*(j-f));d=d>0.0?d:0.0;break}else d=d*d+e*e+f*f;while(0);g[k>>2]=+C(+d);k=1;return k|0}function Jk(a,b){a=a|0;b=b|0;var d=0.0,e=0.0,f=0,h=0,i=0;b=c[b+36>>2]|0;i=c[b+8>>2]|0;h=c[b+12>>2]|0;f=c[b+16>>2]|0;e=+g[a+52>>2];d=+lh(a+4|0,+g[a+36>>2],+g[a+40>>2],+g[a+44>>2],+g[i+8>>2],+g[i+12>>2],+g[i+16>>2],+g[h+8>>2],+g[h+12>>2],+g[h+16>>2],+g[f+8>>2],+g[f+12>>2],+g[f+16>>2],e);if(!(d>0.0&d<e)){i=a+60|0;h=c[i>>2]|0;h=h+1|0;c[i>>2]=h;return}g[a+52>>2]=d;c[a+56>>2]=b;i=a+60|0;h=c[i>>2]|0;h=h+1|0;c[i>>2]=h;return}function Kk(a,b,c){a=a|0;b=b|0;c=c|0;var d=0.0;a:do if(c>>>0>=3)if((c+-3|0)>>>0<3)switch(b|0){case 2:{d=+g[a+868+(c+-3<<6)+32>>2];break a}case 4:{d=+g[a+868+(c+-3<<6)+36>>2];break a}case 3:{d=+g[a+868+(c+-3<<6)+28>>2];break a}default:{d=0.0;break a}}else d=0.0;else switch(b|0){case 2:{d=+g[a+756+(c<<2)>>2];break a}case 4:{d=+g[a+772+(c<<2)>>2];break a}case 3:{d=+g[a+740+(c<<2)>>2];break a}default:{d=0.0;break a}}while(0);return +d}function Lk(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0.0,j=0.0;Rb[c[(c[b>>2]|0)+68>>2]&127](a,b,d);if(!(+zb[c[(c[b>>2]|0)+48>>2]&15](b)!=0.0))return;h=+g[d>>2];f=+g[d+4>>2];e=+g[d+8>>2];j=h*h+f*f+e*e<1.4210854715202004e-14?-1.0:h;i=h*h+f*f+e*e<1.4210854715202004e-14?-1.0:f;e=h*h+f*f+e*e<1.4210854715202004e-14?-1.0:e;f=1.0/+C(+(e*e+(j*j+i*i)));h=+zb[c[(c[b>>2]|0)+48>>2]&15](b);g[a>>2]=+g[a>>2]+h*f*j;g[a+4>>2]=h*f*i+ +g[a+4>>2];g[a+8>>2]=h*f*e+ +g[a+8>>2];return}function Mk(b,d,e){b=b|0;d=d|0;e=+e;var f=0.0,h=0.0,i=0.0,j=0.0,k=0.0;a[b+171>>0]=0;c[b+60>>2]=c[d>>2];c[b+60+4>>2]=c[d+4>>2];c[b+60+8>>2]=c[d+8>>2];c[b+60+12>>2]=c[d+12>>2];f=+g[b+60>>2];h=+g[b+64>>2];j=+g[b+68>>2];i=1.0/+C(+(f*f+h*h+j*j));if(+C(+(j*i*j*i+(f*i*f*i+h*i*h*i)))<1.1920928955078125e-07){k=0.0;h=0.0;f=0.0;d=0}else{k=f*i;h=h*i;f=j*i;d=c[b+72>>2]|0}g[b+76>>2]=k;g[b+80>>2]=h;g[b+84>>2]=f;c[b+88>>2]=d;g[b+172>>2]=+g[b+172>>2]+e;return}function Nk(b,d,e,f,g){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;do if(!(HB(b,c[d+8>>2]|0)|0)){if(HB(b,c[d>>2]|0)|0){if((c[d+16>>2]|0)!=(e|0)?(c[d+20>>2]|0)!=(e|0):0){c[d+32>>2]=f;c[d+20>>2]=e;c[d+40>>2]=(c[d+40>>2]|0)+1;if((c[d+36>>2]|0)==1?(c[d+24>>2]|0)==2:0)a[d+54>>0]=1;c[d+44>>2]=4;break}if((f|0)==1)c[d+32>>2]=1}}else rr(d,e,f);while(0);return}function Ok(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0;a:do if(!(HB(b,c[d+8>>2]|0)|0)){g=c[b+12>>2]|0;On(b+16|0,d,e,f);if((g|0)>1){h=b+24|0;do{On(h,d,e,f);if(a[d+54>>0]|0)break a;h=h+8|0}while(h>>>0<(b+16+(g<<3)|0)>>>0)}}else Fm(d,e,f);while(0);return}function Pk(b,d,e,f,h){b=b|0;d=+d;e=e|0;f=f|0;h=h|0;g[b>>2]=d;c[b+4>>2]=e;c[b+72>>2]=f;c[b+76>>2]=c[h>>2];c[b+76+4>>2]=c[h+4>>2];c[b+76+8>>2]=c[h+8>>2];c[b+76+12>>2]=c[h+12>>2];g[b+92>>2]=0.0;g[b+96>>2]=0.0;g[b+100>>2]=.5;g[b+104>>2]=0.0;g[b+108>>2]=0.0;g[b+112>>2]=.800000011920929;g[b+116>>2]=1.0;a[b+120>>0]=0;g[b+124>>2]=.004999999888241291;g[b+128>>2]=.009999999776482582;g[b+132>>2]=.009999999776482582;g[b+136>>2]=.009999999776482582;oq(b+8|0);return}function Qk(b,d,e){b=b|0;d=d|0;e=e|0;b=Br(152)|0;c[b>>2]=4944;a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;c[b+12>>2]=0;a[b+40>>0]=1;c[b+36>>2]=0;c[b+28>>2]=0;c[b+32>>2]=0;a[b+60>>0]=1;c[b+56>>2]=0;c[b+48>>2]=0;c[b+52>>2]=0;a[b+80>>0]=1;c[b+76>>2]=0;c[b+68>>2]=0;c[b+72>>2]=0;c[b+100>>2]=e;g[b+104>>2]=0.0;a[b+148>>0]=1;c[b+144>>2]=0;c[b+136>>2]=0;c[b+140>>2]=0;c[b+116>>2]=d;c[b+120>>2]=0;c[b+124>>2]=2;c[b+128>>2]=1;g[b+112>>2]=0.0;g[b+108>>2]=0.0;return b|0}function Rk(b){b=b|0;var d=0,e=0,f=0;e=Br(5260)|0;c[e>>2]=5256;c[e+4>>2]=2;a[e+24>>0]=1;c[e+20>>2]=0;c[e+12>>2]=0;c[e+16>>2]=0;c[e+28>>2]=5728;c[e+5256>>2]=b;c[e+60>>2]=79;c[e+64>>2]=lb[c[(c[b>>2]|0)+12>>2]&127](b)|0;c[e+68>>2]=lb[c[(c[b>>2]|0)+8>>2]&127](b)|0;b=0;do{d=0;do{f=c[e+5256>>2]|0;c[e+72+(b*144|0)+(d<<2)>>2]=vb[c[(c[f>>2]|0)+16>>2]&63](f,b,d)|0;d=d+1|0}while((d|0)<36);b=b+1|0}while((b|0)<36);return e|0}function Sk(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=Gb[c[(c[d>>2]|0)+40>>2]&31](d,a)|0;f=Gb[c[(c[d>>2]|0)+28>>2]&31](d,e)|0;c[b>>2]=f;if(f|0)jb[c[(c[d>>2]|0)+48>>2]&127](d,e);c[b+4>>2]=c[a+4>>2];c[b+28>>2]=c[a+28>>2];c[b+32>>2]=c[a+32>>2];c[b+36>>2]=c[a+36>>2];c[b+40>>2]=c[a+40>>2];c[b+12>>2]=c[a+12>>2];c[b+16>>2]=c[a+16>>2];c[b+20>>2]=c[a+20>>2];c[b+24>>2]=c[a+24>>2];c[b+44>>2]=c[a+44>>2];c[b+52>>2]=c[a+52>>2];return 17987}function Tk(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=Gb[c[(c[d>>2]|0)+40>>2]&31](d,a)|0;f=Gb[c[(c[d>>2]|0)+28>>2]&31](d,e)|0;c[b>>2]=f;if(f|0)jb[c[(c[d>>2]|0)+48>>2]&127](d,e);c[b+4>>2]=c[a+4>>2];c[b+28>>2]=c[a+28>>2];c[b+32>>2]=c[a+32>>2];c[b+36>>2]=c[a+36>>2];c[b+40>>2]=c[a+40>>2];c[b+12>>2]=c[a+12>>2];c[b+16>>2]=c[a+16>>2];c[b+20>>2]=c[a+20>>2];c[b+24>>2]=c[a+24>>2];c[b+44>>2]=c[a+44>>2];c[b+52>>2]=c[a+52>>2];return 17531}function Uk(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=Gb[c[(c[d>>2]|0)+40>>2]&31](d,a)|0;f=Gb[c[(c[d>>2]|0)+28>>2]&31](d,e)|0;c[b>>2]=f;if(f|0)jb[c[(c[d>>2]|0)+48>>2]&127](d,e);c[b+4>>2]=c[a+4>>2];c[b+28>>2]=c[a+28>>2];c[b+32>>2]=c[a+32>>2];c[b+36>>2]=c[a+36>>2];c[b+40>>2]=c[a+40>>2];c[b+12>>2]=c[a+12>>2];c[b+16>>2]=c[a+16>>2];c[b+20>>2]=c[a+20>>2];c[b+24>>2]=c[a+24>>2];c[b+44>>2]=c[a+44>>2];c[b+52>>2]=c[a+68>>2];return 16551}function Vk(a,b,c){a=a|0;b=b|0;c=c|0;var d=0;d=l;l=l+32|0;if(!(+g[a+344>>2]!=0.0)){l=d;return}Gn(a,+g[b>>2],+g[b+4>>2],+g[b+8>>2]);if(!(bH(a+544|0)|0)){l=d;return}qp(d,+g[b>>2],+g[b+4>>2],+g[b+8>>2],+g[a+348>>2],+g[a+352>>2],+g[a+356>>2]);Fo(d+16|0,+g[c>>2],+g[c+4>>2],+g[c+8>>2],+g[d>>2],+g[d+4>>2],+g[d+8>>2]);Hn(a,+g[d+16>>2],+g[d+16+4>>2],+g[d+16+8>>2]);l=d;return}function Wk(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;a[b+53>>0]=1;do if((c[b+4>>2]|0)==(e|0)){a[b+52>>0]=1;e=c[b+16>>2]|0;if(!e){c[b+16>>2]=d;c[b+24>>2]=f;c[b+36>>2]=1;if(!((f|0)==1?(c[b+48>>2]|0)==1:0))break;a[b+54>>0]=1;break}if((e|0)!=(d|0)){c[b+36>>2]=(c[b+36>>2]|0)+1;a[b+54>>0]=1;break}e=c[b+24>>2]|0;if((e|0)==2){c[b+24>>2]=f;e=f}if((e|0)==1?(c[b+48>>2]|0)==1:0)a[b+54>>0]=1}while(0);return}function Xk(a,b,d){a=a|0;b=+b;d=d|0;var e=0,f=0.0,h=0.0,i=0.0,j=0,k=0;e=l;l=l+16|0;j=c[a+52>>2]|0;k=c[a+28+(((j+2|0)%3|0)<<2)>>2]|0;c[e>>2]=k;c[e+4>>2]=k;c[e+8>>2]=k;g[e+12>>2]=0.0;g[e+(j<<2)>>2]=+g[a+28+(j<<2)>>2]+ +g[e+(j<<2)>>2];h=(+g[e>>2]+.03999999910593033)*2.0;f=(+g[e+4>>2]+.03999999910593033)*2.0;i=(+g[e+8>>2]+.03999999910593033)*2.0;g[d>>2]=b*.0833333283662796*(f*f+i*i);g[d+4>>2]=b*.0833333283662796*(h*h+i*i);g[d+8>>2]=b*.0833333283662796*(h*h+f*f);l=e;return}function Yk(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;g=l;l=l+64|0;if(!(HB(a,b)|0))if((b|0)!=0?(f=Pi(b,2744)|0,(f|0)!=0):0){b=g+4|0;e=b+52|0;do{c[b>>2]=0;b=b+4|0}while((b|0)<(e|0));c[g>>2]=f;c[g+8>>2]=a;c[g+12>>2]=-1;c[g+48>>2]=1;Vb[c[(c[f>>2]|0)+28>>2]&127](f,g,c[d>>2]|0,1);if((c[g+24>>2]|0)==1){c[d>>2]=c[g+16>>2];b=1}else b=0}else b=0;else b=1;l=g;return b|0}function Zk(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;b=c[d>>2]|0;b=Gb[c[(c[b>>2]|0)+56>>2]&31](b,80)|0;c[b>>2]=9172;c[b+4>>2]=c[d>>2];c[b>>2]=5632;a[b+8>>0]=1;d=c[d>>2]|0;c[b+12>>2]=5680;c[b+60>>2]=d;c[b+64>>2]=0;c[b+16>>2]=f;c[b+20>>2]=e;d=vb[c[(c[d>>2]|0)+12>>2]&63](d,c[f+8>>2]|0,c[e+8>>2]|0)|0;c[b+76>>2]=d;f=c[b+60>>2]|0;jb[c[(c[f>>2]|0)+20>>2]&127](f,d);return b|0}function _k(b,d){b=b|0;d=d|0;var e=0;e=Wr()|0;c[e+8>>2]=0;c[e+12>>2]=1065353216;c[e+16>>2]=1065353216;c[e+20>>2]=1065353216;g[e+24>>2]=0.0;g[e+44>>2]=.03999999910593033;c[e+52>>2]=0;c[e+56>>2]=1065353216;c[e+60>>2]=1065353216;c[e+64>>2]=1065353216;g[e+68>>2]=0.0;c[e+72>>2]=-1082130432;c[e+76>>2]=-1082130432;c[e+80>>2]=-1082130432;g[e+84>>2]=0.0;a[e+88>>0]=0;c[e>>2]=7816;c[e+92>>2]=b;c[e+4>>2]=3;if(!d)return e|0;ej(e);return e|0}function $k(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0,j=0.0,k=0.0,l=0.0,m=0;if((d|0)<=0)return;m=0;do{e=+g[a+32>>2];h=+g[a+28>>2];i=b+(m<<4)|0;k=+g[b+(m<<4)+4>>2];f=+g[b+(m<<4)+8>>2];l=+C(+(k*k+f*f));if(l!=0.0){j=f*(e/l);f=+g[i>>2]<0.0?-h:h;e=k*(e/l)}else{j=0.0;f=+g[i>>2]<0.0?-h:h}g[c+(m<<4)>>2]=f;g[c+(m<<4)+4>>2]=e;g[c+(m<<4)+8>>2]=j;m=m+1|0}while((m|0)!=(d|0));return}function al(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0;j=c[b>>2]|0;if(!e)e=c[a+188>>2]|0;h=c[a+268>>2]|0;if((h|0)<=0)return;i=c[a+276>>2]|0;f=0;while(1){g=i+(f<<2)|0;if((c[g>>2]|0)==(j|0))break;f=f+1|0;if((f|0)>=(h|0)){k=9;break}}if((k|0)==9)return;if((f|0)>=(h|0))return;c[g>>2]=c[i+(h+-1<<2)>>2];c[a+268>>2]=h+-1;k=c[a+284>>2]|0;pb[c[(c[k>>2]|0)+12>>2]&31](k,e,b,d)|0;return}function bl(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;b=c[d>>2]|0;b=Gb[c[(c[b>>2]|0)+56>>2]&31](b,80)|0;c[b>>2]=9172;c[b+4>>2]=c[d>>2];c[b>>2]=5632;a[b+8>>0]=0;d=c[d>>2]|0;c[b+12>>2]=5680;c[b+60>>2]=d;c[b+64>>2]=0;c[b+16>>2]=e;c[b+20>>2]=f;d=vb[c[(c[d>>2]|0)+12>>2]&63](d,c[e+8>>2]|0,c[f+8>>2]|0)|0;c[b+76>>2]=d;f=c[b+60>>2]|0;jb[c[(c[f>>2]|0)+20>>2]&127](f,d);return b|0}function cl(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;e=l;l=l+32|0;d=c[a+216>>2]|0;if(+g[d+4>>2]==0.0){a=0;l=e;return a|0}b=c[b>>2]|0;if(!(Gb[c[(c[d>>2]|0)+8>>2]&31](d,c[b+188>>2]|0)|0)){a=1;l=e;return a|0}f=c[b+192>>2]|0;d=c[a+216>>2]|0;c[e>>2]=0;c[e+4>>2]=f;c[e+8>>2]=b;c[e+12>>2]=b+4;c[e+16>>2]=-1;c[e+20>>2]=-1;Jc(a+68|0,a+132|0,e,d);a=1;l=e;return a|0}function dl(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=Gb[c[(c[d>>2]|0)+40>>2]&31](d,a)|0;f=Gb[c[(c[d>>2]|0)+28>>2]&31](d,e)|0;c[b>>2]=f;if(f|0)jb[c[(c[d>>2]|0)+48>>2]&127](d,e);c[b+4>>2]=c[a+4>>2];c[b+28>>2]=c[a+28>>2];c[b+32>>2]=c[a+32>>2];c[b+36>>2]=c[a+36>>2];c[b+40>>2]=c[a+40>>2];c[b+12>>2]=c[a+12>>2];c[b+16>>2]=c[a+16>>2];c[b+20>>2]=c[a+20>>2];c[b+24>>2]=c[a+24>>2];c[b+44>>2]=c[a+44>>2];return 11212}function el(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=Gb[c[(c[d>>2]|0)+40>>2]&31](d,a)|0;f=Gb[c[(c[d>>2]|0)+28>>2]&31](d,e)|0;c[b>>2]=f;if(f|0)jb[c[(c[d>>2]|0)+48>>2]&127](d,e);c[b+4>>2]=c[a+4>>2];c[b+12>>2]=c[a+68>>2];c[b+16>>2]=c[a+72>>2];c[b+20>>2]=c[a+76>>2];c[b+24>>2]=c[a+80>>2];c[b+28>>2]=c[a+48>>2];c[b+32>>2]=c[a+52>>2];c[b+36>>2]=c[a+56>>2];c[b+40>>2]=c[a+60>>2];c[b+44>>2]=c[a+64>>2];return 17228}function fl(b,d){b=b|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0.0,j=0.0;a[b+171>>0]=1;c[b+60>>2]=c[d>>2];c[b+60+4>>2]=c[d+4>>2];c[b+60+8>>2]=c[d+8>>2];c[b+60+12>>2]=c[d+12>>2];e=+g[b+60>>2];f=+g[b+64>>2];i=+g[b+68>>2];h=1.0/+C(+(e*e+f*f+i*i));if(+C(+(i*h*i*h+(e*h*e*h+f*h*f*h)))<1.1920928955078125e-07){j=0.0;f=0.0;e=0.0;d=0}else{j=e*h;f=f*h;e=i*h;d=c[b+72>>2]|0}g[b+76>>2]=j;g[b+80>>2]=f;g[b+84>>2]=e;c[b+88>>2]=d;return}function gl(a,b){a=a|0;b=b|0;var d=0.0,e=0.0,f=0.0,h=0,i=0,j=0;j=c[a+68>>2]|0;i=c[a+64>>2]|0;h=c[a+72>>2]|0;e=+g[a+60>>2]*(+g[b+(j<<2)>>2]/+g[a+12+(j<<2)>>2]);g[a+60>>2]=e;f=+g[a+56>>2]*(+g[b+(i<<2)>>2]/+g[a+12+(i<<2)>>2]+ +g[b+(h<<2)>>2]/+g[a+12+(h<<2)>>2])*.5;g[a+56>>2]=f;g[a+52>>2]=f/+C(+(e*e+f*f));f=+B(+(+g[b>>2]));e=+B(+(+g[b+4>>2]));d=+B(+(+g[b+8>>2]));g[a+12>>2]=f;g[a+16>>2]=e;g[a+20>>2]=d;g[a+24>>2]=0.0;return}function hl(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0;if((d|0)<=0)return;m=0;do{e=+g[a+28>>2];h=+g[a+36>>2];k=+g[b+(m<<4)>>2];f=+g[b+(m<<4)+4>>2];l=+C(+(k*k+f*f));i=+g[b+(m<<4)+8>>2];if(l!=0.0){j=f*(e/l);f=i<0.0?-h:h;e=k*(e/l)}else{j=0.0;f=i<0.0?-h:h}g[c+(m<<4)>>2]=e;g[c+(m<<4)+4>>2]=j;g[c+(m<<4)+8>>2]=f;m=m+1|0}while((m|0)!=(d|0));return}function il(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,l=0.0,m=0;if((d|0)<=0)return;m=0;do{e=+g[a+28>>2];h=+g[a+32>>2];k=+g[b+(m<<4)>>2];f=+g[b+(m<<4)+8>>2];l=+C(+(k*k+f*f));i=+g[b+(m<<4)+4>>2];if(l!=0.0){j=f*(e/l);f=i<0.0?-h:h;e=k*(e/l)}else{j=0.0;f=i<0.0?-h:h}g[c+(m<<4)>>2]=e;g[c+(m<<4)+4>>2]=f;g[c+(m<<4)+8>>2]=j;m=m+1|0}while((m|0)!=(d|0));return}function jl(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0;f=l;l=l+48|0;c[f+32>>2]=9064;c[f+32+4>>2]=e;c[f>>2]=c[b>>2];c[f+4>>2]=c[b+4>>2];c[f+8>>2]=c[b+8>>2];c[f+12>>2]=c[b+12>>2];c[f+16>>2]=c[d>>2];c[f+16+4>>2]=c[d+4>>2];c[f+16+8>>2]=c[d+8>>2];c[f+16+12>>2]=c[d+12>>2];Qe(c[a+4>>2]|0,f,f+32|0);Qe(c[a+64>>2]|0,f,f+32|0);l=f;return}function kl(b){b=b|0;var d=0;d=c[b>>2]|0;if(d|0)Sm(b,d);d=c[b+4>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+4>>2]=0;c[b+8>>2]=-1;d=c[b+32>>2]|0;if(!d){a[b+36>>0]=1;c[b+32>>2]=0;c[b+24>>2]=0;d=b+28|0;c[d>>2]=0;b=b+16|0;c[b>>2]=0;return}if(a[b+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+32>>2]=0;a[b+36>>0]=1;c[b+32>>2]=0;c[b+24>>2]=0;d=b+28|0;c[d>>2]=0;b=b+16|0;c[b>>2]=0;return}function ll(b,d){b=b|0;d=+d;var e=0,f=0.0,h=0;d=1.0/+g[(c[b+116>>2]|0)+344>>2];if((c[b+136>>2]|0)<=0)return;h=0;do{e=c[b+144>>2]|0;if(!(a[e+(h*284|0)+84>>0]|0))f=0.0;else{f=+g[e+(h*284|0)+272>>2];f=d*(+g[e+(h*284|0)+216>>2]*(+g[e+(h*284|0)+204>>2]-+g[e+(h*284|0)+32>>2])*+g[e+(h*284|0)+268>>2]-f*+g[(f<0.0?e+(h*284|0)+220|0:e+(h*284|0)+224|0)>>2]);f=f<0.0?0.0:f}g[e+(h*284|0)+276>>2]=f;h=h+1|0}while((h|0)<(c[b+136>>2]|0));return}function ml(a,b,c,d){a=a|0;b=+b;c=+c;d=+d;var e=0,f=0.0,h=0.0,i=0.0;e=l;l=l+48|0;f=+RG(b);h=+RG(c);i=+RG(d);b=+QG(b);c=+QG(c);d=+QG(d);g[e+32>>2]=h*i;g[e+28>>2]=c*b*i-f*d;g[e+24>>2]=c*f*i+b*d;g[e+20>>2]=h*d;g[e+16>>2]=c*b*d+f*i;g[e+12>>2]=c*f*d-b*i;g[e+8>>2]=-c;g[e+4>>2]=h*b;g[e>>2]=h*f;Oo(a,e+32|0,e+28|0,e+24|0,e+20|0,e+16|0,e+12|0,e+8|0,e+4|0,e);l=e;return}function nl(a,d,f,g,h,i){a=a|0;d=d|0;f=f|0;g=g|0;h=h|0;i=i|0;var j=0;j=c[a+108>>2]|0;if(j|0){xb[c[(c[j>>2]|0)+24>>2]&7](j,d,f,g,h,i);return}j=b[a+56>>1]|0;if(!(j<<16>>16))return;d=1;h=1;do{i=c[a+68>>2]|0;if(b[i+(d<<2)>>1]&1){Gb[c[(c[g>>2]|0)+8>>2]&31](g,(c[a+60>>2]|0)+((e[i+(d<<2)+2>>1]|0)<<6)|0)|0;j=b[a+56>>1]|0}h=h+1<<16>>16;d=h&65535}while(d>>>0<((j&65535)<<1|1)>>>0);return}function ol(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0,h=0.0,i=0.0;e=+g[a+28>>2];i=+g[a+32>>2];h=+g[a+36>>2];switch(d|0){case 0:{a=0;d=0;f=1065353216;break}case 1:{a=0;d=0;f=-1082130432;break}case 2:{a=0;d=1065353216;f=0;e=i;break}case 3:{a=0;d=-1082130432;f=0;e=i;break}case 4:{a=1065353216;d=0;f=0;e=h;break}case 5:{a=-1082130432;d=0;f=0;e=h;break}default:return}c[b>>2]=f;c[b+4>>2]=d;c[b+8>>2]=a;g[b+12>>2]=-e;return}function pl(b){b=b|0;var d=0;c[b>>2]=5212;d=c[b+284>>2]|0;hb[c[c[d>>2]>>2]&511](d);d=c[b+284>>2]|0;if(d|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b>>2]=5168;d=c[b+276>>2]|0;if(!d){a[b+280>>0]=1;c[b+276>>2]=0;c[b+268>>2]=0;d=b+272|0;c[d>>2]=0;c[b>>2]=5132;return}if(a[b+280>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+276>>2]=0;a[b+280>>0]=1;c[b+276>>2]=0;c[b+268>>2]=0;d=b+272|0;c[d>>2]=0;c[b>>2]=5132;return}function ql(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;b=c[d>>2]|0;b=Gb[c[(c[b>>2]|0)+56>>2]&31](b,16)|0;c[b>>2]=9172;d=c[d>>2]|0;c[b+4>>2]=d;c[b>>2]=5700;a[b+8>>0]=0;c[b+12>>2]=0;if(!(vb[c[(c[d>>2]|0)+24>>2]&63](d,c[e+8>>2]|0,c[f+8>>2]|0)|0))return b|0;d=c[b+4>>2]|0;c[b+12>>2]=vb[c[(c[d>>2]|0)+12>>2]&63](d,c[e+8>>2]|0,c[f+8>>2]|0)|0;a[b+8>>0]=1;return b|0}function rl(a){a=a|0;var b=0,d=0,e=0,f=0.0,h=0.0;e=c[a+232>>2]|0;if((e|0)<=0)return;a=c[a+240>>2]|0;d=0;do{b=c[a+(d<<2)>>2]|0;switch(c[b+216>>2]|0){case 2:case 5:break;default:if(!(c[b+204>>2]&3)){h=+g[b+368>>2]*+g[b+352>>2];f=+g[b+372>>2]*+g[b+356>>2];g[b+412>>2]=+g[b+364>>2]*+g[b+348>>2]+ +g[b+412>>2];g[b+416>>2]=h+ +g[b+416>>2];g[b+420>>2]=f+ +g[b+420>>2]}}d=d+1|0}while((d|0)!=(e|0));return}function sl(a,b){a=a|0;b=b|0;var c=0,d=0.0,e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0,m=0.0;c=l;l=l+16|0;m=+g[a+12>>2];i=+g[(bH(b)|0)>>2];j=+g[a>>2];k=+g[b+12>>2];h=+g[a+4>>2];d=+g[(HG(b)|0)>>2];e=+g[a+8>>2];f=+g[(IG(b)|0)>>2];g[c+12>>2]=m*i+j*k+h*d-e*f;g[c+8>>2]=m*f+h*k+e*i-j*d;g[c+4>>2]=m*d+e*k+j*f-h*i;g[c>>2]=m*k-j*i-h*f-e*d;ir(a,c+12|0,c+8|0,c+4|0,c);l=c;return a|0}function tl(b){b=b|0;var d=0;d=Wr()|0;c[d+8>>2]=0;c[d+12>>2]=1065353216;c[d+16>>2]=1065353216;c[d+20>>2]=1065353216;g[d+24>>2]=0.0;g[d+44>>2]=.03999999910593033;c[d+52>>2]=0;c[d+56>>2]=1065353216;c[d+60>>2]=1065353216;c[d+64>>2]=1065353216;g[d+68>>2]=0.0;c[d+72>>2]=-1082130432;c[d+76>>2]=-1082130432;c[d+80>>2]=-1082130432;g[d+84>>2]=0.0;a[d+88>>0]=0;c[d>>2]=7816;c[d+92>>2]=b;c[d+4>>2]=3;ej(d);return d|0}function ul(a,b){a=a|0;b=+b;var d=0.0,e=0.0,f=0.0,h=0.0,i=0.0;h=+zb[c[(c[a>>2]|0)+48>>2]&15](a);e=+zb[c[(c[a>>2]|0)+48>>2]&15](a);i=+zb[c[(c[a>>2]|0)+48>>2]&15](a);h=h+ +g[a+28>>2];e=e+ +g[a+32>>2];i=i+ +g[a+36>>2];g[a+44>>2]=b;f=+zb[c[(c[a>>2]|0)+48>>2]&15](a);d=+zb[c[(c[a>>2]|0)+48>>2]&15](a);b=i-+zb[c[(c[a>>2]|0)+48>>2]&15](a);g[a+28>>2]=h-f;g[a+32>>2]=e-d;g[a+36>>2]=b;g[a+40>>2]=0.0;return}function vl(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;if((c[a+8>>2]|0)<=0)return;g=0;a:while(1){while(1){e=c[a+16>>2]|0;f=e+(g<<4)|0;if(!(Gb[c[(c[b>>2]|0)+8>>2]&31](b,f)|0))break;pb[c[(c[a>>2]|0)+12>>2]&31](a,c[f>>2]|0,c[e+(g<<4)+4>>2]|0,d)|0;c[6160]=(c[6160]|0)+-1;if((g|0)>=(c[a+8>>2]|0)){e=7;break a}}g=g+1|0;if((g|0)>=(c[a+8>>2]|0)){e=7;break}}if((e|0)==7)return}function wl(b,d,e,f,g){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0;g=(a[b+16>>0]|0)!=0;h=c[(g?e:d)+8>>2]|0;e=g?d:e;g=c[e+8>>2]|0;b=c[h+268>>2]|0;a:do if((b|0)>0){d=c[h+276>>2]|0;f=0;while(1){if((c[d+(f<<2)>>2]|0)==(g|0))break;f=f+1|0;if((f|0)>=(b|0))break a}if((f|0)!=(b|0))return}while(0);d=c[h+284>>2]|0;Rb[c[(c[d>>2]|0)+36>>2]&127](d,h,e);return}function xl(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0.0,h=0.0,i=0.0,j=0.0,k=0.0;i=+zb[c[(c[a>>2]|0)+48>>2]&15](a);h=+zb[c[(c[a>>2]|0)+48>>2]&15](a);f=+zb[c[(c[a>>2]|0)+48>>2]&15](a);k=+g[b+52>>2]-h;j=+g[b+56>>2]-f;g[d>>2]=+g[b+48>>2]-i;g[d+4>>2]=k;g[d+8>>2]=j;g[d+12>>2]=0.0;h=h+ +g[b+52>>2];f=f+ +g[b+56>>2];g[e>>2]=i+ +g[b+48>>2];g[e+4>>2]=h;g[e+8>>2]=f;g[e+12>>2]=0.0;return}function yl(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0;g=c[d>>2]|0;g=Gb[c[(c[g>>2]|0)+56>>2]&31](g,20)|0;h=c[d+4>>2]|0;b=a[b+4>>0]|0;c[g>>2]=9172;d=c[d>>2]|0;c[g+4>>2]=d;c[g>>2]=6128;a[g+8>>0]=0;c[g+12>>2]=h;a[g+16>>0]=b;if(h|0)return g|0;c[g+12>>2]=vb[c[(c[d>>2]|0)+12>>2]&63](d,c[e+8>>2]|0,c[f+8>>2]|0)|0;a[g+8>>0]=1;return g|0}function zl(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;b=c[d>>2]|0;b=Gb[c[(c[b>>2]|0)+56>>2]&31](b,44)|0;c[b>>2]=9172;c[b+4>>2]=c[d>>2];c[b>>2]=6288;a[b+24>>0]=1;c[b+20>>2]=0;c[b+12>>2]=0;c[b+16>>2]=0;a[b+28>>0]=1;c[b+32>>2]=c[d+4>>2];a[b+36>>0]=0;c[b+40>>2]=c[(c[f+4>>2]|0)+68>>2];Ng(b,e,f);return b|0}function Al(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;g=c[a+720>>2]|0;h=c[a+732>>2]|0;if((h|0)<=0){d=0;return d|0}a=c[a+740>>2]|0;f=0;while(1){e=c[a+(f*52|0)+8>>2]|0;if((e|0)==(g+(b*104|0)|0)?(c[a+(f*52|0)+12>>2]|0)==(g+(d*104|0)|0):0){a=1;e=8;break}if((e|0)==(g+(d*104|0)|0)?(c[a+(f*52|0)+12>>2]|0)==(g+(b*104|0)|0):0){a=1;e=8;break}f=f+1|0;if((f|0)>=(h|0)){a=0;e=8;break}}if((e|0)==8)return a|0;return 0}function Bl(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;b=c[d>>2]|0;b=Gb[c[(c[b>>2]|0)+56>>2]&31](b,44)|0;c[b>>2]=9172;c[b+4>>2]=c[d>>2];c[b>>2]=6288;a[b+24>>0]=1;c[b+20>>2]=0;c[b+12>>2]=0;c[b+16>>2]=0;a[b+28>>0]=0;c[b+32>>2]=c[d+4>>2];a[b+36>>0]=0;c[b+40>>2]=c[(c[e+4>>2]|0)+68>>2];Ng(b,e,f);return b|0}function Cl(a){a=a|0;var b=0,d=0,e=0.0,f=0.0;if((c[a+136>>2]|0)<=0)return;b=0;do{d=c[a+144>>2]|0;c[d+(b*284|0)+32>>2]=c[d+(b*284|0)+204>>2];g[d+(b*284|0)+272>>2]=0.0;f=-+g[d+(b*284|0)+56>>2];e=-+g[d+(b*284|0)+60>>2];g[d+(b*284|0)>>2]=-+g[d+(b*284|0)+52>>2];g[d+(b*284|0)+4>>2]=f;g[d+(b*284|0)+8>>2]=e;g[d+(b*284|0)+12>>2]=0.0;g[d+(b*284|0)+268>>2]=1.0;b=b+1|0}while((b|0)<(c[a+136>>2]|0));return}function Dl(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0;f=c[d>>2]|0;f=Gb[c[(c[f>>2]|0)+56>>2]&31](f,36)|0;g=c[d+4>>2]|0;i=c[b+12>>2]|0;h=c[b+8>>2]|0;e=c[b+16>>2]|0;b=c[b+20>>2]|0;c[f>>2]=9172;c[f+4>>2]=c[d>>2];c[f>>2]=6176;c[f+8>>2]=i;c[f+12>>2]=h;a[f+16>>0]=0;c[f+20>>2]=g;a[f+24>>0]=0;c[f+28>>2]=e;c[f+32>>2]=b;return f|0}function El(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0;f=l;l=l+48|0;c[f>>2]=7152;c[f+4>>2]=b;c[f+8>>2]=c[d>>2];c[f+8+4>>2]=c[d+4>>2];c[f+8+8>>2]=c[d+8>>2];c[f+8+12>>2]=c[d+12>>2];c[f+24>>2]=c[e>>2];c[f+24+4>>2]=c[e+4>>2];c[f+24+8>>2]=c[e+8>>2];c[f+24+12>>2]=c[e+12>>2];a=c[a+48>>2]|0;Vb[c[(c[a>>2]|0)+8>>2]&127](a,f,d,e);l=f;return}function Fl(a,b,d){a=a|0;b=+b;d=d|0;var e=0.0,f=0.0,h=0.0,i=0.0,j=0.0;i=+g[a+28>>2];f=+g[a+32>>2];j=+g[a+36>>2];h=+zb[c[(c[a>>2]|0)+48>>2]&15](a);e=+zb[c[(c[a>>2]|0)+48>>2]&15](a);j=(j+ +zb[c[(c[a>>2]|0)+48>>2]&15](a))*2.0;g[d>>2]=b/12.0*((f+e)*2.0*(f+e)*2.0+j*j);g[d+4>>2]=b/12.0*((i+h)*2.0*(i+h)*2.0+j*j);g[d+8>>2]=b/12.0*((i+h)*2.0*(i+h)*2.0+(f+e)*2.0*(f+e)*2.0);g[d+12>>2]=0.0;return}function Gl(a,b){a=a|0;b=+b;var d=0,e=0.0,f=0.0,h=0.0,i=0.0;d=is()|0;c[d+4>>2]=35;c[d+8>>2]=0;g[d+12>>2]=0.0;c[d>>2]=7172;i=+g[a>>2];h=+g[a+4>>2];f=+g[a+8>>2];a=c[a+12>>2]|0;e=1.0/+C(+(i*i+h*h+f*f));g[d+48>>2]=i*e;g[d+52>>2]=h*e;g[d+56>>2]=f*e;c[d+60>>2]=a;g[d+64>>2]=b;c[d+68>>2]=0;c[d+68+4>>2]=0;c[d+68+8>>2]=0;c[d+68+12>>2]=0;c[d+4>>2]=28;return d|0}function Hl(a,b,c){a=a|0;b=b|0;c=c|0;var d=0;d=l;l=l+32|0;zp(a,+g[b>>2],+g[b+4>>2],+g[b+8>>2]);qp(d,+g[b>>2],+g[b+4>>2],+g[b+8>>2],+g[a+348>>2],+g[a+352>>2],+g[a+356>>2]);Fo(d+16|0,+g[c>>2],+g[c+4>>2],+g[c+8>>2],+g[d>>2],+g[d+4>>2],+g[d+8>>2]);Ep(a,+g[d+16>>2],+g[d+16+4>>2],+g[d+16+8>>2]);l=d;return}function Il(a,b){a=a|0;b=b|0;var d=0;d=l;l=l+64|0;c[d>>2]=1065353216;c[d+4>>2]=0;c[d+4+4>>2]=0;c[d+4+8>>2]=0;c[d+4+12>>2]=0;c[d+20>>2]=1065353216;c[d+24>>2]=0;c[d+24+4>>2]=0;c[d+24+8>>2]=0;c[d+24+12>>2]=0;c[d+40>>2]=1065353216;c[d+44>>2]=0;c[d+48>>2]=c[b>>2];c[d+48+4>>2]=c[b+4>>2];c[d+48+8>>2]=c[b+8>>2];c[d+48+12>>2]=c[b+12>>2];wd(a,d);l=d;return}function Jl(a,b,c,d,e){a=a|0;b=b|0;c=+c;d=+d;e=+e;var f=0,h=0;f=l;l=l+16|0;h=aF(b,0)|0;g[f+8>>2]=+dx(+g[h>>2],+g[h+4>>2],+g[h+8>>2],c,d,e);h=aF(b,1)|0;g[f+4>>2]=+dx(+g[h>>2],+g[h+4>>2],+g[h+8>>2],c,d,e);b=aF(b,2)|0;g[f>>2]=+dx(+g[b>>2],+g[b+4>>2],+g[b+8>>2],c,d,e);Ur(a,f+8|0,f+4|0,f);l=f;return}function Kl(b,d){b=b|0;d=d|0;var e=0,f=0,g=0;if((d|0)==0?1:(c[d+236>>2]&2|0)==0){d=1;return d|0}g=c[b+488>>2]|0;if((g|0)<=0){d=1;return d|0}b=c[b+496>>2]|0;f=0;while(1){e=c[b+(f<<2)>>2]|0;if(a[e+20>>0]|0){if((c[e+28>>2]|0)==(d|0)){b=0;e=8;break}if((c[e+32>>2]|0)==(d|0)){b=0;e=8;break}}f=f+1|0;if((f|0)>=(g|0)){b=1;e=8;break}}if((e|0)==8)return b|0;return 0}function Ll(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0.0,j=0.0;j=+g[a+28>>2];h=+g[a+32>>2];e=+g[a+36>>2];i=+zb[c[(c[a>>2]|0)+48>>2]&15](a);f=+zb[c[(c[a>>2]|0)+48>>2]&15](a);e=e+ +zb[c[(c[a>>2]|0)+48>>2]&15](a);g[d>>2]=+(b&1^1|0)*(j+i)-+(b&1|0)*(j+i);g[d+4>>2]=+(b>>>1&1^1|0)*(h+f)-+(b>>>1&1|0)*(h+f);g[d+8>>2]=+(b>>>2&1^1|0)*e-+(b>>>2&1|0)*e;g[d+12>>2]=0.0;return}function Ml(b,d){b=b|0;d=d|0;if((c[b+16>>2]|0)!=(0-(c[b+76>>2]|0)|0))return;kl(b+4|0);kl(b+64|0);a[b+193>>0]=0;a[b+194>>0]=1;c[b+144>>2]=0;c[b+164>>2]=0;c[b+148>>2]=1;c[b+152>>2]=0;c[b+156>>2]=10;c[b+160>>2]=1;c[b+124>>2]=0;c[b+124+4>>2]=0;c[b+124+8>>2]=0;c[b+168>>2]=0;c[b+168+4>>2]=0;c[b+168+8>>2]=0;c[b+168+12>>2]=0;c[b+168+16>>2]=0;c[b+168+20>>2]=0;return}function Nl(a,b,c,d,e){a=a|0;b=b|0;c=+c;d=+d;e=+e;var f=0,h=0,i=0,j=0;f=l;l=l+16|0;j=aF(b,0)|0;i=aF(b,1)|0;h=aF(b,2)|0;um(f,c,d,e,+g[j>>2],+g[j+4>>2],+g[j+8>>2],+g[i>>2],+g[i+4>>2],+g[i+8>>2],+g[h>>2],+g[h+4>>2],+g[h+8>>2]);pp(a,+g[f>>2],+g[f+4>>2],+g[f+8>>2],+g[b+48>>2],+g[b+52>>2],+g[b+56>>2]);l=f;return}function Ol(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0.0,h=0.0,i=0.0,j=0.0;i=+g[b+28>>2];j=+g[b+32>>2];e=+g[b+36>>2];h=+zb[c[(c[b>>2]|0)+48>>2]&15](b);f=+zb[c[(c[b>>2]|0)+48>>2]&15](b);e=e+ +zb[c[(c[b>>2]|0)+48>>2]&15](b);f=+g[d+4>>2]>=0.0?j+f:-(j+f);e=+g[d+8>>2]>=0.0?e:-e;g[a>>2]=+g[d>>2]>=0.0?i+h:-(i+h);g[a+4>>2]=f;g[a+8>>2]=e;g[a+12>>2]=0.0;return}function Pl(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0.0,h=0.0,i=0.0;if((d|0)<=0)return;e=0;do{i=+g[a+28>>2];h=+g[a+32>>2];h=+g[b+(e<<4)+4>>2]>=0.0?h:-h;f=+g[a+36>>2];f=+g[b+(e<<4)+8>>2]>=0.0?f:-f;g[c+(e<<4)>>2]=+g[b+(e<<4)>>2]>=0.0?i:-i;g[c+(e<<4)+4>>2]=h;g[c+(e<<4)+8>>2]=f;g[c+(e<<4)+12>>2]=0.0;e=e+1|0}while((e|0)!=(d|0));return}function Ql(b){b=b|0;var d=0,e=0;c[b>>2]=6416;d=c[b+64>>2]|0;if(d|0?(Oh(d),e=c[b+64>>2]|0,e|0):0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}d=c[b+24>>2]|0;if(!d){a[b+28>>0]=1;c[b+24>>2]=0;c[b+16>>2]=0;b=b+20|0;c[b>>2]=0;return}if(a[b+28>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+24>>2]=0;a[b+28>>0]=1;c[b+24>>2]=0;c[b+16>>2]=0;b=b+20|0;c[b>>2]=0;return}function Rl(a,b,d,e,f,g,h,i,j,k){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;a=c[a+32>>2]|0;c[d>>2]=c[a+(k<<5)+12>>2];c[b>>2]=c[a+(k<<5)+16>>2];c[e>>2]=c[a+(k<<5)+28>>2];c[f>>2]=c[a+(k<<5)+20>>2];c[i>>2]=c[a+(k<<5)>>2];c[g>>2]=c[a+(k<<5)+4>>2];c[h>>2]=c[a+(k<<5)+8>>2];c[j>>2]=c[a+(k<<5)+24>>2];return}function Sl(b){b=b|0;var d=0,e=0;c[b>>2]=7380;d=c[b+104>>2]|0;if(d|0){if(a[b+108>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+104>>2]=0}a[b+108>>0]=1;c[b+104>>2]=0;c[b+96>>2]=0;c[b+100>>2]=0;c[b>>2]=7248;d=c[b+52>>2]|0;if(d|0?(hb[c[c[d>>2]>>2]&511](d),e=c[b+52>>2]|0,e|0):0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}c[6433]=(c[6433]|0)+1;Pc(c[b+-4>>2]|0);return}function Tl(a,b,d){a=a|0;b=b|0;d=d|0;var e=0;switch(b|0){case 0:{b=0;a=0;e=1065353216;break}case 1:{b=0;a=0;e=-1082130432;break}case 2:{b=0;a=1065353216;e=0;break}case 3:{b=0;a=-1082130432;e=0;break}case 4:{b=1065353216;a=0;e=0;break}case 5:{b=-1082130432;a=0;e=0;break}default:return}c[d>>2]=e;c[d+4>>2]=a;c[d+8>>2]=b;g[d+12>>2]=0.0;return}function Ul(b,d,e,f){b=b|0;d=d|0;e=e|0;f=+f;c[b+4>>2]=c[d>>2];c[b+4+4>>2]=c[d+4>>2];c[b+4+8>>2]=c[d+8>>2];c[b+4+12>>2]=c[d+12>>2];c[b+20>>2]=c[e>>2];c[b+20+4>>2]=c[e+4>>2];c[b+20+8>>2]=c[e+8>>2];c[b+20+12>>2]=c[e+12>>2];g[b+36>>2]=f;a[b+40>>0]=1;return}function Vl(a,e,f){a=a|0;e=e|0;f=f|0;var h=0.0;switch(c[a+96>>2]|0){case 0:{h=+g[(c[a+92>>2]|0)+((O(c[a+64>>2]|0,f)|0)+e<<2)>>2];return +h}case 5:{h=+(d[(c[a+92>>2]|0)+((O(c[a+64>>2]|0,f)|0)+e)>>0]|0)*+g[a+88>>2];return +h}case 3:{h=+(b[(c[a+92>>2]|0)+((O(c[a+64>>2]|0,f)|0)+e<<1)>>1]|0)*+g[a+88>>2];return +h}default:{h=0.0;return +h}}return 0.0}function Wl(a,b){a=a|0;b=b|0;var c=0.0,d=0;d=l;l=l+32|0;c=+g[b+12>>2];if(1.0-c*c<1.1920928955078125e-06){g[d+20>>2]=1.0;g[d+16>>2]=0.0;g[d+12>>2]=0.0;Ur(a,d+20|0,d+16|0,d+12|0);l=d;return}else{c=1.0/+PG(1.0-c*c);g[d+8>>2]=+g[b>>2]*c;g[d+4>>2]=+g[b+4>>2]*c;g[d>>2]=+g[b+8>>2]*c;Ur(a,d+8|0,d+4|0,d);l=d;return}}function Xl(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;d=l;l=l+16|0;c[d>>2]=9100;c[d+4>>2]=e;he(a+4|0,c[a+4>>2]|0,b,e+4|0,e+20|0,+g[e+32>>2],f,h,d);he(a+64|0,c[a+64>>2]|0,b,e+4|0,e+20|0,+g[e+32>>2],f,h,d);l=d;return}function Yl(b){b=b|0;var d=0;c[b>>2]=7380;d=c[b+104>>2]|0;if(d|0){if(a[b+108>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+104>>2]=0}a[b+108>>0]=1;c[b+104>>2]=0;c[b+96>>2]=0;c[b+100>>2]=0;c[b>>2]=7248;d=c[b+52>>2]|0;if(!d)return;hb[c[c[d>>2]>>2]&511](d);d=c[b+52>>2]|0;if(!d)return;c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0);return}function Zl(a,b){a=+a;b=b|0;var d=0,e=0,f=0;h[j>>3]=a;d=c[j>>2]|0;e=c[j+4>>2]|0;f=zt(d|0,e|0,52)|0;switch(f&2047){case 0:{if(a!=0.0){a=+Zl(a*18446744073709551616.0,b);d=(c[b>>2]|0)+-64|0}else d=0;c[b>>2]=d;break}case 2047:break;default:{c[b>>2]=(f&2047)+-1022;c[j>>2]=d;c[j+4>>2]=e&-2146435073|1071644672;a=+h[j>>3]}}return +a}function _l(a,b){a=+a;b=+b;var d=0;d=zs()|0;c[d+8>>2]=0;c[d+12>>2]=1065353216;c[d+16>>2]=1065353216;c[d+20>>2]=1065353216;g[d+24>>2]=0.0;g[d+44>>2]=.03999999910593033;g[d+56>>2]=a;g[d+60>>2]=b;c[d+4>>2]=11;g[d+52>>2]=a/+C(+(a*a+b*b));c[d>>2]=6596;c[d+64>>2]=0;c[d+68>>2]=2;c[d+72>>2]=1;g[d+28>>2]=a;g[d+36>>2]=b;g[d+32>>2]=a;return d|0}function $l(a,b){a=+a;b=+b;var d=0;d=zs()|0;c[d+8>>2]=0;c[d+12>>2]=1065353216;c[d+16>>2]=1065353216;c[d+20>>2]=1065353216;g[d+24>>2]=0.0;g[d+44>>2]=.03999999910593033;g[d+56>>2]=a;g[d+60>>2]=b;c[d+4>>2]=11;g[d+52>>2]=a/+C(+(a*a+b*b));c[d>>2]=6696;c[d+64>>2]=1;c[d+68>>2]=0;c[d+72>>2]=2;g[d+32>>2]=a;g[d+28>>2]=b;g[d+36>>2]=a;return d|0}function am(a,b){a=+a;b=+b;var d=0;d=zs()|0;c[d+8>>2]=0;c[d+12>>2]=1065353216;c[d+16>>2]=1065353216;c[d+20>>2]=1065353216;g[d+24>>2]=0.0;g[d+44>>2]=.03999999910593033;c[d>>2]=6496;g[d+56>>2]=a;g[d+60>>2]=b;c[d+4>>2]=11;c[d+64>>2]=0;c[d+68>>2]=1;c[d+72>>2]=2;g[d+28>>2]=a;g[d+32>>2]=b;g[d+36>>2]=a;g[d+52>>2]=a/+C(+(a*a+b*b));return d|0}function bm(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0.0,g=0;e=l;l=l+16|0;c[e>>2]=-1;c[e+4>>2]=c[a+16>>2];if(!(c[b+4>>2]|0))c[b+4>>2]=e;g=c[a+12>>2]|0;f=+Hb[c[(c[g>>2]|0)+12>>2]&15](g,b,d);c[a+4>>2]=c[(c[a+12>>2]|0)+4>>2];l=e;return +f}function cm(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=bH(c[a+4>>2]|0)|0;if((e|0)>(b|0)){c[a+4>>2]=b;return}if((e|0)<(b|0))tn(a,b);while(1){if((e|0)>=(b|0))break;f=(c[a+12>>2]|0)+(e*104|0)|0;g=d;h=f+104|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));e=e+1|0}c[a+4>>2]=b;return}function dm(a,b){a=a|0;b=b|0;var d=0;d=l;l=l+16|0;c[a+348>>2]=c[b>>2];c[a+348+4>>2]=c[b+4>>2];c[a+348+8>>2]=c[b+8>>2];c[a+348+12>>2]=c[b+12>>2];Up(d,+g[a+348>>2],+g[a+352>>2],+g[a+356>>2],+g[a+344>>2]);c[a+560>>2]=c[d>>2];c[a+560+4>>2]=c[d+4>>2];c[a+560+8>>2]=c[d+8>>2];c[a+560+12>>2]=c[d+12>>2];l=d;return}function em(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0;g=c[a+268>>2]|0;if((g|0)<=0)return;b=c[b>>2]|0;f=c[a+276>>2]|0;d=0;while(1){e=f+(d<<2)|0;if((c[e>>2]|0)==(b|0))break;d=d+1|0;if((d|0)>=(g|0)){h=7;break}}if((h|0)==7)return;if((d|0)>=(g|0))return;c[e>>2]=c[f+(g+-1<<2)>>2];c[a+268>>2]=g+-1;return}function fm(a,b,c,d){a=a|0;b=+b;c=+c;d=+d;var e=0,f=0.0,h=0.0,i=0.0;e=l;l=l+16|0;f=+RG(b*.5);b=+QG(b*.5);h=+RG(c*.5);c=+QG(c*.5);i=+RG(d*.5);d=+QG(d*.5);g[e+12>>2]=d*h*f-i*c*b;g[e+8>>2]=i*c*f+d*h*b;g[e+4>>2]=i*h*b-d*c*f;g[e>>2]=i*h*f+d*c*b;ir(a,e+12|0,e+8|0,e+4|0,e);l=e;return}function gm(a){a=a|0;var b=0;b=l;l=l+32|0;g[a>>2]=1.2000000476837158;g[a+4>>2]=0.0;g[a+8>>2]=0.0;g[a+12>>2]=1.0e3;g[b+20>>2]=0.0;g[b+16>>2]=0.0;g[b+12>>2]=0.0;Ur(a+16|0,b+20|0,b+16|0,b+12|0);c[a+32>>2]=0;c[a+36>>2]=0;g[b+8>>2]=0.0;g[b+4>>2]=-10.0;g[b>>2]=0.0;Ur(a+40|0,b+8|0,b+4|0,b);JA(a+56|0);l=b;return}function hm(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;b=c[d>>2]|0;b=Gb[c[(c[b>>2]|0)+56>>2]&31](b,16)|0;c[b>>2]=9172;d=c[d>>2]|0;c[b+4>>2]=d;c[b>>2]=9408;a[b+8>>0]=0;c[b+12>>2]=0;c[b+12>>2]=vb[c[(c[d>>2]|0)+12>>2]&63](d,c[e+8>>2]|0,c[f+8>>2]|0)|0;a[b+8>>0]=1;return b|0}function im(b,e){b=b|0;e=e|0;var f=0,g=0;f=0;while(1){if((d[20073+f>>0]|0)==(b|0)){g=2;break}f=f+1|0;if((f|0)==87){f=87;b=20161;g=5;break}}if((g|0)==2)if(!f)f=20161;else{b=20161;g=5}if((g|0)==5)while(1){do{g=b;b=b+1|0}while((a[g>>0]|0)!=0);f=f+-1|0;if(!f){f=b;break}else g=5}return lF(f,c[e+20>>2]|0)|0}function jm(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=+h;c[a>>2]=b;c[a+4>>2]=d;c[a+8>>2]=c[e>>2];c[a+8+4>>2]=c[e+4>>2];c[a+8+8>>2]=c[e+8>>2];c[a+8+12>>2]=c[e+12>>2];c[a+24>>2]=c[f>>2];c[a+24+4>>2]=c[f+4>>2];c[a+24+8>>2]=c[f+8>>2];c[a+24+12>>2]=c[f+12>>2];g[a+40>>2]=h;return}function km(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;f=c[a+280>>2]|0;if((f|0)<=0)return;g=c[a+288>>2]|0;d=0;while(1){e=g+(d<<2)|0;if((c[e>>2]|0)==(b|0))break;d=d+1|0;if((d|0)>=(f|0)){h=7;break}}if((h|0)==7)return;if((d|0)>=(f|0))return;c[e>>2]=c[g+(f+-1<<2)>>2];c[(c[a+288>>2]|0)+(f+-1<<2)>>2]=b;c[a+280>>2]=f+-1;return}function lm(){var b=0;b=l;l=l+48|0;if(a[22608]|0){l=b;return}if(!(jy(22608)|0)){l=b;return}g[b+32>>2]=1.0;g[b+28>>2]=0.0;g[b+24>>2]=0.0;g[b+20>>2]=0.0;g[b+16>>2]=1.0;g[b+12>>2]=0.0;g[b+8>>2]=0.0;g[b+4>>2]=0.0;g[b>>2]=1.0;Xp(22912,b+32|0,b+28|0,b+24|0,b+20|0,b+16|0,b+12|0,b+8|0,b+4|0,b);l=b;return}function mm(){var b=0,e=0,f=0;f=l;l=l+16|0;a[f>>0]=10;b=c[2401]|0;if(!b)if(!(eo(9588)|0)){b=c[2401]|0;e=4}else b=-1;else e=4;do if((e|0)==4){e=c[2402]|0;if(!(e>>>0>=b>>>0|(a[9663]|0)==10)){c[2402]=e+1;a[e>>0]=10;b=10;break}if((vb[c[9624>>2]&63](9588,f,1)|0)==1)b=d[f>>0]|0;else b=-1}while(0);l=f;return b|0}function nm(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0.0,g=0;e=l;l=l+16|0;c[e>>2]=-1;c[e+4>>2]=c[a+24>>2];if(!(c[b+4>>2]|0))c[b+4>>2]=e;g=c[a+20>>2]|0;f=+Hb[c[(c[g>>2]|0)+12>>2]&15](g,b,d);c[a+4>>2]=c[(c[a+20>>2]|0)+4>>2];l=e;return +f}function om(a,b,c){a=a|0;b=b|0;c=+c;var d=0,e=0.0;d=l;l=l+16|0;e=+dz(+g[b>>2],+g[b+4>>2],+g[b+8>>2]);e=+QG(c*.5)/e;g[d+12>>2]=+g[(bH(b)|0)>>2]*e;g[d+8>>2]=+g[(IG(b)|0)>>2]*e;g[d+4>>2]=+g[(HG(b)|0)>>2]*e;g[d>>2]=+RG(c*.5);ir(a,d+12|0,d+8|0,d+4|0,d);l=d;return}function pm(a,b){a=a|0;b=b|0;c[a>>2]=c[b>>2];c[a+4>>2]=c[b+4>>2];c[a+8>>2]=c[b+8>>2];c[a+12>>2]=c[b+12>>2];c[a+16>>2]=c[b+16>>2];c[a+16+4>>2]=c[b+16+4>>2];c[a+16+8>>2]=c[b+16+8>>2];c[a+16+12>>2]=c[b+16+12>>2];c[a+32>>2]=c[b+32>>2];c[a+32+4>>2]=c[b+32+4>>2];c[a+32+8>>2]=c[b+32+8>>2];c[a+32+12>>2]=c[b+32+12>>2];return}function qm(a,b,c){a=a|0;b=b|0;c=c|0;var d=0.0;a:do switch(b|0){case 2:case 1:{if(c>>>0<3){d=+g[a+600>>2];break a}if((c+-3|0)>>>0<3)d=+g[a+432>>2];else d=0.0;break}case 4:case 3:{if(c>>>0<3){d=+g[a+596>>2];break a}if((c+-3|0)>>>0<3)d=+g[a+604>>2];else d=0.0;break}default:d=0.0}while(0);return +d}function rm(b,c,d){b=b|0;c=c|0;d=d|0;var e=0;if(c>>>0>0|(c|0)==0&b>>>0>4294967295)while(1){e=yr(b|0,c|0,10,0)|0;d=d+-1|0;a[d>>0]=e&255|48;e=b;b=Nz(b|0,c|0,10,0)|0;if(!(c>>>0>9|(c|0)==9&e>>>0>4294967295))break;else c=z}if(b)while(1){d=d+-1|0;a[d>>0]=(b>>>0)%10|0|48;if(b>>>0<10)break;else b=(b>>>0)/10|0}return d|0}function sm(a,b){a=a|0;b=b|0;var d=0,e=0;d=c[a+56>>2]|0;if(!d)return;e=lb[c[(c[d>>2]|0)+8>>2]&127](d)|0;e=vb[c[(c[b>>2]|0)+16>>2]&63](b,e,1)|0;d=c[a+56>>2]|0;d=vb[c[(c[d>>2]|0)+12>>2]&63](d,c[e+8>>2]|0,b)|0;fb[c[(c[b>>2]|0)+20>>2]&31](b,e,d,1346456916,c[a+56>>2]|0);return}function tm(a,b){a=a|0;b=b|0;var d=0,e=0;d=c[a+52>>2]|0;if(!d)return;e=lb[c[(c[d>>2]|0)+12>>2]&127](d)|0;e=vb[c[(c[b>>2]|0)+16>>2]&63](b,e,1)|0;d=c[a+52>>2]|0;d=vb[c[(c[d>>2]|0)+16>>2]&63](d,c[e+8>>2]|0,b)|0;fb[c[(c[b>>2]|0)+20>>2]&31](b,e,d,1213612625,c[a+52>>2]|0);return}function um(a,b,c,d,e,f,h,i,j,k,m,n,o){a=a|0;b=+b;c=+c;d=+d;e=+e;f=+f;h=+h;i=+i;j=+j;k=+k;m=+m;n=+n;o=+o;var p=0;p=l;l=l+16|0;g[p+8>>2]=+dx(b,c,d,e,f,h);g[p+4>>2]=+dx(b,c,d,i,j,k);g[p>>2]=+dx(b,c,d,m,n,o);Ur(a,p+8|0,p+4|0,p);l=p;return}function vm(a,b,c){a=a|0;b=b|0;c=+c;var d=0.0,e=0.0,f=0.0,h=0.0;e=+g[a+28>>2];f=+g[a+32>>2];h=+g[a+36>>2];d=+g[b>>2];if(!(d<=e+c)){b=0;return b|0}if(!(d>=-e-c)){b=0;return b|0}d=+g[b+4>>2];if(!(d<=f+c)){b=0;return b|0}if(!(d>=-f-c)){b=0;return b|0}d=+g[b+8>>2];if(!(d<=h+c)){b=0;return b|0}b=d>=-h-c;return b|0}function wm(a,b,d){a=a|0;b=b|0;d=d|0;gv(a);c[a>>2]=3076;c[a+12>>2]=c[b>>2];c[a+12+4>>2]=c[b+4>>2];c[a+12+8>>2]=c[b+8>>2];c[a+12+12>>2]=c[b+12>>2];c[a+28>>2]=c[d>>2];c[a+28+4>>2]=c[d+4>>2];c[a+28+8>>2]=c[d+8>>2];c[a+28+12>>2]=c[d+12>>2];c[a+76>>2]=0;return}function xm(b,d,e,f){b=b|0;d=d|0;e=e|0;f=+f;if(!(+g[b+36>>2]>f))return;a[b+40>>0]=1;c[b+4>>2]=c[d>>2];c[b+4+4>>2]=c[d+4>>2];c[b+4+8>>2]=c[d+8>>2];c[b+4+12>>2]=c[d+12>>2];c[b+20>>2]=c[e>>2];c[b+20+4>>2]=c[e+4>>2];c[b+20+8>>2]=c[e+8>>2];c[b+20+12>>2]=c[e+12>>2];g[b+36>>2]=f;return}function ym(a,b,c){a=a|0;b=b|0;c=c|0;var d=0.0,e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0;d=+g[b+28>>2];i=+g[b+36>>2];j=+g[c>>2];e=+g[c+4>>2];k=+C(+(j*j+e*e));f=+g[c+8>>2];if(k!=0.0){h=e*(d/k);e=f<0.0?-i:i;d=j*(d/k)}else{h=0.0;e=f<0.0?-i:i}g[a>>2]=d;g[a+8>>2]=e;g[a+4>>2]=h;return}function zm(a,b,c){a=a|0;b=b|0;c=c|0;var d=0.0,e=0.0,f=0.0,h=0.0,i=0.0,j=0.0,k=0.0;d=+g[b+28>>2];i=+g[b+32>>2];j=+g[c>>2];e=+g[c+8>>2];k=+C(+(j*j+e*e));f=+g[c+4>>2];if(k!=0.0){h=e*(d/k);e=f<0.0?-i:i;d=j*(d/k)}else{h=0.0;e=f<0.0?-i:i}g[a>>2]=d;g[a+4>>2]=e;g[a+8>>2]=h;return}function Am(a,b,c){a=a|0;b=b|0;c=c|0;var d=0.0,e=0.0,f=0.0,h=0.0,i=0.0,j=0.0;d=+g[b+32>>2];f=+g[b+28>>2];i=+g[c+4>>2];e=+g[c+8>>2];j=+C(+(i*i+e*e));if(j!=0.0){h=e*(d/j);e=+g[c>>2]<0.0?-f:f;d=i*(d/j)}else{h=0.0;e=+g[c>>2]<0.0?-f:f}g[a+4>>2]=d;g[a>>2]=e;g[a+8>>2]=h;return}function Bm(a,b){a=a|0;b=+b;var c=0,d=0.0;c=l;l=l+16|0;if(!(+g[a+68>>2]>0.0)){l=c;return}d=-+g[a+92>>2];b=-+g[a+96>>2];g[c>>2]=-+g[a+88>>2];g[c+4>>2]=d;g[c+8>>2]=b;g[c+12>>2]=0.0;Ki(a+4|0,c,a+164|0);Ki(a+16|0,a+88|0,a+180|0);l=c;return}function Cm(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0.0,f=0,g=0;if((d|0)>-1|(d|0)==-1&c>>>0>4294967295){e=(+(c>>>0)+4294967296.0*+(d>>>0))*18446744073709551616.0+(+(a>>>0)+4294967296.0*+(b>>>0));return +e}else{g=St(0,0,a|0,b|0)|0;f=z;d=xv((a|0)==0&(b|0)==0&1|0,0,~c|0,~d|0)|0;e=-+Cm(g,f,d,z);return +e}return 0.0}function Dm(a){a=a|0;var b=0.0,d=0.0,e=0.0;d=+g[(c[a+28>>2]|0)+344>>2];e=+g[(c[a+32>>2]|0)+344>>2];e=e==0.0?1.0:d/(d+e);d=+g[a+1116>>2]*e+(1.0-e)*+g[a+1180>>2];b=e*+g[a+1120>>2]+(1.0-e)*+g[a+1184>>2];g[a+1284>>2]=+g[a+1112>>2]*e+ +g[a+1176>>2]*(1.0-e);g[a+1288>>2]=d;g[a+1292>>2]=b;g[a+1296>>2]=0.0;return}function Em(a,d){a=a|0;d=d|0;var e=0,f=0,g=0;if(b[a+56>>1]|0)return;b[a+64>>1]=1;d=b[a+58>>1]|0;g=c[a+60>>2]|0;if((d&65535)>1){e=1;d=1;while(1){b[g+(e<<6)+48>>1]=e+1;f=d+1<<16>>16;d=b[a+58>>1]|0;if((f&65535)<(d&65535)){e=f&65535;d=f}else break}}b[g+((d&65535)+-1<<6)+48>>1]=0;return}function Fm(b,d,e){b=b|0;d=d|0;e=e|0;var f=0;f=c[b+16>>2]|0;do if(f){if((f|0)!=(d|0)){c[b+36>>2]=(c[b+36>>2]|0)+1;c[b+24>>2]=2;a[b+54>>0]=1;break}if((c[b+24>>2]|0)==2)c[b+24>>2]=e}else{c[b+16>>2]=d;c[b+24>>2]=e;c[b+36>>2]=1}while(0);return}function Gm(a,d){a=a|0;d=d|0;var e=0,f=0;e=c[d>>2]|0;f=c[a+80>>2]|0;if((e|0)==(f|0)){a=0;return a|0}if(!((b[a+10>>1]&b[d+4>>1])<<16>>16)){a=0;return a|0}if(!((b[d+6>>1]&b[a+8>>1])<<16>>16)){a=0;return a|0}a=c[a+92>>2]|0;a=vb[c[(c[a>>2]|0)+28>>2]&63](a,f,e)|0;return a|0}function Hm(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;f=c[a+8>>2]|0;a=c[f+8>>2]|0;if((a|0)<=0)return;e=0;do{d=c[(c[f+16>>2]|0)+(e*12|0)+8>>2]|0;if(d){jb[c[(c[d>>2]|0)+16>>2]&127](d,b);a=c[f+8>>2]|0}e=e+1|0}while((e|0)<(a|0));return}function Im(a,b,d,e){a=a|0;b=b|0;d=+d;e=e|0;switch(e|0){case 5:case -1:break;default:return}switch(b|0){case 2:{g[a+760>>2]=d;c[a+748>>2]=c[a+748>>2]|2;return}case 4:{g[a+756>>2]=d;c[a+748>>2]=c[a+748>>2]|1;return}case 3:{g[a+752>>2]=d;c[a+748>>2]=c[a+748>>2]|4;return}default:return}}function Jm(a,b,d){a=a|0;b=b|0;d=d|0;Js(a);c[a>>2]=2904;c[a+20>>2]=c[b>>2];c[a+20+4>>2]=c[b+4>>2];c[a+20+8>>2]=c[b+8>>2];c[a+20+12>>2]=c[b+12>>2];c[a+36>>2]=c[d>>2];c[a+36+4>>2]=c[d+4>>2];c[a+36+8>>2]=c[d+8>>2];c[a+36+12>>2]=c[d+12>>2];return}function Km(){var b=0,d=0,e=0;do if((c[2416]|0)>=0?(fH()|0)!=0:0){if((a[9663]|0)!=10?(d=c[2402]|0,d>>>0<(c[2401]|0)>>>0):0){c[2402]=d+1;a[d>>0]=10;break}mm()|0}else e=3;while(0);do if((e|0)==3){if((a[9663]|0)!=10?(b=c[2402]|0,b>>>0<(c[2401]|0)>>>0):0){c[2402]=b+1;a[b>>0]=10;break}mm()|0}while(0);return}function Lm(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0;f=c[d>>2]|0;a=Tw(c[b>>2]|0)|0;f=Tw(f)|0;if(a|0)Vb[c[(c[a>>2]|0)+32>>2]&127](a,d,e,b);if(!f)return 0;Vb[c[(c[f>>2]|0)+32>>2]&127](f,b,e,d);return 0}function Mm(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=l;l=l+48|0;f=c[b+192>>2]|0;Vb[c[(c[f>>2]|0)+8>>2]&127](f,b+4|0,e+32|0,e+16|0);c[e>>2]=6080;c[e+4>>2]=b;c[e+8>>2]=a;c[e+12>>2]=d;a=c[a+68>>2]|0;Vb[c[(c[a>>2]|0)+28>>2]&127](a,e+32|0,e+16|0,e);l=e;return}function Nm(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0;f=l;l=l+256|0;if((c|0)>(d|0)&(e&73728|0)==0){Hk(f|0,b|0,((c-d|0)>>>0<256?c-d|0:256)|0)|0;if((c-d|0)>>>0>255){b=c-d|0;do{vy(a,f,256);b=b+-256|0}while(b>>>0>255);b=c-d&255}else b=c-d|0;vy(a,f,b)}l=f;return}function Om(a,b,d){a=a|0;b=b|0;d=d|0;a:do switch(c[b+216>>2]|0){case 2:case 5:{switch(c[d+216>>2]|0){case 2:case 5:{b=0;break}default:break a}return b|0}default:{}}while(0);if(c[b+256>>2]|0?!(Gb[c[c[b>>2]>>2]&31](b,d)|0):0){a=0;return a|0}a=1;return a|0}function Pm(a,b,d){a=a|0;b=b|0;d=d|0;Sh(a,b,d)|0;c[b+52>>2]=c[a+300>>2];c[b+56>>2]=c[a+304>>2];c[b+60>>2]=c[a+308>>2];c[b+64>>2]=c[a+312>>2];c[b+68>>2]=c[a+316>>2];c[b+72>>2]=c[a+320>>2];c[b+76>>2]=c[a+324>>2];c[b+80>>2]=c[a+328>>2];return 12717}function Qm(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;f=l;l=l+112|0;d=bH(c[b+4>>2]|0)|0;e=f;g=e+104|0;do{c[e>>2]=0;e=e+4|0}while((e|0)<(g|0));RE(f);cm(a,d,f);Sn(b,d,c[a+12>>2]|0);l=f;return}function Rm(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0;j=bH(b)|0;i=bH(b+16|0)|0;h=bH(b+32|0)|0;g=IG(b)|0;f=IG(b+16|0)|0;e=IG(b+32|0)|0;d=HG(b)|0;c=HG(b+16|0)|0;Xp(a,j,i,h,g,f,e,d,c,HG(b+32|0)|0);return}function Sm(a,b){a=a|0;b=b|0;var d=0;if(c[b+40>>2]|0){Sm(a,c[b+36>>2]|0);Sm(a,c[b+40>>2]|0)}if((c[a>>2]|0)==(b|0))c[a>>2]=0;d=c[a+4>>2]|0;if(!d){c[a+4>>2]=b;return}c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0);c[a+4>>2]=b;return}function Tm(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0;g=c[a+32>>2]|0;c[g>>2]=(c[g>>2]|0)+1;ag(a,xd(a,b,f)|0);ag(a,xd(a,d,f)|0);ag(a,xd(a,e,f)|0);return}function Um(a,b,d,e,f,g){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;if(HB(a,c[b+8>>2]|0)|0)Wk(b,d,e,f);else{a=c[a+8>>2]|0;xb[c[(c[a>>2]|0)+20>>2]&7](a,b,d,e,f,g)}return}function Vm(a){a=a|0;var b=0;b=l;l=l+48|0;g[b+32>>2]=1.0;g[b+28>>2]=0.0;g[b+24>>2]=0.0;g[b+20>>2]=0.0;g[b+16>>2]=1.0;g[b+12>>2]=0.0;g[b+8>>2]=0.0;g[b+4>>2]=0.0;g[b>>2]=1.0;Oo(a,b+32|0,b+28|0,b+24|0,b+20|0,b+16|0,b+12|0,b+8|0,b+4|0,b);l=b;return}function Wm(a,b){a=a|0;b=b|0;var d=0,e=0;c[a+68>>2]=(c[a+68>>2]|0)+1;d=c[a+16>>2]|0;if((d|0)>0)do{e=d;d=d+-1|0;if((c[(c[a+24>>2]|0)+(d*80|0)+64>>2]|0)==(b|0))ee(a,d)}while((e|0)>1);hb[c[(c[a>>2]|0)+68>>2]&511](a);return}function Xm(a,b){a=+a;b=+b;var d=0;d=Ds()|0;c[d+8>>2]=0;c[d+12>>2]=1065353216;c[d+16>>2]=1065353216;c[d+20>>2]=1065353216;g[d+24>>2]=0.0;g[d+44>>2]=.03999999910593033;c[d+4>>2]=10;c[d>>2]=7716;c[d+52>>2]=2;g[d+28>>2]=a;g[d+32>>2]=a;g[d+36>>2]=b*.5;g[d+40>>2]=0.0;return d|0}function Ym(a,b){a=+a;b=+b;var d=0;d=Ds()|0;c[d+8>>2]=0;c[d+12>>2]=1065353216;c[d+16>>2]=1065353216;c[d+20>>2]=1065353216;g[d+24>>2]=0.0;g[d+44>>2]=.03999999910593033;c[d+4>>2]=10;c[d>>2]=7616;c[d+52>>2]=0;g[d+28>>2]=b*.5;g[d+32>>2]=a;g[d+36>>2]=a;g[d+40>>2]=0.0;return d|0}function Zm(a,b){a=+a;b=+b;var d=0;d=Ds()|0;c[d+8>>2]=0;c[d+12>>2]=1065353216;c[d+16>>2]=1065353216;c[d+20>>2]=1065353216;g[d+24>>2]=0.0;g[d+44>>2]=.03999999910593033;c[d>>2]=7516;c[d+4>>2]=10;c[d+52>>2]=1;g[d+28>>2]=a;g[d+32>>2]=b*.5;g[d+36>>2]=a;g[d+40>>2]=0.0;return d|0}function _m(a,b,c){a=a|0;b=b|0;c=c|0;var d=0.0;a:do switch(c|0){case 5:case -1:switch(b|0){case 2:{d=+g[a+760>>2];break a}case 4:{d=+g[a+756>>2];break a}case 3:{d=+g[a+752>>2];break a}default:{d=0.0;break a}}default:d=0.0}while(0);return +d}function $m(a,b,d,e){a=a|0;b=b|0;d=+d;e=e|0;switch(b|0){case 2:case 1:if(e>>>0<3){g[a+600>>2]=d;c[a+592>>2]=c[a+592>>2]|2;return}else{g[a+432>>2]=d;return}case 4:case 3:{g[(e>>>0<3?a+596|0:a+604|0)>>2]=d;c[a+592>>2]=c[a+592>>2]|(e>>>0<3?1:4);return}default:return}}function an(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0;f=l;l=l+16|0;c[f>>2]=a;c[f+4>>2]=e;a=c[a+72+((c[(c[b+4>>2]|0)+4>>2]|0)*144|0)+(c[(c[d+4>>2]|0)+4>>2]<<2)>>2]|0;a=pb[c[(c[a>>2]|0)+8>>2]&31](a,f,b,d)|0;l=f;return a|0}function bn(a,b){a=a|0;b=b|0;var d=0;a=c[a+64>>2]|0;if(!b)return;d=c[a+16>>2]|0;if(d>>>0<=b>>>0?(d+(O(c[a>>2]|0,c[a+4>>2]|0)|0)|0)>>>0>b>>>0:0){c[b>>2]=c[a+12>>2];c[a+12>>2]=b;c[a+8>>2]=(c[a+8>>2]|0)+1;return}c[6433]=(c[6433]|0)+1;Pc(c[b+-4>>2]|0);return}function cn(a){a=a|0;var b=0,d=0;if((c[a+232>>2]|0)<=0)return;b=0;do{d=(c[(c[a+240>>2]|0)+(b<<2)>>2]|0)+412|0;c[d>>2]=0;c[d+4>>2]=0;c[d+8>>2]=0;c[d+12>>2]=0;c[d+16>>2]=0;c[d+20>>2]=0;c[d+24>>2]=0;c[d+28>>2]=0;b=b+1|0}while((b|0)<(c[a+232>>2]|0));return}function dn(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=c[a+12>>2]|0;if((d|0)<=0)return;f=0;do{e=c[(c[a+20>>2]|0)+(f<<2)>>2]|0;if(e){jb[c[(c[e>>2]|0)+16>>2]&127](e,b);d=c[a+12>>2]|0}f=f+1|0}while((f|0)<(d|0));return}function en(a,b,d){a=a|0;b=b|0;d=d|0;var e=0;e=bH(c[a+4>>2]|0)|0;if((e|0)>(b|0)){c[a+4>>2]=b;return}if((e|0)<(b|0))mn(a,b);while(1){if((e|0)>=(b|0))break;c[(c[a+12>>2]|0)+(e<<2)>>2]=c[d>>2];e=e+1|0}c[a+4>>2]=b;return}function fn(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0;f=c[a+32>>2]|0;c[f>>2]=(c[f>>2]|0)+1;ag(a,xd(a,b,0)|0);ag(a,xd(a,d,0)|0);ag(a,xd(a,e,0)|0);return}function gn(a,b,d){a=a|0;b=b|0;d=d|0;c[a+52>>2]=c[b>>2];c[a+52+4>>2]=c[b+4>>2];c[a+52+8>>2]=c[b+8>>2];c[a+52+12>>2]=c[b+12>>2];c[a+68>>2]=c[d>>2];c[a+68+4>>2]=c[d+4>>2];c[a+68+8>>2]=c[d+8>>2];c[a+68+12>>2]=c[d+12>>2];c[a+48>>2]=1;return}function hn(a,b,d){a=a|0;b=b|0;d=d|0;var e=0;e=c[d>>2]|0;a=Tw(c[b>>2]|0)|0;e=Tw(e)|0;if(a|0)Rb[c[(c[a>>2]|0)+28>>2]&127](a,d,b);if(!e)return 0;Rb[c[(c[e>>2]|0)+28>>2]&127](e,b,d);return 0}function jn(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=a;e=b;f=d+104|0;do{c[d>>2]=c[e>>2];d=d+4|0;e=e+4|0}while((d|0)<(f|0));Eu(a+104|0,b+104|0);Fu(a+124|0,b+124|0);Fu(a+144|0,b+144|0);return}function kn(a,b,c){a=+a;b=b|0;c=c|0;var d=0,e=0;e=l;l=l+32|0;d=Br(140)|0;g[e+8>>2]=0.0;g[e+4>>2]=0.0;g[e>>2]=0.0;Ur(e+16|0,e+8|0,e+4|0,e);Pk(d,a,b,c,e+16|0);l=e;return d|0}function ln(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;c[d>>2]=c[b+16>>2];c[d+4>>2]=c[b+16+4>>2];c[d+8>>2]=c[b+16+8>>2];c[d+12>>2]=c[b+16+12>>2];c[e>>2]=c[b+32>>2];c[e+4>>2]=c[b+32+4>>2];c[e+8>>2]=c[b+32+8>>2];c[e+12>>2]=c[b+32+12>>2];return}function mn(b,d){b=b|0;d=d|0;var e=0;if((bH(c[b+8>>2]|0)|0)>=(d|0))return;e=ys(d)|0;yq(b,bH(c[b+4>>2]|0)|0,e);Zr(b);a[b+16>>0]=1;c[b+12>>2]=e;c[b+8>>2]=d;return}function nn(a,b,d,e,f,g){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0,i=0;h=c[a+4>>2]|0;if(!(h&1))i=h>>8;else i=c[(c[e>>2]|0)+(h>>8)>>2]|0;a=c[a>>2]|0;xb[c[(c[a>>2]|0)+20>>2]&7](a,b,d,e+i|0,h&2|0?f:2,g);return}function on(a,b){a=a|0;b=b|0;var d=0;a=c[a+64>>2]|0;d=c[a+8>>2]|0;if(d|0){b=c[a+12>>2]|0;c[a+12>>2]=c[b>>2];c[a+8>>2]=d+-1;return b|0}c[6432]=(c[6432]|0)+1;a=ec(b+19|0)|0;if(!a){b=0;return b|0}c[(a+4+15&-16)+-4>>2]=a;b=a+4+15&-16;return b|0}function pn(a,b,c,d,e,f){a=a|0;b=+b;c=+c;d=+d;e=+e;f=+f;g[a+692>>2]=(c-b)*.5;c=+Vg((c-b)*.5+b,6.2831854820251465);if(!(c<-3.1415927410125732)){if(c>3.1415927410125732)c=c+-6.2831854820251465}else c=c+6.2831854820251465;g[a+688>>2]=c;g[a+696>>2]=d;g[a+700>>2]=e;g[a+704>>2]=f;return}function qn(a,b,d){a=a|0;b=+b;d=+d;var e=0;e=l;l=l+16|0;g[e+12>>2]=b;g[e+8>>2]=d;g[e+4>>2]=0.0;g[e>>2]=1.0;c[a+444>>2]=c[(b<0.0?e+4|0:b>1.0?e:e+12|0)>>2];g[e+4>>2]=0.0;g[e>>2]=1.0;c[a+448>>2]=c[(d<0.0?e+4|0:d>1.0?e:e+8|0)>>2];l=e;return}function rn(){var b=0;b=l;l=l+32|0;if(a[22600]|0){l=b;return}if(!(jy(22600)|0)){l=b;return}lm();g[b+8>>2]=0.0;g[b+4>>2]=0.0;g[b>>2]=0.0;Ur(b+16|0,b+8|0,b+4|0,b);$p(22848,22912,b+16|0);l=b;return}function sn(a,b){a=a|0;b=b|0;var d=0,e=0;d=c[(c[b>>2]|0)+16>>2]|0;e=lb[c[(c[a>>2]|0)+16>>2]&127](a)|0;e=vb[d&63](b,e,1)|0;d=vb[c[(c[a>>2]|0)+20>>2]&63](a,c[e+8>>2]|0,b)|0;fb[c[(c[b>>2]|0)+20>>2]&31](b,e,d,1497645650,a);return}function tn(b,d){b=b|0;d=d|0;var e=0;if((bH(c[b+8>>2]|0)|0)>=(d|0))return;e=Us(d)|0;Sn(b,bH(c[b+4>>2]|0)|0,e);Zr(b);a[b+16>>0]=1;c[b+12>>2]=e;c[b+8>>2]=d;return}function un(a,b,c,d){a=a|0;b=+b;c=+c;d=+d;var e=0;e=l;l=l+32|0;Jl(e,bH(a+4|0)|0,b,c,d);qp(e+16|0,+g[e>>2],+g[e+4>>2],+g[e+8>>2],+g[a+348>>2],+g[a+352>>2],+g[a+356>>2]);vr(a+412|0,e+16|0)|0;l=e;return}function vn(a,b,d){a=a|0;b=b|0;d=d|0;c[b>>2]=c[a+52>>2];c[b+4>>2]=c[a+52+4>>2];c[b+8>>2]=c[a+52+8>>2];c[b+12>>2]=c[a+52+12>>2];c[d>>2]=c[a+68>>2];c[d+4>>2]=c[a+68+4>>2];c[d+8>>2]=c[a+68+8>>2];c[d+12>>2]=c[a+68+12>>2];return}function wn(a){a=a|0;var b=0,d=0,e=0;b=c[a+24>>2]|0;if((b|0)<=0)return;e=0;do{d=c[(c[a+32>>2]|0)+(e<<2)>>2]|0;switch(c[d+216>>2]|0){case 2:case 5:break;default:{gg(d);b=c[a+24>>2]|0}}e=e+1|0}while((e|0)<(b|0));return}function xn(a,b){a=a|0;b=b|0;var d=0,e=0;e=lb[c[(c[a>>2]|0)+16>>2]&127](a)|0;e=vb[c[(c[b>>2]|0)+16>>2]&63](b,e,1)|0;d=vb[c[(c[a>>2]|0)+20>>2]&63](a,c[e+8>>2]|0,b)|0;fb[c[(c[b>>2]|0)+20>>2]&31](b,e,d,1245859651,a);return}function yn(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;if(HB(a,c[b+8>>2]|0)|0)Fm(b,d,e);else{a=c[a+8>>2]|0;Vb[c[(c[a>>2]|0)+28>>2]&127](a,b,d,e)}return}function zn(a,b,c){a=a|0;b=b|0;c=+c;var d=0;d=l;l=l+16|0;g[d+12>>2]=+g[(bH(b)|0)>>2]*c;g[d+8>>2]=+g[(IG(b)|0)>>2]*c;g[d+4>>2]=+g[(HG(b)|0)>>2]*c;g[d>>2]=+g[b+12>>2]*c;Vu(a,d+12|0,d+8|0,d+4|0,d);l=d;return}function An(a,b,d){a=a|0;b=b|0;d=d|0;c[b>>2]=c[a+8>>2];c[b+4>>2]=c[a+8+4>>2];c[b+8>>2]=c[a+8+8>>2];c[b+12>>2]=c[a+8+12>>2];c[d>>2]=c[a+24>>2];c[d+4>>2]=c[a+24+4>>2];c[d+8>>2]=c[a+24+8>>2];c[d+12>>2]=c[a+24+12>>2];return}function Bn(a,b){a=a|0;b=b|0;var d=0,e=0;e=lb[c[(c[a>>2]|0)+52>>2]&127](a)|0;e=vb[c[(c[b>>2]|0)+16>>2]&63](b,e,1)|0;d=vb[c[(c[a>>2]|0)+56>>2]&63](a,c[e+8>>2]|0,b)|0;fb[c[(c[b>>2]|0)+20>>2]&31](b,e,d,1346455635,a);return}function Cn(a,b,c,d){a=a|0;b=+b;c=+c;d=+d;var e=0;e=l;l=l+32|0;Jl(e,bH(a+4|0)|0,b,c,d);qp(e+16|0,+g[e>>2],+g[e+4>>2],+g[e+8>>2],+g[a+544>>2],+g[a+548>>2],+g[a+552>>2]);vr(a+428|0,e+16|0)|0;l=e;return}function Dn(a,b){a=a|0;b=b|0;var c=0;c=l;l=l+80|0;Rm(c+32|0,b);Gq(c,+g[b+48>>2],+g[b+52>>2],+g[b+56>>2]);Jl(c+16|0,c+32|0,+g[c>>2],+g[c+4>>2],+g[c+8>>2]);$p(a,c+32|0,c+16|0);l=c;return}function En(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0;g=c[a+4>>2]|0;if(!(g&1))h=g>>8;else h=c[(c[d>>2]|0)+(g>>8)>>2]|0;a=c[a>>2]|0;fb[c[(c[a>>2]|0)+24>>2]&31](a,b,d+h|0,g&2|0?e:2,f);return}function Fn(b){b=b|0;var d=0;c[b>>2]=5168;d=c[b+276>>2]|0;if(d|0){if(a[b+280>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+276>>2]=0}a[b+280>>0]=1;c[b+276>>2]=0;c[b+268>>2]=0;c[b+272>>2]=0;c[b>>2]=5132;c[6433]=(c[6433]|0)+1;Pc(c[b+-4>>2]|0);return}function Gn(a,b,c,d){a=a|0;b=+b;c=+c;d=+d;var e=0;e=l;l=l+32|0;qp(e,b,c,d,+g[a+348>>2],+g[a+352>>2],+g[a+356>>2]);Up(e+16|0,+g[e>>2],+g[e+4>>2],+g[e+8>>2],+g[a+344>>2]);vr(a+312|0,e+16|0)|0;l=e;return}function Hn(a,b,c,d){a=a|0;b=+b;c=+c;d=+d;var e=0;e=l;l=l+32|0;Jl(e,a+264|0,b,c,d);qp(e+16|0,+g[e>>2],+g[e+4>>2],+g[e+8>>2],+g[a+544>>2],+g[a+548>>2],+g[a+552>>2]);vr(a+328|0,e+16|0)|0;l=e;return}function In(a,b,d){a=a|0;b=b|0;d=d|0;c[a+164>>2]=c[b>>2];c[a+164+4>>2]=c[b+4>>2];c[a+164+8>>2]=c[b+8>>2];c[a+164+12>>2]=c[b+12>>2];b=bH(b)|0;if((!(+g[b>>2]!=1.0)?!(+g[b+4>>2]!=1.0):0)?!(+g[b+8>>2]!=1.0):0)d=0;c[a+180>>2]=d;return}function Jn(b){b=b|0;var d=0;c[b>>2]=4236;d=c[b+496>>2]|0;if(d|0){if(a[b+500>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+496>>2]=0}a[b+500>>0]=1;c[b+496>>2]=0;c[b+488>>2]=0;c[b+492>>2]=0;c[b>>2]=5132;c[6433]=(c[6433]|0)+1;Pc(c[b+-4>>2]|0);return}function Kn(a,b,d){a=a|0;b=b|0;d=d|0;c[b>>2]=c[a+892>>2];c[b+4>>2]=c[a+892+4>>2];c[b+8>>2]=c[a+892+8>>2];c[b+12>>2]=c[a+892+12>>2];c[d>>2]=c[a+908>>2];c[d+4>>2]=c[a+908+4>>2];c[d+8>>2]=c[a+908+8>>2];c[d+12>>2]=c[a+908+12>>2];return}function Ln(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;f=c[d>>2]|0;f=Gb[c[(c[f>>2]|0)+56>>2]&31](f,20)|0;b=a[b+4>>0]|0;c[f>>2]=9172;c[f+4>>2]=c[d>>2];c[f>>2]=3740;a[f+16>>0]=b;return f|0}function Mn(a,b,c){a=a|0;b=b|0;c=c|0;var d=0.0;a:do if((c|0)==-1)switch(b|0){case 2:case 1:{d=+g[a+336>>2];break a}case 4:case 3:{d=+g[a+340>>2];break a}default:{d=3402823466385288598117041.0e14;break a}}else d=3402823466385288598117041.0e14;while(0);return +d}function Nn(a,b,c){a=a|0;b=b|0;c=c|0;var d=0.0,e=0.0,f=0.0;f=+g[b+28>>2];e=+g[b+32>>2];e=+g[c+4>>2]>=0.0?e:-e;d=+g[b+36>>2];d=+g[c+8>>2]>=0.0?d:-d;g[a>>2]=+g[c>>2]>=0.0?f:-f;g[a+4>>2]=e;g[a+8>>2]=d;g[a+12>>2]=0.0;return}function On(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0;f=c[a+4>>2]|0;if(!(f&1))g=f>>8;else g=c[(c[d>>2]|0)+(f>>8)>>2]|0;a=c[a>>2]|0;Vb[c[(c[a>>2]|0)+28>>2]&127](a,b,d+g|0,f&2|0?e:2);return}function Pn(b){b=b|0;var d=0;c[b>>2]=5e3;d=c[b+140>>2]|0;if(d|0){if(a[b+144>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+140>>2]=0}a[b+144>>0]=1;c[b+140>>2]=0;c[b+132>>2]=0;c[b+136>>2]=0;c[6433]=(c[6433]|0)+1;Pc(c[b+-4>>2]|0);return}function Qn(b){b=b|0;var d=0;d=l;l=l+16|0;if(!(a[22584]|0))jy(22584)|0;Go(d,c[b+116>>2]|0,c[b+128>>2]|0);c[5704]=c[d>>2];c[5705]=c[d+4>>2];c[5706]=c[d+8>>2];c[5707]=c[d+12>>2];l=d;return 22816}function Rn(a,b){a=a|0;b=b|0;var d=0;d=c[a+4>>2]|0;if((c[b>>2]|0)!=(d|0)?(c[b+4>>2]|0)!=(d|0):0)return 0;d=c[a+8>>2]|0;Rb[c[(c[d>>2]|0)+32>>2]&127](d,b,c[a+12>>2]|0);return 0}function Sn(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=0;while(1){if((e|0)>=(b|0))break;f=d+(e*104|0)|0;g=(c[a+12>>2]|0)+(e*104|0)|0;h=f+104|0;do{c[f>>2]=c[g>>2];f=f+4|0;g=g+4|0}while((f|0)<(h|0));e=e+1|0}return}function Tn(b){b=b|0;var d=0;c[b>>2]=9520;d=c[b+32>>2]|0;if(d|0){if(a[b+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+32>>2]=0}a[b+36>>0]=1;c[b+32>>2]=0;c[b+24>>2]=0;c[b+28>>2]=0;c[6433]=(c[6433]|0)+1;Pc(c[b+-4>>2]|0);return}function Un(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0;e=Gb[c[(c[d>>2]|0)+40>>2]&31](d,a)|0;f=Gb[c[(c[d>>2]|0)+28>>2]&31](d,e)|0;c[b>>2]=f;if(f|0)jb[c[(c[d>>2]|0)+48>>2]&127](d,e);c[b+4>>2]=c[a+4>>2];return 17347}function Vn(a,b){a=a|0;b=b|0;var c=0;c=l;l=l+16|0;g[c+12>>2]=-+g[(bH(b)|0)>>2];g[c+8>>2]=-+g[(IG(b)|0)>>2];g[c+4>>2]=-+g[(HG(b)|0)>>2];g[c>>2]=-+g[b+12>>2];Vu(a,c+12|0,c+8|0,c+4|0,c);l=c;return}function Wn(a,b){a=a|0;b=b|0;var c=0.0,d=0.0,e=0;e=l;l=l+16|0;d=+LD(a);d=+PG(d*+LD(b));c=+Lo(a,b);if(c<0.0){Vn(e,b);c=+Lo(a,e)}d=+sz(c/d)*2.0;l=e;return +d}function Xn(a,b,d){a=a|0;b=b|0;d=d|0;var e=0.0,f=0.0,h=0;h=c[a+104>>2]|0;f=+g[h+(b<<4)+4>>2]*+g[a+16>>2];e=+g[h+(b<<4)+8>>2]*+g[a+20>>2];g[d>>2]=+g[h+(b<<4)>>2]*+g[a+12>>2];g[d+4>>2]=f;g[d+8>>2]=e;g[d+12>>2]=0.0;return}function Yn(a,b,d){a=a|0;b=b|0;d=d|0;var e=0;e=l;l=l+32|0;c[e>>2]=c[a+60>>2];c[e+4>>2]=0;c[e+8>>2]=b;c[e+12>>2]=e+20;c[e+16>>2]=d;if((hB(Za(140,e|0)|0)|0)<0){c[e+20>>2]=-1;a=-1}else a=c[e+20>>2]|0;l=e;return a|0}function Zn(a,b){a=a|0;b=b|0;var c=0.0;c=+g[(bH(b)|0)>>2];g[a>>2]=+g[a>>2]+c;c=+g[(IG(b)|0)>>2];g[a+4>>2]=+g[a+4>>2]+c;c=+g[(HG(b)|0)>>2];g[a+8>>2]=+g[a+8>>2]+c;g[a+12>>2]=+g[a+12>>2]+ +g[b+12>>2];return a|0}function _n(a,b){a=a|0;b=b|0;var c=0.0;c=+g[(bH(b)|0)>>2];g[a>>2]=+g[a>>2]-c;c=+g[(IG(b)|0)>>2];g[a+4>>2]=+g[a+4>>2]-c;c=+g[(HG(b)|0)>>2];g[a+8>>2]=+g[a+8>>2]-c;g[a+12>>2]=+g[a+12>>2]-+g[b+12>>2];return a|0}function $n(b){b=b|0;var d=0;d=l;l=l+16|0;if(!(a[22576]|0))jy(22576)|0;jb[c[(c[b>>2]|0)+76>>2]&127](d,b);c[5700]=c[d>>2];c[5701]=c[d+4>>2];c[5702]=c[d+8>>2];c[5703]=c[d+12>>2];l=d;return 22800}function ao(b){b=b|0;var d=0;d=l;l=l+16|0;if(!(a[22624]|0))jy(22624)|0;jb[c[(c[b>>2]|0)+76>>2]&127](d,b);c[5744]=c[d>>2];c[5745]=c[d+4>>2];c[5746]=c[d+8>>2];c[5747]=c[d+12>>2];l=d;return 22976}function bo(a){a=a|0;var b=0,d=0;d=a+15&-16|0;b=c[i>>2]|0;a=b+d|0;if((d|0)>0&(a|0)<(b|0)|(a|0)<0){W()|0;Ra(12);return -1}c[i>>2]=a;if((a|0)>(V()|0)?(U()|0)==0:0){Ra(12);c[i>>2]=b;return -1}return b|0}function co(a,b){a=a|0;b=b|0;var d=0,e=0;d=l;l=l+16|0;e=bH(c[b+4>>2]|0)|0;c[d>>2]=0;en(a,e,d);yq(b,e,c[a+12>>2]|0);l=d;return}function eo(b){b=b|0;var d=0;d=a[b+74>>0]|0;a[b+74>>0]=d+255|d;d=c[b>>2]|0;if(!(d&8)){c[b+8>>2]=0;c[b+4>>2]=0;d=c[b+44>>2]|0;c[b+28>>2]=d;c[b+20>>2]=d;c[b+16>>2]=d+(c[b+48>>2]|0);d=0}else{c[b>>2]=d|32;d=-1}return d|0}function fo(a,b,d,e){a=a|0;b=b|0;d=+d;e=e|0;if((e|0)!=-1)return;switch(b|0){case 2:case 1:{g[a+336>>2]=d;c[a+332>>2]=c[a+332>>2]|1;return}case 4:case 3:{g[a+340>>2]=d;c[a+332>>2]=c[a+332>>2]|2;return}default:return}}function go(a,b){a=a|0;b=b|0;var c=0.0,d=0.0;c=+g[(HG(a)|0)>>2];c=c*+g[(bH(b)|0)>>2];d=+g[(HG(a+16|0)|0)>>2];d=c+d*+g[(IG(b)|0)>>2];c=+g[(HG(a+32|0)|0)>>2];return +(d+c*+g[(HG(b)|0)>>2])}function ho(a,b){a=a|0;b=b|0;var c=0.0,d=0.0;c=+g[(IG(a)|0)>>2];c=c*+g[(bH(b)|0)>>2];d=+g[(IG(a+16|0)|0)>>2];d=c+d*+g[(IG(b)|0)>>2];c=+g[(IG(a+32|0)|0)>>2];return +(d+c*+g[(HG(b)|0)>>2])}function io(a,b,d){a=a|0;b=b|0;d=d|0;var e=0;if((b|0)==(d|0))return;e=c[(c[a+4>>2]|0)+136>>2]|0;vb[c[(c[e>>2]|0)+8>>2]&63](e,c[b+36>>2]|0,c[d+36>>2]|0)|0;a=(c[a+4>>2]|0)+160|0;c[a>>2]=(c[a>>2]|0)+1;return}function jo(b,d,e){b=b|0;d=d|0;e=+e;var f=0;f=l;l=l+16|0;if(!(a[22592]|0))jy(22592)|0;Ji(f,b,d,e);c[5708]=c[f>>2];c[5709]=c[f+4>>2];c[5710]=c[f+8>>2];c[5711]=c[f+12>>2];l=f;return 22832}function ko(b,d,e){b=b|0;d=d|0;e=+e;var f=0;f=l;l=l+16|0;if(!(a[22632]|0))jy(22632)|0;Ji(f,b,d,e);c[5748]=c[f>>2];c[5749]=c[f+4>>2];c[5750]=c[f+8>>2];c[5751]=c[f+12>>2];l=f;return 22992}function lo(a){a=a|0;var b=0,d=0.0,e=0.0,f=0.0;b=l;l=l+32|0;Rb[c[(c[a>>2]|0)+12>>2]&127](a,b+8|0,b);f=+g[b+8>>2];e=+g[b+8+4>>2];d=+g[b+8+8>>2];d=+C(+(f*f+e*e+d*d));l=b;return +(d+ +g[b>>2])}function mo(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;if((e|0)>0)a=0;else return;do{b=d+(a<<4)|0;a=a+1|0;c[b>>2]=0;c[b+4>>2]=0;c[b+8>>2]=0;c[b+12>>2]=0}while((a|0)!=(e|0));return}function no(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;a=c[b>>2]|0;a=Gb[c[(c[a>>2]|0)+56>>2]&31](a,24)|0;c[a>>2]=9172;c[a+4>>2]=c[b>>2];c[a>>2]=4208;return a|0}function oo(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0;f=l;l=l+16|0;c[f>>2]=5328;c[f+4>>2]=d;c[f+8>>2]=a;Rb[c[(c[b>>2]|0)+48>>2]&127](b,f,e);l=f;return}function po(b,c){b=b|0;c=c|0;var d=0,e=0;d=a[b>>0]|0;e=a[c>>0]|0;if(!(d<<24>>24==0?1:d<<24>>24!=e<<24>>24))do{b=b+1|0;c=c+1|0;d=a[b>>0]|0;e=a[c>>0]|0}while(!(d<<24>>24==0?1:d<<24>>24!=e<<24>>24));return (d&255)-(e&255)|0}function qo(a,b,d){a=a|0;b=b|0;d=d|0;a=c[b+8>>2]|0;if(!((d|0)!=0&(a|0)!=0))return;hb[c[c[a>>2]>>2]&511](a);jb[c[(c[d>>2]|0)+60>>2]&127](d,c[b+8>>2]|0);c[b+8>>2]=0;return}function ro(b){b=b|0;var d=0;c[b>>2]=5168;d=c[b+276>>2]|0;if(d|0){if(a[b+280>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+276>>2]=0}a[b+280>>0]=1;c[b+276>>2]=0;c[b+268>>2]=0;c[b+272>>2]=0;c[b>>2]=5132;return}function so(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;a=c[b>>2]|0;a=Gb[c[(c[a>>2]|0)+56>>2]&31](a,8)|0;c[a>>2]=9172;c[a+4>>2]=c[b>>2];c[a>>2]=9380;return a|0}function to(a,b,d){a=a|0;b=b|0;d=d|0;var e=0;e=l;l=l+16|0;c[e>>2]=8924;c[e+4>>2]=b;c[e+8>>2]=a;c[e+12>>2]=d;Rb[c[(c[a>>2]|0)+48>>2]&127](a,e,d);l=e;return}function uo(b){b=b|0;var d=0;c[b>>2]=6896;if(a[b+61>>0]|0?(d=c[b+52>>2]|0,hb[c[c[d>>2]>>2]&511](d),d=c[b+52>>2]|0,d|0):0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[6433]=(c[6433]|0)+1;Pc(c[b+-4>>2]|0);return}function vo(b){b=b|0;var d=0;c[b>>2]=4236;d=c[b+496>>2]|0;if(d|0){if(a[b+500>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+496>>2]=0}a[b+500>>0]=1;c[b+496>>2]=0;c[b+488>>2]=0;c[b+492>>2]=0;c[b>>2]=5132;return}function wo(a,b,c,d){a=+a;b=+b;c=+c;d=+d;var e=0,f=0;f=l;l=l+16|0;g[f+12>>2]=a;g[f+8>>2]=b;g[f+4>>2]=c;g[f>>2]=d;e=Fs()|0;Et(e,f+12|0,f+8|0,f+4|0,f);l=f;return e|0}function xo(a,b,c,d){a=+a;b=+b;c=+c;d=+d;var e=0,f=0;f=l;l=l+16|0;g[f+12>>2]=a;g[f+8>>2]=b;g[f+4>>2]=c;g[f>>2]=d;e=Br(16)|0;Vu(e,f+12|0,f+8|0,f+4|0,f);l=f;return e|0}function yo(a,b,d,e,f,g){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;if(HB(a,c[b+8>>2]|0)|0)Wk(b,d,e,f);return}function zo(a){a=a|0;var b=0.0,d=0,e=0,f=0.0;e=c[a+712>>2]|0;if((e|0)<=0){b=0.0;return +b}a=c[a+720>>2]|0;d=0;b=0.0;do{f=+g[a+(d*104|0)+88>>2];b=b+(f>0.0?1.0/f:0.0);d=d+1|0}while((d|0)!=(e|0));return +b}function Ao(a){a=a|0;var b=0;c[a>>2]=5632;c[a+12>>2]=5680;b=c[a+60>>2]|0;jb[c[(c[b>>2]|0)+20>>2]&127](b,c[a+76>>2]|0);b=c[a+60>>2]|0;jb[c[(c[b>>2]|0)+16>>2]&127](b,c[a+76>>2]|0);YG(a);return}function Bo(b){b=b|0;var d=0;c[b>>2]=5e3;d=c[b+140>>2]|0;if(d|0){if(a[b+144>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+140>>2]=0}a[b+144>>0]=1;c[b+140>>2]=0;c[b+132>>2]=0;c[b+136>>2]=0;return}function Co(b){b=b|0;var d=0;d=l;l=l+16|0;if(!(a[22568]|0))jy(22568)|0;Vy(d,b);c[5696]=c[d>>2];c[5697]=c[d+4>>2];c[5698]=c[d+8>>2];c[5699]=c[d+12>>2];l=d;return 22784}function Do(b){b=b|0;var d=0;d=l;l=l+16|0;if(!(a[22560]|0))jy(22560)|0;Gx(d,b);c[5692]=c[d>>2];c[5693]=c[d+4>>2];c[5694]=c[d+8>>2];c[5695]=c[d+12>>2];l=d;return 22768}function Eo(a,b,d){a=a|0;b=+b;d=d|0;b=b*.4000000059604645*+zb[c[(c[a>>2]|0)+48>>2]&15](a);b=b*+zb[c[(c[a>>2]|0)+48>>2]&15](a);g[d>>2]=b;g[d+4>>2]=b;g[d+8>>2]=b;g[d+12>>2]=0.0;return}function Fo(a,b,c,d,e,f,h){a=a|0;b=+b;c=+c;d=+d;e=+e;f=+f;h=+h;var i=0;i=l;l=l+16|0;g[i+8>>2]=c*h-d*f;g[i+4>>2]=d*e-b*h;g[i>>2]=b*f-c*e;Ur(a,i+8|0,i+4|0,i);l=i;return}function Go(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;b=bH(b+4|0)|0;e=(bH(aF(b,0)|0)|0)+(c<<2)|0;d=(bH(aF(b,1)|0)|0)+(c<<2)|0;Ur(a,e,d,(bH(aF(b,2)|0)|0)+(c<<2)|0);return}function Ho(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;c[d>>2]=-581039253;c[d+4>>2]=-581039253;c[d+8>>2]=-581039253;g[d+12>>2]=0.0;c[e>>2]=1566444395;c[e+4>>2]=1566444395;c[e+8>>2]=1566444395;g[e+12>>2]=0.0;return}function Io(a,b){a=a|0;b=b|0;var c=0.0,d=0.0;c=+g[(bH(a)|0)>>2];c=c*+g[(bH(b)|0)>>2];d=+g[(bH(a+16|0)|0)>>2];d=c+d*+g[(IG(b)|0)>>2];c=+g[(bH(a+32|0)|0)>>2];return +(d+c*+g[(HG(b)|0)>>2])}function Jo(b){b=b|0;var d=0;d=l;l=l+16|0;if(!(a[22544]|0))jy(22544)|0;sp(d,b);c[5684]=c[d>>2];c[5685]=c[d+4>>2];c[5686]=c[d+8>>2];c[5687]=c[d+12>>2];l=d;return 22736}function Ko(b){b=b|0;var d=0;d=l;l=l+16|0;if(!(a[22552]|0))jy(22552)|0;Wl(d,b);c[5688]=c[d>>2];c[5689]=c[d+4>>2];c[5690]=c[d+8>>2];c[5691]=c[d+12>>2];l=d;return 22752}function Lo(a,b){a=a|0;b=b|0;var c=0.0,d=0.0;c=+g[a>>2];c=c*+g[(bH(b)|0)>>2];d=+g[a+4>>2];d=c+d*+g[(IG(b)|0)>>2];c=+g[a+8>>2];c=d+c*+g[(HG(b)|0)>>2];return +(c+ +g[a+12>>2]*+g[b+12>>2])}function Mo(b){b=b|0;var d=0;c[b>>2]=8964;if(a[b+192>>0]|0?(d=c[b+136>>2]|0,hb[c[c[d>>2]>>2]&511](d),d=c[b+136>>2]|0,d|0):0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}Oh(b+64|0);Oh(b+4|0);return}function No(b){b=b|0;var d=0;c[b>>2]=9520;d=c[b+32>>2]|0;if(d|0){if(a[b+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+32>>2]=0}a[b+36>>0]=1;c[b+32>>2]=0;c[b+24>>2]=0;c[b+28>>2]=0;return}function Oo(a,b,c,d,e,f,g,h,i,j){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;Ur(a,b,c,d);Ur(a+16|0,e,f,g);Ur(a+32|0,h,i,j);return}function Po(a,b,c){a=a|0;b=b|0;c=c|0;var d=0;d=l;l=l+64|0;jk(d+16|0,b,c);Nl(d,b,+g[c+48>>2],+g[c+52>>2],+g[c+56>>2]);$p(a,d+16|0,d);l=d;return}function Qo(a){a=a|0;var b=0;c[a>>2]=5632;c[a+12>>2]=5680;b=c[a+60>>2]|0;jb[c[(c[b>>2]|0)+20>>2]&127](b,c[a+76>>2]|0);b=c[a+60>>2]|0;jb[c[(c[b>>2]|0)+16>>2]&127](b,c[a+76>>2]|0);return}function Ro(b){b=b|0;var d=0;c[b>>2]=3124;d=c[b+32>>2]|0;if(d|0){if(a[b+36>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+32>>2]=0}a[b+36>>0]=1;c[b+32>>2]=0;c[b+24>>2]=0;c[b+28>>2]=0;return}function So(a){a=a|0;var b=0,d=0;c[a>>2]=7248;b=c[a+52>>2]|0;if(b|0?(hb[c[c[b>>2]>>2]&511](b),d=c[a+52>>2]|0,d|0):0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[6433]=(c[6433]|0)+1;Pc(c[a+-4>>2]|0);return}function To(a,b){a=a|0;b=b|0;var d=0;d=(c[a+92>>2]|0)+4|0;c[d>>2]=c[b>>2];c[d+4>>2]=c[b+4>>2];c[d+8>>2]=c[b+8>>2];c[d+12>>2]=c[b+12>>2];ej(a);return}function Uo(b,d){b=b|0;d=d|0;var e=0;if(a[b+273>>0]|0?(e=c[b+200>>2]|0,e|0):0){c[6433]=(c[6433]|0)+1;Pc(c[e+-4>>2]|0)}a[b+273>>0]=0;c[b+200>>2]=d;c[(c[b+196>>2]|0)+8>>2]=d;return}function Vo(b){b=b|0;var d=0;c[b>>2]=5256;d=c[b+20>>2]|0;if(d|0){if(a[b+24>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+20>>2]=0}a[b+24>>0]=1;c[b+20>>2]=0;c[b+12>>2]=0;c[b+16>>2]=0;return}function Wo(a,b){a=a|0;b=+b;c[a+8>>2]=0;c[a+12>>2]=1065353216;c[a+16>>2]=1065353216;c[a+20>>2]=1065353216;g[a+24>>2]=0.0;g[a+44>>2]=.03999999910593033;c[a>>2]=6796;c[a+4>>2]=8;OE(a+28|0,b);g[a+44>>2]=b;return}function Xo(b){b=b|0;var d=0;c[b>>2]=8772;d=c[b+16>>2]|0;if(d|0){if(a[b+20>>0]|0){c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0)}c[b+16>>2]=0}a[b+20>>0]=1;c[b+16>>2]=0;c[b+8>>2]=0;c[b+12>>2]=0;return}function Yo(a,b,c,d,e){a=a|0;b=+b;c=+c;d=+d;e=+e;var f=0;f=l;l=l+16|0;g[f+12>>2]=b;g[f+8>>2]=c;g[f+4>>2]=d;g[f>>2]=e;ir(a,f+12|0,f+8|0,f+4|0,f);l=f;return}function Zo(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;a=c[b+8>>2]|0;b=c[a+284>>2]|0;Rb[c[(c[b>>2]|0)+40>>2]&127](b,a,c[d+8>>2]|0);return}function _o(b){b=b|0;var d=0,e=0;c[b>>2]=6128;if(!(a[b+8>>0]|0)){YG(b);return}d=c[b+12>>2]|0;if(!d){YG(b);return}e=c[b+4>>2]|0;jb[c[(c[e>>2]|0)+16>>2]&127](e,d);YG(b);return}function $o(b){b=b|0;var d=0,e=0;c[b>>2]=9408;if(!(a[b+8>>0]|0)){YG(b);return}d=c[b+12>>2]|0;if(!d){YG(b);return}e=c[b+4>>2]|0;jb[c[(c[e>>2]|0)+16>>2]&127](e,d);YG(b);return}function ap(b){b=b|0;var d=0,e=0;c[b>>2]=5604;if(!(a[b+8>>0]|0)){YG(b);return}d=c[b+12>>2]|0;if(!d){YG(b);return}e=c[b+4>>2]|0;jb[c[(c[e>>2]|0)+16>>2]&127](e,d);YG(b);return}function bp(b){b=b|0;var d=0;c[b>>2]=6896;if(!(a[b+61>>0]|0))return;d=c[b+52>>2]|0;hb[c[c[d>>2]>>2]&511](d);b=c[b+52>>2]|0;if(!b)return;c[6433]=(c[6433]|0)+1;Pc(c[b+-4>>2]|0);return}function cp(b){b=b|0;var d=0,e=0,f=0;d=c[b>>2]|0;e=(a[d>>0]|0)+-48|0;if(e>>>0<10){f=d;d=0;do{d=e+(d*10|0)|0;f=f+1|0;c[b>>2]=f;e=(a[f>>0]|0)+-48|0}while(e>>>0<10)}else d=0;return d|0}function dp(a,b,d){a=a|0;b=b|0;d=d|0;var e=0;e=l;l=l+16|0;c[e>>2]=8944;c[e+4>>2]=b;Rb[c[(c[a>>2]|0)+48>>2]&127](a,e,d);l=e;return}function ep(b){b=b|0;var d=0,e=0;c[b>>2]=5700;if(!(a[b+8>>0]|0)){YG(b);return}d=c[b+12>>2]|0;if(!d){YG(b);return}e=c[b+4>>2]|0;jb[c[(c[e>>2]|0)+16>>2]&127](e,d);YG(b);return}function fp(b,c,d){b=b|0;c=c|0;d=d|0;var e=0;if((c|0)<(b|0)&(b|0)<(c+d|0)){e=b;c=c+d|0;b=b+d|0;while((d|0)>0){b=b-1|0;c=c-1|0;d=d-1|0;a[b>>0]=a[c>>0]|0}b=e}else Th(b,c,d)|0;return b|0}function gp(){var a=0,b=0;b=l;l=l+32|0;a=Br(112)|0;Ms(b);bg(a,b);l=b;return a|0}function hp(a,b){a=a|0;b=b|0;var c=0,d=0,e=0;c=O(b&65535,a&65535)|0;e=(c>>>16)+(O(b&65535,a>>>16)|0)|0;d=O(b>>>16,a&65535)|0;return (z=(e>>>16)+(O(b>>>16,a>>>16)|0)+(((e&65535)+d|0)>>>16)|0,e+d<<16|c&65535|0)|0}function ip(b){b=b|0;var d=0,e=0;c[b>>2]=6176;if(!(a[b+16>>0]|0)){YG(b);return}d=c[b+20>>2]|0;if(!d){YG(b);return}e=c[b+4>>2]|0;jb[c[(c[e>>2]|0)+16>>2]&127](e,d);YG(b);return}function jp(a,b){a=a|0;b=b|0;var c=0.0,d=0.0,e=0.0;e=+B(+(+g[b>>2]));d=+B(+(+g[b+4>>2]));c=+B(+(+g[b+8>>2]));g[a+12>>2]=e;g[a+16>>2]=d;g[a+20>>2]=c;g[a+24>>2]=0.0;return}function kp(a,b){a=a|0;b=b|0;Ef(a,c[b+36>>2]|0);return}function lp(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;if(HB(a,c[b+8>>2]|0)|0)Fm(b,d,e);return}function mp(a){a=a|0;var b=0;c[a>>2]=5680;b=c[a+48>>2]|0;jb[c[(c[b>>2]|0)+20>>2]&127](b,c[a+64>>2]|0);b=c[a+48>>2]|0;jb[c[(c[b>>2]|0)+16>>2]&127](b,c[a+64>>2]|0);YG(a);return}function np(a,b,c,d,e,f,g,h,i,j,k,l,m){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=+f;g=+g;h=+h;i=+i;j=+j;k=k|0;l=+l;m=m|0;Mb[a&0](b|0,c|0,d|0,e|0,+f,+g,+h,+i,+j,k|0,+l,m|0)}function op(a,b,c,d){a=a|0;b=b|0;c=c|0;d=+d;g[a>>2]=(1.0-d)*+g[b>>2]+ +g[c>>2]*d;g[a+4>>2]=(1.0-d)*+g[b+4>>2]+ +g[c+4>>2]*d;g[a+8>>2]=(1.0-d)*+g[b+8>>2]+ +g[c+8>>2]*d;return}function pp(a,b,c,d,e,f,h){a=a|0;b=+b;c=+c;d=+d;e=+e;f=+f;h=+h;var i=0;i=l;l=l+16|0;g[i+8>>2]=b+e;g[i+4>>2]=c+f;g[i>>2]=d+h;Ur(a,i+8|0,i+4|0,i);l=i;return}function qp(a,b,c,d,e,f,h){a=a|0;b=+b;c=+c;d=+d;e=+e;f=+f;h=+h;var i=0;i=l;l=l+16|0;g[i+8>>2]=b*e;g[i+4>>2]=c*f;g[i>>2]=d*h;Ur(a,i+8|0,i+4|0,i);l=i;return}function rp(a,b,c,d,e,f,h){a=a|0;b=+b;c=+c;d=+d;e=+e;f=+f;h=+h;var i=0;i=l;l=l+16|0;g[i+8>>2]=b-e;g[i+4>>2]=c-f;g[i>>2]=d-h;Ur(a,i+8|0,i+4|0,i);l=i;return}function sp(a,b){a=a|0;b=b|0;var c=0;c=l;l=l+16|0;g[c+8>>2]=-+g[b>>2];g[c+4>>2]=-+g[b+4>>2];g[c>>2]=-+g[b+8>>2];Vu(a,c+8|0,c+4|0,c,b+12|0);l=c;return}function tp(a){a=a|0;var b=0;c[a>>2]=7248;b=c[a+52>>2]|0;if(!b)return;hb[c[c[b>>2]>>2]&511](b);b=c[a+52>>2]|0;if(!b)return;c[6433]=(c[6433]|0)+1;Pc(c[b+-4>>2]|0);return}function up(a,b,c,d,e,f,g,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;return +(+$a(0,a|0,b|0,c|0,d|0,e|0,f|0,g|0,h|0))}function vp(b,c,e,f){b=b|0;c=c|0;e=e|0;f=f|0;if(!((b|0)==0&(c|0)==0))do{e=e+-1|0;a[e>>0]=d[20055+(b&15)>>0]|0|f;b=zt(b|0,c|0,4)|0;c=z}while(!((b|0)==0&(c|0)==0));return e|0}function wp(a){a=a|0;var b=0;c[a>>2]=5680;b=c[a+48>>2]|0;jb[c[(c[b>>2]|0)+20>>2]&127](b,c[a+64>>2]|0);b=c[a+48>>2]|0;jb[c[(c[b>>2]|0)+16>>2]&127](b,c[a+64>>2]|0);return}function xp(){var b=0;b=Br(40)|0;g[b+12>>2]=1.0;c[b+8>>2]=0;c[b+4>>2]=5;c[b>>2]=3124;a[b+36>>0]=1;c[b+32>>2]=0;c[b+24>>2]=0;c[b+28>>2]=0;a[b+16>>0]=1;return b|0}function yp(b){b=b|0;var c=0;c=a[n+(b&255)>>0]|0;if((c|0)<8)return c|0;c=a[n+(b>>8&255)>>0]|0;if((c|0)<8)return c+8|0;c=a[n+(b>>16&255)>>0]|0;if((c|0)<8)return c+16|0;return (a[n+(b>>>24)>>0]|0)+24|0}function zp(a,b,c,d){a=a|0;b=+b;c=+c;d=+d;var e=0;e=l;l=l+16|0;qp(e,b,c,d,+g[a+348>>2],+g[a+352>>2],+g[a+356>>2]);vr(a+412|0,e)|0;l=e;return}function Ap(a,b,c){a=+a;b=+b;c=+c;var d=0,e=0;e=l;l=l+16|0;g[e+8>>2]=a;g[e+4>>2]=b;g[e>>2]=c;d=Fs()|0;Ur(d,e+8|0,e+4|0,e);l=e;return d|0}function Bp(a,b){a=a|0;b=b|0;c[a+12>>2]=c[b>>2];c[a+12+4>>2]=c[b+4>>2];c[a+12+8>>2]=c[b+8>>2];c[a+12+12>>2]=c[b+12>>2];ej(a);return}function Cp(a,b,c,d,e,f,g,h,i,j,k){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;return kb[a&3](b|0,c|0,d|0,e|0,f|0,g|0,h|0,i|0,j|0,k|0)|0}function Dp(a,b){a=a|0;b=b|0;a=c[a+12>>2]|0;return Gb[c[(c[a>>2]|0)+8>>2]&31](a,b)|0}function Ep(a,b,c,d){a=a|0;b=+b;c=+c;d=+d;var e=0;e=l;l=l+16|0;qp(e,b,c,d,+g[a+544>>2],+g[a+548>>2],+g[a+552>>2]);vr(a+428|0,e)|0;l=e;return}function Fp(a,b,c,d,e,f,g,h,i,j,k){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;return +Ib[a&3](b|0,c|0,d|0,e|0,f|0,g|0,h|0,i|0,j|0,k|0)}function Gp(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0;h=ks()|0;me(h,a,b,c,d,e,f,g);return h|0}function Hp(){var a=0,b=0;b=ur()|0;if((b|0?(a=c[b>>2]|0,a|0):0)?((c[a+48>>2]&-256|0)==1126902528?(c[a+48+4>>2]|0)==1129074247:0):0)Ow(c[a+12>>2]|0);Ow(xD()|0)}function Ip(a,b,d){a=a|0;b=b|0;d=d|0;By(a,b);c[a+48>>2]=c[d>>2];c[a+48+4>>2]=c[d+4>>2];c[a+48+8>>2]=c[d+8>>2];c[a+48+12>>2]=c[d+12>>2];return}function Jp(a,b){a=a|0;b=b|0;c[a+260>>2]=(c[a+260>>2]|0)+1;c[a+328>>2]=c[b>>2];c[a+328+4>>2]=c[b+4>>2];c[a+328+8>>2]=c[b+8>>2];c[a+328+12>>2]=c[b+12>>2];return}function Kp(){var a=0,b=0;b=l;l=l+32|0;a=Br(92)|0;Ms(b);Ed(a,b);l=b;return a|0}function Lp(a,b,d){a=a|0;b=b|0;d=d|0;c[d>>2]=c[a+56+(b<<4)>>2];c[d+4>>2]=c[a+56+(b<<4)+4>>2];c[d+8>>2]=c[a+56+(b<<4)+8>>2];c[d+12>>2]=c[a+56+(b<<4)+12>>2];return}function Mp(a,b){a=a|0;b=b|0;c[a+260>>2]=(c[a+260>>2]|0)+1;c[a+312>>2]=c[b>>2];c[a+312+4>>2]=c[b+4>>2];c[a+312+8>>2]=c[b+8>>2];c[a+312+12>>2]=c[b+12>>2];return}function Np(b,d){b=b|0;d=d|0;if(!(a[22616]|0))jy(22616)|0;b=aF(b,d)|0;c[5740]=c[b>>2];c[5741]=c[b+4>>2];c[5742]=c[b+8>>2];c[5743]=c[b+12>>2];return 22960}function Op(a,b){a=a|0;b=b|0;c[a+260>>2]=(c[a+260>>2]|0)+1;c[a+544>>2]=c[b>>2];c[a+544+4>>2]=c[b+4>>2];c[a+544+8>>2]=c[b+8>>2];c[a+544+12>>2]=c[b+12>>2];return}function Pp(a,b,c,d,e,f,g,h,i,j,k,l){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=+f;g=+g;h=+h;i=+i;j=j|0;k=k|0;l=+l;sb[a&0](b|0,c|0,d|0,e|0,+f,+g,+h,+i,j|0,k|0,+l)}function Qp(a){a=a|0;var b=0.0,d=0.0;d=+g[a+32>>2];+zb[c[(c[a>>2]|0)+48>>2]&15](a);b=+zb[c[(c[a>>2]|0)+48>>2]&15](a);+zb[c[(c[a>>2]|0)+48>>2]&15](a);return +(d+b)}function Rp(a){a=a|0;var b=0.0,d=0.0;d=+g[a+28>>2];b=+zb[c[(c[a>>2]|0)+48>>2]&15](a);+zb[c[(c[a>>2]|0)+48>>2]&15](a);+zb[c[(c[a>>2]|0)+48>>2]&15](a);return +(d+b)}function Sp(a,b,c,d,e,f,g,h,i,j,k){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;Fb[a&3](b|0,c|0,d|0,e|0,f|0,g|0,h|0,i|0,j|0,k|0)}function Tp(a,b,d){a=a|0;b=b|0;d=d|0;var e=0;e=l;l=l+16|0;c[e>>2]=c[d>>2];a=vb[c[(c[a>>2]|0)+16>>2]&63](a,b,e)|0;if(a)c[d>>2]=c[e>>2];l=e;return a&1|0}function Up(a,b,c,d,e){a=a|0;b=+b;c=+c;d=+d;e=+e;var f=0;f=l;l=l+16|0;g[f+8>>2]=b*e;g[f+4>>2]=c*e;g[f>>2]=d*e;Ur(a,f+8|0,f+4|0,f);l=f;return}function Vp(a,b){a=a|0;b=b|0;g[a>>2]=+g[a>>2]*+g[b>>2];g[a+4>>2]=+g[a+4>>2]*+g[b>>2];g[a+8>>2]=+g[a+8>>2]*+g[b>>2];g[a+12>>2]=+g[a+12>>2]*+g[b>>2];return a|0}function Wp(){var a=0;a=Br(8)|0;c[6431]=a;Va(a|0,0)|0;c[6421]=19534;c[6422]=0;c[6423]=0;c[6424]=0;c[6425]=0;c[6426]=0;c[6427]=0;c[6428]=0;c[6429]=0;Xq(25684);return}function Xp(a,b,c,d,e,f,g,h,i,j){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;Oo(a,b,c,d,e,f,g,h,i,j);return}function Yp(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;d=Or(324)|0;Ld(d,a,b,c);return d|0}function Zp(b){b=b|0;var d=0;c[b>>2]=3124;d=c[b+32>>2]|0;if(!d){YG(b);return}if(!(a[b+36>>0]|0)){YG(b);return}c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0);YG(b);return}function _p(a,b,d){a=a|0;b=b|0;d=d|0;a=c[b+204>>2]|0;if(a&4|0)return 0;b=c[d+204>>2]|0;if(!(b&4))return (a&3|0)==0|(b&3|0)==0|0;else return 0;return 0}function $p(a,b,d){a=a|0;b=b|0;d=d|0;pm(a,b);c[a+48>>2]=c[d>>2];c[a+48+4>>2]=c[d+4>>2];c[a+48+8>>2]=c[d+8>>2];c[a+48+12>>2]=c[d+12>>2];return}function aq(b){b=b|0;var d=0;c[b>>2]=6128;if(!(a[b+8>>0]|0))return;d=c[b+12>>2]|0;if(!d)return;b=c[b+4>>2]|0;jb[c[(c[b>>2]|0)+16>>2]&127](b,d);return}function bq(b){b=b|0;var d=0;c[b>>2]=5256;d=c[b+20>>2]|0;if(!d){YG(b);return}if(!(a[b+24>>0]|0)){YG(b);return}c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0);YG(b);return}function cq(a,b){a=a|0;b=b|0;var c=0;c=l;l=l+128|0;Dn(c,a+68|0);Po(c+64|0,c,a+4|0);zq(b,c+64|0);l=c;return}function dq(b){b=b|0;var d=0;c[b>>2]=9408;if(!(a[b+8>>0]|0))return;d=c[b+12>>2]|0;if(!d)return;b=c[b+4>>2]|0;jb[c[(c[b>>2]|0)+16>>2]&127](b,d);return}function eq(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0;g=ks()|0;me(g,a,b,c,d,e,f,0);return g|0}function fq(b){b=b|0;var d=0;c[b>>2]=5604;if(!(a[b+8>>0]|0))return;d=c[b+12>>2]|0;if(!d)return;b=c[b+4>>2]|0;jb[c[(c[b>>2]|0)+16>>2]&127](b,d);return}function gq(a,b){a=a|0;b=b|0;a=c[a+4>>2]|0;return ((c[b>>2]|0)==(a|0)?1:(c[b+4>>2]|0)==(a|0))|0}function hq(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0;f=Yr()|0;te(f,a,b,c,d,e);return f|0}function iq(a,b){a=a|0;b=b|0;a=c[a+20>>2]|0;return Gb[c[(c[a>>2]|0)+8>>2]&31](a,b)|0}function jq(b){b=b|0;var d=0;c[b>>2]=8772;d=c[b+16>>2]|0;if(!d){YG(b);return}if(!(a[b+20>>0]|0)){YG(b);return}c[6433]=(c[6433]|0)+1;Pc(c[d+-4>>2]|0);YG(b);return}function kq(a,b,c,d){a=a|0;b=+b;c=+c;d=+d;var e=0;e=l;l=l+16|0;g[e+8>>2]=b;g[e+4>>2]=c;g[e>>2]=d;Ur(a,e+8|0,e+4|0,e);l=e;return}function lq(b){b=b|0;var d=0;c[b>>2]=5700;if(!(a[b+8>>0]|0))return;d=c[b+12>>2]|0;if(!d)return;b=c[b+4>>2]|0;jb[c[(c[b>>2]|0)+16>>2]&127](b,d);return}function mq(a,b,d){a=a|0;b=b|0;d=d|0;SF(a);c[a>>2]=3008;zq(a+4|0,b);zq(a+68|0,d);zq(a+132|0,b);c[a+196>>2]=0;return}function nq(b){b=b|0;var d=0;c[b>>2]=6176;if(!(a[b+16>>0]|0))return;d=c[b+20>>2]|0;if(!d)return;b=c[b+4>>2]|0;jb[c[(c[b>>2]|0)+16>>2]&127](b,d);return}function oq(a){a=a|0;var b=0;b=l;l=l+16|0;Vm(a);g[b+8>>2]=0.0;g[b+4>>2]=0.0;g[b>>2]=0.0;Ur(a+48|0,b+8|0,b+4|0,b);l=b;return}function pq(a,b,c,d,e,f,g,h,i,j){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;return Pb[a&3](b|0,c|0,d|0,e|0,f|0,g|0,h|0,i|0,j|0)|0}function qq(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=+e;var f=0;f=Br(44)|0;jm(f,a,b,c,d,e);return f|0}function rq(a,b,c){a=a|0;b=b|0;c=+c;switch(b|0){case 3:{b=a+452|0;break}case 4:{b=a+448|0;break}case 5:{b=a+444|0;break}default:return}g[b>>2]=c;return}function sq(a,b){a=a|0;b=b|0;b=c[b+36>>2]|0;Ae(a,c[(c[(c[(c[a+4>>2]|0)+4>>2]|0)+24>>2]|0)+(b*80|0)+64>>2]|0,b);return}function tq(a,b,c,d,e,f,g,h,i,j){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;return +Kb[a&3](b|0,c|0,d|0,e|0,f|0,g|0,h|0,i|0,j|0)}function uq(a,b){a=a|0;b=b|0;var c=0;c=0;while(1){if((c|0)==3)break;g[a+868+(c<<6)+4>>2]=+js(+g[(bH(b)|0)+(c<<2)>>2]);c=c+1|0}return}function vq(a,b,c,d){a=+a;b=b|0;c=c|0;d=d|0;var e=0;e=Br(140)|0;Pk(e,a,b,c,d);return e|0}function wq(a,b,d,e,f,g,h,i){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;return +(+rb[c[(c[a>>2]|0)+12>>2]&1](a,b,d,e,f,g,h,i))}function xq(b,c,d){b=b|0;c=c|0;d=d|0;if(!((b|0)==0&(c|0)==0))do{d=d+-1|0;a[d>>0]=b&7|48;b=zt(b|0,c|0,3)|0;c=z}while(!((b|0)==0&(c|0)==0));return d|0}function yq(a,b,d){a=a|0;b=b|0;d=d|0;var e=0;e=0;while(1){if((e|0)>=(b|0))break;c[d+(e<<2)>>2]=c[(c[a+12>>2]|0)+(e<<2)>>2];e=e+1|0}return}function zq(a,b){a=a|0;b=b|0;pm(a,b);c[a+48>>2]=c[b+48>>2];c[a+48+4>>2]=c[b+48+4>>2];c[a+48+8>>2]=c[b+48+8>>2];c[a+48+12>>2]=c[b+48+12>>2];return}function Aq(a,b){a=a|0;b=b|0;Ur(a,b,b+16|0,b+32|0);Ur(a+16|0,b+4|0,b+20|0,b+36|0);Ur(a+32|0,b+8|0,b+24|0,b+40|0);return}function Bq(a,b){a=a|0;b=b|0;var c=0;c=0;while(1){if((c|0)==3)break;g[a+868+(c<<6)>>2]=+js(+g[(bH(b)|0)+(c<<2)>>2]);c=c+1|0}return}function Cq(a){a=a|0;c[6432]=(c[6432]|0)+1;a=ec((a<<2|3)+16|0)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function Dq(a,b){a=a|0;b=b|0;hb[c[(c[b>>2]|0)+32>>2]&511](b);ad(a,b);hb[c[(c[b>>2]|0)+36>>2]&511](b);return}function Eq(a,b,c,d,e,f,g,h,i,j){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;Eb[a&1](b|0,c|0,d|0,e|0,f|0,g|0,h|0,i|0,j|0)}function Fq(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;Rb[c[(c[a>>2]|0)+108>>2]&127](a,b,d);Rb[c[(c[a>>2]|0)+108>>2]&127](a,(b+1|0)%3|0,e);return}function Gq(a,b,c,d){a=a|0;b=+b;c=+c;d=+d;var e=0;e=l;l=l+16|0;g[e+8>>2]=-b;g[e+4>>2]=-c;g[e>>2]=-d;Ur(a,e+8|0,e+4|0,e);l=e;return}function Hq(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0;f=as()|0;Td(f,a,b,c&65535,d,e);return f|0}function Iq(a){a=a|0;c[6432]=(c[6432]|0)+1;a=ec((a*104|3)+16|0)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function Jq(a,b){a=a|0;b=b|0;c[a+12>>2]=c[b>>2];c[a+12+4>>2]=c[b+4>>2];c[a+12+8>>2]=c[b+8>>2];c[a+12+12>>2]=c[b+12>>2];return}function Kq(a,b){a=a|0;b=b|0;c[a+44>>2]=c[b>>2];c[a+44+4>>2]=c[b+4>>2];c[a+44+8>>2]=c[b+8>>2];c[a+44+12>>2]=c[b+12>>2];return}function Lq(a,c){a=a|0;c=c|0;if(!((b[c+4>>1]&b[a+6>>1])<<16>>16)){a=0;return a|0}a=(b[a+4>>1]&b[c+6>>1])<<16>>16!=0;return a|0}function Mq(a,c){a=a|0;c=c|0;if(!((b[c+4>>1]&b[a+10>>1])<<16>>16)){a=0;return a|0}a=(b[a+8>>1]&b[c+6>>1])<<16>>16!=0;return a|0}function Nq(a,b){a=a|0;b=b|0;c[a+696>>2]=c[b>>2];c[a+696+4>>2]=c[b+4>>2];c[a+696+8>>2]=c[b+8>>2];c[a+696+12>>2]=c[b+12>>2];return}function Oq(a,b){a=a|0;b=b|0;c[a+680>>2]=c[b>>2];c[a+680+4>>2]=c[b+4>>2];c[a+680+8>>2]=c[b+8>>2];c[a+680+12>>2]=c[b+12>>2];return}function Pq(a,b){a=a|0;b=b|0;c[a+60>>2]=c[b>>2];c[a+60+4>>2]=c[b+4>>2];c[a+60+8>>2]=c[b+8>>2];c[a+60+12>>2]=c[b+12>>2];return}function Qq(a,b){a=a|0;b=b|0;c[a+28>>2]=c[b>>2];c[a+28+4>>2]=c[b+4>>2];c[a+28+8>>2]=c[b+8>>2];c[a+28+12>>2]=c[b+12>>2];return}function Rq(a,b){a=a|0;b=b|0;c[a+156>>2]=c[b>>2];c[a+156+4>>2]=c[b+4>>2];c[a+156+8>>2]=c[b+8>>2];c[a+156+12>>2]=c[b+12>>2];return}function Sq(b,c,d){b=b|0;c=c|0;d=d|0;a[b+1309+c>>0]=d&1;if((c|0)<3){a[b+788+c>>0]=d&1;return}else{a[b+868+(c+-3<<6)+44>>0]=d&1;return}}function Tq(a,c){a=a|0;c=c|0;if(!((b[c+4>>1]&b[a+14>>1])<<16>>16)){a=0;return a|0}a=(b[a+12>>1]&b[c+6>>1])<<16>>16!=0;return a|0}function Uq(a,b){a=a|0;b=b|0;c[a+108>>2]=c[b>>2];c[a+108+4>>2]=c[b+4>>2];c[a+108+8>>2]=c[b+8>>2];c[a+108+12>>2]=c[b+12>>2];return}function Vq(b){b=b|0;if(a[22656]|0)return 23120;if(!(jy(22656)|0))return 23120;c[5780]=1065353216;c[5781]=1065353216;c[5782]=1065353216;g[5783]=0.0;return 23120}function Wq(a,b){a=a|0;b=b|0;c[a+20>>2]=c[b>>2];c[a+20+4>>2]=c[b+4>>2];c[a+20+8>>2]=c[b+8>>2];c[a+20+12>>2]=c[b+12>>2];return}function Xq(a){a=a|0;var b=0;do{c[a+4>>2]=0;g[a+8>>2]=0.0;b=c[a+24>>2]|0;if(b|0)Xq(b);a=c[a+28>>2]|0}while((a|0)!=0);return}function Yq(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=+f;ud(a,b,c,d,e,f);return}function Zq(a,b){a=a|0;b=b|0;c[a+172>>2]=c[b>>2];c[a+172+4>>2]=c[b+4>>2];c[a+172+8>>2]=c[b+8>>2];c[a+172+12>>2]=c[b+12>>2];return}function _q(a,b){a=a|0;b=b|0;c[a+32>>2]=c[b>>2];c[a+32+4>>2]=c[b+4>>2];c[a+32+8>>2]=c[b+8>>2];c[a+32+12>>2]=c[b+12>>2];return}function $q(a){a=a|0;g[a>>2]=5.880000114440918;g[a+4>>2]=.8299999833106995;g[a+8>>2]=.8799999952316284;g[a+12>>2]=500.0;g[a+16>>2]=10.5;g[a+20>>2]=6.0e3;return}function ar(a,b){a=a|0;b=b|0;c[a+24>>2]=c[b>>2];c[a+24+4>>2]=c[b+4>>2];c[a+24+8>>2]=c[b+8>>2];c[a+24+12>>2]=c[b+12>>2];return}function br(a,b){a=a|0;b=b|0;c[a+316>>2]=c[b>>2];c[a+316+4>>2]=c[b+4>>2];c[a+316+8>>2]=c[b+8>>2];c[a+316+12>>2]=c[b+12>>2];return}function cr(a,b){a=a|0;b=b|0;c[a+300>>2]=c[b>>2];c[a+300+4>>2]=c[b+4>>2];c[a+300+8>>2]=c[b+8>>2];c[a+300+12>>2]=c[b+12>>2];return}function dr(a,b){a=a|0;b=b|0;c[a+64>>2]=c[b>>2];c[a+64+4>>2]=c[b+4>>2];c[a+64+8>>2]=c[b+8>>2];c[a+64+12>>2]=c[b+12>>2];return}function er(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0;e=as()|0;Td(e,a,b,c&65535,d,0);return e|0}function fr(a,b){a=a|0;b=b|0;c[a+52>>2]=c[b>>2];c[a+52+4>>2]=c[b+4>>2];c[a+52+8>>2]=c[b+8>>2];c[a+52+12>>2]=c[b+12>>2];return}function gr(a,b){a=a|0;b=b|0;c[a+188>>2]=c[b>>2];c[a+188+4>>2]=c[b+4>>2];c[a+188+8>>2]=c[b+8>>2];c[a+188+12>>2]=c[b+12>>2];return}function hr(a,b){a=a|0;b=b|0;c[a+40>>2]=c[b>>2];c[a+40+4>>2]=c[b+4>>2];c[a+40+8>>2]=c[b+8>>2];c[a+40+12>>2]=c[b+12>>2];return}function ir(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;c[a>>2]=c[b>>2];c[a+4>>2]=c[d>>2];c[a+8>>2]=c[e>>2];c[a+12>>2]=c[f>>2];return}function jr(a,b,c,d,e,f,g,h,i){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;return +rb[a&1](b|0,c|0,d|0,e|0,f|0,g|0,h|0,i|0)}function kr(a,b){a=a|0;b=b|0;c[a+16>>2]=c[b>>2];c[a+16+4>>2]=c[b+4>>2];c[a+16+8>>2]=c[b+8>>2];c[a+16+12>>2]=c[b+12>>2];return}function lr(a,b,d){a=a|0;b=b|0;d=+d;jb[c[(c[a>>2]|0)+32>>2]&127](a,b);Tb[c[(c[a>>2]|0)+36>>2]&7](a,b,d);return}function mr(a,b){a=a|0;b=b|0;c[a+68>>2]=c[b>>2];c[a+68+4>>2]=c[b+4>>2];c[a+68+8>>2]=c[b+8>>2];c[a+68+12>>2]=c[b+12>>2];return}function nr(a,b){a=a|0;b=b|0;c[a+36>>2]=c[b>>2];c[a+36+4>>2]=c[b+4>>2];c[a+36+8>>2]=c[b+8>>2];c[a+36+12>>2]=c[b+12>>2];return}function or(a,b){a=a|0;b=b|0;c[a>>2]=c[b+248>>2];c[a+4>>2]=c[b+248+4>>2];c[a+8>>2]=c[b+248+8>>2];c[a+12>>2]=c[b+248+12>>2];return}function pr(a,b,c){a=a|0;b=b|0;c=c|0;var d=0;d=Yr()|0;Gd(d,a,b,c);return d|0}function qr(){var a=0;a=fs()|0;rn();rn();mq(a,22848,22848);return a|0}function rr(a,b,d){a=a|0;b=b|0;d=d|0;if((c[a+4>>2]|0)==(b|0)?(c[a+28>>2]|0)!=1:0)c[a+28>>2]=d;return}function sr(){var a=0,b=0;b=Xr(c[5682]|0,c[5683]|0,1284865837,1481765933)|0;b=xv(b|0,z|0,1,0)|0;a=z;c[5682]=b;c[5683]=a;a=zt(b|0,a|0,33)|0;return a|0}function tr(a,b){a=a|0;b=b|0;c[a+48>>2]=c[b>>2];c[a+48+4>>2]=c[b+4>>2];c[a+48+8>>2]=c[b+8>>2];c[a+48+12>>2]=c[b+12>>2];return}function ur(){var a=0,b=0;a=l;l=l+16|0;if(!(Wa(26296,3)|0)){b=Ma(c[6575]|0)|0;l=a;return b|0}else Cv(22240,a);return 0}function vr(a,b){a=a|0;b=b|0;g[a>>2]=+g[a>>2]+ +g[b>>2];g[a+4>>2]=+g[a+4>>2]+ +g[b+4>>2];g[a+8>>2]=+g[a+8>>2]+ +g[b+8>>2];return a|0}function wr(a,b){a=a|0;b=b|0;g[a>>2]=+g[a>>2]-+g[b>>2];g[a+4>>2]=+g[a+4>>2]-+g[b+4>>2];g[a+8>>2]=+g[a+8>>2]-+g[b+8>>2];return a|0}function xr(a,b){a=a|0;b=b|0;var c=0;c=l;l=l+64|0;Po(c,b,a+68|0);zq(a+4|0,c);l=c;return}function yr(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0;f=l;l=l+16|0;Je(a,b,d,e,f|0)|0;l=f;return (z=c[f+4>>2]|0,c[f>>2]|0)|0}function zr(a){a=a|0;var b=0;b=Br(112)|0;bg(b,a);return b|0}function Ar(a,b,c){a=a|0;b=b|0;c=c|0;var d=0;d=as()|0;Td(d,a,b,c&65535,0,0);return d|0}function Br(a){a=a|0;var b=0;b=(a|0)==0?1:a;while(1){a=ec(b)|0;if(a|0)break;a=sD()|0;if(!a){a=0;break}Sb[a&3]()}return a|0}function Cr(a,b){a=a|0;b=b|0;c[a>>2]=c[b>>2];c[a+4>>2]=c[b+4>>2];c[a+8>>2]=c[b+8>>2];c[a+12>>2]=c[b+12>>2];return}function Dr(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0;e=Or(1252)|0;oc(e,a,b,c,d);return e|0}function Er(a,b){a=a|0;b=b|0;c[a+72>>2]=c[b>>2];c[a+72+4>>2]=c[b+4>>2];c[a+72+8>>2]=c[b+8>>2];c[a+72+12>>2]=c[b+12>>2];return}function Fr(a,b){a=a|0;b=b|0;g[a>>2]=+g[a>>2]*+g[b>>2];g[a+4>>2]=+g[a+4>>2]*+g[b>>2];g[a+8>>2]=+g[a+8>>2]*+g[b>>2];return a|0}function Gr(a,b){a=a|0;b=b|0;c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;g[a+(c[b+52>>2]<<2)>>2]=1.0;return}function Hr(a){a=a|0;var b=0;b=l;l=l+16|0;Pc(a);if(!(Oa(c[6575]|0,0)|0)){l=b;return}else Cv(22339,b)}function Ir(a,b){a=a|0;b=b|0;c[a+8>>2]=c[b>>2];c[a+8+4>>2]=c[b+4>>2];c[a+8+8>>2]=c[b+8>>2];c[a+8+12>>2]=c[b+12>>2];return}function Jr(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(215)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function Kr(a,b,c){a=a|0;b=b|0;c=c|0;var d=0;d=zs()|0;Ie(d,a,b,c);return d|0}function Lr(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return _b(b,c,d,e)|0}function Mr(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(203)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function Nr(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(1407)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function Or(a){a=a|0;c[6432]=(c[6432]|0)+1;a=ec(a+19|0)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function Pr(a){a=a|0;var b=0;b=fs()|0;rn();mq(b,a,22848);return b|0}function Qr(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(191)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function Rr(a,b){a=a|0;b=b|0;if(!b?c[a+204>>2]&3|0:0)return;if((c[a+216>>2]&-2|0)!=4)c[a+216>>2]=1;g[a+220>>2]=0.0;return}function Sr(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;Vb[c[(c[a+-4>>2]|0)+8>>2]&127](a+-4|0,b,d,e);return}function Tr(a,b){a=a|0;b=b|0;var c=0.0;c=+LD(a);c=+PG(c*+LD(b));return +(+sz(+Lo(a,b)/c))}function Ur(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;c[a>>2]=c[b>>2];c[a+4>>2]=c[d>>2];c[a+8>>2]=c[e>>2];g[a+12>>2]=0.0;return}function Vr(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(143)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function Wr(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(115)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function Xr(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0;e=hp(a,c)|0;f=z;return (z=(O(b,c)|0)+(O(d,a)|0)+f|f&0,e|0|0)|0}function Yr(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(1331)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function Zr(b){b=b|0;var d=0;d=c[b+12>>2]|0;if(!d)return;if(a[b+16>>0]&1)ax(d);c[b+12>>2]=0;return}function _r(a,b,c,d,e,f,g,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;Db[a&1](b|0,c|0,d|0,e|0,f|0,g|0,h|0)}function $r(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(379)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function as(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(135)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function bs(a,b,c,d){a=a|0;b=b|0;c=c|0;d=+d;return}function cs(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(627)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function ds(a,b){a=a|0;b=b|0;var c=0;c=as()|0;Td(c,a,b,16384,0,0);return c|0}function es(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(791)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function fs(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(219)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function gs(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(1147)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function hs(a,b){a=a|0;b=b|0;var c=0;c=Br(80)|0;wm(c,a,b);return c|0}function is(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(103)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function js(a){a=+a;a=+WF(a);if(a<-3.1415927410125732){a=a+6.2831854820251465;return +a}if(!(a>3.1415927410125732))return +a;a=a+-6.2831854820251465;return +a}function ks(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(783)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function ls(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(131)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function ms(a,b){a=a|0;b=b|0;c[a+348>>2]=c[b>>2];c[a+348+4>>2]=c[b+4>>2];c[a+348+8>>2]=c[b+8>>2];return}function ns(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(111)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function os(a,b){a=a|0;b=b|0;c[a+480>>2]=b;if(!b)return;jb[c[(c[b>>2]|0)+8>>2]&127](b,a+4|0);return}function ps(a,b){a=a|0;b=b|0;var c=0;c=zs()|0;Ie(c,a,b,1);return c|0}function qs(a){a=a|0;var b=0;b=Br(92)|0;Ed(b,a);return b|0}function rs(a,b){a=a|0;b=b|0;c[a>>2]=1065353216;c[a+4>>2]=1065353216;c[a+8>>2]=1065353216;g[a+12>>2]=0.0;return}function ss(b){b=b|0;if(!(lb[c[(c[b>>2]|0)+40>>2]&127](b)|0))return;c[b+16>>2]=c[b+28>>2];a[b+169>>0]=1;return}function ts(a){a=a|0;Oz(a+144|0);Oz(a+124|0);Oz(a+104|0);return}function us(a,b){a=a|0;b=b|0;var d=0;d=c[a+8>>2]|0;Rb[c[d+60>>2]&127](b,d,c[a+4>>2]|0);return 0}function vs(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(71)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function ws(a,b){a=a|0;b=b|0;var d=0;d=a+92|0;do{c[a>>2]=c[b>>2];a=a+4|0;b=b+4|0}while((a|0)<(d|0));return}function xs(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;vg(a,b,c,d);return}function ys(a){a=a|0;if(!a){a=0;return a|0}a=Cq(a)|0;return a|0}function zs(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(95)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function As(a,b){a=a|0;b=b|0;return +(+dx(+g[a>>2],+g[a+4>>2],+g[a+8>>2],+g[b>>2],+g[b+4>>2],+g[b+8>>2]))}function Bs(a,b){a=a|0;b=b|0;var c=0;c=Br(84)|0;Jm(c,a,b);return c|0}function Cs(a,b,d){a=a|0;b=b|0;d=d|0;c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;return}function Ds(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(75)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function Es(a){a=a|0;var b=0;b=l;l=l+16|0;c[b>>2]=bH(c[a+60>>2]|0)|0;a=hB(Sa(6,b|0)|0)|0;l=b;return a|0}function Fs(){var a=0;c[6432]=(c[6432]|0)+1;a=ec(35)|0;if(!a){a=0;return a|0}c[(a+4+15&-16)+-4>>2]=a;a=a+4+15&-16;return a|0}function Gs(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;return Ab[a&3](b|0,c|0,d|0,e|0,f|0,g|0)|0}function Hs(a){a=a|0;Xf(a);if(!a)return;c[6433]=(c[6433]|0)+1;Pc(c[a+-4>>2]|0);return}function Is(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;Vb[c[(c[a>>2]|0)+8>>2]&127](a,b,d,e);return}function Js(a){a=a|0;c[a>>2]=2928;g[a+4>>2]=1.0;c[a+8>>2]=0;b[a+12>>1]=1;b[a+14>>1]=-1;c[a+16>>2]=0;return}function Ks(a){a=a|0;var b=0;b=Ds()|0;Ih(b,a);c[b>>2]=8472;c[b+52>>2]=2;return b|0}function Ls(a){a=a|0;var b=0;b=Ds()|0;Ih(b,a);c[b>>2]=8368;c[b+52>>2]=0;return b|0}function Ms(a){a=a|0;c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=4096;c[a+12>>2]=4096;c[a+16>>2]=0;c[a+20>>2]=1;return}function Ns(a,b,d){a=a|0;b=b|0;d=d|0;ge(c[a+116>>2]|0,c[a+144>>2]|0,b,d);return}function Os(a,b){a=a|0;b=+b;var c=0;c=l;l=l+16|0;g[c>>2]=b;a=Vp(a,c)|0;l=c;return a|0}function Ps(a,b){a=a|0;b=b|0;var c=0;c=fs()|0;mq(c,a,b);return c|0}function Qs(a,b,d){a=a|0;b=b|0;d=d|0;Rb[c[(c[b>>2]|0)+64>>2]&127](a,b,d);return}function Rs(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return 0.0}function Ss(a,b,d){a=a|0;b=+b;d=d|0;c[d>>2]=0;c[d+4>>2]=0;c[d+8>>2]=0;c[d+12>>2]=0;return}function Ts(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;Vb[c[(c[a>>2]|0)+80>>2]&127](a,b,d,e);return}function Us(a){a=a|0;if(!a){a=0;return a|0}a=Iq(a)|0;return a|0}function Vs(){var a=0;a=l;l=l+16|0;if(!(Pa(26300,262)|0)){l=a;return}else Cv(22289,a)}function Ws(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=+e;f=f|0;g=g|0;return +Bb[a&3](b|0,c|0,d|0,+e,f|0,g|0)}function Xs(a,b){a=a|0;b=+b;var c=0;c=l;l=l+16|0;g[c>>2]=b;a=Fr(a,c)|0;l=c;return a|0}function Ys(a){a=a|0;if(c[a+204>>2]&3|0)return;if((c[a+216>>2]&-2|0)!=4)c[a+216>>2]=1;g[a+220>>2]=0.0;return}function Zs(a,b){a=a|0;b=b|0;un(a,+g[b>>2],+g[b+4>>2],+g[b+8>>2]);return}function _s(){var a=0;a=Br(8)|0;c[a>>2]=0;c[a+4>>2]=0;Xx(a);return a|0}function $s(a,b){a=a|0;b=b|0;a=c[a+4>>2]|0;Gb[c[(c[a>>2]|0)+8>>2]&31](a,c[b+36>>2]|0)|0;return}function at(a,b){a=a|0;b=b|0;Aq(a,b);Ur(a+48|0,b+48|0,b+52|0,b+56|0);return}function bt(a,b,d){a=a|0;b=b|0;d=d|0;xg(c[a+116>>2]|0,b,d);return}function ct(a,b){a=a|0;b=b|0;c[a+260>>2]=(c[a+260>>2]|0)+1;c[a+192>>2]=b;c[a+200>>2]=b;return}function dt(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;xb[a&7](b|0,c|0,d|0,e|0,f|0,g|0)}function et(a,b,c,d,e,f,g,h,i,j,k,l){a=a|0;b=b|0;c=c|0;d=d|0;e=+e;f=+f;g=+g;h=+h;i=+i;j=j|0;k=+k;l=l|0;S(33)}function ft(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;Vb[c[(c[a>>2]|0)+24>>2]&127](a,b,d,e);return}function gt(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;Vb[c[(c[a>>2]|0)+88>>2]&127](a,b,d,e);return}function ht(a,b,d){a=a|0;b=b|0;d=d|0;Rb[c[(c[b>>2]|0)+68>>2]&127](a,b,d);return}function it(b,d){b=b|0;d=d|0;b=(a[b+344>>0]|0)==0?3:0;c[d>>2]=b;c[d+4>>2]=b;return}function jt(a,b){a=a|0;b=+b;var c=0;c=l;l=l+16|0;g[c>>2]=1.0/b;a=Vp(a,c)|0;l=c;return a|0}function kt(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;Vb[c[(c[a>>2]|0)+36>>2]&127](a,b,d,e);return}function lt(a,b,d){a=a|0;b=+b;d=d|0;return Ub[c[(c[a>>2]|0)+52>>2]&1](a,b,d,.01666666753590107)|0}function mt(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){z=b<<c|(a&(1<<c)-1<<32-c)>>>32-c;return a<<c}z=a<<c-32;return 0}function nt(a,b,d){a=a|0;b=+b;d=d|0;c[d>>2]=0;c[d+4>>2]=0;c[d+8>>2]=0;c[d+12>>2]=0;return}function ot(a,b){a=a|0;b=b|0;Gn(a,+g[b>>2],+g[b+4>>2],+g[b+8>>2]);return}function pt(a,b,d,e){a=a|0;b=+b;d=d|0;e=+e;return Ub[c[(c[a>>2]|0)+52>>2]&1](a,b,d,e)|0}function qt(a,b){a=a|0;b=b|0;c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=1065353216;g[a+12>>2]=0.0;return}function rt(a,b){a=a|0;b=b|0;c[a>>2]=1065353216;c[a+4>>2]=0;c[a+8>>2]=0;g[a+12>>2]=0.0;return}function st(a,b){a=a|0;b=b|0;c[a>>2]=0;c[a+4>>2]=1065353216;c[a+8>>2]=0;g[a+12>>2]=0.0;return}function tt(a,b){a=a|0;b=b|0;Rb[c[(c[a>>2]|0)+8>>2]&127](a,b,c[(c[a+8>>2]|0)+48>>2]|0);return}function ut(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=+g;wb[a&0](b|0,c|0,d|0,e|0,f|0,+g)}function vt(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=+e;f=f|0;g=g|0;ib[a&0](b|0,c|0,d|0,+e,f|0,g|0)}function wt(a,b){a=a|0;b=b|0;Hn(a,+g[b>>2],+g[b+4>>2],+g[b+8>>2]);return}function xt(b,d,e){b=b|0;d=d|0;e=+e;g[(c[b+720>>2]|0)+(d*104|0)+88>>2]=e>0.0?1.0/e:0.0;a[b+924>>0]=1;return}function yt(a,b,d){a=a|0;b=b|0;d=+d;Tb[c[(c[a>>2]|0)+20>>2]&7](a,b,d);return}function zt(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){z=b>>>c;return a>>>c|(b&(1<<c)-1)<<32-c}z=0;return b>>>c-32|0}function At(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;Vb[c[(c[a>>2]|0)+124>>2]&127](a,e,b,d);return}function Bt(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;c[a+120>>2]=b;c[a+124>>2]=d;c[a+128>>2]=e;return}function Ct(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;pb[c[(c[a>>2]|0)+8>>2]&31](a,b,d,e)|0;return}function Dt(a,b){a=a|0;b=b|0;zp(a,+g[b>>2],+g[b+4>>2],+g[b+8>>2]);return}function Et(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;Ur(a,b,d,e);c[a+12>>2]=c[f>>2];return}function Ft(b,c,d,e){b=b|0;c=c|0;d=+d;e=+e;a[b+737>>0]=c&1;g[b+680>>2]=d;g[b+684>>2]=e;return}function Gt(a,b){a=a|0;b=b|0;Cn(a,+g[b>>2],+g[b+4>>2],+g[b+8>>2]);return}function Ht(a,b,c,d,e,f){a=a|0;b=+b;c=+c;d=+d;e=+e;f=+f;pn(a,b,c,d,e,f);return}function It(a){a=a|0;Nj(a);if(!a)return;c[6433]=(c[6433]|0)+1;Pc(c[a+-4>>2]|0);return}function Jt(a){a=a|0;pl(a);if(!a)return;c[6433]=(c[6433]|0)+1;Pc(c[a+-4>>2]|0);return}function Kt(a,b,c,d,e,f,g){a=a|0;b=b|0;c=+c;d=+d;e=e|0;f=f|0;g=g|0;nb[a&0](b|0,+c,+d,e|0,f|0,g|0)}function Lt(a,b,c,d,e,f,g,h,i,j){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;S(29);return 0.0}function Mt(a,b,d){a=a|0;b=b|0;d=d|0;Vb[c[(c[a>>2]|0)+36>>2]&127](a,b,d,-3);return}function Nt(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return 1.0}function Ot(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return}function Pt(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;Vb[c[(c[a>>2]|0)+32>>2]&127](a,b,d,e);return}function Qt(a){a=a|0;wg(a);if(!a)return;c[6433]=(c[6433]|0)+1;Pc(c[a+-4>>2]|0);return}function Rt(){}function St(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;d=b-d-(c>>>0>a>>>0|0)>>>0;return (z=d,a-c>>>0|0)|0}function Tt(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;Df(a,b,c,d,e);return}function Ut(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;Mf(a,b,c,d,e);return}function Vt(a){a=a|0;var b=0.0,c=0;c=+Lo(a,a)<0.0;b=+g[a+12>>2];return +(+sz(c?b:-b)*2.0)}function Wt(a,b,c,d,e,f,g,h,i,j){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;S(5);return 0}function Xt(a,b){a=a|0;b=b|0;He(a,b);return}function Yt(a,b,c,d,e,f,g,h,i,j,k){a=a|0;b=b|0;c=c|0;d=d|0;e=+e;f=+f;g=+g;h=+h;i=i|0;j=j|0;k=+k;S(13)}function Zt(a,b){a=a|0;b=b|0;xg(c[a+116>>2]|0,b,1);return}function _t(a,b){a=a|0;b=b|0;c[a+260>>2]=(c[a+260>>2]|0)+1;zq(a+4|0,b);return}function $t(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;return +tb[a&15](b|0,c|0,d|0,e|0,f|0)}function au(a,b){a=a|0;b=b|0;var c=0;c=Qr()|0;Qf(c,a,b);return c|0}function bu(a,b){a=a|0;b=b|0;if(!b)b=0;else b=Ci(c[b>>2]|0,c[b+4>>2]|0,a)|0;return (b|0?b:a)|0}function cu(a,b){a=a|0;b=b|0;Ep(a,+g[b>>2],+g[b+4>>2],+g[b+8>>2]);return}function du(a,b,d){a=a|0;b=b|0;d=d|0;Vb[c[(c[a>>2]|0)+36>>2]&127](a,b,d,-1);return}function eu(a,b){a=a|0;b=+b;var c=0;c=l;l=l+16|0;g[c>>2]=1.0/b;Fr(a,c)|0;l=c;return}function fu(a,b){a=a|0;b=+b;return Ub[c[(c[a>>2]|0)+52>>2]&1](a,b,1,.01666666753590107)|0}function gu(a){a=a|0;var b=0;b=Br(8)|0;_u(b,a);return b|0}function hu(a,b,d){a=a|0;b=b|0;d=d|0;Rb[c[(c[a>>2]|0)+56>>2]&127](a,b,d);return}function iu(a,b,d){a=a|0;b=b|0;d=+d;Tb[c[(c[a>>2]|0)+36>>2]&7](a,b,d);return}function ju(a){a=a|0;Vh(a);if(!a)return;c[6433]=(c[6433]|0)+1;Pc(c[a+-4>>2]|0);return}function ku(a,b,c,d,e,f,g,h,i,j){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;S(26)}function lu(a){a=a|0;dj(a);if(!a)return;c[6433]=(c[6433]|0)+1;Pc(c[a+-4>>2]|0);return}function mu(a,b,c,d,e){a=a|0;b=+b;c=+c;d=+d;e=+e;pn(a,b,c,d,e,1.0);return}function nu(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=+d;e=e|0;f=f|0;return +Nb[a&3](b|0,c|0,+d,e|0,f|0)}function ou(a,b,c,d){a=a|0;b=b|0;c=+c;d=+d;Ft(a,b,c,d);return}function pu(a){a=a|0;c[a>>2]=8184;if(!a)return;c[6433]=(c[6433]|0)+1;Pc(c[a+-4>>2]|0);return}function qu(a,b){a=a|0;b=b|0;return c[(tA(c[a+24>>2]|0,b)|0)+64>>2]|0}function ru(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;fb[a&31](b|0,c|0,d|0,e|0,f|0)}function su(a){a=a|0;if(!(c[a+12>>2]|0)){a=0;return a|0}a=c[a+20>>2]|0;return a|0}function tu(a){a=a|0;Zr(a);qv(a);return}function uu(a){a=a|0;Ql(a);if(!a)return;c[6433]=(c[6433]|0)+1;Pc(c[a+-4>>2]|0);return}function vu(a,b){a=a|0;b=b|0;var c=0;c=Br(64)|0;Ip(c,a,b);return c|0}function wu(){var a=0;a=Br(24)|0;Ms(a);return a|0}function xu(a,b,d){a=a|0;b=b|0;d=+d;gb[c[(c[a>>2]|0)+16>>2]&31](a,d);return}function yu(a,b,c){a=a|0;b=b|0;c=c|0;In(a,b,c);return}function zu(a,b){a=a|0;b=b|0;Vb[c[(c[a>>2]|0)+36>>2]&127](a,b,2,-3);return}function Au(a,b,d){a=a|0;b=+b;d=d|0;qb[c[(c[a>>2]|0)+32>>2]&15](a,b,d);return}function Bu(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=+e;return}function Cu(a){a=a|0;Wh(a);if(!a)return;c[6433]=(c[6433]|0)+1;Pc(c[a+-4>>2]|0);return}function Du(a){a=a|0;Yh(a);if(!a)return;c[6433]=(c[6433]|0)+1;Pc(c[a+-4>>2]|0);return}function Eu(a,b){a=a|0;b=b|0;co(a,b);return}function Fu(a,b){a=a|0;b=b|0;co(a,b);return}function Gu(a,b,c,d,e,f,g,h,i){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;S(31);return 0.0}function Hu(a,b){a=a|0;b=b|0;co(a,b);return}function Iu(a,b){a=a|0;b=b|0;return c[(pC(c[a+276>>2]|0,b)|0)>>2]|0}function Ju(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=+f;Jb[a&1](b|0,c|0,d|0,e|0,+f)}function Ku(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=+d;e=e|0;f=f|0;Cb[a&0](b|0,c|0,+d,e|0,f|0)}function Lu(a,b,c,d,e,f,g,h,i){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;S(36);return 0}function Mu(a){a=a|0;if(!(+g[a+16>>2]==0.0)){a=0;return a|0}a=+g[a+20>>2]==0.0;return a|0}function Nu(a){a=a|0;c[a>>2]=4560;if(!a)return;c[6433]=(c[6433]|0)+1;Pc(c[a+-4>>2]|0);return}function Ou(a){a=a|0;c[a>>2]=5132;if(!a)return;c[6433]=(c[6433]|0)+1;Pc(c[a+-4>>2]|0);return}function Pu(a,b){a=a|0;b=b|0;jb[c[(c[a>>2]|0)+16>>2]&127](a,b);return}function Qu(a,b){a=a|0;b=b|0;jb[c[(c[a>>2]|0)+40>>2]&127](a,b);return}function Ru(a,b,d){a=a|0;b=b|0;d=+d;Tb[c[(c[a>>2]|0)+8>>2]&7](a,b,d);return}function Su(a,b){a=a|0;b=b|0;Py(a,b);return}function Tu(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;Fc(a,b,c,d)|0;return 1}function Uu(a,b){a=a|0;b=b|0;jb[c[(c[a>>2]|0)+68>>2]&127](a,b);return}function Vu(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;ir(a,b,c,d,e);return}function Wu(a){a=a|0;var b=0;b=Qr()|0;Qf(b,a,1);return b|0}function Xu(a,b,d){a=a|0;b=+b;d=d|0;g[(c[a+144>>2]|0)+(d*284|0)+232>>2]=b;return}function Yu(a,b,d){a=a|0;b=+b;d=d|0;g[(c[a+144>>2]|0)+(d*284|0)+252>>2]=b;return}function Zu(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return}function _u(a,b){a=a|0;b=b|0;CF(a);c[a>>2]=4980;c[a+4>>2]=b;return}function $u(a,b){a=a|0;b=b|0;uq(a,b);return}function av(a,b){a=a|0;b=b|0;Bq(a,b);return}function bv(a,b){a=a|0;b=b|0;Vb[c[(c[a>>2]|0)+36>>2]&127](a,b,1,-1);return}function cv(a){a=+a;var b=0;h[j>>3]=a;b=c[j>>2]|0;z=c[j+4>>2]|0;return b|0}function dv(a,b){a=a|0;b=b|0;jb[c[(c[a>>2]|0)+64>>2]&127](a,b);return}function ev(a,b,c){a=a|0;b=b|0;c=c|0;Hh(b,c);return}function fv(a){a=a|0;hd(a);if(!a)return;c[6433]=(c[6433]|0)+1;Pc(c[a+-4>>2]|0);return}function gv(a){a=a|0;c[a>>2]=3100;g[a+4>>2]=1.0;b[a+8>>1]=1;b[a+10>>1]=-1;return}function hv(a,b){a=a|0;b=b|0;return c[(pC(c[a+12>>2]|0,b)|0)>>2]|0}function iv(a,b){a=a|0;b=b|0;if((c[a+216>>2]&-2|0)==4)return;c[a+216>>2]=b;return}function jv(a,b){a=a|0;b=b|0;Nq(a,b);return}function kv(a,b){a=a|0;b=b|0;Oq(a,b);return}function lv(a,b){a=a|0;b=b|0;Rb[c[(c[a>>2]|0)+56>>2]&127](a,b,0);return}function mv(a,b){a=a|0;b=+b;Pw(a,b);return}function nv(a,b){a=a|0;b=b|0;return Gb[c[(c[a>>2]|0)+40>>2]&31](a,b)|0}function ov(a,b){a=a|0;b=b|0;jb[c[(c[a>>2]|0)+60>>2]&127](a,b);return}function pv(a,b,d){a=a|0;b=b|0;d=+d;jb[c[(c[a>>2]|0)+12>>2]&127](a,b);return}function qv(b){b=b|0;a[b+16>>0]=1;c[b+12>>2]=0;c[b+4>>2]=0;c[b+8>>2]=0;return}function rv(a,b){a=a|0;b=b|0;jb[c[(c[a>>2]|0)+92>>2]&127](a,b);return}function sv(a,b){a=a|0;b=b|0;Qm(a,b);return}function tv(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return pb[a&31](b|0,c|0,d|0,e|0)|0}function uv(a,b){a=a|0;b=b|0;jb[c[(c[a>>2]|0)+32>>2]&127](a,b);return}function vv(a){a=a|0;var b=0;b=Ds()|0;Ih(b,a);return b|0}function wv(a,b,c,d,e,f,g,h,i){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;S(25)}function xv(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return (z=b+d+(a+c>>>0>>>0<a>>>0|0)>>>0,a+c>>>0|0)|0}function yv(a,b,d){a=a|0;b=+b;d=d|0;g[(c[a+144>>2]|0)+(d*284|0)+256>>2]=b;return}function zv(a,b){a=a|0;b=b|0;jb[c[(c[a>>2]|0)+84>>2]&127](a,b);return}function Av(a,b,c,d){a=a|0;b=+b;c=+c;d=+d;fm(a,b,c,d);return}function Bv(a,b){a=a|0;b=b|0;jb[c[(c[a>>2]|0)+28>>2]&127](a,b);return}function Cv(a,b){a=a|0;b=b|0;var d=0;d=l;l=l+16|0;c[d>>2]=b;uk(a,d);Km();Qa()}function Dv(a,b){a=a|0;b=+b;c[a+260>>2]=(c[a+260>>2]|0)+1;g[a+232>>2]=b;return}function Ev(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return +Ob[a&1](b|0,c|0,d|0,e|0)}function Fv(a,b){a=a|0;b=b|0;jb[c[(c[a>>2]|0)+72>>2]&127](a,b);return}function Gv(){var a=0;a=ls()|0;Wf(a,0,0,16);return a|0}function Hv(a){a=a|0;var b=0;b=Br(284)|0;oj(b,a);return b|0}function Iv(a){a=a|0;if(!a)return;hb[c[(c[a>>2]|0)+8>>2]&511](a);return}function Jv(a,b){a=a|0;b=+b;g[a+36>>2]=b;g[a+40>>2]=+E(+b);return}function Kv(a){a=a|0;if(!a)return;hb[c[(c[a>>2]|0)+4>>2]&511](a);return}function Lv(a,b){a=a|0;b=+b;return +(+zb[c[(c[a>>2]|0)+16>>2]&15](a)*b)}function Mv(a){a=a|0;eu(a,+dz(+g[a>>2],+g[a+4>>2],+g[a+8>>2]));return}function Nv(a,b,c,d,e,f,g,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;S(12);return 0.0}function Ov(a,b){a=a|0;b=+b;_z(a,b);return}function Pv(a,b){a=a|0;b=b|0;Hu(a+868|0,b);return}function Qv(a,b){a=a|0;b=+b;c[a+260>>2]=(c[a+260>>2]|0)+1;g[a+228>>2]=b;return}function Rv(a,b){a=a|0;b=b|0;ze(a,b);return}function Sv(a,b){a=a|0;b=b|0;jb[c[(c[a>>2]|0)+8>>2]&127](a,b);return}function Tv(a){a=a|0;if(!a)return;Oz(a);YG(a);return}function Uv(a,b,c){a=a|0;b=b|0;c=c|0;fi(a,b,c);return}function Vv(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;Vb[a&127](b|0,c|0,d|0,e|0)}function Wv(a,b){a=a|0;b=b|0;jb[c[(c[a>>2]|0)+12>>2]&127](a,b);return}function Xv(a,b,c){a=a|0;b=b|0;c=c|0;Vk(a,b,c);return}function Yv(a,b){a=a|0;b=b|0;jb[c[(c[a>>2]|0)+68>>2]&127](a,b);return}function Zv(a,b){a=a|0;b=+b;c[a+260>>2]=(c[a+260>>2]|0)+1;g[a+224>>2]=b;return}function _v(){var a=0;a=Qr()|0;Qf(a,1,1);return a|0}function $v(a,b,c){a=a|0;b=+b;c=+c;Lw(a,b,c);return}function aw(a,b){a=a|0;b=+b;gb[c[(c[a>>2]|0)+20>>2]&31](a,b);return}function bw(a,b,c,d){a=a|0;b=+b;c=+c;d=+d;ml(a,b,c,d);return}function cw(a,b){a=a|0;b=+b;gb[c[(c[a>>2]|0)+16>>2]&31](a,b);return}function dw(a,b){a=a|0;b=b|0;return +(+g[(c[a+144>>2]|0)+(b*284|0)+232>>2])}function ew(){var a=0;a=Br(196)|0;xh(a,0);return a|0}function fw(a,b){a=a|0;b=b|0;jb[c[(c[a>>2]|0)+24>>2]&127](a,b);return}function gw(a,b,d){a=a|0;b=b|0;d=d|0;c[a+20>>2]=b;c[a+28>>2]=d;return}function hw(a,b,d){a=a|0;b=b|0;d=d|0;c[a+16>>2]=b;c[a+24>>2]=d;return}function iw(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return 0}function jw(a,b,c,d,e){a=a|0;b=b|0;c=+c;d=d|0;e=+e;return Ub[a&1](b|0,+c,d|0,+e)|0}function kw(a,b,c){a=a|0;b=b|0;c=+c;om(a,b,c);return}function lw(a,b){a=a|0;b=b|0;jb[c[(c[a>>2]|0)+64>>2]&127](a,b);return}function mw(a){a=a|0;var b=0;b=((bH(c[a+236>>2]|0)|0)&2|0)==0;return (b?0:a)|0}function nw(a,b){a=a|0;b=b|0;return CA(c[a+12>>2]|0,b)|0}function ow(a,b,c){a=a|0;b=b|0;c=c|0;Hl(a,b,c);return}function pw(a,b,c){a=a|0;b=b|0;c=+c;g[a+1340+(b<<2)>>2]=c;return}function qw(a,b,c){a=a|0;b=b|0;c=c|0;return $b(a,b,c)|0}function rw(a,b){a=a|0;b=b|0;Jw(a,b);return}function sw(a,b,c){a=a|0;b=b|0;c=+c;rq(a,b,c);return}function tw(a){a=a|0;c[a>>2]=3768;yi(a+12|0);YG(a);return}function uw(a,b){a=a|0;b=b|0;sv(a+708|0,b);return}function vw(a){a=a|0;if(!a)return;HD(a);YG(a);return}function ww(a,b,c){a=a|0;b=b|0;c=+c;g[a+1364+(b<<2)>>2]=c;return}function xw(a,b){a=a|0;b=b|0;ee(a,b);return}function yw(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=+e;Qb[a&15](b|0,c|0,d|0,+e)}function zw(a){a=+a;var b=0;b=vs()|0;Wo(b,a);return b|0}function Aw(a,b){a=a|0;b=b|0;_t(a,b);return}function Bw(a,b){a=a|0;b=+b;g[a+132>>2]=b;return}function Cw(a,b){a=a|0;b=+b;Px(a,b);return}function Dw(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=+d;e=e|0;mb[a&7](b|0,c|0,+d,e|0)}function Ew(a,b,c,d,e){a=a|0;b=b|0;c=+c;d=d|0;e=e|0;ob[a&0](b|0,+c,d|0,e|0)}function Fw(a,b){a=a|0;b=+b;g[a+128>>2]=b;return}function Gw(a,b){a=a|0;b=b|0;IA(a,b);return}function Hw(a,b){a=a|0;b=b|0;br(a,b);return}function Iw(a,b){a=a|0;b=b|0;cr(a,b);return}function Jw(a,b){a=a|0;b=b|0;c[a+176>>2]=(b|0)<0?0:(b|0)<2?b:2;return}function Kw(a,b){a=a|0;b=b|0;c[a+24>>2]=b;return}function Lw(a,b,c){a=a|0;b=+b;c=+c;g[a+472>>2]=b;g[a+476>>2]=c;return}function Mw(a,b){a=a|0;b=b|0;return VA(a,b)|0}function Nw(a,b){a=a|0;b=b|0;g[a+48>>2]=+(b|0);return}function Ow(a){a=a|0;var b=0;b=l;l=l+16|0;Sb[a&3]();Cv(22392,b)}function Pw(b,c){b=b|0;c=+c;g[b+572>>2]=c;a[b+553>>0]=1;return}function Qw(a,b){a=a|0;b=b|0;return c[(c[a+20>>2]|0)+(b<<2)>>2]|0}function Rw(a){a=a|0;return +(+mG(+g[a+16>>2]))}function Sw(a){a=a|0;return lb[c[(c[a>>2]|0)+40>>2]&127](a)|0}function Tw(a){a=a|0;var b=0;b=(bH(c[a+236>>2]|0)|0)==4;return (b?a:0)|0}function Uw(a){a=a|0;return +(+dz(+g[a>>2],+g[a+4>>2],+g[a+8>>2]))}function Vw(a,b){a=a|0;b=+b;uA(a,b);return}function Ww(a,b){a=a|0;b=b|0;YA(a,b);return}function Xw(a,b){a=a|0;b=b|0;sA(a,b);return}function Yw(a,b){a=a|0;b=+b;gb[c[(c[a>>2]|0)+44>>2]&31](a,b);return}function Zw(a,b){a=a|0;b=b|0;Jp(a,b);return}function _w(a,b){a=a|0;b=+b;g[a+136>>2]=b;return}function $w(a){a=a|0;return xE(+g[a+4>>2])|0}function ax(a){a=a|0;if(!a)return;c[6433]=(c[6433]|0)+1;Pc(c[a+-4>>2]|0);return}function bx(a,b){a=a|0;b=b|0;return (c[a+144>>2]|0)+(b*284|0)+92|0}function cx(a,b){a=a|0;b=b|0;return Iu(a,b)|0}function dx(a,b,c,d,e,f){a=+a;b=+b;c=+c;d=+d;e=+e;f=+f;return +(a*d+b*e+c*f)}function ex(a){a=a|0;c[a>>2]=2880;b[a+4>>1]=1;b[a+6>>1]=-1;return}function fx(a){a=a|0;var b=0;b=(bH(c[a+236>>2]|0)|0)==8;return (b?a:0)|0}function gx(){var a=0;a=Br(24)|0;$q(a);return a|0}function hx(a,b){a=a|0;b=b|0;Mp(a,b);return}function ix(a,b){a=a|0;b=+b;jB(a,b);return}function jx(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return}function kx(a){a=a|0;g[a>>2]=.30000001192092896;g[a+4>>2]=1.0;g[a+8>>2]=0.0;return}function lx(a,b){a=a|0;b=+b;EA(a,b);return}function mx(a){a=a|0;hb[c[(c[a>>2]|0)+44>>2]&511](a);return}function nx(a,b){a=a|0;b=b|0;zq(a+4|0,b);return}function ox(a){a=a|0;return XD(c[a+204>>2]|0)|0}function px(a,b){a=a|0;b=+b;kB(a,b);return}function qx(a,b){a=a|0;b=+b;sy(a,b);return}function rx(a,b){a=a|0;b=+b;lB(a,b);return}function sx(a,b){a=a|0;b=+b;ty(a,b);return}function tx(a,b){a=a|0;b=b|0;os(a,b);return}function ux(a,b){a=a|0;b=b|0;Op(a,b);return}function vx(a){a=a|0;return +(+mG(+g[a+112>>2]))}function wx(b,c){b=b|0;c=c|0;a[b+32>>0]=c&1;return}function xx(a){a=a|0;return QD(c[a+8>>2]|0)|0}function yx(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return vb[a&63](b|0,c|0,d|0)|0}function zx(a,b){a=a|0;b=b|0;return +(+Wn(a,b))}function Ax(a,b){a=a|0;b=b|0;fi(a,b,1);return}function Bx(a,b){a=a|0;b=b|0;OA(a,b);return}function Cx(a){a=a|0;if(!a)a=0;else a=(Pi(a,2816)|0)!=0;return a&1|0}function Dx(a){a=a|0;qj(a);YG(a);return}function Ex(a,b){a=a|0;b=b|0;dm(a,b);return}function Fx(a,b){a=a|0;b=+b;g[a+116>>2]=b;return}function Gx(a,b){a=a|0;b=b|0;Fz(a,b,+HC(b));return}function Hx(a){a=a|0;c[a>>2]=3768;yi(a+12|0);return}function Ix(a,b){a=a|0;b=b|0;iB(a,b);return}function Jx(a,b){a=a|0;b=b|0;at(a,b);return}function Kx(){var a=0;a=Br(100)|0;gm(a);return a|0}function Lx(a,b){a=a|0;b=+b;g[a+112>>2]=b;return}function Mx(a,b){a=a|0;b=+b;g[a+124>>2]=b;return}function Nx(a,b){a=a|0;b=b|0;WA(a,b);return}function Ox(a,b){a=a|0;b=b|0;return c[(c[a+220>>2]|0)+(b<<2)>>2]|0}function Px(b,c){b=b|0;c=+c;g[b+572>>2]=c;a[b+553>>0]=0;return}function Qx(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return +Hb[a&15](b|0,c|0,d|0)}function Rx(a,b){a=a|0;b=b|0;XA(a,b);return}function Sx(a,b){a=a|0;b=b|0;return $b(a,b,8192)|0}function Tx(b,c){b=b|0;c=c|0;a[b+120>>0]=c&1;return}function Ux(){var a=0;a=Br(12)|0;kx(a);return a|0}function Vx(a){a=a|0;if(!a)return;ts(a);YG(a);return}function Wx(a){a=a|0;return lb[c[(c[a>>2]|0)+48>>2]&127](a)|0}function Xx(a){a=a|0;ex(a);c[a>>2]=2856;return}function Yx(a){a=a|0;return zE(a)|0}function Zx(a,b){a=a|0;b=+b;Dv(a,b);return}function _x(a,b){a=a|0;b=b|0;return +(+jf(a,b))}function $x(a){a=a|0;return +(+mG(+g[a+120>>2]))}function ay(){var a=0;a=Br(4)|0;kA(a);return a|0}function by(a,b,c,d){a=a|0;b=b|0;c=c|0;d=+d;return}function cy(a,b){a=a|0;b=+b;TB(a,b);return}function dy(a,b){a=a|0;b=b|0;eh(a,b);return}function ey(a,b){a=a|0;b=+b;RB(a,b);return}function fy(a,b){a=a|0;b=b|0;return qu(a,b)|0}function gy(a,b,c,d){a=a|0;b=b|0;c=c|0;d=+d;return yb[a&7](b|0,c|0,+d)|0}function hy(a){a=a|0;return +(+g[a+132>>2])}function iy(a){a=a|0;return Iy(c[a+68>>2]|0)|0}function jy(b){b=b|0;if((a[b>>0]|0)==1)b=0;else{a[b>>0]=1;b=1}return b|0}function ky(b,c){b=b|0;c=c|0;a[b+80>>0]=c&1;return}function ly(a,b){a=a|0;b=b|0;mB(a,b);return}function my(a){a=a|0;return +(+g[a+128>>2])}function ny(a,b){a=a|0;b=b|0;return (c[a+144>>2]|0)+(b*284|0)|0}function oy(a,b){a=a|0;b=b|0;sB(a,b);return}function py(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;S(24)}function qy(a){a=a|0;return QB(a)|0}function ry(a){a=a|0;qv(a);return}function sy(a,b){a=a|0;b=+b;g[a+196>>2]=+js(b);return}function ty(a,b){a=a|0;b=+b;g[a+192>>2]=+js(b);return}function uy(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;Rb[a&127](b|0,c|0,d|0)}function vy(a,b,d){a=a|0;b=b|0;d=d|0;if(!(c[a>>2]&32))hk(b,d,a);return}function wy(a,b){a=a|0;b=b|0;zq(a+92|0,b);return}function xy(a){a=a|0;mj(a);YG(a);return}function yy(a,b){a=a|0;b=+b;g[a+268>>2]=b;return}function zy(a){a=a|0;return +(+mG(+g[a+80>>2]))}function Ay(a,b){a=a|0;b=b|0;c[b+748>>2]=0;return}function By(a,b){a=a|0;b=b|0;gk(a,b);return}function Cy(a){a=a|0;return bF(a)|0}function Dy(a,b){a=a|0;b=+b;Qv(a,b);return}function Ey(a,b){a=a|0;b=+b;g[a+96>>2]=b;return}function Fy(a){a=a|0;return +(+zb[c[(c[a>>2]|0)+48>>2]&15](a))}function Gy(a,c){a=a|0;c=c|0;b[a+10>>1]=c;return}function Hy(a,c){a=a|0;c=c|0;b[a+8>>1]=c;return}function Iy(a){a=a|0;return lb[c[(c[a>>2]|0)+36>>2]&127](a)|0}function Jy(a){a=a|0;var b=0;b=l;l=l+a|0;l=l+15&-16;return b|0}function Ky(a,b){a=a|0;b=b|0;wd(a,b);return}function Ly(a,b){a=a|0;b=b|0;SB(a,b);return}function My(a,b){a=a|0;b=+b;g[a+92>>2]=b;return}function Ny(a){a=a|0;return +(+g[a+136>>2])}function Oy(b){b=b|0;return (a[b+32>>0]&1)!=0|0}function Py(b,c){b=b|0;c=c|0;a[b+170>>0]=c&1;return}function Qy(a,b){a=a|0;b=b|0;tr(a,b);return}function Ry(a,b){a=a|0;b=b|0;jn(a+288|0,b);return}function Sy(a,b){a=a|0;b=b|0;return mw(b)|0}function Ty(a,b){a=a|0;b=+b;g[a+108>>2]=b;return}function Uy(a,c){a=a|0;c=c|0;b[a+12>>1]=c;return}function Vy(a,b){a=a|0;b=b|0;eh(b,a);return}function Wy(a,b){a=a|0;b=+b;g[a+272>>2]=b;return}function Xy(a){a=a|0;return eF(a)|0}function Yy(a){a=a|0;return fF(a)|0}function Zy(a){a=a|0;return iF(a)|0}function _y(a,c){a=a|0;c=c|0;b[a+14>>1]=c;return}function $y(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;S(21);return 0}function az(a,b){a=a|0;b=b|0;By(a,b);return}function bz(a,b){a=a|0;b=b|0;return fx(b)|0}function cz(a,b){a=a|0;b=b|0;c[a+44>>2]=b&1;return}function dz(a,b,c){a=+a;b=+b;c=+c;return +(+PG(+rz(a,b,c)))}function ez(a,b,c,d){a=a|0;b=b|0;c=+c;d=d|0;qb[a&15](b|0,+c,d|0)}function fz(a,b){a=a|0;b=b|0;if(!a)a=0;else a=vk(a,b)|0;return a|0}function gz(a,b){a=a|0;b=+b;g[a+220>>2]=b;return}function hz(a,b){a=a|0;b=+b;g[a+100>>2]=b;return}function iz(b){b=b|0;return (a[b+120>>0]&1)!=0|0}function jz(b,c){b=b|0;c=c|0;a[b+24>>0]=c&1;return}function kz(a){a=a|0;return ~~+g[a+48>>2]|0}function lz(b,c){b=b|0;c=c|0;a[b+180>>0]=c&1;return}function mz(a,b,c,d){a=a|0;b=b|0;c=c|0;d=+d;Tb[a&7](b|0,c|0,+d)}function nz(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=+d;e=e|0;f=f|0;S(22);return 0.0}function oz(a,b){a=a|0;b=+b;g[a+224>>2]=b;return}function pz(a,b){a=a|0;b=+b;Zv(a,b);return}function qz(a){a=a|0;return TA(c[a+216>>2]|0)|0}function rz(a,b,c){a=+a;b=+b;c=+c;return +(+dx(a,b,c,a,b,c))}function sz(a){a=+a;if(!(a<-1.0)){if(a>1.0)a=1.0}else a=-1.0;return +(+H(+a))}function tz(a){a=a|0;return +(+g[a+116>>2])}function uz(a){a=a|0;return +(+Vt(a))}function vz(b,c){b=b|0;c=c|0;a[b+16>>0]=c&1;return}function wz(a,b){a=a|0;b=b|0;c[a+20>>2]=b;return}function xz(a){a=a|0;return GC(a)|0}function yz(a,b){a=a|0;b=+b;g[a+276>>2]=b;return}function zz(a,b){a=a|0;b=+b;g[a+204>>2]=b;return}function Az(a,b){a=a|0;b=+b;g[a+208>>2]=b;return}function Bz(a){a=a|0;return +(+g[a+112>>2])}function Cz(a){a=a|0;return +(+g[a+124>>2])}function Dz(a,b,c){a=a|0;b=+b;c=c|0;return}function Ez(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return}function Fz(a,b,c){a=a|0;b=b|0;c=+c;zn(a,b,1.0/c);return}function Gz(a){a=a|0;Ve(a);YG(a);return}function Hz(a,b){a=a|0;b=b|0;var c=0;c=fA(a|0)|0;return ((b|0)==0?a:c)|0}function Iz(a,b){a=a|0;b=+b;g[a+216>>2]=b;return}function Jz(b){b=b|0;return (a[b+80>>0]&1)!=0|0}function Kz(a){a=a|0;if(!a)return;ax(a);return}function Lz(a,b){a=a|0;b=b|0;c[a+36>>2]=b;return}function Mz(a,b){a=a|0;b=b|0;c[a+32>>2]=b;return}function Nz(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return Je(a,b,c,d,0)|0}function Oz(a){a=a|0;tu(a);return}function Pz(b,c){b=b|0;c=c|0;a[b+260>>0]=c&1;return}function Qz(a){a=a|0;return DF(a)|0}function Rz(b,c){b=b|0;c=c|0;a[b+25>>0]=c&1;return}function Sz(a,b,c){a=a|0;b=+b;c=c|0;return}function Tz(a,b){a=a|0;b=b|0;c[a+72>>2]=b;return}function Uz(a){a=a|0;jt(a,+HC(a))|0;return}function Vz(a,b,c,d){a=a|0;b=b|0;c=+c;d=+d;ub[a&7](b|0,+c,+d)}function Wz(a){a=a|0;return +(+GF(+g[a+12>>2]))}function Xz(a,b){a=a|0;b=b|0;c[a+8>>2]=b;return}function Yz(a){a=a|0;return zF(a)|0}function Zz(a,b){a=a|0;b=b|0;return +(+Tr(a,b))}function _z(a,b){a=a|0;b=+b;g[a+16>>2]=b;return}function $z(a,b){a=a|0;b=b|0;c[a+216>>2]=b;return}function aA(b,c){b=b|0;c=c|0;a[b+26>>0]=c&1;return}function bA(b,c){b=b|0;c=c|0;a[b+84>>0]=c&1;return}function cA(a){a=a|0;$j(a);YG(a);return}function dA(a){a=a|0;wk(a);YG(a);return}function eA(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;S(18)}function fA(a){a=a|0;return (a&255)<<24|(a>>8&255)<<16|(a>>16&255)<<8|a>>>24|0}function gA(a){a=a|0;return HF(a)|0}function hA(a){a=a|0;return eD(a)|0}function iA(a){a=a|0;return (c[a+116>>2]|0)+4|0}function jA(a,b){a=a|0;b=b|0;c[a+4>>2]=b;return}function kA(a){a=a|0;PE(a);c[a>>2]=2952;return}function lA(a,b,c){a=a|0;b=b|0;c=c|0;return Gb[a&31](b|0,c|0)|0}function mA(a,b){a=a|0;b=+b;g[a+244>>2]=b;return}function nA(a,b){a=a|0;b=+b;g[a+240>>2]=b;return}function oA(a){a=a|0;return +(+g[a+104>>2])}function pA(a,b){a=a|0;b=b|0;return sl(a,b)|0}function qA(a){a=a|0;return NF(a)|0}function rA(a){a=a|0;_j(a);YG(a);return}function sA(b,c){b=b|0;c=c|0;a[b+524>>0]=c&1;return}function tA(a,b){a=a|0;b=b|0;return a+(b*80|0)|0}function uA(a,b){a=a|0;b=+b;g[a+248>>2]=b;return}function vA(a,b){a=a|0;b=+b;g[a+212>>2]=b;return}function wA(a,b){a=a|0;b=+b;g[a+228>>2]=b;return}function xA(a){a=a|0;return +(+g[a+268>>2])}function yA(a){a=a|0;return bH(c[a+84>>2]|0)|0}function zA(a,b){a=a|0;b=b|0;return _n(a,b)|0}function AA(a,b){a=a|0;b=b|0;return Zn(a,b)|0}function BA(a,b){a=a|0;b=b|0;return +(+Lo(a,b))}function CA(a,b){a=a|0;b=b|0;return a+(b*104|0)|0}function DA(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=+f;S(17)}function EA(a,b){a=a|0;b=+b;g[a+252>>2]=b;return}function FA(a){a=a|0;return +(+g[a+96>>2])}function GA(a){a=a|0;return (c[a+44>>2]|0)!=0|0}function HA(a){a=a|0;yi(a);YG(a);return}function IA(a,b){a=a|0;b=b|0;c[a+84>>2]=b;return}function JA(a){a=a|0;ry(a);return}function KA(a){a=a|0;return +(+g[a+92>>2])}function LA(a){a=a|0;return bH(c[a+88>>2]|0)|0}function MA(a){a=a|0;return bH(c[a+748>>2]|0)|0}function NA(b){b=b|0;return (a[b+24>>0]&1)!=0|0}function OA(b,c){b=b|0;c=c|0;a[b+552>>0]=c&1;return}function PA(a,b,c){a=a|0;b=b|0;c=c|0;return 0}function QA(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=+d;e=e|0;f=f|0;S(3)}function RA(a){a=a|0;return dE(a)|0}function SA(a){a=a|0;return +(+g[a+108>>2])}function TA(a){a=a|0;a=bH(a)|0;return (a|0)!=5&(a|0)!=2|0}function UA(a){a=a|0;ak(a);YG(a);return}function VA(a,b){a=a|0;b=b|0;return a+4+(b*184|0)|0}function WA(b,c){b=b|0;c=c|0;a[b+736>>0]=c&1;return}function XA(a,b){a=a|0;b=b|0;c[a+204>>2]=b;return}function YA(a,b){a=a|0;b=b|0;c[a+88>>2]=b;return}function ZA(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;S(14);return 0.0}function _A(a,b){a=a|0;b=+b;g[a+232>>2]=b;return}function $A(a,b){a=a|0;b=+b;g[a+280>>2]=b;return}function aB(a,b){a=a|0;b=+b;g[a+236>>2]=b;return}function bB(a){a=a|0;return +(+g[a+272>>2])}function cB(a,b){a=a|0;b=+b;return jt(a,b)|0}function dB(b){b=b|0;return (a[b+16>>0]&1)!=0|0}function eB(a,b){a=a|0;b=b|0;c[a>>2]=b;return}function fB(a){a=a|0;return b[a+10>>1]|0}function gB(a){a=a|0;return b[a+8>>1]|0}function hB(a){a=a|0;if(a>>>0>4294963200){c[6577]=0-a;a=-1}return a|0}function iB(b,c){b=b|0;c=c|0;a[b+21>>0]=c&1;return}function jB(a,b){a=a|0;b=+b;g[a+684>>2]=b;return}function kB(a,b){a=a|0;b=+b;g[a+188>>2]=b;return}function lB(a,b){a=a|0;b=+b;g[a+184>>2]=b;return}function mB(a,b){a=a|0;b=b|0;c[a+240>>2]=b;return}function nB(a,b,c,d,e,f){a=a|0;b=+b;c=+c;d=d|0;e=e|0;f=f|0;S(8)}function oB(a){a=a|0;return +(+g[a+220>>2])}function pB(a){a=a|0;return +(+g[a+100>>2])}function qB(a){a=a|0;return bH(c[a+128>>2]|0)|0}function rB(a){a=a|0;return b[a+12>>1]|0}function sB(b,c){b=b|0;c=c|0;a[b+737>>0]=c&1;return}function tB(a,b,c,d,e){a=a|0;b=b|0;c=+c;d=d|0;e=e|0;S(34);return 0.0}function uB(a,b){a=a|0;b=+b;g[a+256>>2]=b;return}function vB(a){a=a|0;return +(+g[a+224>>2])}function wB(a,b){a=a|0;b=b|0;return wr(a,b)|0}function xB(a,b){a=a|0;b=b|0;return vr(a,b)|0}function yB(a){a=a|0;return Qg(a)|0}function zB(a){a=a|0;return b[a+14>>1]|0}function AB(a,b){a=a|0;b=b|0;c[a+84>>2]=b;return}function BB(a,b){a=a|0;b=b|0;c[a+88>>2]=b;return}function CB(a,b){a=a|0;b=b|0;c[a+92>>2]=b;return}function DB(a,b){a=a|0;b=b|0;c[a+100>>2]=b;return}function EB(a,b){a=a|0;b=b|0;c[a+96>>2]=b;return}function FB(a){a=a|0;return (c[a+48>>2]|0)==1|0}function GB(a){a=a|0;bk(a);YG(a);return}function HB(a,b){a=a|0;b=b|0;return (a|0)==(b|0)|0}function IB(a,b){a=a|0;b=b|0;if(!o){o=a;p=b}}function JB(b){b=b|0;return (a[b+260>>0]&1)!=0|0}function KB(a){a=a|0;return bH(c[a+116>>2]|0)|0}function LB(a){a=a|0;return bH(c[a+120>>2]|0)|0}function MB(a){a=a|0;return bH(c[a+744>>2]|0)|0}function NB(a){a=a|0;return bH(c[a+740>>2]|0)|0}function OB(b){b=b|0;return (a[b+25>>0]&1)!=0|0}function PB(a){a=a|0;return (c[a+92>>2]|0)+4|0}function QB(a){a=a|0;return bH(c[a+268>>2]|0)|0}function RB(a,b){a=a|0;b=+b;g[a+440>>2]=b;return}function SB(a,b){a=a|0;b=b|0;c[a+240>>2]=b;return}function TB(a,b){a=a|0;b=+b;g[a+104>>2]=b;return}function UB(a,b,c){a=a|0;b=b|0;c=c|0;jb[a&127](b|0,c|0)}function VB(a,b,c){a=a|0;b=b|0;c=+c;return +Lb[a&1](b|0,+c)}function WB(a){a=a|0;return +(+g[a+276>>2])}function XB(a){a=a|0;return +(+g[a+208>>2])}function YB(a){a=a|0;return bH(c[a+192>>2]|0)|0}function ZB(a){a=a|0;return bH(c[a+204>>2]|0)|0}function _B(a){a=a|0;return bH(c[a+24>>2]|0)|0}function $B(a){a=a|0;return bH(c[a+68>>2]|0)|0}function aC(a,b){a=a|0;b=b|0;c[a+16>>2]=b;return}function bC(a,b){a=a|0;b=+b;g[a+64>>2]=b;return}function cC(a,b){a=a|0;b=+b;g[a+68>>2]=b;return}function dC(a){a=a|0;if(!a)return;YG(a);return}function eC(a){a=+a;return (g[j>>2]=a,c[j>>2]|0)|0}function fC(a){a=a|0;return +(+g[a+216>>2])}function gC(a){a=a|0;return bH(c[a+480>>2]|0)|0}function hC(a){a=a|0;return bH(c[a+124>>2]|0)|0}function iC(a,b){a=a|0;b=+b;YD(a,b);return}function jC(b){b=b|0;return (a[b+26>>0]&1)!=0|0}function kC(a){a=a|0;return c[a+20>>2]|0}function lC(b){b=b|0;return (a[b+84>>0]&1)!=0|0}function mC(a,b){a=a|0;b=+b;g[a+80>>2]=b;return}function nC(a,b){a=a|0;b=+b;g[a+76>>2]=b;return}function oC(a){a=a|0;return +(+g[a+28>>2]*+g[a+12>>2])}function pC(a,b){a=a|0;b=b|0;return a+(b<<2)|0}function qC(a,b,c){a=a|0;b=b|0;c=c|0;return}function rC(a){a=a|0;return +(+g[a+248>>2])}function sC(a){a=a|0;return bH(c[a+240>>2]|0)|0}function tC(a,b){a=a|0;b=+b;g[a+60>>2]=b;return}function uC(a,b){a=a|0;b=+b;g[a+52>>2]=b;return}function vC(a,b){a=a|0;b=+b;g[a+56>>2]=b;return}function wC(a,b,c){a=a|0;b=b|0;c=+c;return 0}function xC(a){a=a|0;return +(+g[a+204>>2])}function yC(a){a=a|0;oq(a);return}function zC(a,b){a=a|0;b=b|0;return}function AC(a,b){a=a|0;b=+b;uE(a,b);return}function BC(a,b){a=a|0;b=+b;vE(a,b);return}function CC(a,b){a=a|0;b=+b;OE(a,b);return}function DC(a){a=a|0;return c[a+36>>2]|0}function EC(a){a=a|0;return c[a+32>>2]|0}function FC(a){a=a|0;return (c[a+48>>2]|0)+4|0}function GC(a){a=a|0;return bH(c[a+16>>2]|0)|0}function HC(a){a=a|0;return +(+PG(+LD(a)))}function IC(a){a=a|0;return a+44|0}function JC(a){a=a|0;return c[a+68>>2]|0}function KC(a){a=a|0;Oz(a);return}function LC(a,b,c){a=a|0;b=b|0;c=+c;gb[a&31](b|0,+c)}function MC(a){a=a|0;return +(+g[(HG(a)|0)>>2])}function NC(a){a=a|0;return +(+g[(IG(a)|0)>>2])}function OC(a){a=a|0;return +(+g[(GG(a)|0)>>2])}function PC(a){a=a|0;return cG(a)|0}function QC(a){a=a|0;Uz(a);return}function RC(a){a=a|0;return c[a+8>>2]|0}function SC(a,b){a=a|0;b=+b;g[a+40>>2]=b;return}function TC(a,b){a=a|0;b=+b;g[a+36>>2]=b;return}function UC(a,b){a=a|0;b=+b;g[a+48>>2]=b;return}function VC(a){a=a|0;return a+60|0}function WC(a){a=a|0;return c[a+200>>2]|0}function XC(a){a=a|0;return +(+g[a+244>>2])}function YC(a){a=a|0;return +(+g[a+240>>2])}function ZC(a){a=a|0;return +(+LD(a))}function _C(a,b){a=a|0;b=+b;g[a+24>>2]=b;return}function $C(a,b){a=a|0;b=+b;g[a+20>>2]=b;return}function aD(a,b){a=a|0;b=+b;g[a+32>>2]=b;return}function bD(a,b){a=a|0;b=+b;g[a+16>>2]=b;return}function cD(a,b){a=a|0;b=+b;g[a+28>>2]=b;return}function dD(a){a=a|0;return c[a+212>>2]|0}function eD(a){a=a|0;return bH(c[a+136>>2]|0)|0}function fD(a){a=a|0;c[a+192>>2]=0;return}function gD(a,b,c){a=a|0;b=b|0;c=c|0;return}function hD(a,b){a=a|0;b=+b;g[a+72>>2]=b;return}function iD(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;S(0)}function jD(a){a=a|0;return +(+g[a+212>>2])}function kD(a){a=a|0;return +(+g[a+228>>2])}function lD(a){a=a|0;return c[a+24>>2]|0}function mD(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=+e;S(30)}function nD(a,b,c,d,e){a=a|0;b=b|0;c=+c;d=d|0;e=e|0;S(23)}function oD(a){a=a|0;return +(+g[a+252>>2])}function pD(a){a=a|0;return IG(a)|0}function qD(a){a=a|0;return +(+HC(a))}function rD(a){a=a|0;return c[a+4>>2]|0}function sD(){var a=0;a=c[6576]|0;c[6576]=a+0;return a|0}function tD(a){a=a|0;return c[a+136>>2]|0}function uD(a,b){a=a|0;b=+b;g[a+44>>2]=b;return}function vD(a){a=a|0;return a+156|0}function wD(a){a=a|0;return a+20|0}function xD(){var a=0;a=c[2428]|0;c[2428]=a+0;return a|0}function yD(a){a=a|0;_h(a);YG(a);return}function zD(a){a=a|0;Mo(a);YG(a);return}function AD(a){a=a|0;vj(a);YG(a);return}function BD(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;S(35);return 0.0}function CD(a){a=a|0;return +(+g[a+232>>2])}function DD(a){a=a|0;return +(+g[a+280>>2])}function ED(a){a=a|0;return +(+g[a+236>>2])}function FD(a){a=a|0;return 348}function GD(a){a=a|0;return c[a+12>>2]|0}function HD(a){a=a|0;KC(a+56|0);return}function ID(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;S(10);return 0}function JD(a){a=a|0;Mv(a);return}function KD(a){a=a|0;return bH(c[a+4>>2]|0)|0}function LD(a){a=a|0;return +(+Lo(a,a))}function MD(a){a=a|0;return +(+g[a+256>>2])}function ND(a){a=a|0;return a+348|0}function OD(a){a=a|0;return +(+g[a>>2])}function PD(a){a=a|0;return c[a>>2]|0}function QD(a){a=a|0;return (a|0)!=0|0}function RD(a,b){a=a|0;b=b|0;return lb[a&127](b|0)|0}function SD(a){a=a|0;return a+24|0}function TD(a){a=a|0;Na(a|0)|0;Hp()}function UD(a){a=a|0;return a+64|0}function VD(a){a=a|0;return +(+g[a+64>>2])}function WD(a){a=a|0;return +(+g[a+68>>2])}function XD(a){a=a|0;return (a&2|0)!=0|0}function YD(a,b){a=a|0;b=+b;g[a+12>>2]=b;return}function ZD(a){a=a|0;return a+172|0}function _D(a){a=a|0;return c[a+84>>2]|0}function $D(a){a=a|0;return c[a+88>>2]|0}function aE(a){a=a|0;return c[a+92>>2]|0}function bE(a){a=a|0;return c[a+100>>2]|0}function cE(a){a=a|0;return 252}function dE(a){a=a|0;return c[a+240>>2]|0}function eE(a,b,c,d){a=a|0;b=+b;c=c|0;d=+d;S(41);return 0}function fE(a){a=a|0;return +(+g[(bH(a)|0)>>2])}function gE(a){a=a|0;return a+52|0}function hE(a){a=a|0;return +(+g[a+80>>2])}function iE(a){a=a|0;return +(+g[a+76>>2])}function jE(a){a=a|0;return 28}function kE(a){a=a|0;return c[a+72>>2]|0}function lE(a,b){a=a|0;b=b|0;return +zb[a&15](b|0)}function mE(a){a=a|0;return a+40|0}function nE(a){a=a|0;return c[a+16>>2]|0}function oE(a){a=a|0;return +(+g[a+60>>2])}function pE(a){a=a|0;return +(+g[a+52>>2])}function qE(a){a=a|0;return +(+g[a+56>>2])}function rE(a){a=a|0;return a+108|0}function sE(a){a=a|0;return 212}function tE(a){a=a|0;return c[a+96>>2]|0}function uE(a,b){a=a|0;b=+b;g[a+8>>2]=b;return}function vE(a,b){a=a|0;b=+b;g[a+4>>2]=b;return}function wE(a){a=a|0;return a+16|0}function xE(a){a=+a;return a<1.0|0}function yE(a,b){a=a|0;b=b|0;return 1}function zE(a){a=a|0;return a+324|0}function AE(a){a=a|0;OF(a);return}function BE(a,b){a=a|0;b=b|0;l=a;m=b}function CE(a){a=a|0;return a+188|0}function DE(a){a=a|0;return 204}function EE(a,b){a=a|0;b=b|0;return}function FE(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;S(42)}function GE(a){a=a|0;return a+36|0}function HE(a){a=a|0;return +(+g[a+44>>2])}function IE(a){a=a|0;return +(+g[a+40>>2])}function JE(a){a=a|0;return +(+g[a+36>>2])}function KE(a){a=a|0;return +(+g[a+48>>2])}function LE(a){a=a|0;return 220}function ME(a){a=a|0;return 256}function NE(a){a=a|0;return +(+g[a+72>>2])}function OE(a,b){a=a|0;b=+b;g[a>>2]=b;return}function PE(a){a=a|0;c[a>>2]=2980;return}function QE(a){a=a|0;c[a>>2]=8184;return}function RE(a){a=a|0;AE(a);return}function SE(a){a=a|0;return +(+g[a+24>>2])}function TE(a){a=a|0;return +(+g[a+4>>2])}function UE(a){a=a|0;return +(+g[a+20>>2])}function VE(a){a=a|0;return +(+g[a+32>>2])}function WE(a){a=a|0;return +(+g[a+16>>2])}function XE(a){a=a|0;return +(+g[a+12>>2])}function YE(a){a=a|0;return +(+g[a+28>>2])}function ZE(a){a=a|0;return 52}function _E(a){a=a|0;return 68}function $E(a){a=a|0;return 84}function aF(a,b){a=a|0;b=b|0;return a+(b<<4)|0}function bF(a){a=a|0;return a+352|0}function cF(a){a=a|0;return a+868|0}function dF(a){a=a|0;return +(+g[a+8>>2])}function eF(a){a=a|0;return a+316|0}function fF(a){a=a|0;return a+300|0}function gF(a,b){a=a|0;b=b|0;hb[a&511](b|0)}function hF(a,b,c,d){a=a|0;b=b|0;c=c|0;d=+d;S(37)}function iF(a){a=a|0;return a+32|0}function jF(a){a=a|0;return 24}function kF(a,b){a=a|0;b=+b;return}function lF(a,b){a=a|0;b=b|0;return bu(a,b)|0}function mF(a){a=a|0;return a+68|0}function nF(a){a=a|0;ax(a);return}function oF(a,b,c,d){a=a|0;b=+b;c=c|0;d=d|0;S(9)}function pF(a,b,c,d){a=a|0;b=b|0;c=+c;d=d|0;S(7)}function qF(a){a=a|0;YG(a+-4|0);return}function rF(a){a=a|0;Yh(a);return}function sF(a,b,c){a=a|0;b=b|0;c=c|0;S(28);return 0.0}function tF(a){a=a|0;return bH(a)|0}function uF(a){a=a|0;return a+708|0}function vF(a){a=a|0;return 488}function wF(a,b,c){a=a|0;b=b|0;c=c|0;S(16);return 0}function xF(a){a=a|0;return 32}function yF(a){a=a|0;return a+76|0}function zF(a){a=a|0;return a+328|0}function AF(a){a=a|0;return 60}function BF(a){a=a|0;return 428}function CF(a){a=a|0;c[a>>2]=3056;return}function DF(a){a=a|0;return a+28|0}function EF(a){a=a|0;return a+288|0}function FF(){return Br(1)|0}function GF(a){a=+a;return +(+sz(a)*2.0)}function HF(a){a=a|0;return a+312|0}function IF(a){a=a|0;c[a>>2]=4560;return}function JF(a){a=a|0;c[a>>2]=5132;return}function KF(a){a=a|0;return (a&255)<<8|a>>8&255|0}function LF(a,b,c){a=a|0;b=b|0;c=+c;S(19);return 0}function MF(a){a=a|0;return 11238}function NF(a){a=a|0;return a+92|0}function OF(a){a=a|0;c[a>>2]=0;return}function PF(a){a=a|0;return 4}function QF(a){a=a|0;return 17947}function RF(a){a=a|0;return 17663}function SF(a){a=a|0;c[a>>2]=3032;return}function TF(){return Fs()|0}function UF(a){a=a|0;return 11126}function VF(a){a=a|0;return 16809}function WF(a){a=+a;return +(+Vg(a,6.2831854820251465))}function XF(a){a=a|0;return a+72|0}function YF(a,b,c){a=a|0;b=b|0;c=c|0;S(38)}function ZF(a){a=a|0;return 17193}function _F(a){a=a|0;return 0}function $F(a,b){a=+a;b=b|0;return +(+Zl(a,b))}function aG(){return Br(64)|0}function bG(a){a=a|0;return 17251}function cG(a){a=a|0;return a+48|0}function dG(a){a=a|0;return 17449}function eG(a){a=a|0;return 1}function fG(a,b,c){a=a|0;b=b|0;c=+c;S(40)}function gG(a,b,c){a=a|0;b=+b;c=c|0;S(11)}function hG(a){a=a|0;return 18064}function iG(a){a=a|0;return 18035}function jG(a){a=a|0;return 3}function kG(a){a=a|0;return im(a,25776)|0}function lG(a){a=a|0;return 11505}function mG(a){a=+a;return +a}function nG(a){a=a|0;return 18007}function oG(a){a=a|0;return 16524}function pG(a){a=a|0;return 17607}function qG(a){a=a|0;return 17580}function rG(a){a=a|0;return 17550}function sG(a){a=a|0;return 8}function tG(a,b,c){a=a|0;b=+b;c=+c;S(15)}function uG(a){a=a|0;return 16628}function vG(a,b){a=a|0;b=b|0;S(27);return 0}function wG(a){a=a|0;return 16586}function xG(a){a=a|0;return 16607}function yG(a){a=a|0;return 6}function zG(a){a=a|0;return 12}function AG(){return 4}function BG(a){a=a|0;return 16567}function CG(a,b){a=a|0;b=+b;S(32);return 0.0}function DG(a){a=a|0;return 2}function EG(a){a=a|0;return 17722}function FG(){c[5682]=1805;c[5683]=0;return}function GG(a){a=a|0;return a+12|0}function HG(a){a=a|0;return a+8|0}function IG(a){a=a|0;return a+4|0}function JG(a){a=a|0;Sb[a&3]()}function KG(){return 2}function LG(){return 1}function MG(){return 5}function NG(){return 3}function OG(){bb()}function PG(a){a=+a;return +(+C(+a))}function QG(a){a=+a;return +(+F(+a))}function RG(a){a=+a;return +(+E(+a))}function SG(a,b){a=a|0;b=b|0;S(4)}function TG(a){a=a|0;return}function UG(a){a=a|0;return Br(a)|0}function VG(a){a=a|0;YG(a);return}function WG(a){a=a|0;l=a}function XG(a,b){a=a|0;b=+b;S(1)}function YG(a){a=a|0;Pc(a);return}function ZG(a){a=a|0;z=a}function _G(a){a=a|0;S(20);return 0.0}function $G(){return 25736}function aH(a){a=a|0;S(6);return 0}function bH(a){a=a|0;return a|0}function cH(){return z|0}function dH(){return l|0}function eH(a){a=a|0;S(2)}function fH(){return 0}function gH(){S(39)}\n\n// EMSCRIPTEN_END_FUNCS\nvar fb=[iD,Gg,wl,Vf,Zo,Ec,Oe,Kf,Gf,Xb,Uc,rc,Id,Nd,Ac,Ot,mg,gc,Fd,Nk,wi,Xe,iD,iD,iD,iD,iD,iD,iD,iD,iD,iD];var gb=[XG,dc,Lc,Bm,YD,uD,kF,uD,rk,Sc,If,ke,eg,Pj,Te,Ic,ne,uc,hD,uD,ul,ul,ul,Vi,XG,XG,XG,XG,XG,XG,XG,XG];var hb=[eH,TG,VG,TG,VG,TG,VG,TG,VG,TG,VG,TG,VG,TG,nF,TG,VG,TG,VG,TG,VG,TG,VG,Ro,Zp,wn,qj,Dx,TG,VG,VG,VG,VG,hd,fv,TG,VG,TG,VG,TG,ax,VG,VG,TG,ax,VG,VG,TG,VG,Hx,tw,TG,VG,TG,VG,tp,So,yi,HA,Nj,It,le,Dk,Yb,wh,Uf,cn,Ne,rl,TG,VG,TG,VG,vo,Jn,wg,Qt,ac,VG,_j,rA,IF,Nu,Ad,Dm,Nu,TG,Nu,Nu,xe,Nu,Nu,ce,Nu,Dc,Xf,Hs,fD,_h,yD,VG,Bo,Pn,ss,VG,TG,VG,JF,Ou,ro,Fn,pl,Jt,Vo,bq,TG,VG,Ve,Gz,VG,VG,VG,VG,VG,VG,VG,VG,VG,VG,ak,UA,fq,ap,Qo,Ao,VG,wp,mp,lq,ep,TG,VG,vj,AD,Qd,VG,VG,VG,VG,VG,TG,VG,TG,qF,VG,VG,VG,VG,VG,VG,aq,_o,TG,VG,nq,ip,VG,VG,VG,wk,dA,VG,mj,xy,VG,Ql,uu,Oi,ax,ax,ax,ax,bp,uo,TG,VG,VG,VG,TG,ax,VG,TG,VG,TG,ax,So,Yl,Sl,ax,ax,ax,So,VG,So,rF,Du,VG,VG,QE,pu,ax,ax,ax,Wh,Cu,dj,lu,TG,lu,Xo,jq,$j,cA,VG,VG,Mo,zD,TG,VG,VG,VG,Yh,Du,TG,VG,VG,TG,VG,VG,VG,VG,VG,VG,TG,VG,VG,dq,$o,VG,VG,bk,GB,Vh,ju,No,Tn,TG,VG,TG,TG,VG,VG,Hr,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH,eH];var ib=[QA];var jb=[SG,cq,xr,EE,jA,Xz,EE,xn,Jk,EE,rs,Bn,tc,Zd,jp,EE,EE,EE,zC,Tz,Xh,dg,dh,Fj,km,xj,or,Zg,ti,Uo,dv,Uu,lw,Yv,yc,EE,Ri,ct,sn,zj,Fh,rg,Nf,gh,it,ef,kh,mc,Gk,bd,kj,lc,Di,EE,fl,mk,Ck,sk,lz,nk,Ay,bn,ok,Ri,_i,Ri,kk,Dq,kp,Ri,Si,dn,sq,Hm,Sd,Wm,gl,st,qt,rt,fh,tm,sm,Eg,mr,Bp,Fk,Gr,To,Fk,gd,ed,Uq,Fk,Gr,EE,EE,nh,ph,be,Em,EE,EE,EE,Kw,Tz,kf,$c,Ml,tt,$s,$s,EE,Ri,EE,EE,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG];var kb=[Wt,Gc,Wg,Wt];var lb=[aH,_F,eG,rD,RC,RC,nE,lD,BF,DG,Vq,UF,zG,GG,MF,ZE,_F,xF,lG,DG,jG,jG,eG,kE,WC,dD,PF,vF,DG,cE,ZE,FD,$E,DE,sE,LE,eG,Wx,Mu,ME,GD,su,JC,JC,yF,oG,jF,BG,AF,wG,xG,uG,FC,VF,AF,ZF,mF,bG,ZE,dG,_E,tE,tE,_F,rG,AF,qG,pG,PB,RF,_F,_F,_F,EG,yG,sG,zG,yG,$E,rE,QF,nG,AF,iG,hG,lD,FB,jE,aE,aE,nE,nE,IG,_F,eG,nE,nE,IG,RC,_F,tD,tD,nE,Es,aH,aH,aH,aH,aH,aH,aH,aH,aH,aH,aH,aH,aH,aH,aH,aH,aH,aH,aH,aH,aH,aH,aH,aH];var mb=[pF,Xj,fo,Ei,$m,Im,pF,pF];var nb=[nB];var ob=[oF];var pb=[ID,Lm,no,Ln,Tj,Rj,Eh,an,bl,Zk,Bl,$f,zl,so,hm,yl,ql,vi,Dl,Fc,Tu,iw,qf,ID,ID,ID,ID,ID,ID,ID,ID,ID];var qb=[gG,Fg,Sz,Dz,nt,Ej,Fi,Eo,nt,nt,Ti,Xk,Fl,Ss,xi,gG];var rb=[Nv,up];var sb=[Yt];var tb=[ZA,Nt,Ud,Nt,Nt,Vd,Nt,Nt,Cf,gf,Rs,Nt,Nt,ZA,ZA,ZA];var ub=[tG,Pd,fg,fj,Of,tf,tG,tG];var vb=[wF,hn,mi,bc,Un,dl,Zf,Og,Sh,nf,Pm,Ah,qh,pf,Ze,lf,Om,_p,Sj,wf,Uk,pg,el,Lh,Tk,ve,Sk,vd,PA,PA,cf,Mj,Ag,ng,ai,Yn,Yk,wF,wF,wF,wF,wF,wF,wF,wF,wF,wF,wF,wF,wF,wF,wF,wF,wF,wF,wF,wF,wF,wF,wF,wF,wF,wF,wF];var wb=[DA];var xb=[eA,Kd,nl,Xl,yo,Um,Ai,eA];var yb=[LF,rh,wC,wC,vm,LF,LF,LF];var zb=[_G,lo,XE,Fy,HE,NE,oC,Rp,Qp,Rp,_G,_G,_G,_G,_G,_G];var Ab=[$y,Yc,jd,Bd];var Bb=[nz,ek,dk,nz];var Cb=[nD];var Db=[py,Dg];var Eb=[wv,oh];var Fb=[ku,Rl,Rl,ku];var Gb=[vG,Lq,Tq,Mq,yE,yE,yE,Wb,Ox,Ox,od,Kl,Gm,Qw,on,us,cl,iq,Dp,Ak,hi,Rn,gq,vG,vG,vG,vG,vG,vG,vG,vG,vG];var Hb=[sF,nj,Vj,ci,Kk,Mn,Kj,qm,_m,yh,nm,bm,Vl,sF,sF,sF];var Ib=[Lt,Ii,Kc,Lt];var Jb=[mD,Bu];var Kb=[Gu,jc,ri,Gu];var Lb=[CG,Lv];var Mb=[et];var Nb=[tB,Uj,Uj,tB];var Ob=[BD,Mc];var Pb=[Lu,ld,Bf,Lu];var Qb=[hF,by,fc,Wd,Ge,bs,lj,je,Ul,xm,hF,hF,hF,hF,hF,hF];var Rb=[YF,gD,gi,se,ev,Uh,Kn,gD,gj,wj,Qs,gD,zd,fd,gD,Lk,Bk,xk,Lp,Li,bf,Nh,gD,gD,si,Rh,$e,hw,gw,qC,qC,qC,qC,kd,Mh,Dj,ik,Cs,hh,ht,Ke,oe,ff,Xg,Lk,Cj,Xn,ih,Lk,Kh,gD,Ol,Nn,Tl,Ll,ol,Ij,zm,Am,ym,gn,vn,af,An,gD,gD,gD,gD,dp,qo,to,vl,sj,Ph,io,qC,qC,qC,qC,ii,md,Jh,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF,YF];var Sb=[gH,OG,ck,Vs];var Tb=[fG,pv,xu,lr,Mk,pc,fG,fG];var Ub=[eE,hg];var Vb=[FE,Me,Ez,jx,Zu,Ff,Af,Ts,uj,Fq,At,tk,xc,sc,Se,xs,$g,xf,Zb,Bt,em,al,oo,Af,Pe,vg,Jf,qe,Is,Sr,jg,bh,Ts,Zh,xl,mo,ah,Jd,El,bj,jj,Ho,Yf,zg,th,oi,zk,Ez,uh,tg,di,Ez,Ez,Wi,aj,Pl,Ek,Wj,Xd,ie,$h,zc,aj,il,$k,hl,Wc,ln,ij,ln,jl,lp,yn,Ok,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE,FE];return{_emscripten_bind_btCylinderShape___destroy___0:Kv,_emscripten_bind_btGeneric6DofConstraint_enableFeedback_1:Ix,_emscripten_bind_btGhostObject___destroy___0:Iv,_emscripten_bind_Config_get_kSRHR_CL_0:pE,_emscripten_bind_btPoint2PointConstraint_set_m_setting_1:ms,_emscripten_bind_btQuaternion_dot_1:BA,_emscripten_bind_btDispatcherInfo_set_m_useContinuous_1:vz,_emscripten_bind_btKinematicCharacterController_setWalkDirection_1:Pu,_emscripten_bind_btCollisionObject_isActive_0:qz,_emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelsDampingRelaxation_1:cC,_emscripten_bind_btVehicleTuning_set_m_frictionSlip_1:bD,_emscripten_bind_btDiscreteDynamicsWorld_btDiscreteDynamicsWorld_4:Yp,_emscripten_bind_btCapsuleShapeX_getMargin_0:Fy,_emscripten_bind_Node_set_m_n_1:Er,_emscripten_bind_btCompoundShape_getMargin_0:Fy,_emscripten_bind_RaycastInfo_set_m_wheelDirectionWS_1:fr,_emscripten_bind_btVehicleRaycasterResult_get_m_hitNormalInWorld_0:wE,_emscripten_bind_btRigidBody_setUserPointer_1:ly,_emscripten_bind_ClosestRayResultCallback_get_m_hitPointWorld_0:mF,_emscripten_bind_btTypedConstraint_setBreakingImpulseThreshold_1:Ov,_emscripten_bind_btQuaternion_setX_1:CC,_emscripten_bind_btCylinderShapeZ_getMargin_0:Fy,_emscripten_bind_btDispatcherInfo_get_m_timeOfImpact_0:XE,_emscripten_bind_btQuaternion_setZ_1:AC,_emscripten_bind_btCollisionObject_getUserIndex_0:RA,_emscripten_bind_btDispatcherInfo_get_m_allowedCcdPenetration_0:YE,_emscripten_bind_LocalConvexResult_get_m_hitNormalLocal_0:HG,_emscripten_bind_btSoftBodyWorldInfo_set_water_density_1:vE,_emscripten_bind_btRigidBodyConstructionInfo_get_m_restitution_0:SA,_emscripten_bind_btKinematicCharacterController_setMaxSlope_1:Jv,_emscripten_bind_btQuadWord_z_0:MC,_emscripten_bind_btSoftBody_setCcdMotionThreshold_1:lx,_emscripten_bind_Material___destroy___0:dC,_emscripten_bind_btHingeConstraint_btHingeConstraint_2:Tf,_emscripten_bind_btSoftBody_rotate_1:Oj,_emscripten_bind_btWheelInfo_get_m_suspensionRestLength1_0:xC,_emscripten_bind_btWheelInfo_get_m_suspensionStiffness_0:fC,_emscripten_bind_btVector4_setY_1:BC,_emscripten_enum_PHY_ScalarType_PHY_UCHAR:MG,_emscripten_bind_btQuaternion_setW_1:iC,_emscripten_bind_btSoftRigidDynamicsWorld___destroy___0:Kv,_emscripten_bind_btSoftRigidDynamicsWorld_removeConstraint_1:ov,_emscripten_bind_RaycastInfo_get_m_wheelAxleWS_0:mF,_emscripten_bind_btRigidBodyConstructionInfo_get_m_angularDamping_0:FA,_emscripten_bind_btCollisionDispatcher___destroy___0:Kv,_emscripten_bind_btRigidBody_applyCentralImpulse_1:ot,_emscripten_bind_btConvexHullShape_getMargin_0:Fy,_emscripten_bind_btDefaultMotionState_getWorldTransform_1:Sv,_emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_1:fu,_emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_3:pt,_emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_2:lt,_emscripten_bind_btSoftRigidDynamicsWorld_addAction_1:lw,_emscripten_bind_btDynamicsWorld_rayTest_3:Pt,_emscripten_bind_Config_set_kSR_SPLT_CL_1:bC,_emscripten_bind_btQuadWord_x_0:fE,_emscripten_bind_Config_get_diterations_0:aE,_emscripten_bind_btCollisionObject_isKinematicObject_0:ox,_emscripten_bind_btSoftRigidDynamicsWorld_removeSoftBody_1:ui,_emscripten_bind_btSphereShape___destroy___0:Kv,_emscripten_bind_btGeneric6DofSpringConstraint_setLinearUpperLimit_1:jv,_emscripten_bind_btQuaternion_getAngleShortestPath_0:uz,_emscripten_bind_ClosestConvexResultCallback_set_m_hitNormalWorld_1:Kq,_emscripten_bind_btSoftBody_isKinematicObject_0:ox,_emscripten_bind_btRigidBody_getCenterOfMassTransform_0:pD,_emscripten_bind_btTransform_setIdentity_0:yC,_emscripten_bind_btGhostObject_isKinematicObject_0:ox,_emscripten_bind_btGeneric6DofSpringConstraint_btGeneric6DofSpringConstraint_5:fk,_emscripten_bind_btWheelInfoConstructionInfo___destroy___0:dC,_emscripten_bind_btCapsuleShape___destroy___0:Kv,_emscripten_bind_btDefaultCollisionConfiguration_btDefaultCollisionConfiguration_1:qs,_emscripten_bind_btCollisionObject_activate_1:Rr,_emscripten_bind_btCollisionObject_activate_0:Ys,_emscripten_bind_btKinematicCharacterController_setUpAxis_1:rw,_emscripten_bind_btSoftRigidDynamicsWorld_addConstraint_1:lv,_emscripten_bind_Config_set_kSSHR_CL_1:tC,_emscripten_bind_btWheelInfoConstructionInfo_get_m_maxSuspensionForce_0:iE,_emscripten_bind_btDispatcherInfo_set_m_timeOfImpact_1:YD,_emscripten_bind_btCollisionDispatcher_btCollisionDispatcher_1:Rk,_emscripten_bind_btVector3_setX_1:CC,_emscripten_bind_btCollisionConfiguration___destroy___0:Kv,_emscripten_bind_btCapsuleShapeZ_setMargin_1:Yw,_emscripten_bind_btHingeConstraint_enableFeedback_1:Ix,_emscripten_bind_btActionInterface_updateAction_2:Ru,stackAlloc:Jy,_emscripten_bind_btHeightfieldTerrainShape_setLocalScaling_1:fw,_emscripten_bind_btManifoldPoint_set_m_positionWorldOnB_1:_q,_emscripten_bind_btRaycastVehicle_updateSuspension_1:ll,_emscripten_bind_btManifoldPoint_set_m_localPointB_1:kr,_emscripten_bind_btVector3_setZ_1:AC,_emscripten_bind_btKinematicCharacterController_setUseGhostSweepTest_1:Su,_emscripten_bind_btQuaternion_setValue_4:Yo,_emscripten_bind_btDispatcherInfo_set_m_dispatchFunc_1:Xz,_emscripten_bind_btQuaternion_setRotation_2:kw,_emscripten_bind_btMotionState_setWorldTransform_1:Wv,_emscripten_bind_LocalShapeInfo___destroy___0:dC,_emscripten_bind_btSoftBody_appendAnchor_4:Dd,_emscripten_bind_btPoint2PointConstraint_get_m_setting_0:ND,_emscripten_bind_btQuadWord_setY_1:BC,_emscripten_bind_btRigidBody_isKinematicObject_0:ox,_emscripten_bind_ContactResultCallback_addSingleResult_7:wq,_emscripten_bind_btRigidBodyConstructionInfo_set_m_restitution_1:Ty,_emscripten_bind_btVector4_rotate_2:jo,_emscripten_bind_btDefaultMotionState_get_m_graphicsWorldTrans_0:IG,_emscripten_bind_btSliderConstraint_btSliderConstraint_5:hf,_emscripten_bind_btConeTwistConstraint_setDamping_1:ey,_emscripten_bind_btPairCachingGhostObject_btPairCachingGhostObject_0:Dh,_emscripten_bind_btWheelInfoConstructionInfo_get_m_suspensionRestLength_0:KE,_emscripten_bind_btDiscreteDynamicsWorld_getSolverInfo_0:qA,_emscripten_bind_btCylinderShape_setMargin_1:Yw,_emscripten_bind_btRaycastVehicle_rayCast_1:_x,_emscripten_bind_btCollisionWorld___destroy___0:Kv,_emscripten_bind_btSoftBodyWorldInfo_get_m_broadphase_0:EC,_emscripten_bind_LocalConvexResult_get_m_hitPointLocal_0:SD,_emscripten_bind_btBoxShape_btBoxShape_1:Gh,_emscripten_bind_btPersistentManifold_getBody1_0:MB,_emscripten_bind_ClosestRayResultCallback_set_m_collisionObject_1:Xz,_emscripten_bind_RaycastInfo_set_m_isInContact_1:bA,_emscripten_bind_btKinematicCharacterController_setGravity_1:uD,_emscripten_bind_btGeneric6DofConstraint_btGeneric6DofConstraint_5:hq,_emscripten_bind_btGeneric6DofConstraint_btGeneric6DofConstraint_3:pr,_emscripten_bind_LocalShapeInfo_get_m_shapePart_0:PD,_emscripten_bind_btSoftRigidDynamicsWorld_removeAction_1:Yv,_emscripten_bind_btWheelInfo_get_m_rollInfluence_0:XC,_emscripten_bind_btRigidBody_activate_0:Ys,_emscripten_bind_btVector4_setValue_4:Yo,_emscripten_bind_btBvhTriangleMeshShape_setLocalScaling_1:fw,_emscripten_bind_tNodeArray_size_0:KD,_emscripten_bind_btPoint2PointConstraint_setBreakingImpulseThreshold_1:Ov,_emscripten_bind_btDynamicsWorld_getDispatchInfo_0:Qz,_emscripten_bind_btCompoundShape_removeChildShapeByIndex_1:xw,_emscripten_bind_btSoftBody_appendFace_4:Ut,_emscripten_bind_btConvexTriangleMeshShape_btConvexTriangleMeshShape_2:_k,_emscripten_bind_btConvexTriangleMeshShape_btConvexTriangleMeshShape_1:tl,_emscripten_bind_ClosestConvexResultCallback_set_m_hitPointWorld_1:Pq,_emscripten_bind_RayResultCallback_set_m_collisionFilterMask_1:_y,_emscripten_bind_btBoxShape_getMargin_0:Fy,_emscripten_bind_btPairCachingGhostObject___destroy___0:Iv,_emscripten_bind_btPairCachingGhostObject_setUserPointer_1:ly,_emscripten_bind_btDynamicsWorld_addCollisionObject_3:kt,_emscripten_bind_btPairCachingGhostObject_activate_0:Ys,_emscripten_bind_btPairCachingGhostObject_activate_1:Rr,_emscripten_bind_btWheelInfoConstructionInfo_set_m_suspensionStiffness_1:tC,_emscripten_bind_btContactSolverInfo_get_m_splitImpulsePenetrationThreshold_0:kz,_emscripten_bind_btSoftBody_setUserPointer_1:ly,_emscripten_bind_btSoftBody_setMass_2:xt,_emscripten_bind_Config_get_kCHR_0:JE,_emscripten_bind_btPairCachingGhostObject_forceActivationState_1:$z,_emscripten_bind_btDefaultMotionState___destroy___0:Kv,_emscripten_bind_btDispatcherInfo_get_m_stepCount_0:rD,_emscripten_bind_btRigidBodyConstructionInfo_set_m_angularDamping_1:Ey,_emscripten_bind_btQuadWord_setW_1:iC,_emscripten_bind_btRigidBodyConstructionInfo_get_m_friction_0:pB,_emscripten_bind_btCapsuleShapeX_btCapsuleShapeX_2:Ym,_emscripten_bind_LocalShapeInfo_set_m_shapePart_1:eB,_emscripten_bind_btRigidBody_setLinearFactor_1:Ex,_emscripten_bind_btCompoundShape_getChildShape_1:fy,_emscripten_bind_btDispatcherInfo_set_m_useConvexConservativeDistanceUtil_1:wx,_emscripten_bind_btSoftRigidDynamicsWorld_setGravity_1:Fv,_emscripten_bind_btRaycastVehicle_getUpAxis_0:hC,_emscripten_bind_btRaycastVehicle_getCurrentSpeedKmHour_0:vx,_emscripten_bind_btWheelInfo_get_m_engineForce_0:oD,_emscripten_bind_Config_get_kSR_SPLT_CL_0:VD,_emscripten_bind_btRaycastVehicle_setSteeringValue_2:Xu,_emscripten_bind_btPoint2PointConstraint___destroy___0:Kv,_emscripten_bind_btSoftBody_getUserPointer_0:sC,_emscripten_bind_btCollisionShape_setMargin_1:Yw,_emscripten_bind_btGeneric6DofConstraint_setAngularUpperLimit_1:$u,_emscripten_bind_btDiscreteDynamicsWorld_addConstraint_2:hu,_emscripten_bind_btDiscreteDynamicsWorld_addConstraint_1:lv,_emscripten_bind_btRigidBodyConstructionInfo_set_m_angularSleepingThreshold_1:Fx,_emscripten_bind_Config_get_kVCF_0:TE,_emscripten_bind_btWheelInfoConstructionInfo_get_m_suspensionStiffness_0:oE,_emscripten_bind_btRaycastVehicle_getRightAxis_0:LB,_emscripten_bind_btContactSolverInfo_set_m_numIterations_1:wz,_malloc:ec,_emscripten_bind_btDispatcherInfo_get_m_useEpa_0:jC,_emscripten_bind_btTransform_btTransform_2:vu,_emscripten_bind_btTransform_btTransform_0:aG,_emscripten_bind_btPairCachingGhostObject_getUserIndex_0:RA,_emscripten_bind_Config_set_kVC_1:_C,_emscripten_bind_btSoftRigidDynamicsWorld_addSoftBody_3:Xi,_emscripten_bind_btVector3_op_sub_1:wB,_emscripten_bind_btWheelInfo_set_m_wheelsRadius_1:vA,_emscripten_bind_btQuaternion_length_0:qD,_emscripten_bind_btDispatcherInfo_set_m_enableSPU_1:Rz,_emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelsDampingCompression_0:VD,_emscripten_bind_btRaycastVehicle_setCoordinateSystem_3:ft,_emscripten_bind_btSoftBody_appendNode_2:Tc,_emscripten_bind_btCollisionObject_setActivationState_1:iv,_emscripten_bind_btQuaternion_angle_1:Zz,_emscripten_bind_btPersistentManifold___destroy___0:Kz,_emscripten_bind_btConstraintSetting_get_m_impulseClamp_0:dF,_emscripten_bind_btCylinderShapeZ___destroy___0:Kv,_emscripten_bind_btMatrix3x3___destroy___0:dC,setTempRet0:ZG,_emscripten_bind_btQuaternion_angleShortestPath_1:zx,_emscripten_bind_Config_set_kKHR_1:SC,_emscripten_bind_ConvexResultCallback_hasHit_0:$w,_emscripten_bind_btCollisionShape_calculateLocalInertia_2:Au,_emscripten_bind_btGeneric6DofSpringConstraint_setBreakingImpulseThreshold_1:Ov,_emscripten_bind_Config_set_kPR_1:$C,_emscripten_bind_btCollisionWorld_convexSweepTest_5:Yq,_emscripten_bind_btSoftBody_set_m_materials_1:Pv,_emscripten_bind_ClosestRayResultCallback_set_m_hitPointWorld_1:mr,_emscripten_bind_btVehicleRaycasterResult___destroy___0:dC,_emscripten_bind_btCapsuleShapeX_calculateLocalInertia_2:Au,_emscripten_bind_btConstraintSetting_set_m_damping_1:vE,_emscripten_bind_btWheelInfo_set_m_bIsFrontWheel_1:Pz,_emscripten_bind_btRigidBody_setCcdMotionThreshold_1:lx,_emscripten_bind_btConvexHullShape_setMargin_1:Yw,_emscripten_bind_btRigidBody_applyForce_2:ow,_emscripten_bind_btConeShapeZ_calculateLocalInertia_2:Au,_emscripten_bind_btConstraintSetting_set_m_tau_1:OE,_emscripten_bind_btConvexHullShape_calculateLocalInertia_2:Au,_emscripten_bind_btQuaternion_op_div_1:cB,___uremdi3:yr,_emscripten_bind_RaycastInfo_get_m_contactPointWS_0:wE,_emscripten_bind_btSoftBody_setCollisionFlags_1:Rx,_emscripten_bind_btSphereShape_calculateLocalInertia_2:Au,_emscripten_bind_Config_set_maxvolume_1:nC,_emscripten_bind_btSoftRigidDynamicsWorld_getSolverInfo_0:qA,_emscripten_bind_btCollisionDispatcher_getManifoldByIndexInternal_1:nv,_emscripten_bind_btSoftBody_setTotalMass_2:Tg,_emscripten_bind_ClosestRayResultCallback_get_m_rayToWorld_0:GE,_emscripten_bind_btGhostObject_setFriction_1:pz,_emscripten_bind_btCollisionWorld_rayTest_3:Pt,stackRestore:WG,_emscripten_bind_btRigidBody_setCcdSweptSphereRadius_1:Vw,_emscripten_bind_btCylinderShapeZ_setMargin_1:Yw,_emscripten_bind_btRigidBody_setFriction_1:pz,_emscripten_bind_LocalConvexResult_set_m_hitPointLocal_1:ar,_emscripten_bind_btGhostObject_setWorldTransform_1:Aw,_emscripten_bind_tMaterialArray_size_0:KD,_emscripten_bind_RaycastInfo_set_m_hardPointWS_1:nr,_emscripten_bind_btManifoldPoint_getAppliedImpulse_0:$x,_emscripten_bind_btDiscreteDynamicsWorld_removeRigidBody_1:rv,_emscripten_bind_btConvexHullShape___destroy___0:Kv,_emscripten_bind_btDiscreteDynamicsWorld_getBroadphase_0:$B,_emscripten_bind_btDiscreteDynamicsWorld_addAction_1:lw,_emscripten_bind_btVector4_setX_1:CC,_emscripten_bind_btKinematicCharacterController_jump_0:mx,_emscripten_bind_btCollisionObject_getUserPointer_0:sC,_emscripten_bind_btWheelInfo_set_m_raycastInfo_1:ws,_emscripten_bind_btCollisionWorld_contactTest_2:Mm,_emscripten_bind_btConeTwistConstraint_setMaxMotorImpulseNormalized_1:mv,_emscripten_bind_btConvexTriangleMeshShape_setLocalScaling_1:fw,_emscripten_bind_btRigidBody_upcast_1:Sy,_emscripten_bind_btTransform_setOrigin_1:Qy,_emscripten_bind_btVector4_setZ_1:AC,_emscripten_bind_btQuadWord_y_0:NC,_emscripten_bind_btTransform_getBasis_0:tF,_emscripten_bind_btPairCachingGhostObject_setFriction_1:pz,_emscripten_bind_btSoftBody_setRollingFriction_1:Zx,_emscripten_bind_Config_set_kSRHR_CL_1:uC,_emscripten_bind_btCollisionDispatcher_getNumManifolds_0:Iy,_emscripten_bind_btVehicleRaycaster___destroy___0:Kv,_emscripten_bind_ClosestRayResultCallback___destroy___0:Kv,_emscripten_bind_ClosestConvexResultCallback_get_m_convexFromWorld_0:GG,_emscripten_bind_btCylinderShapeX_setMargin_1:Yw,_emscripten_bind_btQuadWord_w_0:OC,_emscripten_bind_Node___destroy___0:dC,_emscripten_bind_btAxisSweep3___destroy___0:Kv,_emscripten_bind_btDiscreteDynamicsWorld_contactTest_2:Mm,_emscripten_bind_btBvhTriangleMeshShape_calculateLocalInertia_2:Au,_emscripten_bind_btCompoundShape_setMargin_1:Yw,_emscripten_bind_btCompoundShape_getNumChildShapes_0:xz,_emscripten_bind_btSoftBodyWorldInfo_set_m_broadphase_1:Mz,_emscripten_bind_btCapsuleShape_setLocalScaling_1:fw,_emscripten_bind_btGhostObject_btGhostObject_0:Bi,_emscripten_bind_btConeShape_btConeShape_2:am,_emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalAngularDampingFactor_1:_w,_emscripten_bind_btManifoldPoint_set_m_localPointA_1:Cr,_emscripten_bind_btCapsuleShapeX_setMargin_1:Yw,_emscripten_bind_Config_set_kMT_1:aD,_emscripten_bind_btVector3_dot_1:As,_emscripten_bind_btGhostObject_getUserPointer_0:sC,_emscripten_bind_btVector4_op_add_1:xB,_emscripten_bind_btWheelInfo___destroy___0:dC,_emscripten_bind_btSoftRigidDynamicsWorld_getSoftBodyArray_0:Yx,_emscripten_bind_btHingeConstraint_btHingeConstraint_4:qg,_emscripten_bind_btTransform_setRotation_1:az,_emscripten_bind_Config_set_kSHR_1:uD,_emscripten_bind_btPoint2PointConstraint_enableFeedback_1:Ix,_emscripten_bind_ClosestRayResultCallback_set_m_collisionFilterGroup_1:Uy,_emscripten_bind_btAxisSweep3_btAxisSweep3_2:ds,_emscripten_bind_btAxisSweep3_btAxisSweep3_3:Ar,_emscripten_bind_btDynamicsWorld___destroy___0:Kv,_emscripten_bind_btVector3_setY_1:BC,_emscripten_bind_btAxisSweep3_btAxisSweep3_4:er,_emscripten_bind_btAxisSweep3_btAxisSweep3_5:Hq,_emscripten_bind_btQuadWord_setX_1:CC,_emscripten_bind_tMaterialArray___destroy___0:Tv,_emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalLinearDampingThresholdSqr_1:Fw,_emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalLinearDampingThresholdSqr_0:my,_emscripten_bind_Config_set_piterations_1:BB,_emscripten_bind_btOverlappingPairCache___destroy___0:Kv,_emscripten_bind_btRigidBody_setUserIndex_1:Ly,_emscripten_bind_Material_get_m_kAST_0:dF,_emscripten_bind_btConstraintSetting___destroy___0:dC,_emscripten_bind_btWheelInfo_btWheelInfo_1:Hv,_emscripten_bind_RayResultCallback___destroy___0:Kv,_emscripten_bind_RaycastInfo_get_m_contactNormalWS_0:bH,_emscripten_bind_btSoftBodyWorldInfo_get_water_density_0:TE,_emscripten_bind_btPersistentManifold_getBody0_0:NB,_emscripten_bind_btConeShapeX_btConeShapeX_2:$l,_emscripten_bind_btSoftBody_setCcdSweptSphereRadius_1:Vw,_emscripten_bind_btConeTwistConstraint_enableFeedback_1:Ix,_emscripten_bind_btRaycastVehicle_setPitchControl_1:cy,_emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration_btSoftBodyRigidBodyCollisionConfiguration_0:gp,_emscripten_bind_btCapsuleShapeZ_setLocalScaling_1:fw,_emscripten_bind_Config_get_piterations_0:$D,_emscripten_bind_btSoftBody_translate_1:Il,_emscripten_bind_btSliderConstraint_setUpperLinLimit_1:px,_emscripten_bind_btConeTwistConstraint_btConeTwistConstraint_2:Bg,_emscripten_bind_btVector3_op_mul_1:Xs,_emscripten_bind_btConcaveShape___destroy___0:Kv,_emscripten_bind_Config_get_kSK_SPLT_CL_0:WD,_emscripten_bind_btConeTwistConstraint_btConeTwistConstraint_4:ig,_emscripten_bind_btQuaternion_x_0:fE,_emscripten_bind_btSoftRigidDynamicsWorld_btSoftRigidDynamicsWorld_5:mf,_emscripten_bind_btVehicleRaycasterResult_set_m_distFraction_1:aD,_emscripten_bind_Config_set_timescale_1:mC,_emscripten_bind_LocalConvexResult_set_m_hitNormalLocal_1:Ir,_emscripten_bind_btConcaveShape_setLocalScaling_1:fw,_emscripten_bind_btDiscreteDynamicsWorld_getDispatchInfo_0:Qz,_emscripten_bind_btConeShapeX_setLocalScaling_1:fw,_emscripten_bind_btSoftBody_appendLink_4:Tt,_emscripten_bind_btQuaternion_z_0:MC,_emscripten_bind_btConvexHullShape_btConvexHullShape_0:Gv,_emscripten_bind_btWheelInfo_set_m_maxSuspensionForce_1:uA,_emscripten_bind_btConstraintSetting_get_m_damping_0:TE,_emscripten_bind_btVector4_op_mul_1:Xs,_emscripten_bind_btSoftRigidDynamicsWorld_removeCollisionObject_1:Qu,_emscripten_bind_Config_get_kLF_0:WE,_emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_3:kt,_emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_2:Mt,_emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_1:zu,_emscripten_bind_btGhostObject_setContactProcessingThreshold_1:rx,_emscripten_bind_btSoftBodyHelpers_CreateFromConvexHull_4:Lr,_emscripten_bind_btCollisionWorld_getBroadphase_0:$B,_emscripten_bind_btCylinderShape_btCylinderShape_1:vv,_emscripten_bind_btDispatcherInfo_set_m_stepCount_1:jA,_emscripten_bind_btContactSolverInfo_set_m_splitImpulse_1:cz,_emscripten_bind_btKinematicCharacterController_updateAction_2:Ru,_emscripten_bind_btDefaultMotionState_btDefaultMotionState_2:Ps,_emscripten_bind_Material_set_m_flags_1:aC,_emscripten_bind_btDefaultMotionState_btDefaultMotionState_0:qr,_emscripten_bind_btDefaultMotionState_btDefaultMotionState_1:Pr,_emscripten_bind_Config_get_viterations_0:_D,_emscripten_bind_btKinematicCharacterController_canJump_0:Sw,_emscripten_bind_btSoftBodyArray_at_1:hv,_emscripten_bind_btPairCachingGhostObject_setUserIndex_1:Ly,_emscripten_bind_btRigidBody_isActive_0:qz,_emscripten_bind_btRaycastVehicle_btRaycastVehicle_3:Qk,_emscripten_bind_btSoftBody_transform_1:Ky,_emscripten_bind_btSoftRigidDynamicsWorld_getDispatcher_0:_B,_emscripten_bind_btCylinderShape_setLocalScaling_1:fw,_emscripten_bind_btPairCachingGhostObject_getWorldTransform_0:pD,_emscripten_bind_btCompoundShape_calculateLocalInertia_2:Au,_emscripten_bind_btCollisionWorld_getDispatchInfo_0:Qz,_emscripten_bind_btRigidBody_setCollisionShape_1:Wv,_emscripten_bind_btSoftBody_appendTetra_5:zf,_emscripten_bind_btConeShapeX___destroy___0:Kv,_emscripten_bind_btCollisionObject_getCollisionFlags_0:ZB,_emscripten_bind_btDispatcherInfo_set_m_enableSatConvex_1:jz,_emscripten_bind_btConeTwistConstraint_enableMotor_1:Bx,_emscripten_bind_btWheelInfo_set_m_chassisConnectionPointCS_1:Rq,_emscripten_bind_btVehicleRaycasterResult_get_m_hitPointInWorld_0:bH,_emscripten_bind_btWheelInfo_set_m_wheelsDampingCompression_1:gz,_emscripten_bind_btDefaultCollisionConfiguration_btDefaultCollisionConfiguration_0:Kp,_emscripten_bind_btPairCachingGhostObject_setRestitution_1:Dy,_emscripten_bind_Config_set_kAHR_1:UC,_emscripten_bind_btHeightfieldTerrainShape_getMargin_0:Fy,_emscripten_bind_ConvexResultCallback___destroy___0:Kv,_emscripten_bind_btSoftRigidDynamicsWorld_rayTest_3:Pt,_emscripten_bind_btQuaternion_getAngle_0:Wz,_emscripten_bind_btSliderConstraint_getBreakingImpulseThreshold_0:Rw,_emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalDampingFactor_1:Mx,_emscripten_bind_btKinematicCharacterController_btKinematicCharacterController_3:Yj,_emscripten_bind_btCollisionObject_setContactProcessingThreshold_1:rx,_emscripten_bind_btCompoundShape___destroy___0:Kv,_emscripten_bind_btHingeConstraint_setMotorTarget_2:Jj,_emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalAngularDampingFactor_0:Ny,_emscripten_bind_LocalConvexResult___destroy___0:dC,_emscripten_bind_btSequentialImpulseConstraintSolver___destroy___0:Kv,setThrew:IB,_emscripten_bind_btSoftBodyHelpers_CreateRope_5:Bh,_emscripten_bind_btRaycastVehicle___destroy___0:Kv,_emscripten_bind_btCollisionWorld_addCollisionObject_3:kt,_emscripten_bind_btRigidBody_getCollisionFlags_0:ZB,_emscripten_bind_btCollisionShape_setLocalScaling_1:fw,_emscripten_bind_ClosestConvexResultCallback_get_m_closestHitFraction_0:TE,_emscripten_bind_LocalConvexResult_get_m_hitCollisionObject_0:PD,_emscripten_bind_btMatrix3x3_setEulerZYX_3:bw,_emscripten_bind_btSoftBody_getTotalMass_0:zo,_emscripten_bind_btDispatcherInfo_get_m_convexConservativeDistanceThreshold_0:JE,_emscripten_bind_btRigidBody_getUserPointer_0:sC,_emscripten_bind_Config_get_kSHR_0:HE,_emscripten_bind_btHeightfieldTerrainShape_calculateLocalInertia_2:Au,_emscripten_bind_btRigidBody_setMotionState_1:tx,_emscripten_bind_RayResultCallback_get_m_collisionFilterMask_0:zB,_emscripten_bind_btCollisionWorld_getDispatcher_0:_B,_emscripten_bind_btVector4_dot_1:As,_emscripten_bind_btSoftBody_forceActivationState_1:$z,_emscripten_bind_btCollisionObject_setRollingFriction_1:Zx,_emscripten_bind_Config_set_kSK_SPLT_CL_1:cC,_emscripten_bind_RayResultCallback_set_m_collisionFilterGroup_1:Uy,_emscripten_bind_btVehicleRaycaster_castRay_3:Ct,_i64Subtract:St,_emscripten_bind_btCylinderShapeX_getMargin_0:Fy,_emscripten_bind_btRigidBody_setDamping_2:qn,_emscripten_bind_btDynamicsWorld_getDispatcher_0:_B,_emscripten_bind_btGhostObject_setCollisionFlags_1:Rx,_emscripten_bind_btMatrix3x3_getRotation_1:dy,_emscripten_bind_btWheelInfo_set_m_engineForce_1:EA,_emscripten_bind_btConeTwistConstraint_setMaxMotorImpulse_1:Cw,_emscripten_bind_btPersistentManifold_getNumContacts_0:MA,_emscripten_bind_btCylinderShapeX_setLocalScaling_1:fw,_emscripten_bind_btDbvtBroadphase_btDbvtBroadphase_0:ew,_emscripten_bind_btSoftBodyHelpers_btSoftBodyHelpers_0:FF,_emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalDamping_0:iz,_emscripten_bind_btWheelInfoConstructionInfo_get_m_bIsFrontWheel_0:Jz,_emscripten_bind_btOverlappingPairCallback___destroy___0:Kv,_emscripten_bind_btWheelInfo_get_m_suspensionRelativeVelocity_0:bB,_emscripten_bind_btManifoldPoint_get_m_positionWorldOnB_0:iF,_emscripten_bind_tNodeArray___destroy___0:Tv,_emscripten_bind_btPairCachingGhostObject_setCcdSweptSphereRadius_1:Vw,_emscripten_bind_btHingeConstraint_enableAngularMotor_3:ou,_emscripten_bind_btRigidBody_setContactProcessingThreshold_1:rx,_emscripten_bind_btRigidBody_getLinearVelocity_0:gA,_emscripten_bind_btRigidBody_applyImpulse_2:Xv,_emscripten_bind_btConcaveShape_calculateLocalInertia_2:Au,_emscripten_bind_RaycastInfo_get_m_groundObject_0:$D,_emscripten_bind_btRigidBody_setWorldTransform_1:Aw,_emscripten_bind_LocalConvexResult_set_m_localShapeInfo_1:jA,_emscripten_bind_btRigidBody_setAngularVelocity_1:Zw,_emscripten_bind_btGeneric6DofSpringConstraint_btGeneric6DofSpringConstraint_3:qk,_emscripten_bind_Config_get_kDP_0:dF,_emscripten_bind_btConvexShape_setLocalScaling_1:fw,_emscripten_bind_Config_get_collisions_0:bE,_emscripten_bind_Node_get_m_n_0:XF,_emscripten_bind_btTriangleMeshShape_calculateLocalInertia_2:Au,stackSave:dH,___udivdi3:Nz,_emscripten_bind_btRaycastVehicle_setUserConstraintId_1:Ww,_free:Pc,_emscripten_bind_btPairCachingGhostObject_setContactProcessingThreshold_1:rx,_emscripten_bind_btGeneric6DofConstraint_setLinearUpperLimit_1:jv,_emscripten_bind_ClosestRayResultCallback_get_m_collisionFilterMask_0:zB,_emscripten_bind_RayResultCallback_hasHit_0:xx,_emscripten_bind_btRigidBody_applyLocalTorque_1:Gt,_bitshift64Shl:mt,_emscripten_bind_Config___destroy___0:Vx,_emscripten_bind_btVehicleTuning_set_m_maxSuspensionForce_1:$C,_emscripten_bind_btVehicleTuning_get_m_suspensionDamping_0:dF,_emscripten_bind_btRaycastVehicle_getWheelTransformWS_1:bx,_emscripten_bind_btQuaternion_normalize_0:QC,_emscripten_bind_btQuaternion___destroy___0:dC,_emscripten_bind_btWheelInfo_get_m_frictionSlip_0:kD,_emscripten_bind_btConeShapeZ_setLocalScaling_1:fw,_emscripten_bind_btSoftBodyWorldInfo_get_m_dispatcher_0:DC,_emscripten_bind_btGeneric6DofSpringConstraint___destroy___0:Kv,_emscripten_bind_btRaycastVehicle_getNumWheels_0:hA,_emscripten_bind_btVehicleTuning_set_m_maxSuspensionTravelCm_1:YD,_emscripten_bind_Material_set_m_kAST_1:uE,_emscripten_bind_btGhostObject_setRollingFriction_1:Zx,_emscripten_bind_btCylinderShapeZ_btCylinderShapeZ_1:Ks,___muldi3:Xr,_emscripten_bind_btSoftBodyArray___destroy___0:Tv,_emscripten_bind_btCompoundShape_btCompoundShape_0:hj,_emscripten_bind_btCompoundShape_btCompoundShape_1:Zi,_emscripten_bind_btOverlappingPairCache_setInternalGhostPairCallback_1:ov,_emscripten_bind_btStaticPlaneShape_btStaticPlaneShape_2:Gl,__GLOBAL__sub_I_btQuickprof_cpp:Wp,_emscripten_bind_btDispatcherInfo_set_m_convexConservativeDistanceThreshold_1:TC,_emscripten_bind_btSoftBody_checkLink_2:Al,_emscripten_bind_btSoftBody_getCollisionShape_0:YB,_emscripten_bind_Config_get_kDG_0:XE,_emscripten_bind_btRigidBodyConstructionInfo_set_m_linearDamping_1:My,_emscripten_bind_btDefaultVehicleRaycaster___destroy___0:Kv,_emscripten_bind_btPairCachingGhostObject_setAnisotropicFriction_2:yu,_emscripten_bind_Node_get_m_x_0:HG,_emscripten_bind_btCollisionObject_getWorldTransform_0:pD,_emscripten_bind_ClosestRayResultCallback_hasHit_0:xx,_emscripten_bind_btCompoundShape_addChildShape_2:yd,_emscripten_bind_btDispatcher___destroy___0:Kv,_emscripten_bind_btVehicleTuning_get_m_suspensionCompression_0:TE,_llvm_bswap_i16:KF,_emscripten_bind_btDiscreteDynamicsWorld___destroy___0:Kv,_emscripten_bind_btConvexShape___destroy___0:Kv,_emscripten_bind_btRaycastVehicle_updateWheelTransformsWS_1:Zt,_emscripten_bind_btWheelInfo_set_m_brake_1:uB,_memmove:fp,_emscripten_bind_btWheelInfo_set_m_worldTransform_1:wy,_emscripten_bind_btCapsuleShapeX_setLocalScaling_1:fw,_emscripten_bind_btPairCachingGhostObject_getCollisionShape_0:YB,_emscripten_bind_btSoftBody_getCollisionFlags_0:ZB,_emscripten_bind_btRaycastVehicle_getChassisWorldTransform_0:iA,_emscripten_bind_btCollisionObject_setRestitution_1:Dy,_emscripten_bind_btRigidBody_applyCentralForce_1:Dt,_emscripten_bind_btSoftBodyWorldInfo_set_m_gravity_1:hr,_emscripten_bind_LocalConvexResult_get_m_hitFraction_0:IE,_emscripten_bind_btHingeConstraint_setBreakingImpulseThreshold_1:Ov,_emscripten_bind_btQuaternion_w_0:OC,_emscripten_bind_ConvexResultCallback_get_m_collisionFilterGroup_0:gB,_emscripten_bind_btTransform_getRotation_0:Co,_emscripten_bind_Config_set_kSKHR_CL_1:vC,_emscripten_bind_btHingeConstraint_btHingeConstraint_6:eq,_emscripten_bind_btHingeConstraint_btHingeConstraint_7:Gp,_emscripten_bind_btCapsuleShapeZ_getMargin_0:Fy,_emscripten_bind_btHingeConstraint_btHingeConstraint_5:og,_emscripten_bind_btSoftBodyWorldInfo_get_m_maxDisplacement_0:XE,_emscripten_bind_btHingeConstraint_btHingeConstraint_3:Rf,_emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalAngularDampingThresholdSqr_1:Bw,_emscripten_bind_btSoftBody_setWorldTransform_1:Aw,_emscripten_bind_btBoxShape_setMargin_1:Yw,_emscripten_bind_btWheelInfoConstructionInfo_set_m_maxSuspensionTravelCm_1:uC,_emscripten_bind_ClosestConvexResultCallback_get_m_hitNormalWorld_0:IC,_emscripten_bind_btWheelInfoConstructionInfo_get_m_chassisConnectionCS_0:bH,_emscripten_bind_btTypedConstraint___destroy___0:Kv,_emscripten_bind_btCylinderShapeX_btCylinderShapeX_1:Ls,_emscripten_bind_btGeneric6DofSpringConstraint_setAngularUpperLimit_1:$u,_emscripten_bind_btDiscreteDynamicsWorld_addRigidBody_3:gt,_emscripten_bind_btDiscreteDynamicsWorld_addRigidBody_1:zv,_emscripten_bind_Config_set_collisions_1:DB,_emscripten_bind_btQuaternion_btQuaternion_4:xo,_emscripten_bind_btSoftRigidDynamicsWorld_getBroadphase_0:$B,_emscripten_bind_btWheelInfo_set_m_rotation_1:aB,_emscripten_bind_btSphereShape_btSphereShape_1:zw,_emscripten_bind_btWheelInfo_get_m_wheelsSuspensionForce_0:WB,_emscripten_bind_btQuaternion_y_0:NC,_emscripten_bind_btCollisionWorld_addCollisionObject_1:bv,_emscripten_bind_btCollisionWorld_addCollisionObject_2:du,_emscripten_bind_btCompoundShape_setLocalScaling_1:fw,_emscripten_bind_ClosestConvexResultCallback_set_m_collisionFilterGroup_1:Hy,_emscripten_bind_btConeTwistConstraint_setBreakingImpulseThreshold_1:Ov,_emscripten_bind_btWheelInfoConstructionInfo_set_m_chassisConnectionCS_1:Cr,_emscripten_bind_btSoftBodyHelpers_CreateEllipsoid_4:Hg,_emscripten_bind_RaycastInfo_get_m_isInContact_0:lC,_emscripten_bind_btWheelInfo_get_m_skidInfo_0:DD,_emscripten_bind_btHeightfieldTerrainShape_setMargin_1:Yw,_emscripten_bind_ClosestConvexResultCallback_get_m_collisionFilterGroup_0:gB,_emscripten_bind_btCapsuleShape_setMargin_1:Yw,_emscripten_bind_btDefaultVehicleRaycaster_btDefaultVehicleRaycaster_1:gu,_emscripten_bind_btDynamicsWorld_contactTest_2:Mm,_emscripten_bind_btCollisionObject_setUserPointer_1:ly,_emscripten_bind_btSequentialImpulseConstraintSolver_btSequentialImpulseConstraintSolver_0:Lj,_emscripten_bind_btActionInterface___destroy___0:Kv,_emscripten_bind_btSoftBody_generateClusters_2:qw,_emscripten_bind_btDefaultMotionState_setWorldTransform_1:Wv,_emscripten_bind_btSoftBody_generateClusters_1:Sx,_emscripten_bind_RayResultCallback_get_m_collisionObject_0:RC,_emscripten_bind_btPoint2PointConstraint_getPivotInA_0:Yy,_emscripten_bind_Config_get_kAHR_0:KE,_emscripten_bind_btGeneric6DofSpringConstraint_setStiffness_2:pw,_emscripten_bind_btCylinderShape_calculateLocalInertia_2:Au,_emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelRadius_1:vC,_emscripten_bind_ClosestConvexResultCallback___destroy___0:Kv,_emscripten_bind_btQuaternion_normalized_0:Do,_emscripten_bind_btDynamicsWorld_addCollisionObject_1:bv,_emscripten_bind_ClosestConvexResultCallback_get_m_collisionFilterMask_0:fB,___cxa_can_catch:Tp,_emscripten_bind_btDynamicsWorld_addCollisionObject_2:du,_emscripten_bind_btDiscreteDynamicsWorld_getDispatcher_0:_B,_emscripten_bind_btCollisionObject_setFriction_1:pz,_emscripten_bind_btGeneric6DofSpringConstraint_enableFeedback_1:Ix,_emscripten_bind_btVector3_rotate_2:ko,_emscripten_bind_btHeightfieldTerrainShape___destroy___0:Kv,_emscripten_bind_btWheelInfo_get_m_maxSuspensionTravelCm_0:XB,_emscripten_bind_Config_get_kVC_0:SE,_emscripten_bind_btVehicleRaycasterResult_set_m_hitPointInWorld_1:Cr,_emscripten_bind_btQuaternion_op_mulq_1:pA,_emscripten_bind_btPairCachingGhostObject_setActivationState_1:iv,_emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelDirectionCS_1:kr,_emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelAxleCS_1:_q,_emscripten_bind_Material_get_m_kVST_0:XE,_emscripten_bind_Config_set_kVCF_1:vE,_emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_3:pt,_emscripten_bind_btGhostObject_getUserIndex_0:RA,_emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_1:fu,_emscripten_bind_btWheelInfo_set_m_deltaRotation_1:nA,_emscripten_bind_btVector3___destroy___0:Kz,_emscripten_bind_RaycastInfo___destroy___0:dC,_emscripten_bind_btRigidBody_setAngularFactor_1:ux,_emscripten_bind_btCylinderShapeZ_calculateLocalInertia_2:Au,_emscripten_bind_btConeShapeZ_btConeShapeZ_2:_l,_emscripten_bind_LocalShapeInfo_set_m_triangleIndex_1:jA,_emscripten_bind_btMotionState_getWorldTransform_1:Sv,_emscripten_bind_btDynamicsWorld_getSolverInfo_0:qA,_emscripten_bind_btVehicleRaycasterResult_set_m_hitNormalInWorld_1:kr,_emscripten_bind_btSoftRigidDynamicsWorld_convexSweepTest_5:Yq,_emscripten_bind_Config_get_kMT_0:VE,_emscripten_bind_btDynamicsWorld_getBroadphase_0:$B,_emscripten_bind_btSphereShape_getMargin_0:Fy,_emscripten_bind_Config_get_timescale_0:hE,_emscripten_bind_btVector3_x_0:fE,___cxa_is_pointer_type:Cx,_emscripten_bind_btConvexTriangleMeshShape___destroy___0:Kv,_emscripten_bind_btCollisionObject_getCollisionShape_0:YB,_emscripten_bind_btRigidBodyConstructionInfo_btRigidBodyConstructionInfo_4:vq,_emscripten_bind_btManifoldPoint___destroy___0:dC,_emscripten_bind_btRigidBodyConstructionInfo_set_m_rollingFriction_1:TB,_emscripten_bind_btVector4_length_0:Uw,_emscripten_bind_btGhostObject_setUserIndex_1:Ly,_emscripten_bind_btWheelInfo_getSuspensionRestLength_0:xC,_emscripten_bind_btDefaultMotionState_set_m_graphicsWorldTrans_1:nx,_emscripten_bind_btGhostObject_setRestitution_1:Dy,_emscripten_bind_btConeTwistConstraint_setAngularOnly_1:Xw,_emscripten_bind_btQuadWord_setZ_1:AC,_emscripten_bind_btDefaultCollisionConfiguration___destroy___0:Kv,_emscripten_bind_btRigidBody_setMassProps_2:Aj,getTempRet0:cH,_emscripten_bind_btVector3_setValue_3:kq,_emscripten_bind_btPairCachingGhostObject_setCcdMotionThreshold_1:lx,_emscripten_bind_RaycastInfo_get_m_suspensionLength_0:VE,_emscripten_bind_btGhostObject_getCollisionFlags_0:ZB,_emscripten_bind_btCapsuleShapeX___destroy___0:Kv,_emscripten_bind_btWheelInfo_get_m_wheelDirectionCS_0:ZD,_emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelsDampingCompression_1:bC,_emscripten_bind_Material_get_m_flags_0:nE,_emscripten_bind_btQuaternion_getAxis_0:Ko,_emscripten_bind_btRaycastVehicle_getUserConstraintId_0:LA,_emscripten_bind_btRaycastVehicle_updateAction_2:Ru,_emscripten_bind_btHingeConstraint_setLimit_4:mu,_emscripten_bind_btHingeConstraint_setLimit_5:Ht,_emscripten_bind_btSoftBodyWorldInfo_btSoftBodyWorldInfo_0:Kx,_emscripten_bind_Config_set_kDG_1:YD,_emscripten_bind_btWheelInfo_set_m_maxSuspensionTravelCm_1:Az,_emscripten_bind_btWheelInfo_set_m_wheelsSuspensionForce_1:yz,_emscripten_bind_btSoftBody_scale_1:Fe,_emscripten_bind_Config_get_citerations_0:tE,_emscripten_bind_btTypedConstraint_getBreakingImpulseThreshold_0:Rw,_emscripten_bind_btGhostObject_getCollisionShape_0:YB,_emscripten_bind_btCollisionObject_setAnisotropicFriction_2:yu,_emscripten_bind_btBoxShape___destroy___0:Kv,_emscripten_bind_btWheelInfo_get_m_bIsFrontWheel_0:JB,_emscripten_bind_btPersistentManifold_getContactPoint_1:Mw,_emscripten_bind_btGeneric6DofSpringConstraint_getBreakingImpulseThreshold_0:Rw,_emscripten_bind_ConvexResultCallback_set_m_collisionFilterGroup_1:Hy,_emscripten_bind_RaycastInfo_set_m_groundObject_1:BB,_emscripten_bind_btGhostObject_activate_1:Rr,_emscripten_bind_btRaycastVehicle_getForwardAxis_0:qB,_emscripten_bind_btManifoldPoint_getPositionWorldOnB_0:Zy,_emscripten_bind_btManifoldPoint_get_m_positionWorldOnA_0:cG,_emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalDamping_1:Tx,_emscripten_bind_btDefaultSoftBodySolver_btDefaultSoftBodySolver_0:xp,_emscripten_bind_btSphereShape_setMargin_1:Yw,_emscripten_bind_btSoftBody_get_m_cfg_0:EF,_emscripten_bind_btCollisionObject_setUserIndex_1:Ly,_emscripten_bind_btContactSolverInfo_set_m_splitImpulsePenetrationThreshold_1:Nw,_emscripten_bind_btSliderConstraint_setUpperAngLimit_1:qx,_emscripten_bind_btDynamicsWorld_contactPairTest_3:yj,_emscripten_bind_btCollisionWorld_getPairCache_0:iy,_emscripten_bind_btConeTwistConstraint_setMotorTarget_1:Qh,_emscripten_bind_ClosestConvexResultCallback_set_m_convexFromWorld_1:Jq,_emscripten_bind_btWheelInfo_set_m_rollInfluence_1:mA,_emscripten_bind_btGhostObject_setCcdMotionThreshold_1:lx,_emscripten_bind_btGeneric6DofConstraint_setBreakingImpulseThreshold_1:Ov,_emscripten_enum_PHY_ScalarType_PHY_INTEGER:KG,_emscripten_bind_btSoftBodyHelpers_CreatePatchUV_10:Rd,_emscripten_bind_btGhostObject_forceActivationState_1:$z,_emscripten_bind_btGhostPairCallback_btGhostPairCallback_0:ay,_emscripten_bind_btSoftBodyHelpers_CreateFromTriMesh_5:de,_emscripten_bind_btVector4_y_0:NC,_emscripten_bind_VoidPtr___destroy___0:dC,establishStackSpace:BE,_emscripten_bind_RaycastInfo_set_m_contactNormalWS_1:Cr,_emscripten_bind_btSliderConstraint_setLowerAngLimit_1:sx,_emscripten_bind_ClosestRayResultCallback_get_m_collisionObject_0:RC,_emscripten_bind_RaycastInfo_set_m_contactPointWS_1:kr,_emscripten_bind_ClosestConvexResultCallback_ClosestConvexResultCallback_2:hs,_emscripten_bind_ClosestRayResultCallback_get_m_rayFromWorld_0:wD,_emscripten_bind_btSoftBody_setContactProcessingThreshold_1:rx,_emscripten_bind_btPairCachingGhostObject_getNumOverlappingObjects_0:qy,_emscripten_bind_btSliderConstraint_enableFeedback_1:Ix,_emscripten_bind_RayResultCallback_get_m_collisionFilterGroup_0:rB,_emscripten_enum_PHY_ScalarType_PHY_DOUBLE:LG,_emscripten_bind_btConstraintSetting_get_m_tau_0:OD,_emscripten_bind_btConeShape_setLocalScaling_1:fw,_emscripten_bind_btCollisionObject_setCollisionShape_1:Wv,_emscripten_bind_btCollisionShape___destroy___0:Kv,_emscripten_bind_btMatrix3x3_getRow_1:Np,_emscripten_bind_ConvexResultCallback_get_m_closestHitFraction_0:TE,_emscripten_bind_btSoftRigidDynamicsWorld_getPairCache_0:iy,_emscripten_bind_btDispatcherInfo_get_m_dispatchFunc_0:RC,_emscripten_bind_btRigidBodyConstructionInfo_get_m_rollingFriction_0:oA,_emscripten_bind_btSoftBody_getUserIndex_0:RA,_emscripten_bind_btPairCachingGhostObject_setCollisionShape_1:Wv,_emscripten_bind_btKinematicCharacterController_warp_1:Bv,_emscripten_bind_btContactSolverInfo___destroy___0:dC,_emscripten_bind_btSoftBody_getWorldTransform_0:pD,___muldsi3:hp,_emscripten_bind_btTriangleMesh___destroy___0:Kv,_emscripten_bind_btKinematicCharacterController_preStep_1:uv,_emscripten_bind_btRaycastVehicle_applyEngineForce_2:Yu,_emscripten_bind_btBoxShape_calculateLocalInertia_2:Au,_emscripten_bind_btRaycastVehicle_setBrake_2:yv,_emscripten_bind_ConcreteContactResultCallback___destroy___0:Kv,_emscripten_bind_RaycastInfo_set_m_wheelAxleWS_1:mr,_emscripten_bind_btRaycastVehicle_updateVehicle_1:cw,_emscripten_bind_btCollisionObject___destroy___0:Iv,_emscripten_bind_btVehicleTuning_set_m_suspensionDamping_1:uE,_emscripten_bind_btConvexTriangleMeshShape_setMargin_1:Yw,_emscripten_bind_btTriangleMeshShape_setLocalScaling_1:fw,_emscripten_bind_Config_get_kSSHR_CL_0:oE,_emscripten_bind_btConeTwistConstraint_setMotorTargetInConstraintSpace_1:Xt,_emscripten_bind_btQuaternion_op_mul_1:Os,_emscripten_bind_btDispatcherInfo_set_m_timeStep_1:OE,_emscripten_bind_btVector3_btVector3_3:Ap,_emscripten_bind_btVector3_btVector3_0:TF,_emscripten_bind_btRigidBodyConstructionInfo_set_m_friction_1:hz,_emscripten_bind_btDiscreteDynamicsWorld_getGravity_0:ao,_emscripten_bind_btVector3_z_0:MC,_emscripten_bind_ClosestConvexResultCallback_get_m_hitPointWorld_0:VC,_emscripten_bind_btCollisionShape_getMargin_0:Fy,_emscripten_bind_btSoftBodyWorldInfo_set_water_offset_1:uE,_emscripten_bind_btBroadphaseInterface___destroy___0:Kv,_emscripten_bind_btWheelInfo_updateWheel_2:Hi,_emscripten_bind_ConcreteContactResultCallback_addSingleResult_7:wq,_emscripten_bind_RaycastInfo_get_m_hardPointWS_0:GE,_emscripten_bind_btConeTwistConstraint___destroy___0:Kv,_emscripten_bind_btQuadWord___destroy___0:dC,_emscripten_bind_btSoftRigidDynamicsWorld_contactPairTest_3:yj,_emscripten_bind_btQuaternion_setEulerZYX_3:Av,_emscripten_bind_ClosestRayResultCallback_set_m_rayFromWorld_1:Wq,_emscripten_bind_btGeneric6DofSpringConstraint_setDamping_2:ww,_emscripten_bind_RaycastInfo_get_m_wheelDirectionWS_0:gE,_emscripten_bind_btRigidBody_setCenterOfMassTransform_1:Rv,_emscripten_bind_btSoftBody_setUserIndex_1:Ly,_emscripten_bind_btWheelInfo_get_m_chassisConnectionPointCS_0:vD,_emscripten_bind_btSoftBody_setCollisionShape_1:Wv,_emscripten_bind_btGhostObject_setAnisotropicFriction_2:yu,_emscripten_bind_btConstraintSolver___destroy___0:Kv,_emscripten_bind_btSoftBody_isActive_0:qz,_emscripten_bind_btCapsuleShape_btCapsuleShape_2:Zm,_emscripten_bind_btTypedConstraint_enableFeedback_1:Ix,_emscripten_bind_btWheelInfoConstructionInfo_get_m_frictionSlip_0:NE,_emscripten_bind_btGhostObject_activate_0:Ys,_emscripten_bind_btConstraintSetting_btConstraintSetting_0:Ux,_emscripten_bind_btWheelInfo_set_m_clippedInvContactDotSuspension_1:yy,_emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalDampingFactor_0:Cz,_emscripten_bind_btRigidBody_setAnisotropicFriction_2:yu,_emscripten_bind_btSoftBody_btSoftBody_4:Dr,_emscripten_bind_btSoftBody_activate_0:Ys,_emscripten_bind_btRigidBodyConstructionInfo_btRigidBodyConstructionInfo_3:kn,_emscripten_bind_ConvexResultCallback_set_m_closestHitFraction_1:vE,_emscripten_bind_btGeneric6DofSpringConstraint_enableSpring_2:Sq,_emscripten_bind_btPersistentManifold_btPersistentManifold_0:Gi,_emscripten_bind_ConvexResultCallback_get_m_collisionFilterMask_0:fB,_emscripten_bind_ClosestRayResultCallback_ClosestRayResultCallback_2:Bs,_emscripten_bind_btVector4___destroy___0:Kz,_emscripten_bind_btPairCachingGhostObject_isKinematicObject_0:ox,_emscripten_bind_ClosestRayResultCallback_set_m_collisionFilterMask_1:_y,_emscripten_bind_tNodeArray_at_1:nw,_i64Add:xv,_emscripten_bind_btStaticPlaneShape_calculateLocalInertia_2:Au,_emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalAngularDampingThresholdSqr_0:hy,_emscripten_bind_btCollisionObject_setCcdMotionThreshold_1:lx,_emscripten_bind_btKinematicCharacterController_btKinematicCharacterController_4:Qj,_emscripten_bind_btSoftBody_set_m_cfg_1:Ry,_emscripten_bind_btWheelInfo_get_m_brake_0:MD,_emscripten_bind_btRigidBodyConstructionInfo_get_m_angularSleepingThreshold_0:tz,_emscripten_bind_btWheelInfo_get_m_deltaRotation_0:YC,_emscripten_bind_btPoint2PointConstraint_getPivotInB_0:Xy,_emscripten_bind_btKinematicCharacterController_playerStep_2:iu,_emscripten_bind_btDispatcherInfo___destroy___0:dC,_emscripten_bind_btCapsuleShape_getMargin_0:Fy,_emscripten_bind_btCylinderShape_getMargin_0:Fy,_emscripten_bind_btSoftBodyArray_size_0:KD,_emscripten_bind_btStaticPlaneShape_setLocalScaling_1:fw,_emscripten_bind_btConvexTriangleMeshShape_calculateLocalInertia_2:Au,_emscripten_bind_btWheelInfoConstructionInfo_set_m_bIsFrontWheel_1:ky,_emscripten_bind_ClosestConvexResultCallback_get_m_convexToWorld_0:DF,_emscripten_bind_btGhostObject_getWorldTransform_0:pD,_emscripten_bind_btDiscreteDynamicsWorld_getPairCache_0:iy,_emscripten_bind_LocalConvexResult_set_m_hitFraction_1:SC,_emscripten_bind_btCapsuleShapeZ_calculateLocalInertia_2:Au,_emscripten_bind_btDispatcherInfo_get_m_timeStep_0:OD,_emscripten_bind_btHingeConstraint_setAngularOnly_1:Nx,_emscripten_bind_btVehicleTuning_set_m_suspensionCompression_1:vE,_emscripten_bind_btConstraintSetting_set_m_impulseClamp_1:uE,_emscripten_bind_btMotionState___destroy___0:Kv,_emscripten_bind_btCollisionObject_setCollisionFlags_1:Rx,_emscripten_bind_Config_get_kPR_0:UE,_emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_1:zu,_emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_2:Mt,_emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_3:kt,_emscripten_bind_btWheelInfo_set_m_suspensionStiffness_1:Iz,_emscripten_bind_RaycastInfo_set_m_suspensionLength_1:aD,_emscripten_bind_btDispatcher_getManifoldByIndexInternal_1:nv,_emscripten_bind_btSliderConstraint_setBreakingImpulseThreshold_1:Ov,_emscripten_bind_btSoftBodyWorldInfo___destroy___0:vw,_emscripten_bind_btConvexTriangleMeshShape_getMargin_0:Fy,_emscripten_bind_btSoftBodySolver___destroy___0:Kv,_bitshift64Lshr:zt,_emscripten_bind_btWheelInfo_set_m_steering_1:_A,_emscripten_bind_Node_set_m_x_1:Ir,_emscripten_bind_btPairCachingGhostObject_setWorldTransform_1:Aw,_emscripten_bind_btHingeConstraint_getBreakingImpulseThreshold_0:Rw,_emscripten_bind_btDefaultCollisionConstructionInfo___destroy___0:dC,_emscripten_bind_btConeShape___destroy___0:Kv,_emscripten_bind_btGhostObject_setCcdSweptSphereRadius_1:Vw,_emscripten_bind_btPoint2PointConstraint_btPoint2PointConstraint_4:Zj,_emscripten_bind_btRaycastVehicle_updateFriction_1:aw,_emscripten_bind_btPoint2PointConstraint_btPoint2PointConstraint_2:Gj,_emscripten_bind_btKinematicCharacterController_setJumpSpeed_1:cD,_emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration___destroy___0:Kv,_emscripten_bind_btConeShapeX_calculateLocalInertia_2:Au,_emscripten_enum_PHY_ScalarType_PHY_FIXEDPOINT88:AG,_emscripten_bind_btPairCachingGhostObject_getOverlappingObject_1:cx,_emscripten_bind_btGhostObject_getNumOverlappingObjects_0:qy,_emscripten_bind_btRigidBodyConstructionInfo___destroy___0:dC,_emscripten_bind_btGhostPairCallback___destroy___0:Kv,_emscripten_bind_btRigidBody_getWorldTransform_0:pD,_sbrk:bo,_emscripten_bind_btPoint2PointConstraint_setPivotA_1:Iw,_emscripten_bind_ClosestConvexResultCallback_set_m_convexToWorld_1:Qq,_memcpy:Th,_emscripten_bind_Config_get_maxvolume_0:iE,_emscripten_bind_btCapsuleShape_calculateLocalInertia_2:Au,_emscripten_bind_btSoftRigidDynamicsWorld_getGravity_0:$n,_emscripten_bind_btVector3_y_0:NC,_emscripten_bind_btDispatcherInfo_set_m_useEpa_1:aA,_emscripten_bind_btVehicleTuning_get_m_maxSuspensionForce_0:UE,_emscripten_bind_btBvhTriangleMeshShape_btBvhTriangleMeshShape_2:ps,_emscripten_bind_btBvhTriangleMeshShape_btBvhTriangleMeshShape_3:Kr,_emscripten_bind_LocalShapeInfo_get_m_triangleIndex_0:rD,_emscripten_bind_Config_set_kDF_1:cD,_emscripten_bind_btHeightfieldTerrainShape_btHeightfieldTerrainShape_9:cg,_emscripten_bind_btSoftBody_activate_1:Rr,_emscripten_bind_btWheelInfoConstructionInfo_set_m_frictionSlip_1:hD,_emscripten_bind_btGhostObject_setCollisionShape_1:Wv,_emscripten_bind_btDispatcherInfo_set_m_allowedCcdPenetration_1:cD,_emscripten_bind_btRigidBody_setRollingFriction_1:Zx,_emscripten_bind_btPairCachingGhostObject_setRollingFriction_1:Zx,_emscripten_bind_btDiscreteDynamicsWorld_setGravity_1:Fv,_emscripten_get_global_libc:$G,_emscripten_bind_btVehicleTuning_set_m_suspensionStiffness_1:OE,_emscripten_bind_btVector4_z_0:MC,_emscripten_bind_btCollisionObject_forceActivationState_1:$z,_emscripten_bind_btKinematicCharacterController_onGround_0:Wx,_emscripten_bind_btRaycastVehicle_getWheelInfo_1:ny,_emscripten_bind_btGeneric6DofConstraint_getBreakingImpulseThreshold_0:Rw,_emscripten_bind_btVector3_length_0:Uw,_emscripten_bind_ClosestConvexResultCallback_set_m_collisionFilterMask_1:Gy,_emscripten_bind_btSoftBodyWorldInfo_get_water_normal_0:wE,_emscripten_bind_btVector3_normalize_0:JD,_emscripten_bind_btConeTwistConstraint_setLimit_2:sw,_emscripten_bind_btSoftBody_setFriction_1:pz,runPostSets:Rt,_emscripten_bind_btRigidBody_setSleepingThresholds_2:$v,_emscripten_bind_btSoftBody_upcast_1:bz,_emscripten_bind_btCollisionObject_setWorldTransform_1:Aw,_emscripten_bind_LocalConvexResult_get_m_localShapeInfo_0:rD,_emscripten_bind_btSoftBodyWorldInfo_set_m_dispatcher_1:Lz,_emscripten_bind_btConvexHullShape_setLocalScaling_1:fw,_emscripten_bind_btStridingMeshInterface___destroy___0:Kv,_emscripten_bind_btSoftBody_setActivationState_1:iv,_emscripten_bind_btRigidBody_getUserIndex_0:RA,_emscripten_bind_btRigidBodyConstructionInfo_get_m_linearDamping_0:KA,_emscripten_bind_btSoftBodyHelpers_CreatePatch_9:ye,_emscripten_bind_btDispatcher_getNumManifolds_0:Iy,_emscripten_bind_btConvexShape_setMargin_1:Yw,_emscripten_bind_btSoftBody_get_m_nodes_0:uF,_emscripten_bind_btSoftBody___destroy___0:Iv,_emscripten_bind_btRigidBodyConstructionInfo_get_m_linearSleepingThreshold_0:Bz,_emscripten_bind_btRigidBody_activate_1:Rr,_emscripten_bind_btRaycastVehicle_updateWheelTransform_2:Ns,_emscripten_bind_btWheelInfoConstructionInfo_set_m_maxSuspensionForce_1:nC,_emscripten_bind_btSoftBodyWorldInfo_get_m_gravity_0:mE,_emscripten_bind_Material_set_m_kVST_1:YD,_emscripten_bind_btGhostObject_setActivationState_1:iv,_emscripten_bind_Material_set_m_kLST_1:vE,_emscripten_bind_btCollisionWorld_contactPairTest_3:yj,_emscripten_bind_btDispatcherInfo_get_m_useContinuous_0:dB,_emscripten_bind_btHingeConstraint_setMaxMotorImpulse_1:ix,_emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelsDampingRelaxation_0:WD,_emscripten_bind_Config_get_kSS_SPLT_CL_0:NE,_emscripten_bind_btCylinderShapeX___destroy___0:Kv,_emscripten_bind_btRigidBodyConstructionInfo_set_m_linearSleepingThreshold_1:Lx,_emscripten_bind_btRigidBody_updateInertiaTensor_0:tj,_emscripten_bind_ContactResultCallback___destroy___0:Kv,_emscripten_bind_btDispatcherInfo_get_m_useConvexConservativeDistanceUtil_0:Oy,_emscripten_bind_btSoftBody_setAnisotropicFriction_2:yu,_emscripten_bind_btPairCachingGhostObject_setCollisionFlags_1:Rx,_emscripten_bind_btRigidBody_getMotionState_0:gC,_emscripten_bind_btKinematicCharacterController_getGhostObject_0:RC,_emscripten_bind_btRigidBody_btRigidBody_1:qi,_emscripten_bind_btTriangleMeshShape___destroy___0:Kv,_llvm_cttz_i32:yp,_emscripten_bind_btDynamicsWorld_removeAction_1:Yv,_emscripten_bind_btRigidBody_applyTorque_1:cu,_emscripten_bind_btManifoldPoint_get_m_localPointA_0:bH,_emscripten_bind_btDefaultCollisionConstructionInfo_btDefaultCollisionConstructionInfo_0:wu,_emscripten_bind_btVehicleTuning_get_m_suspensionStiffness_0:OD,_emscripten_bind_btManifoldPoint_set_m_normalWorldOnB_1:dr,_emscripten_bind_btGhostObject_setUserPointer_1:ly,_emscripten_bind_btConvexHullShape_addPoint_2:Uv,_emscripten_bind_btKinematicCharacterController_getGravity_0:HE,___udivmoddi4:Je,_emscripten_enum_PHY_ScalarType_PHY_SHORT:NG,_emscripten_bind_btConeTwistConstraint_getBreakingImpulseThreshold_0:Rw,_emscripten_bind_btGeneric6DofConstraint_setAngularLowerLimit_1:av,_emscripten_bind_btVehicleRaycasterResult_get_m_distFraction_0:VE,_emscripten_bind_btQuaternion_op_sub_1:zA,_emscripten_bind_btVector4_normalize_0:JD,_emscripten_bind_btQuaternion_setY_1:BC,_emscripten_bind_btConeShape_calculateLocalInertia_2:Au,_emscripten_bind_btCylinderShapeX_calculateLocalInertia_2:Au,_emscripten_bind_ConvexResultCallback_set_m_collisionFilterMask_1:Gy,_llvm_bswap_i32:fA,_emscripten_bind_btRaycastVehicle_getForwardVector_0:Qn,_emscripten_bind_btKinematicCharacterController_setVelocityForTimeInterval_2:yt,_emscripten_bind_btWheelInfo_set_m_suspensionRelativeVelocity_1:Wy,_emscripten_bind_btSphereShape_setLocalScaling_1:fw,_emscripten_bind_btRigidBody_applyCentralLocalForce_1:Zs,_emscripten_bind_btDiscreteDynamicsWorld_removeAction_1:Yv,_emscripten_bind_btVector4_w_0:OC,_emscripten_bind_btWheelInfo_get_m_worldTransform_0:NF,_emscripten_bind_btManifoldPoint_get_m_normalWorldOnB_0:UD,_emscripten_bind_btBvhTriangleMeshShape___destroy___0:Kv,_emscripten_bind_Config_set_citerations_1:EB,_emscripten_bind_btSoftBody_checkFace_3:yk,_emscripten_bind_Config_get_kSKHR_CL_0:qE,_emscripten_bind_btDispatcherInfo_get_m_enableSatConvex_0:NA,_emscripten_bind_btDefaultVehicleRaycaster_castRay_3:Ct,_emscripten_bind_LocalConvexResult_LocalConvexResult_5:qq,_emscripten_bind_btContactSolverInfo_get_m_numIterations_0:kC,_emscripten_bind_btWheelInfoConstructionInfo_get_m_maxSuspensionTravelCm_0:pE,_emscripten_bind_ClosestConvexResultCallback_set_m_closestHitFraction_1:vE,_emscripten_bind_btDiscreteDynamicsWorld_removeConstraint_1:ov,_emscripten_bind_ConcreteContactResultCallback_ConcreteContactResultCallback_0:_s,_emscripten_bind_Config_set_diterations_1:CB,_emscripten_bind_btRaycastVehicle_getUserConstraintType_0:yA,_emscripten_bind_btGeneric6DofConstraint___destroy___0:Kv,_emscripten_bind_btSoftRigidDynamicsWorld_addRigidBody_1:zv,_emscripten_bind_btSoftRigidDynamicsWorld_addRigidBody_3:gt,_emscripten_bind_Config_set_kDP_1:uE,_emscripten_bind_btVehicleTuning_get_m_maxSuspensionTravelCm_0:XE,_emscripten_bind_btConvexHullShape_addPoint_1:Ax,_emscripten_bind_btQuaternion_length2_0:ZC,_emscripten_bind_btRaycastVehicle_resetSuspension_0:Cl,_emscripten_bind_btPoint2PointConstraint_getBreakingImpulseThreshold_0:Rw,_emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration_btSoftBodyRigidBodyCollisionConfiguration_1:zr,_emscripten_bind_btTransform_getOrigin_0:PC,_emscripten_bind_Config_get_kKHR_0:IE,_emscripten_bind_Material_get_m_kLST_0:TE,_emscripten_bind_btHingeConstraint___destroy___0:Kv,_emscripten_bind_btPairCachingGhostObject_getUserPointer_0:sC,_emscripten_bind_btSoftBody_set_m_nodes_1:uw,_emscripten_bind_btSoftBodyWorldInfo_set_air_density_1:OE,_emscripten_bind_btDbvtBroadphase___destroy___0:Kv,_emscripten_bind_Config_set_viterations_1:AB,_emscripten_bind_btConvexShape_calculateLocalInertia_2:Au,_memset:Hk,_emscripten_bind_btGeneric6DofConstraint_setLinearLowerLimit_1:kv,_emscripten_bind_ClosestRayResultCallback_get_m_hitNormalWorld_0:gE,_emscripten_bind_btTriangleMesh_btTriangleMesh_0:_v,_emscripten_bind_btTriangleMesh_btTriangleMesh_1:Wu,_emscripten_bind_btTriangleMesh_btTriangleMesh_2:au,_emscripten_bind_btWheelInfo_set_m_frictionSlip_1:wA,_emscripten_bind_btSoftBodyHelpers___destroy___0:dC,_emscripten_bind_btRigidBody_getCollisionShape_0:YB,_emscripten_bind_btManifoldPoint_set_m_positionWorldOnA_1:tr,_emscripten_bind_btWheelInfo_get_m_wheelsDampingRelaxation_0:vB,_emscripten_bind_btManifoldPoint_get_m_localPointB_0:wE,_emscripten_bind_btQuaternion_inverse_0:Jo,_emscripten_bind_btDiscreteDynamicsWorld_contactPairTest_3:yj,_emscripten_bind_btSliderConstraint_setLowerLinLimit_1:rx,_emscripten_bind_btRigidBody_getAngularVelocity_0:Yz,_emscripten_bind_btCollisionObject_setCcdSweptSphereRadius_1:Vw,_emscripten_bind_btWheelInfo_get_m_wheelsRadius_0:jD,_emscripten_bind_btRigidBody_setLinearVelocity_1:hx,_emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelDirectionCS_0:wE,_emscripten_bind_btVehicleTuning_btVehicleTuning_0:gx,_emscripten_bind_RayResultCallback_set_m_collisionObject_1:Xz,_emscripten_bind_btDefaultSoftBodySolver___destroy___0:Kv,_emscripten_bind_ClosestRayResultCallback_set_m_rayToWorld_1:nr,_emscripten_bind_ClosestRayResultCallback_get_m_collisionFilterGroup_0:rB,_emscripten_bind_btWheelInfo_set_m_wheelsDampingRelaxation_1:oz,_emscripten_bind_btWheelInfo_get_m_clippedInvContactDotSuspension_0:xA,_emscripten_bind_btDynamicsWorld_addAction_1:lw,_emscripten_bind_btSoftBody_appendMaterial_0:yB,_emscripten_bind_btSoftBodyWorldInfo_set_m_maxDisplacement_1:YD,_emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_2:lt,_emscripten_bind_btPairCachingGhostObject_getCollisionFlags_0:ZB,_emscripten_bind_btSoftBodyWorldInfo_get_air_density_0:OD,_emscripten_bind_btSoftBody_setRestitution_1:Dy,_emscripten_bind_Config_set_kLF_1:bD,_emscripten_bind_btWheelInfo_get_m_rotation_0:ED,_emscripten_enum_PHY_ScalarType_PHY_FLOAT:fH,_emscripten_bind_btWheelInfo_set_m_skidInfo_1:$A,_emscripten_bind_Config_set_kSS_SPLT_CL_1:hD,_emscripten_bind_btGhostObject_isActive_0:qz,_emscripten_bind_btWheelInfoConstructionInfo_set_m_suspensionRestLength_1:UC,_emscripten_bind_btKinematicCharacterController_setFallSpeed_1:_C,_emscripten_bind_btRigidBody_setActivationState_1:iv,_emscripten_bind_btWheelInfo_get_m_wheelsDampingCompression_0:oB,_emscripten_bind_ClosestConvexResultCallback_hasHit_0:$w,_emscripten_bind_btCapsuleShapeZ___destroy___0:Kv,_emscripten_bind_btRaycastVehicle_getRigidBody_0:KB,_emscripten_bind_btWheelInfo_get_m_maxSuspensionForce_0:rC,_emscripten_bind_btSoftBody_get_m_materials_0:cF,_emscripten_bind_btTriangleMesh_addTriangle_3:fn,_emscripten_bind_btGhostObject_getOverlappingObject_1:cx,_emscripten_bind_btTriangleMesh_addTriangle_4:Tm,_emscripten_bind_btSoftRigidDynamicsWorld_getDispatchInfo_0:Qz,_emscripten_bind_btSoftBodyWorldInfo_set_water_normal_1:kr,_emscripten_bind_btSoftRigidDynamicsWorld_addConstraint_2:hu,_emscripten_bind_Config_get_kDF_0:YE,_emscripten_bind_btRigidBody_applyTorqueImpulse_1:wt,_emscripten_bind_btVector3_op_add_1:xB,_emscripten_bind_btRigidBody_setCollisionFlags_1:Rx,_emscripten_bind_btWheelInfo_get_m_steering_0:CD,_emscripten_bind_btRigidBody___destroy___0:Iv,_emscripten_bind_btWheelInfo_set_m_suspensionRestLength1_1:zz,_emscripten_bind_Config_set_kCHR_1:TC,_emscripten_bind_btRaycastVehicle_setUserConstraintType_1:Gw,_emscripten_bind_btSoftRigidDynamicsWorld_contactTest_2:Mm,_emscripten_bind_btCapsuleShapeZ_btCapsuleShapeZ_2:Xm,_emscripten_bind_btDispatcherInfo_get_m_enableSPU_0:OB,_emscripten_bind_btSoftRigidDynamicsWorld_getWorldInfo_0:Cy,_emscripten_bind_btSliderConstraint_btSliderConstraint_3:_d,_emscripten_bind_btTransform___destroy___0:dC,_emscripten_bind_btWheelInfo_get_m_wheelAxleCS_0:CE,_emscripten_bind_btDynamicsWorld_convexSweepTest_5:Yq,_emscripten_bind_btSliderConstraint___destroy___0:Kv,_emscripten_bind_btRigidBody_forceActivationState_1:$z,_emscripten_bind_btPoint2PointConstraint_setPivotB_1:Hw,_emscripten_bind_btManifoldPoint_getDistance_0:zy,_emscripten_bind_btWheelInfo_set_m_wheelAxleCS_1:gr,_emscripten_bind_btTransform_setFromOpenGLMatrix_1:Jx,_emscripten_bind_btKinematicCharacterController_getMaxSlope_0:JE,_emscripten_bind_btManifoldPoint_getPositionWorldOnA_0:PC,_emscripten_bind_btRaycastVehicle_addWheel_7:Hd,_emscripten_bind_btQuaternion_op_add_1:AA,_emscripten_bind_ClosestRayResultCallback_set_m_hitNormalWorld_1:fr,_emscripten_bind_btRaycastVehicle_updateWheelTransformsWS_2:bt,_emscripten_bind_btStaticPlaneShape___destroy___0:Kv,_emscripten_bind_btHingeConstraint_enableMotor_1:oy,_emscripten_bind_btCylinderShapeZ_setLocalScaling_1:fw,_emscripten_bind_btBoxShape_setLocalScaling_1:fw,_emscripten_bind_btConeShapeZ___destroy___0:Kv,_emscripten_bind_btDynamicsWorld_getPairCache_0:iy,_emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelAxleCS_0:iF,_emscripten_bind_btDiscreteDynamicsWorld_convexSweepTest_5:Yq,_emscripten_bind_btSoftRigidDynamicsWorld_removeRigidBody_1:rv,_emscripten_bind_btRigidBody_setRestitution_1:Dy,_emscripten_bind_btVector4_btVector4_0:TF,_emscripten_bind_btVector4_x_0:fE,_emscripten_bind_btVector4_btVector4_4:wo,_emscripten_bind_btKinematicCharacterController___destroy___0:Kv,_emscripten_bind_btGeneric6DofSpringConstraint_setLinearLowerLimit_1:kv,_emscripten_bind_tMaterialArray_at_1:hv,_emscripten_bind_LocalConvexResult_set_m_hitCollisionObject_1:eB,_emscripten_bind_btVector4_op_sub_1:wB,_emscripten_bind_btGeneric6DofSpringConstraint_setAngularLowerLimit_1:av,_emscripten_bind_btSoftBodyWorldInfo_get_water_offset_0:dF,_emscripten_bind_btDiscreteDynamicsWorld_rayTest_3:Pt,_emscripten_bind_btWheelInfo_get_m_raycastInfo_0:bH,_emscripten_bind_btContactSolverInfo_get_m_splitImpulse_0:GA,_emscripten_bind_btConvexShape_getMargin_0:Fy,_emscripten_bind_btRaycastVehicle_getSteeringValue_1:dw,_emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelRadius_0:qE,_emscripten_bind_btKinematicCharacterController_setMaxJumpHeight_1:aD,_emscripten_bind_btPairCachingGhostObject_isActive_0:qz,_emscripten_bind_btWheelInfo_set_m_wheelDirectionCS_1:Zq,_emscripten_bind_btVehicleTuning_get_m_frictionSlip_0:WE,stackAlloc:Jy,stackSave:dH,stackRestore:WG,establishStackSpace:BE,setThrew:IB,setTempRet0:ZG,getTempRet0:cH,dynCall_viiiii:ru,dynCall_vid:LC,dynCall_vi:gF,dynCall_viiidii:vt,dynCall_vii:UB,dynCall_iiiiiiiiiii:Cp,dynCall_ii:RD,dynCall_viidi:Dw,dynCall_viddiii:Kt,dynCall_vidii:Ew,dynCall_iiiii:tv,dynCall_vidi:ez,dynCall_diiiiiiii:jr,dynCall_viiiiddddiid:Pp,dynCall_diiiii:$t,dynCall_vidd:Vz,dynCall_iiii:yx,dynCall_viiiiid:ut,dynCall_viiiiii:dt,dynCall_iiid:gy,dynCall_di:lE,dynCall_iiiiiii:Gs,dynCall_diiidii:Ws,dynCall_viidii:Ku,dynCall_viiiiiii:_r,dynCall_viiiiiiiii:Eq,dynCall_viiiiiiiiii:Sp,dynCall_iii:lA,dynCall_diii:Qx,dynCall_diiiiiiiiii:Fp,dynCall_viiiid:Ju,dynCall_diiiiiiiii:tq,dynCall_did:VB,dynCall_viiiidddddidi:np,dynCall_diidii:nu,dynCall_diiii:Ev,dynCall_iiiiiiiiii:pq,dynCall_viiid:yw,dynCall_viii:uy,dynCall_v:JG,dynCall_viid:mz,dynCall_iidid:jw,dynCall_viiii:Vv}})\n\n\n// EMSCRIPTEN_END_ASM\n(c.B,c.C,buffer),Gb=c._emscripten_bind_btCylinderShape___destroy___0=n._emscripten_bind_btCylinderShape___destroy___0,Hb=c._emscripten_bind_btGeneric6DofConstraint_enableFeedback_1=n._emscripten_bind_btGeneric6DofConstraint_enableFeedback_1,Ib=c._emscripten_bind_btGhostObject___destroy___0=n._emscripten_bind_btGhostObject___destroy___0,Jb=c._emscripten_bind_Config_get_kSRHR_CL_0=n._emscripten_bind_Config_get_kSRHR_CL_0,Kb=c._emscripten_bind_btPoint2PointConstraint_set_m_setting_1=\nn._emscripten_bind_btPoint2PointConstraint_set_m_setting_1,Lb=c._emscripten_bind_btQuaternion_dot_1=n._emscripten_bind_btQuaternion_dot_1,Mb=c._emscripten_bind_btDispatcherInfo_set_m_useContinuous_1=n._emscripten_bind_btDispatcherInfo_set_m_useContinuous_1,Nb=c._emscripten_bind_btKinematicCharacterController_setWalkDirection_1=n._emscripten_bind_btKinematicCharacterController_setWalkDirection_1,Ob=c._emscripten_bind_btCollisionObject_isActive_0=n._emscripten_bind_btCollisionObject_isActive_0,Qb=c._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelsDampingRelaxation_1=\nn._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelsDampingRelaxation_1,Rb=c._emscripten_bind_btVehicleTuning_set_m_frictionSlip_1=n._emscripten_bind_btVehicleTuning_set_m_frictionSlip_1,Sb=c._emscripten_bind_btDiscreteDynamicsWorld_btDiscreteDynamicsWorld_4=n._emscripten_bind_btDiscreteDynamicsWorld_btDiscreteDynamicsWorld_4,Tb=c._emscripten_bind_btCapsuleShapeX_getMargin_0=n._emscripten_bind_btCapsuleShapeX_getMargin_0,Ub=c._emscripten_bind_Node_set_m_n_1=n._emscripten_bind_Node_set_m_n_1,\nVb=c._emscripten_bind_btCompoundShape_getMargin_0=n._emscripten_bind_btCompoundShape_getMargin_0,Wb=c._emscripten_bind_RaycastInfo_set_m_wheelDirectionWS_1=n._emscripten_bind_RaycastInfo_set_m_wheelDirectionWS_1,Xb=c._emscripten_bind_btVehicleRaycasterResult_get_m_hitNormalInWorld_0=n._emscripten_bind_btVehicleRaycasterResult_get_m_hitNormalInWorld_0,Yb=c._emscripten_bind_btRigidBody_setUserPointer_1=n._emscripten_bind_btRigidBody_setUserPointer_1,Zb=c._emscripten_bind_ClosestRayResultCallback_get_m_hitPointWorld_0=\nn._emscripten_bind_ClosestRayResultCallback_get_m_hitPointWorld_0,$b=c._emscripten_bind_btTypedConstraint_setBreakingImpulseThreshold_1=n._emscripten_bind_btTypedConstraint_setBreakingImpulseThreshold_1,ac=c._emscripten_bind_btQuaternion_setX_1=n._emscripten_bind_btQuaternion_setX_1,bc=c._emscripten_bind_btCylinderShapeZ_getMargin_0=n._emscripten_bind_btCylinderShapeZ_getMargin_0,cc=c._emscripten_bind_btDispatcherInfo_get_m_timeOfImpact_0=n._emscripten_bind_btDispatcherInfo_get_m_timeOfImpact_0,dc=\nc._emscripten_bind_btQuaternion_setZ_1=n._emscripten_bind_btQuaternion_setZ_1,ec=c._emscripten_bind_btCollisionObject_getUserIndex_0=n._emscripten_bind_btCollisionObject_getUserIndex_0,fc=c._emscripten_bind_btDispatcherInfo_get_m_allowedCcdPenetration_0=n._emscripten_bind_btDispatcherInfo_get_m_allowedCcdPenetration_0,gc=c._emscripten_bind_LocalConvexResult_get_m_hitNormalLocal_0=n._emscripten_bind_LocalConvexResult_get_m_hitNormalLocal_0,hc=c._emscripten_bind_btSoftBodyWorldInfo_set_water_density_1=\nn._emscripten_bind_btSoftBodyWorldInfo_set_water_density_1,ic=c._emscripten_bind_btRigidBodyConstructionInfo_get_m_restitution_0=n._emscripten_bind_btRigidBodyConstructionInfo_get_m_restitution_0,jc=c._emscripten_bind_btKinematicCharacterController_setMaxSlope_1=n._emscripten_bind_btKinematicCharacterController_setMaxSlope_1,kc=c._emscripten_bind_btQuadWord_z_0=n._emscripten_bind_btQuadWord_z_0,mc=c._emscripten_bind_btSoftBody_setCcdMotionThreshold_1=n._emscripten_bind_btSoftBody_setCcdMotionThreshold_1,\nnc=c._emscripten_bind_Material___destroy___0=n._emscripten_bind_Material___destroy___0,oc=c._emscripten_bind_btHingeConstraint_btHingeConstraint_2=n._emscripten_bind_btHingeConstraint_btHingeConstraint_2,pc=c._emscripten_bind_btSoftBody_rotate_1=n._emscripten_bind_btSoftBody_rotate_1,qc=c._emscripten_bind_btWheelInfo_get_m_suspensionRestLength1_0=n._emscripten_bind_btWheelInfo_get_m_suspensionRestLength1_0,rc=c._emscripten_bind_btWheelInfo_get_m_suspensionStiffness_0=n._emscripten_bind_btWheelInfo_get_m_suspensionStiffness_0,\nsc=c._emscripten_bind_btVector4_setY_1=n._emscripten_bind_btVector4_setY_1,tc=c._emscripten_enum_PHY_ScalarType_PHY_UCHAR=n._emscripten_enum_PHY_ScalarType_PHY_UCHAR,uc=c._emscripten_bind_btQuaternion_setW_1=n._emscripten_bind_btQuaternion_setW_1,vc=c._emscripten_bind_btSoftRigidDynamicsWorld___destroy___0=n._emscripten_bind_btSoftRigidDynamicsWorld___destroy___0,wc=c._emscripten_bind_btSoftRigidDynamicsWorld_removeConstraint_1=n._emscripten_bind_btSoftRigidDynamicsWorld_removeConstraint_1,xc=c._emscripten_bind_RaycastInfo_get_m_wheelAxleWS_0=\nn._emscripten_bind_RaycastInfo_get_m_wheelAxleWS_0,zc=c._emscripten_bind_btRigidBodyConstructionInfo_get_m_angularDamping_0=n._emscripten_bind_btRigidBodyConstructionInfo_get_m_angularDamping_0,Ac=c._emscripten_bind_btCollisionDispatcher___destroy___0=n._emscripten_bind_btCollisionDispatcher___destroy___0,Bc=c._emscripten_bind_btRigidBody_applyCentralImpulse_1=n._emscripten_bind_btRigidBody_applyCentralImpulse_1,Cc=c._emscripten_bind_btConvexHullShape_getMargin_0=n._emscripten_bind_btConvexHullShape_getMargin_0,\nDc=c._emscripten_bind_btDefaultMotionState_getWorldTransform_1=n._emscripten_bind_btDefaultMotionState_getWorldTransform_1,Ec=c._emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_1=n._emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_1,Fc=c._emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_3=n._emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_3,Gc=c._emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_2=n._emscripten_bind_btDiscreteDynamicsWorld_stepSimulation_2,Hc=c._emscripten_bind_btSoftRigidDynamicsWorld_addAction_1=\nn._emscripten_bind_btSoftRigidDynamicsWorld_addAction_1,Ic=c._emscripten_bind_btDynamicsWorld_rayTest_3=n._emscripten_bind_btDynamicsWorld_rayTest_3,Jc=c._emscripten_bind_Config_set_kSR_SPLT_CL_1=n._emscripten_bind_Config_set_kSR_SPLT_CL_1,Kc=c._emscripten_bind_btQuadWord_x_0=n._emscripten_bind_btQuadWord_x_0,Lc=c._emscripten_bind_Config_get_diterations_0=n._emscripten_bind_Config_get_diterations_0,Mc=c._emscripten_bind_btCollisionObject_isKinematicObject_0=n._emscripten_bind_btCollisionObject_isKinematicObject_0,\nNc=c._emscripten_bind_btSoftRigidDynamicsWorld_removeSoftBody_1=n._emscripten_bind_btSoftRigidDynamicsWorld_removeSoftBody_1,Oc=c._emscripten_bind_btSphereShape___destroy___0=n._emscripten_bind_btSphereShape___destroy___0,Pc=c._emscripten_bind_btGeneric6DofSpringConstraint_setLinearUpperLimit_1=n._emscripten_bind_btGeneric6DofSpringConstraint_setLinearUpperLimit_1,Qc=c._emscripten_bind_btQuaternion_getAngleShortestPath_0=n._emscripten_bind_btQuaternion_getAngleShortestPath_0,Rc=c._emscripten_bind_ClosestConvexResultCallback_set_m_hitNormalWorld_1=\nn._emscripten_bind_ClosestConvexResultCallback_set_m_hitNormalWorld_1,Sc=c._emscripten_bind_btSoftBody_isKinematicObject_0=n._emscripten_bind_btSoftBody_isKinematicObject_0,Tc=c._emscripten_bind_btRigidBody_getCenterOfMassTransform_0=n._emscripten_bind_btRigidBody_getCenterOfMassTransform_0,Uc=c._emscripten_bind_btTransform_setIdentity_0=n._emscripten_bind_btTransform_setIdentity_0,Vc=c._emscripten_bind_btGhostObject_isKinematicObject_0=n._emscripten_bind_btGhostObject_isKinematicObject_0,Wc=c._emscripten_bind_btGeneric6DofSpringConstraint_btGeneric6DofSpringConstraint_5=\nn._emscripten_bind_btGeneric6DofSpringConstraint_btGeneric6DofSpringConstraint_5,Xc=c._emscripten_bind_btWheelInfoConstructionInfo___destroy___0=n._emscripten_bind_btWheelInfoConstructionInfo___destroy___0,Yc=c._emscripten_bind_btCapsuleShape___destroy___0=n._emscripten_bind_btCapsuleShape___destroy___0,Zc=c._emscripten_bind_btDefaultCollisionConfiguration_btDefaultCollisionConfiguration_1=n._emscripten_bind_btDefaultCollisionConfiguration_btDefaultCollisionConfiguration_1,$c=c._emscripten_bind_btCollisionObject_activate_1=\nn._emscripten_bind_btCollisionObject_activate_1,ad=c._emscripten_bind_btCollisionObject_activate_0=n._emscripten_bind_btCollisionObject_activate_0,bd=c._emscripten_bind_btKinematicCharacterController_setUpAxis_1=n._emscripten_bind_btKinematicCharacterController_setUpAxis_1,cd=c._emscripten_bind_btSoftRigidDynamicsWorld_addConstraint_1=n._emscripten_bind_btSoftRigidDynamicsWorld_addConstraint_1,dd=c._emscripten_bind_Config_set_kSSHR_CL_1=n._emscripten_bind_Config_set_kSSHR_CL_1,ed=c._emscripten_bind_btWheelInfoConstructionInfo_get_m_maxSuspensionForce_0=\nn._emscripten_bind_btWheelInfoConstructionInfo_get_m_maxSuspensionForce_0,fd=c._emscripten_bind_btDispatcherInfo_set_m_timeOfImpact_1=n._emscripten_bind_btDispatcherInfo_set_m_timeOfImpact_1,gd=c._emscripten_bind_btCollisionDispatcher_btCollisionDispatcher_1=n._emscripten_bind_btCollisionDispatcher_btCollisionDispatcher_1,hd=c._emscripten_bind_btVector3_setX_1=n._emscripten_bind_btVector3_setX_1,id=c._emscripten_bind_btCollisionConfiguration___destroy___0=n._emscripten_bind_btCollisionConfiguration___destroy___0,\njd=c._emscripten_bind_btCapsuleShapeZ_setMargin_1=n._emscripten_bind_btCapsuleShapeZ_setMargin_1,kd=c._emscripten_bind_btHingeConstraint_enableFeedback_1=n._emscripten_bind_btHingeConstraint_enableFeedback_1,ld=c._emscripten_bind_btActionInterface_updateAction_2=n._emscripten_bind_btActionInterface_updateAction_2;c.stackAlloc=n.stackAlloc;\nvar md=c._emscripten_bind_btHeightfieldTerrainShape_setLocalScaling_1=n._emscripten_bind_btHeightfieldTerrainShape_setLocalScaling_1,nd=c._emscripten_bind_btManifoldPoint_set_m_positionWorldOnB_1=n._emscripten_bind_btManifoldPoint_set_m_positionWorldOnB_1,od=c._emscripten_bind_btRaycastVehicle_updateSuspension_1=n._emscripten_bind_btRaycastVehicle_updateSuspension_1,pd=c._emscripten_bind_btManifoldPoint_set_m_localPointB_1=n._emscripten_bind_btManifoldPoint_set_m_localPointB_1,qd=c._emscripten_bind_btVector3_setZ_1=\nn._emscripten_bind_btVector3_setZ_1,rd=c._emscripten_bind_btKinematicCharacterController_setUseGhostSweepTest_1=n._emscripten_bind_btKinematicCharacterController_setUseGhostSweepTest_1,sd=c._emscripten_bind_btQuaternion_setValue_4=n._emscripten_bind_btQuaternion_setValue_4,td=c._emscripten_bind_btDispatcherInfo_set_m_dispatchFunc_1=n._emscripten_bind_btDispatcherInfo_set_m_dispatchFunc_1,ud=c._emscripten_bind_btQuaternion_setRotation_2=n._emscripten_bind_btQuaternion_setRotation_2,vd=c._emscripten_bind_btMotionState_setWorldTransform_1=\nn._emscripten_bind_btMotionState_setWorldTransform_1,wd=c._emscripten_bind_LocalShapeInfo___destroy___0=n._emscripten_bind_LocalShapeInfo___destroy___0,xd=c._emscripten_bind_btSoftBody_appendAnchor_4=n._emscripten_bind_btSoftBody_appendAnchor_4,yd=c._emscripten_bind_btPoint2PointConstraint_get_m_setting_0=n._emscripten_bind_btPoint2PointConstraint_get_m_setting_0,zd=c._emscripten_bind_btQuadWord_setY_1=n._emscripten_bind_btQuadWord_setY_1,Ad=c._emscripten_bind_btRigidBody_isKinematicObject_0=n._emscripten_bind_btRigidBody_isKinematicObject_0,\nBd=c._emscripten_bind_ContactResultCallback_addSingleResult_7=n._emscripten_bind_ContactResultCallback_addSingleResult_7,Cd=c._emscripten_bind_btRigidBodyConstructionInfo_set_m_restitution_1=n._emscripten_bind_btRigidBodyConstructionInfo_set_m_restitution_1,Dd=c._emscripten_bind_btVector4_rotate_2=n._emscripten_bind_btVector4_rotate_2,Ed=c._emscripten_bind_btDefaultMotionState_get_m_graphicsWorldTrans_0=n._emscripten_bind_btDefaultMotionState_get_m_graphicsWorldTrans_0,Fd=c._emscripten_bind_btSliderConstraint_btSliderConstraint_5=\nn._emscripten_bind_btSliderConstraint_btSliderConstraint_5,Gd=c._emscripten_bind_btConeTwistConstraint_setDamping_1=n._emscripten_bind_btConeTwistConstraint_setDamping_1,Hd=c._emscripten_bind_btPairCachingGhostObject_btPairCachingGhostObject_0=n._emscripten_bind_btPairCachingGhostObject_btPairCachingGhostObject_0,Id=c._emscripten_bind_btWheelInfoConstructionInfo_get_m_suspensionRestLength_0=n._emscripten_bind_btWheelInfoConstructionInfo_get_m_suspensionRestLength_0,Jd=c._emscripten_bind_btDiscreteDynamicsWorld_getSolverInfo_0=\nn._emscripten_bind_btDiscreteDynamicsWorld_getSolverInfo_0,Kd=c._emscripten_bind_btCylinderShape_setMargin_1=n._emscripten_bind_btCylinderShape_setMargin_1,Ld=c._emscripten_bind_btRaycastVehicle_rayCast_1=n._emscripten_bind_btRaycastVehicle_rayCast_1,Md=c._emscripten_bind_btCollisionWorld___destroy___0=n._emscripten_bind_btCollisionWorld___destroy___0,Nd=c._emscripten_bind_btSoftBodyWorldInfo_get_m_broadphase_0=n._emscripten_bind_btSoftBodyWorldInfo_get_m_broadphase_0,Od=c._emscripten_bind_LocalConvexResult_get_m_hitPointLocal_0=\nn._emscripten_bind_LocalConvexResult_get_m_hitPointLocal_0,Pd=c._emscripten_bind_btBoxShape_btBoxShape_1=n._emscripten_bind_btBoxShape_btBoxShape_1,Qd=c._emscripten_bind_btPersistentManifold_getBody1_0=n._emscripten_bind_btPersistentManifold_getBody1_0,Rd=c._emscripten_bind_ClosestRayResultCallback_set_m_collisionObject_1=n._emscripten_bind_ClosestRayResultCallback_set_m_collisionObject_1,Sd=c._emscripten_bind_RaycastInfo_set_m_isInContact_1=n._emscripten_bind_RaycastInfo_set_m_isInContact_1,Td=c._emscripten_bind_btKinematicCharacterController_setGravity_1=\nn._emscripten_bind_btKinematicCharacterController_setGravity_1,Ud=c._emscripten_bind_btGeneric6DofConstraint_btGeneric6DofConstraint_5=n._emscripten_bind_btGeneric6DofConstraint_btGeneric6DofConstraint_5,Vd=c._emscripten_bind_btGeneric6DofConstraint_btGeneric6DofConstraint_3=n._emscripten_bind_btGeneric6DofConstraint_btGeneric6DofConstraint_3,Wd=c._emscripten_bind_LocalShapeInfo_get_m_shapePart_0=n._emscripten_bind_LocalShapeInfo_get_m_shapePart_0,Xd=c._emscripten_bind_btSoftRigidDynamicsWorld_removeAction_1=\nn._emscripten_bind_btSoftRigidDynamicsWorld_removeAction_1,Yd=c._emscripten_bind_btWheelInfo_get_m_rollInfluence_0=n._emscripten_bind_btWheelInfo_get_m_rollInfluence_0,Zd=c._emscripten_bind_btRigidBody_activate_0=n._emscripten_bind_btRigidBody_activate_0,$d=c._emscripten_bind_btVector4_setValue_4=n._emscripten_bind_btVector4_setValue_4,ae=c._emscripten_bind_btBvhTriangleMeshShape_setLocalScaling_1=n._emscripten_bind_btBvhTriangleMeshShape_setLocalScaling_1,be=c._emscripten_bind_tNodeArray_size_0=\nn._emscripten_bind_tNodeArray_size_0,ce=c._emscripten_bind_btPoint2PointConstraint_setBreakingImpulseThreshold_1=n._emscripten_bind_btPoint2PointConstraint_setBreakingImpulseThreshold_1,de=c._emscripten_bind_btDynamicsWorld_getDispatchInfo_0=n._emscripten_bind_btDynamicsWorld_getDispatchInfo_0,ee=c._emscripten_bind_btCompoundShape_removeChildShapeByIndex_1=n._emscripten_bind_btCompoundShape_removeChildShapeByIndex_1,fe=c._emscripten_bind_btSoftBody_appendFace_4=n._emscripten_bind_btSoftBody_appendFace_4,\nge=c._emscripten_bind_btConvexTriangleMeshShape_btConvexTriangleMeshShape_2=n._emscripten_bind_btConvexTriangleMeshShape_btConvexTriangleMeshShape_2,he=c._emscripten_bind_btConvexTriangleMeshShape_btConvexTriangleMeshShape_1=n._emscripten_bind_btConvexTriangleMeshShape_btConvexTriangleMeshShape_1,ie=c._emscripten_bind_ClosestConvexResultCallback_set_m_hitPointWorld_1=n._emscripten_bind_ClosestConvexResultCallback_set_m_hitPointWorld_1,je=c._emscripten_bind_RayResultCallback_set_m_collisionFilterMask_1=\nn._emscripten_bind_RayResultCallback_set_m_collisionFilterMask_1,ke=c._emscripten_bind_btBoxShape_getMargin_0=n._emscripten_bind_btBoxShape_getMargin_0,le=c._emscripten_bind_btPairCachingGhostObject___destroy___0=n._emscripten_bind_btPairCachingGhostObject___destroy___0,me=c._emscripten_bind_btPairCachingGhostObject_setUserPointer_1=n._emscripten_bind_btPairCachingGhostObject_setUserPointer_1,ne=c._emscripten_bind_btDynamicsWorld_addCollisionObject_3=n._emscripten_bind_btDynamicsWorld_addCollisionObject_3,\noe=c._emscripten_bind_btPairCachingGhostObject_activate_0=n._emscripten_bind_btPairCachingGhostObject_activate_0,pe=c._emscripten_bind_btPairCachingGhostObject_activate_1=n._emscripten_bind_btPairCachingGhostObject_activate_1,qe=c._emscripten_bind_btWheelInfoConstructionInfo_set_m_suspensionStiffness_1=n._emscripten_bind_btWheelInfoConstructionInfo_set_m_suspensionStiffness_1,re=c._emscripten_bind_btContactSolverInfo_get_m_splitImpulsePenetrationThreshold_0=n._emscripten_bind_btContactSolverInfo_get_m_splitImpulsePenetrationThreshold_0,\nse=c._emscripten_bind_btSoftBody_setUserPointer_1=n._emscripten_bind_btSoftBody_setUserPointer_1,te=c._emscripten_bind_btSoftBody_setMass_2=n._emscripten_bind_btSoftBody_setMass_2,ue=c._emscripten_bind_Config_get_kCHR_0=n._emscripten_bind_Config_get_kCHR_0,ve=c._emscripten_bind_btPairCachingGhostObject_forceActivationState_1=n._emscripten_bind_btPairCachingGhostObject_forceActivationState_1,we=c._emscripten_bind_btDefaultMotionState___destroy___0=n._emscripten_bind_btDefaultMotionState___destroy___0,\nxe=c._emscripten_bind_btDispatcherInfo_get_m_stepCount_0=n._emscripten_bind_btDispatcherInfo_get_m_stepCount_0,ye=c._emscripten_bind_btRigidBodyConstructionInfo_set_m_angularDamping_1=n._emscripten_bind_btRigidBodyConstructionInfo_set_m_angularDamping_1,ze=c._emscripten_bind_btQuadWord_setW_1=n._emscripten_bind_btQuadWord_setW_1,Ae=c._emscripten_bind_btRigidBodyConstructionInfo_get_m_friction_0=n._emscripten_bind_btRigidBodyConstructionInfo_get_m_friction_0,Be=c._emscripten_bind_btCapsuleShapeX_btCapsuleShapeX_2=\nn._emscripten_bind_btCapsuleShapeX_btCapsuleShapeX_2,Ce=c._emscripten_bind_LocalShapeInfo_set_m_shapePart_1=n._emscripten_bind_LocalShapeInfo_set_m_shapePart_1,De=c._emscripten_bind_btRigidBody_setLinearFactor_1=n._emscripten_bind_btRigidBody_setLinearFactor_1,Ee=c._emscripten_bind_btCompoundShape_getChildShape_1=n._emscripten_bind_btCompoundShape_getChildShape_1,Fe=c._emscripten_bind_btDispatcherInfo_set_m_useConvexConservativeDistanceUtil_1=n._emscripten_bind_btDispatcherInfo_set_m_useConvexConservativeDistanceUtil_1,\nGe=c._emscripten_bind_btSoftRigidDynamicsWorld_setGravity_1=n._emscripten_bind_btSoftRigidDynamicsWorld_setGravity_1,He=c._emscripten_bind_btRaycastVehicle_getUpAxis_0=n._emscripten_bind_btRaycastVehicle_getUpAxis_0,Ie=c._emscripten_bind_btRaycastVehicle_getCurrentSpeedKmHour_0=n._emscripten_bind_btRaycastVehicle_getCurrentSpeedKmHour_0,Je=c._emscripten_bind_btWheelInfo_get_m_engineForce_0=n._emscripten_bind_btWheelInfo_get_m_engineForce_0,Ke=c._emscripten_bind_Config_get_kSR_SPLT_CL_0=n._emscripten_bind_Config_get_kSR_SPLT_CL_0,\nLe=c._emscripten_bind_btRaycastVehicle_setSteeringValue_2=n._emscripten_bind_btRaycastVehicle_setSteeringValue_2,Me=c._emscripten_bind_btPoint2PointConstraint___destroy___0=n._emscripten_bind_btPoint2PointConstraint___destroy___0,Ne=c._emscripten_bind_btSoftBody_getUserPointer_0=n._emscripten_bind_btSoftBody_getUserPointer_0,Oe=c._emscripten_bind_btCollisionShape_setMargin_1=n._emscripten_bind_btCollisionShape_setMargin_1,Pe=c._emscripten_bind_btGeneric6DofConstraint_setAngularUpperLimit_1=n._emscripten_bind_btGeneric6DofConstraint_setAngularUpperLimit_1,\nQe=c._emscripten_bind_btDiscreteDynamicsWorld_addConstraint_2=n._emscripten_bind_btDiscreteDynamicsWorld_addConstraint_2,Re=c._emscripten_bind_btDiscreteDynamicsWorld_addConstraint_1=n._emscripten_bind_btDiscreteDynamicsWorld_addConstraint_1,Se=c._emscripten_bind_btRigidBodyConstructionInfo_set_m_angularSleepingThreshold_1=n._emscripten_bind_btRigidBodyConstructionInfo_set_m_angularSleepingThreshold_1,Te=c._emscripten_bind_Config_get_kVCF_0=n._emscripten_bind_Config_get_kVCF_0,Ue=c._emscripten_bind_btWheelInfoConstructionInfo_get_m_suspensionStiffness_0=\nn._emscripten_bind_btWheelInfoConstructionInfo_get_m_suspensionStiffness_0,Ve=c._emscripten_bind_btRaycastVehicle_getRightAxis_0=n._emscripten_bind_btRaycastVehicle_getRightAxis_0,We=c._emscripten_bind_btContactSolverInfo_set_m_numIterations_1=n._emscripten_bind_btContactSolverInfo_set_m_numIterations_1,xa=c._malloc=n._malloc,Xe=c._emscripten_bind_btDispatcherInfo_get_m_useEpa_0=n._emscripten_bind_btDispatcherInfo_get_m_useEpa_0,Ye=c._emscripten_bind_btTransform_btTransform_2=n._emscripten_bind_btTransform_btTransform_2,\nZe=c._emscripten_bind_btTransform_btTransform_0=n._emscripten_bind_btTransform_btTransform_0,$e=c._emscripten_bind_btPairCachingGhostObject_getUserIndex_0=n._emscripten_bind_btPairCachingGhostObject_getUserIndex_0,af=c._emscripten_bind_Config_set_kVC_1=n._emscripten_bind_Config_set_kVC_1,bf=c._emscripten_bind_btSoftRigidDynamicsWorld_addSoftBody_3=n._emscripten_bind_btSoftRigidDynamicsWorld_addSoftBody_3,cf=c._emscripten_bind_btVector3_op_sub_1=n._emscripten_bind_btVector3_op_sub_1,df=c._emscripten_bind_btWheelInfo_set_m_wheelsRadius_1=\nn._emscripten_bind_btWheelInfo_set_m_wheelsRadius_1,ef=c._emscripten_bind_btQuaternion_length_0=n._emscripten_bind_btQuaternion_length_0,ff=c._emscripten_bind_btDispatcherInfo_set_m_enableSPU_1=n._emscripten_bind_btDispatcherInfo_set_m_enableSPU_1,gf=c._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelsDampingCompression_0=n._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelsDampingCompression_0,hf=c._emscripten_bind_btRaycastVehicle_setCoordinateSystem_3=n._emscripten_bind_btRaycastVehicle_setCoordinateSystem_3,\njf=c._emscripten_bind_btSoftBody_appendNode_2=n._emscripten_bind_btSoftBody_appendNode_2,kf=c._emscripten_bind_btCollisionObject_setActivationState_1=n._emscripten_bind_btCollisionObject_setActivationState_1,lf=c._emscripten_bind_btQuaternion_angle_1=n._emscripten_bind_btQuaternion_angle_1,mf=c._emscripten_bind_btPersistentManifold___destroy___0=n._emscripten_bind_btPersistentManifold___destroy___0,nf=c._emscripten_bind_btConstraintSetting_get_m_impulseClamp_0=n._emscripten_bind_btConstraintSetting_get_m_impulseClamp_0,\nof=c._emscripten_bind_btCylinderShapeZ___destroy___0=n._emscripten_bind_btCylinderShapeZ___destroy___0,pf=c._emscripten_bind_btMatrix3x3___destroy___0=n._emscripten_bind_btMatrix3x3___destroy___0;c.setTempRet0=n.setTempRet0;\nvar qf=c._emscripten_bind_btQuaternion_angleShortestPath_1=n._emscripten_bind_btQuaternion_angleShortestPath_1,rf=c._emscripten_bind_Config_set_kKHR_1=n._emscripten_bind_Config_set_kKHR_1,sf=c._emscripten_bind_ConvexResultCallback_hasHit_0=n._emscripten_bind_ConvexResultCallback_hasHit_0,tf=c._emscripten_bind_btCollisionShape_calculateLocalInertia_2=n._emscripten_bind_btCollisionShape_calculateLocalInertia_2,uf=c._emscripten_bind_btGeneric6DofSpringConstraint_setBreakingImpulseThreshold_1=n._emscripten_bind_btGeneric6DofSpringConstraint_setBreakingImpulseThreshold_1,\nvf=c._emscripten_bind_Config_set_kPR_1=n._emscripten_bind_Config_set_kPR_1,wf=c._emscripten_bind_btCollisionWorld_convexSweepTest_5=n._emscripten_bind_btCollisionWorld_convexSweepTest_5,xf=c._emscripten_bind_btSoftBody_set_m_materials_1=n._emscripten_bind_btSoftBody_set_m_materials_1,yf=c._emscripten_bind_ClosestRayResultCallback_set_m_hitPointWorld_1=n._emscripten_bind_ClosestRayResultCallback_set_m_hitPointWorld_1,zf=c._emscripten_bind_btVehicleRaycasterResult___destroy___0=n._emscripten_bind_btVehicleRaycasterResult___destroy___0,\nAf=c._emscripten_bind_btCapsuleShapeX_calculateLocalInertia_2=n._emscripten_bind_btCapsuleShapeX_calculateLocalInertia_2,Bf=c._emscripten_bind_btConstraintSetting_set_m_damping_1=n._emscripten_bind_btConstraintSetting_set_m_damping_1,Cf=c._emscripten_bind_btWheelInfo_set_m_bIsFrontWheel_1=n._emscripten_bind_btWheelInfo_set_m_bIsFrontWheel_1,Df=c._emscripten_bind_btRigidBody_setCcdMotionThreshold_1=n._emscripten_bind_btRigidBody_setCcdMotionThreshold_1,Ef=c._emscripten_bind_btConvexHullShape_setMargin_1=\nn._emscripten_bind_btConvexHullShape_setMargin_1,Ff=c._emscripten_bind_btRigidBody_applyForce_2=n._emscripten_bind_btRigidBody_applyForce_2,Gf=c._emscripten_bind_btConeShapeZ_calculateLocalInertia_2=n._emscripten_bind_btConeShapeZ_calculateLocalInertia_2,Hf=c._emscripten_bind_btConstraintSetting_set_m_tau_1=n._emscripten_bind_btConstraintSetting_set_m_tau_1,If=c._emscripten_bind_btConvexHullShape_calculateLocalInertia_2=n._emscripten_bind_btConvexHullShape_calculateLocalInertia_2,Jf=c._emscripten_bind_btQuaternion_op_div_1=\nn._emscripten_bind_btQuaternion_op_div_1,Db=c.___uremdi3=n.___uremdi3,Kf=c._emscripten_bind_RaycastInfo_get_m_contactPointWS_0=n._emscripten_bind_RaycastInfo_get_m_contactPointWS_0,Lf=c._emscripten_bind_btSoftBody_setCollisionFlags_1=n._emscripten_bind_btSoftBody_setCollisionFlags_1,Mf=c._emscripten_bind_btSphereShape_calculateLocalInertia_2=n._emscripten_bind_btSphereShape_calculateLocalInertia_2,Nf=c._emscripten_bind_Config_set_maxvolume_1=n._emscripten_bind_Config_set_maxvolume_1,Of=c._emscripten_bind_btSoftRigidDynamicsWorld_getSolverInfo_0=\nn._emscripten_bind_btSoftRigidDynamicsWorld_getSolverInfo_0,Pf=c._emscripten_bind_btCollisionDispatcher_getManifoldByIndexInternal_1=n._emscripten_bind_btCollisionDispatcher_getManifoldByIndexInternal_1,Qf=c._emscripten_bind_btSoftBody_setTotalMass_2=n._emscripten_bind_btSoftBody_setTotalMass_2,Rf=c._emscripten_bind_ClosestRayResultCallback_get_m_rayToWorld_0=n._emscripten_bind_ClosestRayResultCallback_get_m_rayToWorld_0,Sf=c._emscripten_bind_btGhostObject_setFriction_1=n._emscripten_bind_btGhostObject_setFriction_1,\nTf=c._emscripten_bind_btCollisionWorld_rayTest_3=n._emscripten_bind_btCollisionWorld_rayTest_3;c.stackRestore=n.stackRestore;\nvar Uf=c._emscripten_bind_btRigidBody_setCcdSweptSphereRadius_1=n._emscripten_bind_btRigidBody_setCcdSweptSphereRadius_1,Vf=c._emscripten_bind_btCylinderShapeZ_setMargin_1=n._emscripten_bind_btCylinderShapeZ_setMargin_1,Wf=c._emscripten_bind_btRigidBody_setFriction_1=n._emscripten_bind_btRigidBody_setFriction_1,Xf=c._emscripten_bind_LocalConvexResult_set_m_hitPointLocal_1=n._emscripten_bind_LocalConvexResult_set_m_hitPointLocal_1,Yf=c._emscripten_bind_btGhostObject_setWorldTransform_1=n._emscripten_bind_btGhostObject_setWorldTransform_1,\nZf=c._emscripten_bind_tMaterialArray_size_0=n._emscripten_bind_tMaterialArray_size_0,$f=c._emscripten_bind_RaycastInfo_set_m_hardPointWS_1=n._emscripten_bind_RaycastInfo_set_m_hardPointWS_1,ag=c._emscripten_bind_btManifoldPoint_getAppliedImpulse_0=n._emscripten_bind_btManifoldPoint_getAppliedImpulse_0,bg=c._emscripten_bind_btDiscreteDynamicsWorld_removeRigidBody_1=n._emscripten_bind_btDiscreteDynamicsWorld_removeRigidBody_1,cg=c._emscripten_bind_btConvexHullShape___destroy___0=n._emscripten_bind_btConvexHullShape___destroy___0,\ndg=c._emscripten_bind_btDiscreteDynamicsWorld_getBroadphase_0=n._emscripten_bind_btDiscreteDynamicsWorld_getBroadphase_0,eg=c._emscripten_bind_btDiscreteDynamicsWorld_addAction_1=n._emscripten_bind_btDiscreteDynamicsWorld_addAction_1,fg=c._emscripten_bind_btVector4_setX_1=n._emscripten_bind_btVector4_setX_1,gg=c._emscripten_bind_btKinematicCharacterController_jump_0=n._emscripten_bind_btKinematicCharacterController_jump_0,hg=c._emscripten_bind_btCollisionObject_getUserPointer_0=n._emscripten_bind_btCollisionObject_getUserPointer_0,\nig=c._emscripten_bind_btWheelInfo_set_m_raycastInfo_1=n._emscripten_bind_btWheelInfo_set_m_raycastInfo_1,jg=c._emscripten_bind_btCollisionWorld_contactTest_2=n._emscripten_bind_btCollisionWorld_contactTest_2,kg=c._emscripten_bind_btConeTwistConstraint_setMaxMotorImpulseNormalized_1=n._emscripten_bind_btConeTwistConstraint_setMaxMotorImpulseNormalized_1,lg=c._emscripten_bind_btConvexTriangleMeshShape_setLocalScaling_1=n._emscripten_bind_btConvexTriangleMeshShape_setLocalScaling_1,mg=c._emscripten_bind_btRigidBody_upcast_1=\nn._emscripten_bind_btRigidBody_upcast_1,ng=c._emscripten_bind_btTransform_setOrigin_1=n._emscripten_bind_btTransform_setOrigin_1,og=c._emscripten_bind_btVector4_setZ_1=n._emscripten_bind_btVector4_setZ_1,pg=c._emscripten_bind_btQuadWord_y_0=n._emscripten_bind_btQuadWord_y_0,qg=c._emscripten_bind_btTransform_getBasis_0=n._emscripten_bind_btTransform_getBasis_0,rg=c._emscripten_bind_btPairCachingGhostObject_setFriction_1=n._emscripten_bind_btPairCachingGhostObject_setFriction_1,sg=c._emscripten_bind_btSoftBody_setRollingFriction_1=\nn._emscripten_bind_btSoftBody_setRollingFriction_1,tg=c._emscripten_bind_Config_set_kSRHR_CL_1=n._emscripten_bind_Config_set_kSRHR_CL_1,ug=c._emscripten_bind_btCollisionDispatcher_getNumManifolds_0=n._emscripten_bind_btCollisionDispatcher_getNumManifolds_0,vg=c._emscripten_bind_btVehicleRaycaster___destroy___0=n._emscripten_bind_btVehicleRaycaster___destroy___0,wg=c._emscripten_bind_ClosestRayResultCallback___destroy___0=n._emscripten_bind_ClosestRayResultCallback___destroy___0,xg=c._emscripten_bind_ClosestConvexResultCallback_get_m_convexFromWorld_0=\nn._emscripten_bind_ClosestConvexResultCallback_get_m_convexFromWorld_0,yg=c._emscripten_bind_btCylinderShapeX_setMargin_1=n._emscripten_bind_btCylinderShapeX_setMargin_1,zg=c._emscripten_bind_btQuadWord_w_0=n._emscripten_bind_btQuadWord_w_0,Ag=c._emscripten_bind_Node___destroy___0=n._emscripten_bind_Node___destroy___0,Bg=c._emscripten_bind_btAxisSweep3___destroy___0=n._emscripten_bind_btAxisSweep3___destroy___0,Cg=c._emscripten_bind_btDiscreteDynamicsWorld_contactTest_2=n._emscripten_bind_btDiscreteDynamicsWorld_contactTest_2,\nDg=c._emscripten_bind_btBvhTriangleMeshShape_calculateLocalInertia_2=n._emscripten_bind_btBvhTriangleMeshShape_calculateLocalInertia_2,Eg=c._emscripten_bind_btCompoundShape_setMargin_1=n._emscripten_bind_btCompoundShape_setMargin_1,Fg=c._emscripten_bind_btCompoundShape_getNumChildShapes_0=n._emscripten_bind_btCompoundShape_getNumChildShapes_0,Gg=c._emscripten_bind_btSoftBodyWorldInfo_set_m_broadphase_1=n._emscripten_bind_btSoftBodyWorldInfo_set_m_broadphase_1,Hg=c._emscripten_bind_btCapsuleShape_setLocalScaling_1=\nn._emscripten_bind_btCapsuleShape_setLocalScaling_1,Ig=c._emscripten_bind_btGhostObject_btGhostObject_0=n._emscripten_bind_btGhostObject_btGhostObject_0,Jg=c._emscripten_bind_btConeShape_btConeShape_2=n._emscripten_bind_btConeShape_btConeShape_2,Kg=c._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalAngularDampingFactor_1=n._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalAngularDampingFactor_1,Lg=c._emscripten_bind_btManifoldPoint_set_m_localPointA_1=n._emscripten_bind_btManifoldPoint_set_m_localPointA_1,\nMg=c._emscripten_bind_btCapsuleShapeX_setMargin_1=n._emscripten_bind_btCapsuleShapeX_setMargin_1,Ng=c._emscripten_bind_Config_set_kMT_1=n._emscripten_bind_Config_set_kMT_1,Og=c._emscripten_bind_btVector3_dot_1=n._emscripten_bind_btVector3_dot_1,Pg=c._emscripten_bind_btGhostObject_getUserPointer_0=n._emscripten_bind_btGhostObject_getUserPointer_0,Qg=c._emscripten_bind_btVector4_op_add_1=n._emscripten_bind_btVector4_op_add_1,Rg=c._emscripten_bind_btWheelInfo___destroy___0=n._emscripten_bind_btWheelInfo___destroy___0,\nSg=c._emscripten_bind_btSoftRigidDynamicsWorld_getSoftBodyArray_0=n._emscripten_bind_btSoftRigidDynamicsWorld_getSoftBodyArray_0,Tg=c._emscripten_bind_btHingeConstraint_btHingeConstraint_4=n._emscripten_bind_btHingeConstraint_btHingeConstraint_4,Ug=c._emscripten_bind_btTransform_setRotation_1=n._emscripten_bind_btTransform_setRotation_1,Vg=c._emscripten_bind_Config_set_kSHR_1=n._emscripten_bind_Config_set_kSHR_1,Wg=c._emscripten_bind_btPoint2PointConstraint_enableFeedback_1=n._emscripten_bind_btPoint2PointConstraint_enableFeedback_1,\nXg=c._emscripten_bind_ClosestRayResultCallback_set_m_collisionFilterGroup_1=n._emscripten_bind_ClosestRayResultCallback_set_m_collisionFilterGroup_1,Yg=c._emscripten_bind_btAxisSweep3_btAxisSweep3_2=n._emscripten_bind_btAxisSweep3_btAxisSweep3_2,Zg=c._emscripten_bind_btAxisSweep3_btAxisSweep3_3=n._emscripten_bind_btAxisSweep3_btAxisSweep3_3,$g=c._emscripten_bind_btDynamicsWorld___destroy___0=n._emscripten_bind_btDynamicsWorld___destroy___0,ah=c._emscripten_bind_btVector3_setY_1=n._emscripten_bind_btVector3_setY_1,\nbh=c._emscripten_bind_btAxisSweep3_btAxisSweep3_4=n._emscripten_bind_btAxisSweep3_btAxisSweep3_4,ch=c._emscripten_bind_btAxisSweep3_btAxisSweep3_5=n._emscripten_bind_btAxisSweep3_btAxisSweep3_5,dh=c._emscripten_bind_btQuadWord_setX_1=n._emscripten_bind_btQuadWord_setX_1,eh=c._emscripten_bind_tMaterialArray___destroy___0=n._emscripten_bind_tMaterialArray___destroy___0,fh=c._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalLinearDampingThresholdSqr_1=n._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalLinearDampingThresholdSqr_1,\ngh=c._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalLinearDampingThresholdSqr_0=n._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalLinearDampingThresholdSqr_0,hh=c._emscripten_bind_Config_set_piterations_1=n._emscripten_bind_Config_set_piterations_1,ih=c._emscripten_bind_btOverlappingPairCache___destroy___0=n._emscripten_bind_btOverlappingPairCache___destroy___0,jh=c._emscripten_bind_btRigidBody_setUserIndex_1=n._emscripten_bind_btRigidBody_setUserIndex_1,kh=c._emscripten_bind_Material_get_m_kAST_0=\nn._emscripten_bind_Material_get_m_kAST_0,lh=c._emscripten_bind_btConstraintSetting___destroy___0=n._emscripten_bind_btConstraintSetting___destroy___0,mh=c._emscripten_bind_btWheelInfo_btWheelInfo_1=n._emscripten_bind_btWheelInfo_btWheelInfo_1,nh=c._emscripten_bind_RayResultCallback___destroy___0=n._emscripten_bind_RayResultCallback___destroy___0,oh=c._emscripten_bind_RaycastInfo_get_m_contactNormalWS_0=n._emscripten_bind_RaycastInfo_get_m_contactNormalWS_0,ph=c._emscripten_bind_btSoftBodyWorldInfo_get_water_density_0=\nn._emscripten_bind_btSoftBodyWorldInfo_get_water_density_0,qh=c._emscripten_bind_btPersistentManifold_getBody0_0=n._emscripten_bind_btPersistentManifold_getBody0_0,rh=c._emscripten_bind_btConeShapeX_btConeShapeX_2=n._emscripten_bind_btConeShapeX_btConeShapeX_2,sh=c._emscripten_bind_btSoftBody_setCcdSweptSphereRadius_1=n._emscripten_bind_btSoftBody_setCcdSweptSphereRadius_1,th=c._emscripten_bind_btConeTwistConstraint_enableFeedback_1=n._emscripten_bind_btConeTwistConstraint_enableFeedback_1,uh=c._emscripten_bind_btRaycastVehicle_setPitchControl_1=\nn._emscripten_bind_btRaycastVehicle_setPitchControl_1,vh=c._emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration_btSoftBodyRigidBodyCollisionConfiguration_0=n._emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration_btSoftBodyRigidBodyCollisionConfiguration_0,wh=c._emscripten_bind_btCapsuleShapeZ_setLocalScaling_1=n._emscripten_bind_btCapsuleShapeZ_setLocalScaling_1,xh=c._emscripten_bind_Config_get_piterations_0=n._emscripten_bind_Config_get_piterations_0,yh=c._emscripten_bind_btSoftBody_translate_1=\nn._emscripten_bind_btSoftBody_translate_1,zh=c._emscripten_bind_btSliderConstraint_setUpperLinLimit_1=n._emscripten_bind_btSliderConstraint_setUpperLinLimit_1,Ah=c._emscripten_bind_btConeTwistConstraint_btConeTwistConstraint_2=n._emscripten_bind_btConeTwistConstraint_btConeTwistConstraint_2,Bh=c._emscripten_bind_btVector3_op_mul_1=n._emscripten_bind_btVector3_op_mul_1,Ch=c._emscripten_bind_btConcaveShape___destroy___0=n._emscripten_bind_btConcaveShape___destroy___0,Dh=c._emscripten_bind_Config_get_kSK_SPLT_CL_0=\nn._emscripten_bind_Config_get_kSK_SPLT_CL_0,Eh=c._emscripten_bind_btConeTwistConstraint_btConeTwistConstraint_4=n._emscripten_bind_btConeTwistConstraint_btConeTwistConstraint_4,Fh=c._emscripten_bind_btQuaternion_x_0=n._emscripten_bind_btQuaternion_x_0,Gh=c._emscripten_bind_btSoftRigidDynamicsWorld_btSoftRigidDynamicsWorld_5=n._emscripten_bind_btSoftRigidDynamicsWorld_btSoftRigidDynamicsWorld_5,Hh=c._emscripten_bind_btVehicleRaycasterResult_set_m_distFraction_1=n._emscripten_bind_btVehicleRaycasterResult_set_m_distFraction_1,\nIh=c._emscripten_bind_Config_set_timescale_1=n._emscripten_bind_Config_set_timescale_1,Jh=c._emscripten_bind_LocalConvexResult_set_m_hitNormalLocal_1=n._emscripten_bind_LocalConvexResult_set_m_hitNormalLocal_1,Kh=c._emscripten_bind_btConcaveShape_setLocalScaling_1=n._emscripten_bind_btConcaveShape_setLocalScaling_1,Lh=c._emscripten_bind_btDiscreteDynamicsWorld_getDispatchInfo_0=n._emscripten_bind_btDiscreteDynamicsWorld_getDispatchInfo_0,Mh=c._emscripten_bind_btConeShapeX_setLocalScaling_1=n._emscripten_bind_btConeShapeX_setLocalScaling_1,\nNh=c._emscripten_bind_btSoftBody_appendLink_4=n._emscripten_bind_btSoftBody_appendLink_4,Oh=c._emscripten_bind_btQuaternion_z_0=n._emscripten_bind_btQuaternion_z_0,Ph=c._emscripten_bind_btConvexHullShape_btConvexHullShape_0=n._emscripten_bind_btConvexHullShape_btConvexHullShape_0,Qh=c._emscripten_bind_btWheelInfo_set_m_maxSuspensionForce_1=n._emscripten_bind_btWheelInfo_set_m_maxSuspensionForce_1,Rh=c._emscripten_bind_btConstraintSetting_get_m_damping_0=n._emscripten_bind_btConstraintSetting_get_m_damping_0,\nSh=c._emscripten_bind_btVector4_op_mul_1=n._emscripten_bind_btVector4_op_mul_1,Th=c._emscripten_bind_btSoftRigidDynamicsWorld_removeCollisionObject_1=n._emscripten_bind_btSoftRigidDynamicsWorld_removeCollisionObject_1,Uh=c._emscripten_bind_Config_get_kLF_0=n._emscripten_bind_Config_get_kLF_0,Vh=c._emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_3=n._emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_3,Wh=c._emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_2=n._emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_2,\nXh=c._emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_1=n._emscripten_bind_btSoftRigidDynamicsWorld_addCollisionObject_1,Yh=c._emscripten_bind_btGhostObject_setContactProcessingThreshold_1=n._emscripten_bind_btGhostObject_setContactProcessingThreshold_1,Zh=c._emscripten_bind_btSoftBodyHelpers_CreateFromConvexHull_4=n._emscripten_bind_btSoftBodyHelpers_CreateFromConvexHull_4,$h=c._emscripten_bind_btCollisionWorld_getBroadphase_0=n._emscripten_bind_btCollisionWorld_getBroadphase_0,ai=c._emscripten_bind_btCylinderShape_btCylinderShape_1=\nn._emscripten_bind_btCylinderShape_btCylinderShape_1,bi=c._emscripten_bind_btDispatcherInfo_set_m_stepCount_1=n._emscripten_bind_btDispatcherInfo_set_m_stepCount_1,ci=c._emscripten_bind_btContactSolverInfo_set_m_splitImpulse_1=n._emscripten_bind_btContactSolverInfo_set_m_splitImpulse_1,di=c._emscripten_bind_btKinematicCharacterController_updateAction_2=n._emscripten_bind_btKinematicCharacterController_updateAction_2,ei=c._emscripten_bind_btDefaultMotionState_btDefaultMotionState_2=n._emscripten_bind_btDefaultMotionState_btDefaultMotionState_2,\nfi=c._emscripten_bind_Material_set_m_flags_1=n._emscripten_bind_Material_set_m_flags_1,gi=c._emscripten_bind_btDefaultMotionState_btDefaultMotionState_0=n._emscripten_bind_btDefaultMotionState_btDefaultMotionState_0,hi=c._emscripten_bind_btDefaultMotionState_btDefaultMotionState_1=n._emscripten_bind_btDefaultMotionState_btDefaultMotionState_1,ii=c._emscripten_bind_Config_get_viterations_0=n._emscripten_bind_Config_get_viterations_0,ji=c._emscripten_bind_btKinematicCharacterController_canJump_0=n._emscripten_bind_btKinematicCharacterController_canJump_0,\nki=c._emscripten_bind_btSoftBodyArray_at_1=n._emscripten_bind_btSoftBodyArray_at_1,li=c._emscripten_bind_btPairCachingGhostObject_setUserIndex_1=n._emscripten_bind_btPairCachingGhostObject_setUserIndex_1,mi=c._emscripten_bind_btRigidBody_isActive_0=n._emscripten_bind_btRigidBody_isActive_0,ni=c._emscripten_bind_btRaycastVehicle_btRaycastVehicle_3=n._emscripten_bind_btRaycastVehicle_btRaycastVehicle_3,oi=c._emscripten_bind_btSoftBody_transform_1=n._emscripten_bind_btSoftBody_transform_1,pi=c._emscripten_bind_btSoftRigidDynamicsWorld_getDispatcher_0=\nn._emscripten_bind_btSoftRigidDynamicsWorld_getDispatcher_0,qi=c._emscripten_bind_btCylinderShape_setLocalScaling_1=n._emscripten_bind_btCylinderShape_setLocalScaling_1,ri=c._emscripten_bind_btPairCachingGhostObject_getWorldTransform_0=n._emscripten_bind_btPairCachingGhostObject_getWorldTransform_0,si=c._emscripten_bind_btCompoundShape_calculateLocalInertia_2=n._emscripten_bind_btCompoundShape_calculateLocalInertia_2,ti=c._emscripten_bind_btCollisionWorld_getDispatchInfo_0=n._emscripten_bind_btCollisionWorld_getDispatchInfo_0,\nui=c._emscripten_bind_btRigidBody_setCollisionShape_1=n._emscripten_bind_btRigidBody_setCollisionShape_1,vi=c._emscripten_bind_btSoftBody_appendTetra_5=n._emscripten_bind_btSoftBody_appendTetra_5,wi=c._emscripten_bind_btConeShapeX___destroy___0=n._emscripten_bind_btConeShapeX___destroy___0,xi=c._emscripten_bind_btCollisionObject_getCollisionFlags_0=n._emscripten_bind_btCollisionObject_getCollisionFlags_0,yi=c._emscripten_bind_btDispatcherInfo_set_m_enableSatConvex_1=n._emscripten_bind_btDispatcherInfo_set_m_enableSatConvex_1,\nzi=c._emscripten_bind_btConeTwistConstraint_enableMotor_1=n._emscripten_bind_btConeTwistConstraint_enableMotor_1,Ai=c._emscripten_bind_btWheelInfo_set_m_chassisConnectionPointCS_1=n._emscripten_bind_btWheelInfo_set_m_chassisConnectionPointCS_1,Bi=c._emscripten_bind_btVehicleRaycasterResult_get_m_hitPointInWorld_0=n._emscripten_bind_btVehicleRaycasterResult_get_m_hitPointInWorld_0,Ci=c._emscripten_bind_btWheelInfo_set_m_wheelsDampingCompression_1=n._emscripten_bind_btWheelInfo_set_m_wheelsDampingCompression_1,\nDi=c._emscripten_bind_btDefaultCollisionConfiguration_btDefaultCollisionConfiguration_0=n._emscripten_bind_btDefaultCollisionConfiguration_btDefaultCollisionConfiguration_0,Ei=c._emscripten_bind_btPairCachingGhostObject_setRestitution_1=n._emscripten_bind_btPairCachingGhostObject_setRestitution_1,Fi=c._emscripten_bind_Config_set_kAHR_1=n._emscripten_bind_Config_set_kAHR_1,Gi=c._emscripten_bind_btHeightfieldTerrainShape_getMargin_0=n._emscripten_bind_btHeightfieldTerrainShape_getMargin_0,Hi=c._emscripten_bind_ConvexResultCallback___destroy___0=\nn._emscripten_bind_ConvexResultCallback___destroy___0,Ii=c._emscripten_bind_btSoftRigidDynamicsWorld_rayTest_3=n._emscripten_bind_btSoftRigidDynamicsWorld_rayTest_3,Ji=c._emscripten_bind_btQuaternion_getAngle_0=n._emscripten_bind_btQuaternion_getAngle_0,Ki=c._emscripten_bind_btSliderConstraint_getBreakingImpulseThreshold_0=n._emscripten_bind_btSliderConstraint_getBreakingImpulseThreshold_0,Li=c._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalDampingFactor_1=n._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalDampingFactor_1,\nMi=c._emscripten_bind_btKinematicCharacterController_btKinematicCharacterController_3=n._emscripten_bind_btKinematicCharacterController_btKinematicCharacterController_3,Ni=c._emscripten_bind_btCollisionObject_setContactProcessingThreshold_1=n._emscripten_bind_btCollisionObject_setContactProcessingThreshold_1,Oi=c._emscripten_bind_btCompoundShape___destroy___0=n._emscripten_bind_btCompoundShape___destroy___0,Pi=c._emscripten_bind_btHingeConstraint_setMotorTarget_2=n._emscripten_bind_btHingeConstraint_setMotorTarget_2,\nQi=c._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalAngularDampingFactor_0=n._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalAngularDampingFactor_0,Ri=c._emscripten_bind_LocalConvexResult___destroy___0=n._emscripten_bind_LocalConvexResult___destroy___0,Si=c._emscripten_bind_btSequentialImpulseConstraintSolver___destroy___0=n._emscripten_bind_btSequentialImpulseConstraintSolver___destroy___0;c.setThrew=n.setThrew;\nvar Ti=c._emscripten_bind_btSoftBodyHelpers_CreateRope_5=n._emscripten_bind_btSoftBodyHelpers_CreateRope_5,Ui=c._emscripten_bind_btRaycastVehicle___destroy___0=n._emscripten_bind_btRaycastVehicle___destroy___0,Vi=c._emscripten_bind_btCollisionWorld_addCollisionObject_3=n._emscripten_bind_btCollisionWorld_addCollisionObject_3,Wi=c._emscripten_bind_btRigidBody_getCollisionFlags_0=n._emscripten_bind_btRigidBody_getCollisionFlags_0,Xi=c._emscripten_bind_btCollisionShape_setLocalScaling_1=n._emscripten_bind_btCollisionShape_setLocalScaling_1,\nYi=c._emscripten_bind_ClosestConvexResultCallback_get_m_closestHitFraction_0=n._emscripten_bind_ClosestConvexResultCallback_get_m_closestHitFraction_0,Zi=c._emscripten_bind_LocalConvexResult_get_m_hitCollisionObject_0=n._emscripten_bind_LocalConvexResult_get_m_hitCollisionObject_0,$i=c._emscripten_bind_btMatrix3x3_setEulerZYX_3=n._emscripten_bind_btMatrix3x3_setEulerZYX_3,aj=c._emscripten_bind_btSoftBody_getTotalMass_0=n._emscripten_bind_btSoftBody_getTotalMass_0,bj=c._emscripten_bind_btDispatcherInfo_get_m_convexConservativeDistanceThreshold_0=\nn._emscripten_bind_btDispatcherInfo_get_m_convexConservativeDistanceThreshold_0,cj=c._emscripten_bind_btRigidBody_getUserPointer_0=n._emscripten_bind_btRigidBody_getUserPointer_0,dj=c._emscripten_bind_Config_get_kSHR_0=n._emscripten_bind_Config_get_kSHR_0,ej=c._emscripten_bind_btHeightfieldTerrainShape_calculateLocalInertia_2=n._emscripten_bind_btHeightfieldTerrainShape_calculateLocalInertia_2,fj=c._emscripten_bind_btRigidBody_setMotionState_1=n._emscripten_bind_btRigidBody_setMotionState_1,gj=c._emscripten_bind_RayResultCallback_get_m_collisionFilterMask_0=\nn._emscripten_bind_RayResultCallback_get_m_collisionFilterMask_0,hj=c._emscripten_bind_btCollisionWorld_getDispatcher_0=n._emscripten_bind_btCollisionWorld_getDispatcher_0,ij=c._emscripten_bind_btVector4_dot_1=n._emscripten_bind_btVector4_dot_1,jj=c._emscripten_bind_btSoftBody_forceActivationState_1=n._emscripten_bind_btSoftBody_forceActivationState_1,kj=c._emscripten_bind_btCollisionObject_setRollingFriction_1=n._emscripten_bind_btCollisionObject_setRollingFriction_1,lj=c._emscripten_bind_Config_set_kSK_SPLT_CL_1=\nn._emscripten_bind_Config_set_kSK_SPLT_CL_1,mj=c._emscripten_bind_RayResultCallback_set_m_collisionFilterGroup_1=n._emscripten_bind_RayResultCallback_set_m_collisionFilterGroup_1,nj=c._emscripten_bind_btVehicleRaycaster_castRay_3=n._emscripten_bind_btVehicleRaycaster_castRay_3,db=c._i64Subtract=n._i64Subtract,oj=c._emscripten_bind_btCylinderShapeX_getMargin_0=n._emscripten_bind_btCylinderShapeX_getMargin_0,pj=c._emscripten_bind_btRigidBody_setDamping_2=n._emscripten_bind_btRigidBody_setDamping_2,\nqj=c._emscripten_bind_btDynamicsWorld_getDispatcher_0=n._emscripten_bind_btDynamicsWorld_getDispatcher_0,rj=c._emscripten_bind_btGhostObject_setCollisionFlags_1=n._emscripten_bind_btGhostObject_setCollisionFlags_1,sj=c._emscripten_bind_btMatrix3x3_getRotation_1=n._emscripten_bind_btMatrix3x3_getRotation_1,tj=c._emscripten_bind_btWheelInfo_set_m_engineForce_1=n._emscripten_bind_btWheelInfo_set_m_engineForce_1,uj=c._emscripten_bind_btConeTwistConstraint_setMaxMotorImpulse_1=n._emscripten_bind_btConeTwistConstraint_setMaxMotorImpulse_1,\nvj=c._emscripten_bind_btPersistentManifold_getNumContacts_0=n._emscripten_bind_btPersistentManifold_getNumContacts_0,wj=c._emscripten_bind_btCylinderShapeX_setLocalScaling_1=n._emscripten_bind_btCylinderShapeX_setLocalScaling_1,xj=c._emscripten_bind_btDbvtBroadphase_btDbvtBroadphase_0=n._emscripten_bind_btDbvtBroadphase_btDbvtBroadphase_0,yj=c._emscripten_bind_btSoftBodyHelpers_btSoftBodyHelpers_0=n._emscripten_bind_btSoftBodyHelpers_btSoftBodyHelpers_0,zj=c._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalDamping_0=\nn._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalDamping_0,Aj=c._emscripten_bind_btWheelInfoConstructionInfo_get_m_bIsFrontWheel_0=n._emscripten_bind_btWheelInfoConstructionInfo_get_m_bIsFrontWheel_0,Bj=c._emscripten_bind_btOverlappingPairCallback___destroy___0=n._emscripten_bind_btOverlappingPairCallback___destroy___0,Cj=c._emscripten_bind_btWheelInfo_get_m_suspensionRelativeVelocity_0=n._emscripten_bind_btWheelInfo_get_m_suspensionRelativeVelocity_0,Dj=c._emscripten_bind_btManifoldPoint_get_m_positionWorldOnB_0=\nn._emscripten_bind_btManifoldPoint_get_m_positionWorldOnB_0,Ej=c._emscripten_bind_tNodeArray___destroy___0=n._emscripten_bind_tNodeArray___destroy___0,Fj=c._emscripten_bind_btPairCachingGhostObject_setCcdSweptSphereRadius_1=n._emscripten_bind_btPairCachingGhostObject_setCcdSweptSphereRadius_1,Gj=c._emscripten_bind_btHingeConstraint_enableAngularMotor_3=n._emscripten_bind_btHingeConstraint_enableAngularMotor_3,Hj=c._emscripten_bind_btRigidBody_setContactProcessingThreshold_1=n._emscripten_bind_btRigidBody_setContactProcessingThreshold_1,\nIj=c._emscripten_bind_btRigidBody_getLinearVelocity_0=n._emscripten_bind_btRigidBody_getLinearVelocity_0,Jj=c._emscripten_bind_btRigidBody_applyImpulse_2=n._emscripten_bind_btRigidBody_applyImpulse_2,Kj=c._emscripten_bind_btConcaveShape_calculateLocalInertia_2=n._emscripten_bind_btConcaveShape_calculateLocalInertia_2,Lj=c._emscripten_bind_RaycastInfo_get_m_groundObject_0=n._emscripten_bind_RaycastInfo_get_m_groundObject_0,Mj=c._emscripten_bind_btRigidBody_setWorldTransform_1=n._emscripten_bind_btRigidBody_setWorldTransform_1,\nNj=c._emscripten_bind_LocalConvexResult_set_m_localShapeInfo_1=n._emscripten_bind_LocalConvexResult_set_m_localShapeInfo_1,Oj=c._emscripten_bind_btRigidBody_setAngularVelocity_1=n._emscripten_bind_btRigidBody_setAngularVelocity_1,Pj=c._emscripten_bind_btGeneric6DofSpringConstraint_btGeneric6DofSpringConstraint_3=n._emscripten_bind_btGeneric6DofSpringConstraint_btGeneric6DofSpringConstraint_3,Qj=c._emscripten_bind_Config_get_kDP_0=n._emscripten_bind_Config_get_kDP_0,Rj=c._emscripten_bind_btConvexShape_setLocalScaling_1=\nn._emscripten_bind_btConvexShape_setLocalScaling_1,Sj=c._emscripten_bind_Config_get_collisions_0=n._emscripten_bind_Config_get_collisions_0,Tj=c._emscripten_bind_Node_get_m_n_0=n._emscripten_bind_Node_get_m_n_0,Uj=c._emscripten_bind_btTriangleMeshShape_calculateLocalInertia_2=n._emscripten_bind_btTriangleMeshShape_calculateLocalInertia_2;c.stackSave=n.stackSave;\nvar vb=c.___udivdi3=n.___udivdi3,Vj=c._emscripten_bind_btRaycastVehicle_setUserConstraintId_1=n._emscripten_bind_btRaycastVehicle_setUserConstraintId_1,Ia=c._free=n._free,Wj=c._emscripten_bind_btPairCachingGhostObject_setContactProcessingThreshold_1=n._emscripten_bind_btPairCachingGhostObject_setContactProcessingThreshold_1,Xj=c._emscripten_bind_btGeneric6DofConstraint_setLinearUpperLimit_1=n._emscripten_bind_btGeneric6DofConstraint_setLinearUpperLimit_1,Yj=c._emscripten_bind_ClosestRayResultCallback_get_m_collisionFilterMask_0=\nn._emscripten_bind_ClosestRayResultCallback_get_m_collisionFilterMask_0,Zj=c._emscripten_bind_RayResultCallback_hasHit_0=n._emscripten_bind_RayResultCallback_hasHit_0,ak=c._emscripten_bind_btRigidBody_applyLocalTorque_1=n._emscripten_bind_btRigidBody_applyLocalTorque_1,hb=c._bitshift64Shl=n._bitshift64Shl,bk=c._emscripten_bind_Config___destroy___0=n._emscripten_bind_Config___destroy___0,ck=c._emscripten_bind_btVehicleTuning_set_m_maxSuspensionForce_1=n._emscripten_bind_btVehicleTuning_set_m_maxSuspensionForce_1,\ndk=c._emscripten_bind_btVehicleTuning_get_m_suspensionDamping_0=n._emscripten_bind_btVehicleTuning_get_m_suspensionDamping_0,ek=c._emscripten_bind_btRaycastVehicle_getWheelTransformWS_1=n._emscripten_bind_btRaycastVehicle_getWheelTransformWS_1,fk=c._emscripten_bind_btQuaternion_normalize_0=n._emscripten_bind_btQuaternion_normalize_0,gk=c._emscripten_bind_btQuaternion___destroy___0=n._emscripten_bind_btQuaternion___destroy___0,hk=c._emscripten_bind_btWheelInfo_get_m_frictionSlip_0=n._emscripten_bind_btWheelInfo_get_m_frictionSlip_0,\nik=c._emscripten_bind_btConeShapeZ_setLocalScaling_1=n._emscripten_bind_btConeShapeZ_setLocalScaling_1,jk=c._emscripten_bind_btSoftBodyWorldInfo_get_m_dispatcher_0=n._emscripten_bind_btSoftBodyWorldInfo_get_m_dispatcher_0,kk=c._emscripten_bind_btGeneric6DofSpringConstraint___destroy___0=n._emscripten_bind_btGeneric6DofSpringConstraint___destroy___0,lk=c._emscripten_bind_btRaycastVehicle_getNumWheels_0=n._emscripten_bind_btRaycastVehicle_getNumWheels_0,mk=c._emscripten_bind_btVehicleTuning_set_m_maxSuspensionTravelCm_1=\nn._emscripten_bind_btVehicleTuning_set_m_maxSuspensionTravelCm_1,nk=c._emscripten_bind_Material_set_m_kAST_1=n._emscripten_bind_Material_set_m_kAST_1,ok=c._emscripten_bind_btGhostObject_setRollingFriction_1=n._emscripten_bind_btGhostObject_setRollingFriction_1,pk=c._emscripten_bind_btCylinderShapeZ_btCylinderShapeZ_1=n._emscripten_bind_btCylinderShapeZ_btCylinderShapeZ_1,yb=c.___muldi3=n.___muldi3,qk=c._emscripten_bind_btSoftBodyArray___destroy___0=n._emscripten_bind_btSoftBodyArray___destroy___0,\nrk=c._emscripten_bind_btCompoundShape_btCompoundShape_0=n._emscripten_bind_btCompoundShape_btCompoundShape_0,sk=c._emscripten_bind_btCompoundShape_btCompoundShape_1=n._emscripten_bind_btCompoundShape_btCompoundShape_1,tk=c._emscripten_bind_btOverlappingPairCache_setInternalGhostPairCallback_1=n._emscripten_bind_btOverlappingPairCache_setInternalGhostPairCallback_1,uk=c._emscripten_bind_btStaticPlaneShape_btStaticPlaneShape_2=n._emscripten_bind_btStaticPlaneShape_btStaticPlaneShape_2,bb=c.__GLOBAL__sub_I_btQuickprof_cpp=\nn.__GLOBAL__sub_I_btQuickprof_cpp,vk=c._emscripten_bind_btDispatcherInfo_set_m_convexConservativeDistanceThreshold_1=n._emscripten_bind_btDispatcherInfo_set_m_convexConservativeDistanceThreshold_1,wk=c._emscripten_bind_btSoftBody_checkLink_2=n._emscripten_bind_btSoftBody_checkLink_2,xk=c._emscripten_bind_btSoftBody_getCollisionShape_0=n._emscripten_bind_btSoftBody_getCollisionShape_0,yk=c._emscripten_bind_Config_get_kDG_0=n._emscripten_bind_Config_get_kDG_0,zk=c._emscripten_bind_btRigidBodyConstructionInfo_set_m_linearDamping_1=\nn._emscripten_bind_btRigidBodyConstructionInfo_set_m_linearDamping_1,Ak=c._emscripten_bind_btDefaultVehicleRaycaster___destroy___0=n._emscripten_bind_btDefaultVehicleRaycaster___destroy___0,Bk=c._emscripten_bind_btPairCachingGhostObject_setAnisotropicFriction_2=n._emscripten_bind_btPairCachingGhostObject_setAnisotropicFriction_2,Ck=c._emscripten_bind_Node_get_m_x_0=n._emscripten_bind_Node_get_m_x_0,Dk=c._emscripten_bind_btCollisionObject_getWorldTransform_0=n._emscripten_bind_btCollisionObject_getWorldTransform_0,\nEk=c._emscripten_bind_ClosestRayResultCallback_hasHit_0=n._emscripten_bind_ClosestRayResultCallback_hasHit_0,Fk=c._emscripten_bind_btCompoundShape_addChildShape_2=n._emscripten_bind_btCompoundShape_addChildShape_2,Gk=c._emscripten_bind_btDispatcher___destroy___0=n._emscripten_bind_btDispatcher___destroy___0,Hk=c._emscripten_bind_btVehicleTuning_get_m_suspensionCompression_0=n._emscripten_bind_btVehicleTuning_get_m_suspensionCompression_0,nb=c._llvm_bswap_i16=n._llvm_bswap_i16,Ik=c._emscripten_bind_btDiscreteDynamicsWorld___destroy___0=\nn._emscripten_bind_btDiscreteDynamicsWorld___destroy___0,Jk=c._emscripten_bind_btConvexShape___destroy___0=n._emscripten_bind_btConvexShape___destroy___0,Kk=c._emscripten_bind_btRaycastVehicle_updateWheelTransformsWS_1=n._emscripten_bind_btRaycastVehicle_updateWheelTransformsWS_1,Lk=c._emscripten_bind_btWheelInfo_set_m_brake_1=n._emscripten_bind_btWheelInfo_set_m_brake_1,Ab=c._memmove=n._memmove,Mk=c._emscripten_bind_btWheelInfo_set_m_worldTransform_1=n._emscripten_bind_btWheelInfo_set_m_worldTransform_1,\nNk=c._emscripten_bind_btCapsuleShapeX_setLocalScaling_1=n._emscripten_bind_btCapsuleShapeX_setLocalScaling_1,Ok=c._emscripten_bind_btPairCachingGhostObject_getCollisionShape_0=n._emscripten_bind_btPairCachingGhostObject_getCollisionShape_0,Pk=c._emscripten_bind_btSoftBody_getCollisionFlags_0=n._emscripten_bind_btSoftBody_getCollisionFlags_0,Qk=c._emscripten_bind_btRaycastVehicle_getChassisWorldTransform_0=n._emscripten_bind_btRaycastVehicle_getChassisWorldTransform_0,Rk=c._emscripten_bind_btCollisionObject_setRestitution_1=\nn._emscripten_bind_btCollisionObject_setRestitution_1,Sk=c._emscripten_bind_btRigidBody_applyCentralForce_1=n._emscripten_bind_btRigidBody_applyCentralForce_1,Tk=c._emscripten_bind_btSoftBodyWorldInfo_set_m_gravity_1=n._emscripten_bind_btSoftBodyWorldInfo_set_m_gravity_1,Uk=c._emscripten_bind_LocalConvexResult_get_m_hitFraction_0=n._emscripten_bind_LocalConvexResult_get_m_hitFraction_0,Vk=c._emscripten_bind_btHingeConstraint_setBreakingImpulseThreshold_1=n._emscripten_bind_btHingeConstraint_setBreakingImpulseThreshold_1,\nWk=c._emscripten_bind_btQuaternion_w_0=n._emscripten_bind_btQuaternion_w_0,Xk=c._emscripten_bind_ConvexResultCallback_get_m_collisionFilterGroup_0=n._emscripten_bind_ConvexResultCallback_get_m_collisionFilterGroup_0,Yk=c._emscripten_bind_btTransform_getRotation_0=n._emscripten_bind_btTransform_getRotation_0,Zk=c._emscripten_bind_Config_set_kSKHR_CL_1=n._emscripten_bind_Config_set_kSKHR_CL_1,$k=c._emscripten_bind_btHingeConstraint_btHingeConstraint_6=n._emscripten_bind_btHingeConstraint_btHingeConstraint_6,\nal=c._emscripten_bind_btHingeConstraint_btHingeConstraint_7=n._emscripten_bind_btHingeConstraint_btHingeConstraint_7,bl=c._emscripten_bind_btCapsuleShapeZ_getMargin_0=n._emscripten_bind_btCapsuleShapeZ_getMargin_0,cl=c._emscripten_bind_btHingeConstraint_btHingeConstraint_5=n._emscripten_bind_btHingeConstraint_btHingeConstraint_5,dl=c._emscripten_bind_btSoftBodyWorldInfo_get_m_maxDisplacement_0=n._emscripten_bind_btSoftBodyWorldInfo_get_m_maxDisplacement_0,el=c._emscripten_bind_btHingeConstraint_btHingeConstraint_3=\nn._emscripten_bind_btHingeConstraint_btHingeConstraint_3,fl=c._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalAngularDampingThresholdSqr_1=n._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalAngularDampingThresholdSqr_1,gl=c._emscripten_bind_btSoftBody_setWorldTransform_1=n._emscripten_bind_btSoftBody_setWorldTransform_1,hl=c._emscripten_bind_btBoxShape_setMargin_1=n._emscripten_bind_btBoxShape_setMargin_1,il=c._emscripten_bind_btWheelInfoConstructionInfo_set_m_maxSuspensionTravelCm_1=\nn._emscripten_bind_btWheelInfoConstructionInfo_set_m_maxSuspensionTravelCm_1,jl=c._emscripten_bind_ClosestConvexResultCallback_get_m_hitNormalWorld_0=n._emscripten_bind_ClosestConvexResultCallback_get_m_hitNormalWorld_0,kl=c._emscripten_bind_btWheelInfoConstructionInfo_get_m_chassisConnectionCS_0=n._emscripten_bind_btWheelInfoConstructionInfo_get_m_chassisConnectionCS_0,ll=c._emscripten_bind_btTypedConstraint___destroy___0=n._emscripten_bind_btTypedConstraint___destroy___0,ml=c._emscripten_bind_btCylinderShapeX_btCylinderShapeX_1=\nn._emscripten_bind_btCylinderShapeX_btCylinderShapeX_1,nl=c._emscripten_bind_btGeneric6DofSpringConstraint_setAngularUpperLimit_1=n._emscripten_bind_btGeneric6DofSpringConstraint_setAngularUpperLimit_1,ol=c._emscripten_bind_btDiscreteDynamicsWorld_addRigidBody_3=n._emscripten_bind_btDiscreteDynamicsWorld_addRigidBody_3,pl=c._emscripten_bind_btDiscreteDynamicsWorld_addRigidBody_1=n._emscripten_bind_btDiscreteDynamicsWorld_addRigidBody_1,ql=c._emscripten_bind_Config_set_collisions_1=n._emscripten_bind_Config_set_collisions_1,\nrl=c._emscripten_bind_btQuaternion_btQuaternion_4=n._emscripten_bind_btQuaternion_btQuaternion_4,sl=c._emscripten_bind_btSoftRigidDynamicsWorld_getBroadphase_0=n._emscripten_bind_btSoftRigidDynamicsWorld_getBroadphase_0,tl=c._emscripten_bind_btWheelInfo_set_m_rotation_1=n._emscripten_bind_btWheelInfo_set_m_rotation_1,ul=c._emscripten_bind_btSphereShape_btSphereShape_1=n._emscripten_bind_btSphereShape_btSphereShape_1,vl=c._emscripten_bind_btWheelInfo_get_m_wheelsSuspensionForce_0=n._emscripten_bind_btWheelInfo_get_m_wheelsSuspensionForce_0,\nwl=c._emscripten_bind_btQuaternion_y_0=n._emscripten_bind_btQuaternion_y_0,xl=c._emscripten_bind_btCollisionWorld_addCollisionObject_1=n._emscripten_bind_btCollisionWorld_addCollisionObject_1,yl=c._emscripten_bind_btCollisionWorld_addCollisionObject_2=n._emscripten_bind_btCollisionWorld_addCollisionObject_2,zl=c._emscripten_bind_btCompoundShape_setLocalScaling_1=n._emscripten_bind_btCompoundShape_setLocalScaling_1,Al=c._emscripten_bind_ClosestConvexResultCallback_set_m_collisionFilterGroup_1=n._emscripten_bind_ClosestConvexResultCallback_set_m_collisionFilterGroup_1,\nBl=c._emscripten_bind_btConeTwistConstraint_setBreakingImpulseThreshold_1=n._emscripten_bind_btConeTwistConstraint_setBreakingImpulseThreshold_1,Cl=c._emscripten_bind_btWheelInfoConstructionInfo_set_m_chassisConnectionCS_1=n._emscripten_bind_btWheelInfoConstructionInfo_set_m_chassisConnectionCS_1,Dl=c._emscripten_bind_btSoftBodyHelpers_CreateEllipsoid_4=n._emscripten_bind_btSoftBodyHelpers_CreateEllipsoid_4,El=c._emscripten_bind_RaycastInfo_get_m_isInContact_0=n._emscripten_bind_RaycastInfo_get_m_isInContact_0,\nFl=c._emscripten_bind_btWheelInfo_get_m_skidInfo_0=n._emscripten_bind_btWheelInfo_get_m_skidInfo_0,Gl=c._emscripten_bind_btHeightfieldTerrainShape_setMargin_1=n._emscripten_bind_btHeightfieldTerrainShape_setMargin_1,Hl=c._emscripten_bind_ClosestConvexResultCallback_get_m_collisionFilterGroup_0=n._emscripten_bind_ClosestConvexResultCallback_get_m_collisionFilterGroup_0,Il=c._emscripten_bind_btCapsuleShape_setMargin_1=n._emscripten_bind_btCapsuleShape_setMargin_1,Jl=c._emscripten_bind_btDefaultVehicleRaycaster_btDefaultVehicleRaycaster_1=\nn._emscripten_bind_btDefaultVehicleRaycaster_btDefaultVehicleRaycaster_1,Kl=c._emscripten_bind_btDynamicsWorld_contactTest_2=n._emscripten_bind_btDynamicsWorld_contactTest_2,Ll=c._emscripten_bind_btCollisionObject_setUserPointer_1=n._emscripten_bind_btCollisionObject_setUserPointer_1,Ml=c._emscripten_bind_btSequentialImpulseConstraintSolver_btSequentialImpulseConstraintSolver_0=n._emscripten_bind_btSequentialImpulseConstraintSolver_btSequentialImpulseConstraintSolver_0,Nl=c._emscripten_bind_btActionInterface___destroy___0=\nn._emscripten_bind_btActionInterface___destroy___0,Ol=c._emscripten_bind_btSoftBody_generateClusters_2=n._emscripten_bind_btSoftBody_generateClusters_2,Pl=c._emscripten_bind_btDefaultMotionState_setWorldTransform_1=n._emscripten_bind_btDefaultMotionState_setWorldTransform_1,Ql=c._emscripten_bind_btSoftBody_generateClusters_1=n._emscripten_bind_btSoftBody_generateClusters_1,Rl=c._emscripten_bind_RayResultCallback_get_m_collisionObject_0=n._emscripten_bind_RayResultCallback_get_m_collisionObject_0,\nSl=c._emscripten_bind_btPoint2PointConstraint_getPivotInA_0=n._emscripten_bind_btPoint2PointConstraint_getPivotInA_0,Tl=c._emscripten_bind_Config_get_kAHR_0=n._emscripten_bind_Config_get_kAHR_0,Ul=c._emscripten_bind_btGeneric6DofSpringConstraint_setStiffness_2=n._emscripten_bind_btGeneric6DofSpringConstraint_setStiffness_2,Vl=c._emscripten_bind_btCylinderShape_calculateLocalInertia_2=n._emscripten_bind_btCylinderShape_calculateLocalInertia_2,Wl=c._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelRadius_1=\nn._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelRadius_1,Xl=c._emscripten_bind_ClosestConvexResultCallback___destroy___0=n._emscripten_bind_ClosestConvexResultCallback___destroy___0,Yl=c._emscripten_bind_btQuaternion_normalized_0=n._emscripten_bind_btQuaternion_normalized_0,Zl=c._emscripten_bind_btDynamicsWorld_addCollisionObject_1=n._emscripten_bind_btDynamicsWorld_addCollisionObject_1,$l=c._emscripten_bind_ClosestConvexResultCallback_get_m_collisionFilterMask_0=n._emscripten_bind_ClosestConvexResultCallback_get_m_collisionFilterMask_0;\nc.___cxa_can_catch=n.___cxa_can_catch;\nvar am=c._emscripten_bind_btDynamicsWorld_addCollisionObject_2=n._emscripten_bind_btDynamicsWorld_addCollisionObject_2,bm=c._emscripten_bind_btDiscreteDynamicsWorld_getDispatcher_0=n._emscripten_bind_btDiscreteDynamicsWorld_getDispatcher_0,cm=c._emscripten_bind_btCollisionObject_setFriction_1=n._emscripten_bind_btCollisionObject_setFriction_1,dm=c._emscripten_bind_btGeneric6DofSpringConstraint_enableFeedback_1=n._emscripten_bind_btGeneric6DofSpringConstraint_enableFeedback_1,em=c._emscripten_bind_btVector3_rotate_2=\nn._emscripten_bind_btVector3_rotate_2,fm=c._emscripten_bind_btHeightfieldTerrainShape___destroy___0=n._emscripten_bind_btHeightfieldTerrainShape___destroy___0,gm=c._emscripten_bind_btWheelInfo_get_m_maxSuspensionTravelCm_0=n._emscripten_bind_btWheelInfo_get_m_maxSuspensionTravelCm_0,hm=c._emscripten_bind_Config_get_kVC_0=n._emscripten_bind_Config_get_kVC_0,im=c._emscripten_bind_btVehicleRaycasterResult_set_m_hitPointInWorld_1=n._emscripten_bind_btVehicleRaycasterResult_set_m_hitPointInWorld_1,jm=\nc._emscripten_bind_btQuaternion_op_mulq_1=n._emscripten_bind_btQuaternion_op_mulq_1,km=c._emscripten_bind_btPairCachingGhostObject_setActivationState_1=n._emscripten_bind_btPairCachingGhostObject_setActivationState_1,lm=c._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelDirectionCS_1=n._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelDirectionCS_1,mm=c._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelAxleCS_1=n._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelAxleCS_1,\nnm=c._emscripten_bind_Material_get_m_kVST_0=n._emscripten_bind_Material_get_m_kVST_0,om=c._emscripten_bind_Config_set_kVCF_1=n._emscripten_bind_Config_set_kVCF_1,pm=c._emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_3=n._emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_3,qm=c._emscripten_bind_btGhostObject_getUserIndex_0=n._emscripten_bind_btGhostObject_getUserIndex_0,rm=c._emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_1=n._emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_1,\nsm=c._emscripten_bind_btWheelInfo_set_m_deltaRotation_1=n._emscripten_bind_btWheelInfo_set_m_deltaRotation_1,tm=c._emscripten_bind_btVector3___destroy___0=n._emscripten_bind_btVector3___destroy___0,um=c._emscripten_bind_RaycastInfo___destroy___0=n._emscripten_bind_RaycastInfo___destroy___0,wm=c._emscripten_bind_btRigidBody_setAngularFactor_1=n._emscripten_bind_btRigidBody_setAngularFactor_1,xm=c._emscripten_bind_btCylinderShapeZ_calculateLocalInertia_2=n._emscripten_bind_btCylinderShapeZ_calculateLocalInertia_2,\nym=c._emscripten_bind_btConeShapeZ_btConeShapeZ_2=n._emscripten_bind_btConeShapeZ_btConeShapeZ_2,zm=c._emscripten_bind_LocalShapeInfo_set_m_triangleIndex_1=n._emscripten_bind_LocalShapeInfo_set_m_triangleIndex_1,Am=c._emscripten_bind_btMotionState_getWorldTransform_1=n._emscripten_bind_btMotionState_getWorldTransform_1,Bm=c._emscripten_bind_btDynamicsWorld_getSolverInfo_0=n._emscripten_bind_btDynamicsWorld_getSolverInfo_0,Cm=c._emscripten_bind_btVehicleRaycasterResult_set_m_hitNormalInWorld_1=n._emscripten_bind_btVehicleRaycasterResult_set_m_hitNormalInWorld_1,\nDm=c._emscripten_bind_btSoftRigidDynamicsWorld_convexSweepTest_5=n._emscripten_bind_btSoftRigidDynamicsWorld_convexSweepTest_5,Em=c._emscripten_bind_Config_get_kMT_0=n._emscripten_bind_Config_get_kMT_0,Fm=c._emscripten_bind_btDynamicsWorld_getBroadphase_0=n._emscripten_bind_btDynamicsWorld_getBroadphase_0,Gm=c._emscripten_bind_btSphereShape_getMargin_0=n._emscripten_bind_btSphereShape_getMargin_0,Hm=c._emscripten_bind_Config_get_timescale_0=n._emscripten_bind_Config_get_timescale_0,Im=c._emscripten_bind_btVector3_x_0=\nn._emscripten_bind_btVector3_x_0;c.___cxa_is_pointer_type=n.___cxa_is_pointer_type;\nvar Jm=c._emscripten_bind_btConvexTriangleMeshShape___destroy___0=n._emscripten_bind_btConvexTriangleMeshShape___destroy___0,Km=c._emscripten_bind_btCollisionObject_getCollisionShape_0=n._emscripten_bind_btCollisionObject_getCollisionShape_0,Lm=c._emscripten_bind_btRigidBodyConstructionInfo_btRigidBodyConstructionInfo_4=n._emscripten_bind_btRigidBodyConstructionInfo_btRigidBodyConstructionInfo_4,Mm=c._emscripten_bind_btManifoldPoint___destroy___0=n._emscripten_bind_btManifoldPoint___destroy___0,Nm=\nc._emscripten_bind_btRigidBodyConstructionInfo_set_m_rollingFriction_1=n._emscripten_bind_btRigidBodyConstructionInfo_set_m_rollingFriction_1,Om=c._emscripten_bind_btVector4_length_0=n._emscripten_bind_btVector4_length_0,Pm=c._emscripten_bind_btGhostObject_setUserIndex_1=n._emscripten_bind_btGhostObject_setUserIndex_1,Qm=c._emscripten_bind_btWheelInfo_getSuspensionRestLength_0=n._emscripten_bind_btWheelInfo_getSuspensionRestLength_0,Rm=c._emscripten_bind_btDefaultMotionState_set_m_graphicsWorldTrans_1=\nn._emscripten_bind_btDefaultMotionState_set_m_graphicsWorldTrans_1,Sm=c._emscripten_bind_btGhostObject_setRestitution_1=n._emscripten_bind_btGhostObject_setRestitution_1,Tm=c._emscripten_bind_btConeTwistConstraint_setAngularOnly_1=n._emscripten_bind_btConeTwistConstraint_setAngularOnly_1,Um=c._emscripten_bind_btQuadWord_setZ_1=n._emscripten_bind_btQuadWord_setZ_1,Vm=c._emscripten_bind_btDefaultCollisionConfiguration___destroy___0=n._emscripten_bind_btDefaultCollisionConfiguration___destroy___0,Wm=\nc._emscripten_bind_btRigidBody_setMassProps_2=n._emscripten_bind_btRigidBody_setMassProps_2;c.getTempRet0=n.getTempRet0;\nvar Xm=c._emscripten_bind_btVector3_setValue_3=n._emscripten_bind_btVector3_setValue_3,Ym=c._emscripten_bind_btPairCachingGhostObject_setCcdMotionThreshold_1=n._emscripten_bind_btPairCachingGhostObject_setCcdMotionThreshold_1,Zm=c._emscripten_bind_RaycastInfo_get_m_suspensionLength_0=n._emscripten_bind_RaycastInfo_get_m_suspensionLength_0,$m=c._emscripten_bind_btGhostObject_getCollisionFlags_0=n._emscripten_bind_btGhostObject_getCollisionFlags_0,an=c._emscripten_bind_btCapsuleShapeX___destroy___0=\nn._emscripten_bind_btCapsuleShapeX___destroy___0,bn=c._emscripten_bind_btWheelInfo_get_m_wheelDirectionCS_0=n._emscripten_bind_btWheelInfo_get_m_wheelDirectionCS_0,cn=c._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelsDampingCompression_1=n._emscripten_bind_btWheelInfoConstructionInfo_set_m_wheelsDampingCompression_1,dn=c._emscripten_bind_Material_get_m_flags_0=n._emscripten_bind_Material_get_m_flags_0,en=c._emscripten_bind_btQuaternion_getAxis_0=n._emscripten_bind_btQuaternion_getAxis_0,\nfn=c._emscripten_bind_btRaycastVehicle_getUserConstraintId_0=n._emscripten_bind_btRaycastVehicle_getUserConstraintId_0,gn=c._emscripten_bind_btRaycastVehicle_updateAction_2=n._emscripten_bind_btRaycastVehicle_updateAction_2,hn=c._emscripten_bind_btHingeConstraint_setLimit_4=n._emscripten_bind_btHingeConstraint_setLimit_4,jn=c._emscripten_bind_btHingeConstraint_setLimit_5=n._emscripten_bind_btHingeConstraint_setLimit_5,kn=c._emscripten_bind_btSoftBodyWorldInfo_btSoftBodyWorldInfo_0=n._emscripten_bind_btSoftBodyWorldInfo_btSoftBodyWorldInfo_0,\nln=c._emscripten_bind_Config_set_kDG_1=n._emscripten_bind_Config_set_kDG_1,mn=c._emscripten_bind_btWheelInfo_set_m_maxSuspensionTravelCm_1=n._emscripten_bind_btWheelInfo_set_m_maxSuspensionTravelCm_1,nn=c._emscripten_bind_btWheelInfo_set_m_wheelsSuspensionForce_1=n._emscripten_bind_btWheelInfo_set_m_wheelsSuspensionForce_1,on=c._emscripten_bind_btSoftBody_scale_1=n._emscripten_bind_btSoftBody_scale_1,pn=c._emscripten_bind_Config_get_citerations_0=n._emscripten_bind_Config_get_citerations_0,qn=c._emscripten_bind_btTypedConstraint_getBreakingImpulseThreshold_0=\nn._emscripten_bind_btTypedConstraint_getBreakingImpulseThreshold_0,rn=c._emscripten_bind_btGhostObject_getCollisionShape_0=n._emscripten_bind_btGhostObject_getCollisionShape_0,sn=c._emscripten_bind_btCollisionObject_setAnisotropicFriction_2=n._emscripten_bind_btCollisionObject_setAnisotropicFriction_2,tn=c._emscripten_bind_btBoxShape___destroy___0=n._emscripten_bind_btBoxShape___destroy___0,un=c._emscripten_bind_btWheelInfo_get_m_bIsFrontWheel_0=n._emscripten_bind_btWheelInfo_get_m_bIsFrontWheel_0,\nvn=c._emscripten_bind_btPersistentManifold_getContactPoint_1=n._emscripten_bind_btPersistentManifold_getContactPoint_1,wn=c._emscripten_bind_btGeneric6DofSpringConstraint_getBreakingImpulseThreshold_0=n._emscripten_bind_btGeneric6DofSpringConstraint_getBreakingImpulseThreshold_0,xn=c._emscripten_bind_ConvexResultCallback_set_m_collisionFilterGroup_1=n._emscripten_bind_ConvexResultCallback_set_m_collisionFilterGroup_1,yn=c._emscripten_bind_RaycastInfo_set_m_groundObject_1=n._emscripten_bind_RaycastInfo_set_m_groundObject_1,\nzn=c._emscripten_bind_btGhostObject_activate_1=n._emscripten_bind_btGhostObject_activate_1,An=c._emscripten_bind_btRaycastVehicle_getForwardAxis_0=n._emscripten_bind_btRaycastVehicle_getForwardAxis_0,Bn=c._emscripten_bind_btManifoldPoint_getPositionWorldOnB_0=n._emscripten_bind_btManifoldPoint_getPositionWorldOnB_0,Cn=c._emscripten_bind_btManifoldPoint_get_m_positionWorldOnA_0=n._emscripten_bind_btManifoldPoint_get_m_positionWorldOnA_0,Dn=c._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalDamping_1=\nn._emscripten_bind_btRigidBodyConstructionInfo_set_m_additionalDamping_1,En=c._emscripten_bind_btDefaultSoftBodySolver_btDefaultSoftBodySolver_0=n._emscripten_bind_btDefaultSoftBodySolver_btDefaultSoftBodySolver_0,Fn=c._emscripten_bind_btSphereShape_setMargin_1=n._emscripten_bind_btSphereShape_setMargin_1,Gn=c._emscripten_bind_btSoftBody_get_m_cfg_0=n._emscripten_bind_btSoftBody_get_m_cfg_0,Hn=c._emscripten_bind_btCollisionObject_setUserIndex_1=n._emscripten_bind_btCollisionObject_setUserIndex_1,\nIn=c._emscripten_bind_btContactSolverInfo_set_m_splitImpulsePenetrationThreshold_1=n._emscripten_bind_btContactSolverInfo_set_m_splitImpulsePenetrationThreshold_1,Jn=c._emscripten_bind_btSliderConstraint_setUpperAngLimit_1=n._emscripten_bind_btSliderConstraint_setUpperAngLimit_1,Kn=c._emscripten_bind_btDynamicsWorld_contactPairTest_3=n._emscripten_bind_btDynamicsWorld_contactPairTest_3,Ln=c._emscripten_bind_btCollisionWorld_getPairCache_0=n._emscripten_bind_btCollisionWorld_getPairCache_0,Mn=c._emscripten_bind_btConeTwistConstraint_setMotorTarget_1=\nn._emscripten_bind_btConeTwistConstraint_setMotorTarget_1,Nn=c._emscripten_bind_ClosestConvexResultCallback_set_m_convexFromWorld_1=n._emscripten_bind_ClosestConvexResultCallback_set_m_convexFromWorld_1,On=c._emscripten_bind_btWheelInfo_set_m_rollInfluence_1=n._emscripten_bind_btWheelInfo_set_m_rollInfluence_1,Pn=c._emscripten_bind_btGhostObject_setCcdMotionThreshold_1=n._emscripten_bind_btGhostObject_setCcdMotionThreshold_1,Qn=c._emscripten_bind_btGeneric6DofConstraint_setBreakingImpulseThreshold_1=\nn._emscripten_bind_btGeneric6DofConstraint_setBreakingImpulseThreshold_1,Rn=c._emscripten_enum_PHY_ScalarType_PHY_INTEGER=n._emscripten_enum_PHY_ScalarType_PHY_INTEGER,Sn=c._emscripten_bind_btSoftBodyHelpers_CreatePatchUV_10=n._emscripten_bind_btSoftBodyHelpers_CreatePatchUV_10,Tn=c._emscripten_bind_btGhostObject_forceActivationState_1=n._emscripten_bind_btGhostObject_forceActivationState_1,Un=c._emscripten_bind_btGhostPairCallback_btGhostPairCallback_0=n._emscripten_bind_btGhostPairCallback_btGhostPairCallback_0,\nVn=c._emscripten_bind_btSoftBodyHelpers_CreateFromTriMesh_5=n._emscripten_bind_btSoftBodyHelpers_CreateFromTriMesh_5,Wn=c._emscripten_bind_btVector4_y_0=n._emscripten_bind_btVector4_y_0,Xn=c._emscripten_bind_VoidPtr___destroy___0=n._emscripten_bind_VoidPtr___destroy___0;c.establishStackSpace=n.establishStackSpace;\nvar Yn=c._emscripten_bind_RaycastInfo_set_m_contactNormalWS_1=n._emscripten_bind_RaycastInfo_set_m_contactNormalWS_1,Zn=c._emscripten_bind_btSliderConstraint_setLowerAngLimit_1=n._emscripten_bind_btSliderConstraint_setLowerAngLimit_1,$n=c._emscripten_bind_ClosestRayResultCallback_get_m_collisionObject_0=n._emscripten_bind_ClosestRayResultCallback_get_m_collisionObject_0,ao=c._emscripten_bind_RaycastInfo_set_m_contactPointWS_1=n._emscripten_bind_RaycastInfo_set_m_contactPointWS_1,bo=c._emscripten_bind_ClosestConvexResultCallback_ClosestConvexResultCallback_2=\nn._emscripten_bind_ClosestConvexResultCallback_ClosestConvexResultCallback_2,co=c._emscripten_bind_ClosestRayResultCallback_get_m_rayFromWorld_0=n._emscripten_bind_ClosestRayResultCallback_get_m_rayFromWorld_0,eo=c._emscripten_bind_btSoftBody_setContactProcessingThreshold_1=n._emscripten_bind_btSoftBody_setContactProcessingThreshold_1,fo=c._emscripten_bind_btPairCachingGhostObject_getNumOverlappingObjects_0=n._emscripten_bind_btPairCachingGhostObject_getNumOverlappingObjects_0,go=c._emscripten_bind_btSliderConstraint_enableFeedback_1=\nn._emscripten_bind_btSliderConstraint_enableFeedback_1,ho=c._emscripten_bind_RayResultCallback_get_m_collisionFilterGroup_0=n._emscripten_bind_RayResultCallback_get_m_collisionFilterGroup_0,io=c._emscripten_enum_PHY_ScalarType_PHY_DOUBLE=n._emscripten_enum_PHY_ScalarType_PHY_DOUBLE,jo=c._emscripten_bind_btConstraintSetting_get_m_tau_0=n._emscripten_bind_btConstraintSetting_get_m_tau_0,ko=c._emscripten_bind_btConeShape_setLocalScaling_1=n._emscripten_bind_btConeShape_setLocalScaling_1,lo=c._emscripten_bind_btCollisionObject_setCollisionShape_1=\nn._emscripten_bind_btCollisionObject_setCollisionShape_1,mo=c._emscripten_bind_btCollisionShape___destroy___0=n._emscripten_bind_btCollisionShape___destroy___0,no=c._emscripten_bind_btMatrix3x3_getRow_1=n._emscripten_bind_btMatrix3x3_getRow_1,oo=c._emscripten_bind_ConvexResultCallback_get_m_closestHitFraction_0=n._emscripten_bind_ConvexResultCallback_get_m_closestHitFraction_0,po=c._emscripten_bind_btSoftRigidDynamicsWorld_getPairCache_0=n._emscripten_bind_btSoftRigidDynamicsWorld_getPairCache_0,\nqo=c._emscripten_bind_btDispatcherInfo_get_m_dispatchFunc_0=n._emscripten_bind_btDispatcherInfo_get_m_dispatchFunc_0,ro=c._emscripten_bind_btRigidBodyConstructionInfo_get_m_rollingFriction_0=n._emscripten_bind_btRigidBodyConstructionInfo_get_m_rollingFriction_0,so=c._emscripten_bind_btSoftBody_getUserIndex_0=n._emscripten_bind_btSoftBody_getUserIndex_0,to=c._emscripten_bind_btPairCachingGhostObject_setCollisionShape_1=n._emscripten_bind_btPairCachingGhostObject_setCollisionShape_1,uo=c._emscripten_bind_btKinematicCharacterController_warp_1=\nn._emscripten_bind_btKinematicCharacterController_warp_1,vo=c._emscripten_bind_btContactSolverInfo___destroy___0=n._emscripten_bind_btContactSolverInfo___destroy___0,wo=c._emscripten_bind_btSoftBody_getWorldTransform_0=n._emscripten_bind_btSoftBody_getWorldTransform_0,xb=c.___muldsi3=n.___muldsi3,xo=c._emscripten_bind_btTriangleMesh___destroy___0=n._emscripten_bind_btTriangleMesh___destroy___0,yo=c._emscripten_bind_btKinematicCharacterController_preStep_1=n._emscripten_bind_btKinematicCharacterController_preStep_1,\nzo=c._emscripten_bind_btRaycastVehicle_applyEngineForce_2=n._emscripten_bind_btRaycastVehicle_applyEngineForce_2,Ao=c._emscripten_bind_btBoxShape_calculateLocalInertia_2=n._emscripten_bind_btBoxShape_calculateLocalInertia_2,Bo=c._emscripten_bind_btRaycastVehicle_setBrake_2=n._emscripten_bind_btRaycastVehicle_setBrake_2,Co=c._emscripten_bind_ConcreteContactResultCallback___destroy___0=n._emscripten_bind_ConcreteContactResultCallback___destroy___0,Do=c._emscripten_bind_RaycastInfo_set_m_wheelAxleWS_1=\nn._emscripten_bind_RaycastInfo_set_m_wheelAxleWS_1,Eo=c._emscripten_bind_btRaycastVehicle_updateVehicle_1=n._emscripten_bind_btRaycastVehicle_updateVehicle_1,Fo=c._emscripten_bind_btCollisionObject___destroy___0=n._emscripten_bind_btCollisionObject___destroy___0,Go=c._emscripten_bind_btVehicleTuning_set_m_suspensionDamping_1=n._emscripten_bind_btVehicleTuning_set_m_suspensionDamping_1,Ho=c._emscripten_bind_btConvexTriangleMeshShape_setMargin_1=n._emscripten_bind_btConvexTriangleMeshShape_setMargin_1,\nIo=c._emscripten_bind_btTriangleMeshShape_setLocalScaling_1=n._emscripten_bind_btTriangleMeshShape_setLocalScaling_1,Jo=c._emscripten_bind_Config_get_kSSHR_CL_0=n._emscripten_bind_Config_get_kSSHR_CL_0,Ko=c._emscripten_bind_btConeTwistConstraint_setMotorTargetInConstraintSpace_1=n._emscripten_bind_btConeTwistConstraint_setMotorTargetInConstraintSpace_1,Lo=c._emscripten_bind_btQuaternion_op_mul_1=n._emscripten_bind_btQuaternion_op_mul_1,Mo=c._emscripten_bind_btDispatcherInfo_set_m_timeStep_1=n._emscripten_bind_btDispatcherInfo_set_m_timeStep_1,\nNo=c._emscripten_bind_btVector3_btVector3_3=n._emscripten_bind_btVector3_btVector3_3,Oo=c._emscripten_bind_btVector3_btVector3_0=n._emscripten_bind_btVector3_btVector3_0,Po=c._emscripten_bind_btRigidBodyConstructionInfo_set_m_friction_1=n._emscripten_bind_btRigidBodyConstructionInfo_set_m_friction_1,Qo=c._emscripten_bind_btDiscreteDynamicsWorld_getGravity_0=n._emscripten_bind_btDiscreteDynamicsWorld_getGravity_0,Ro=c._emscripten_bind_btVector3_z_0=n._emscripten_bind_btVector3_z_0,So=c._emscripten_bind_ClosestConvexResultCallback_get_m_hitPointWorld_0=\nn._emscripten_bind_ClosestConvexResultCallback_get_m_hitPointWorld_0,To=c._emscripten_bind_btCollisionShape_getMargin_0=n._emscripten_bind_btCollisionShape_getMargin_0,Uo=c._emscripten_bind_btSoftBodyWorldInfo_set_water_offset_1=n._emscripten_bind_btSoftBodyWorldInfo_set_water_offset_1,Vo=c._emscripten_bind_btBroadphaseInterface___destroy___0=n._emscripten_bind_btBroadphaseInterface___destroy___0,Wo=c._emscripten_bind_btWheelInfo_updateWheel_2=n._emscripten_bind_btWheelInfo_updateWheel_2,Xo=c._emscripten_bind_ConcreteContactResultCallback_addSingleResult_7=\nn._emscripten_bind_ConcreteContactResultCallback_addSingleResult_7,Yo=c._emscripten_bind_RaycastInfo_get_m_hardPointWS_0=n._emscripten_bind_RaycastInfo_get_m_hardPointWS_0,Zo=c._emscripten_bind_btConeTwistConstraint___destroy___0=n._emscripten_bind_btConeTwistConstraint___destroy___0,$o=c._emscripten_bind_btQuadWord___destroy___0=n._emscripten_bind_btQuadWord___destroy___0,ap=c._emscripten_bind_btSoftRigidDynamicsWorld_contactPairTest_3=n._emscripten_bind_btSoftRigidDynamicsWorld_contactPairTest_3,\nbp=c._emscripten_bind_btQuaternion_setEulerZYX_3=n._emscripten_bind_btQuaternion_setEulerZYX_3,cp=c._emscripten_bind_ClosestRayResultCallback_set_m_rayFromWorld_1=n._emscripten_bind_ClosestRayResultCallback_set_m_rayFromWorld_1,dp=c._emscripten_bind_btGeneric6DofSpringConstraint_setDamping_2=n._emscripten_bind_btGeneric6DofSpringConstraint_setDamping_2,ep=c._emscripten_bind_RaycastInfo_get_m_wheelDirectionWS_0=n._emscripten_bind_RaycastInfo_get_m_wheelDirectionWS_0,fp=c._emscripten_bind_btRigidBody_setCenterOfMassTransform_1=\nn._emscripten_bind_btRigidBody_setCenterOfMassTransform_1,gp=c._emscripten_bind_btSoftBody_setUserIndex_1=n._emscripten_bind_btSoftBody_setUserIndex_1,hp=c._emscripten_bind_btWheelInfo_get_m_chassisConnectionPointCS_0=n._emscripten_bind_btWheelInfo_get_m_chassisConnectionPointCS_0,ip=c._emscripten_bind_btSoftBody_setCollisionShape_1=n._emscripten_bind_btSoftBody_setCollisionShape_1,jp=c._emscripten_bind_btGhostObject_setAnisotropicFriction_2=n._emscripten_bind_btGhostObject_setAnisotropicFriction_2,\nkp=c._emscripten_bind_btConstraintSolver___destroy___0=n._emscripten_bind_btConstraintSolver___destroy___0,lp=c._emscripten_bind_btSoftBody_isActive_0=n._emscripten_bind_btSoftBody_isActive_0,mp=c._emscripten_bind_btCapsuleShape_btCapsuleShape_2=n._emscripten_bind_btCapsuleShape_btCapsuleShape_2,np=c._emscripten_bind_btTypedConstraint_enableFeedback_1=n._emscripten_bind_btTypedConstraint_enableFeedback_1,op=c._emscripten_bind_btWheelInfoConstructionInfo_get_m_frictionSlip_0=n._emscripten_bind_btWheelInfoConstructionInfo_get_m_frictionSlip_0,\npp=c._emscripten_bind_btGhostObject_activate_0=n._emscripten_bind_btGhostObject_activate_0,qp=c._emscripten_bind_btConstraintSetting_btConstraintSetting_0=n._emscripten_bind_btConstraintSetting_btConstraintSetting_0,rp=c._emscripten_bind_btWheelInfo_set_m_clippedInvContactDotSuspension_1=n._emscripten_bind_btWheelInfo_set_m_clippedInvContactDotSuspension_1,sp=c._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalDampingFactor_0=n._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalDampingFactor_0,\ntp=c._emscripten_bind_btRigidBody_setAnisotropicFriction_2=n._emscripten_bind_btRigidBody_setAnisotropicFriction_2,up=c._emscripten_bind_btSoftBody_btSoftBody_4=n._emscripten_bind_btSoftBody_btSoftBody_4,vp=c._emscripten_bind_btSoftBody_activate_0=n._emscripten_bind_btSoftBody_activate_0,wp=c._emscripten_bind_btRigidBodyConstructionInfo_btRigidBodyConstructionInfo_3=n._emscripten_bind_btRigidBodyConstructionInfo_btRigidBodyConstructionInfo_3,xp=c._emscripten_bind_ConvexResultCallback_set_m_closestHitFraction_1=\nn._emscripten_bind_ConvexResultCallback_set_m_closestHitFraction_1,yp=c._emscripten_bind_btGeneric6DofSpringConstraint_enableSpring_2=n._emscripten_bind_btGeneric6DofSpringConstraint_enableSpring_2,zp=c._emscripten_bind_btPersistentManifold_btPersistentManifold_0=n._emscripten_bind_btPersistentManifold_btPersistentManifold_0,Ap=c._emscripten_bind_ConvexResultCallback_get_m_collisionFilterMask_0=n._emscripten_bind_ConvexResultCallback_get_m_collisionFilterMask_0,Bp=c._emscripten_bind_ClosestRayResultCallback_ClosestRayResultCallback_2=\nn._emscripten_bind_ClosestRayResultCallback_ClosestRayResultCallback_2,Cp=c._emscripten_bind_btVector4___destroy___0=n._emscripten_bind_btVector4___destroy___0,Dp=c._emscripten_bind_btPairCachingGhostObject_isKinematicObject_0=n._emscripten_bind_btPairCachingGhostObject_isKinematicObject_0,Ep=c._emscripten_bind_ClosestRayResultCallback_set_m_collisionFilterMask_1=n._emscripten_bind_ClosestRayResultCallback_set_m_collisionFilterMask_1,Fp=c._emscripten_bind_tNodeArray_at_1=n._emscripten_bind_tNodeArray_at_1,\neb=c._i64Add=n._i64Add,Gp=c._emscripten_bind_btStaticPlaneShape_calculateLocalInertia_2=n._emscripten_bind_btStaticPlaneShape_calculateLocalInertia_2,Hp=c._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalAngularDampingThresholdSqr_0=n._emscripten_bind_btRigidBodyConstructionInfo_get_m_additionalAngularDampingThresholdSqr_0,Ip=c._emscripten_bind_btCollisionObject_setCcdMotionThreshold_1=n._emscripten_bind_btCollisionObject_setCcdMotionThreshold_1,Jp=c._emscripten_bind_btKinematicCharacterController_btKinematicCharacterController_4=\nn._emscripten_bind_btKinematicCharacterController_btKinematicCharacterController_4,Kp=c._emscripten_bind_btSoftBody_set_m_cfg_1=n._emscripten_bind_btSoftBody_set_m_cfg_1,Lp=c._emscripten_bind_btWheelInfo_get_m_brake_0=n._emscripten_bind_btWheelInfo_get_m_brake_0,Mp=c._emscripten_bind_btRigidBodyConstructionInfo_get_m_angularSleepingThreshold_0=n._emscripten_bind_btRigidBodyConstructionInfo_get_m_angularSleepingThreshold_0,Np=c._emscripten_bind_btWheelInfo_get_m_deltaRotation_0=n._emscripten_bind_btWheelInfo_get_m_deltaRotation_0,\nOp=c._emscripten_bind_btPoint2PointConstraint_getPivotInB_0=n._emscripten_bind_btPoint2PointConstraint_getPivotInB_0,Pp=c._emscripten_bind_btKinematicCharacterController_playerStep_2=n._emscripten_bind_btKinematicCharacterController_playerStep_2,Qp=c._emscripten_bind_btDispatcherInfo___destroy___0=n._emscripten_bind_btDispatcherInfo___destroy___0,Rp=c._emscripten_bind_btCapsuleShape_getMargin_0=n._emscripten_bind_btCapsuleShape_getMargin_0,Sp=c._emscripten_bind_btCylinderShape_getMargin_0=n._emscripten_bind_btCylinderShape_getMargin_0,\nTp=c._emscripten_bind_btSoftBodyArray_size_0=n._emscripten_bind_btSoftBodyArray_size_0,Up=c._emscripten_bind_btStaticPlaneShape_setLocalScaling_1=n._emscripten_bind_btStaticPlaneShape_setLocalScaling_1,Vp=c._emscripten_bind_btConvexTriangleMeshShape_calculateLocalInertia_2=n._emscripten_bind_btConvexTriangleMeshShape_calculateLocalInertia_2,Wp=c._emscripten_bind_btWheelInfoConstructionInfo_set_m_bIsFrontWheel_1=n._emscripten_bind_btWheelInfoConstructionInfo_set_m_bIsFrontWheel_1,Xp=c._emscripten_bind_ClosestConvexResultCallback_get_m_convexToWorld_0=\nn._emscripten_bind_ClosestConvexResultCallback_get_m_convexToWorld_0,Yp=c._emscripten_bind_btGhostObject_getWorldTransform_0=n._emscripten_bind_btGhostObject_getWorldTransform_0,Zp=c._emscripten_bind_btDiscreteDynamicsWorld_getPairCache_0=n._emscripten_bind_btDiscreteDynamicsWorld_getPairCache_0,$p=c._emscripten_bind_LocalConvexResult_set_m_hitFraction_1=n._emscripten_bind_LocalConvexResult_set_m_hitFraction_1,aq=c._emscripten_bind_btCapsuleShapeZ_calculateLocalInertia_2=n._emscripten_bind_btCapsuleShapeZ_calculateLocalInertia_2,\nbq=c._emscripten_bind_btDispatcherInfo_get_m_timeStep_0=n._emscripten_bind_btDispatcherInfo_get_m_timeStep_0,cq=c._emscripten_bind_btHingeConstraint_setAngularOnly_1=n._emscripten_bind_btHingeConstraint_setAngularOnly_1,dq=c._emscripten_bind_btVehicleTuning_set_m_suspensionCompression_1=n._emscripten_bind_btVehicleTuning_set_m_suspensionCompression_1,eq=c._emscripten_bind_btConstraintSetting_set_m_impulseClamp_1=n._emscripten_bind_btConstraintSetting_set_m_impulseClamp_1,fq=c._emscripten_bind_btMotionState___destroy___0=\nn._emscripten_bind_btMotionState___destroy___0,gq=c._emscripten_bind_btCollisionObject_setCollisionFlags_1=n._emscripten_bind_btCollisionObject_setCollisionFlags_1,hq=c._emscripten_bind_Config_get_kPR_0=n._emscripten_bind_Config_get_kPR_0,iq=c._emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_1=n._emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_1,jq=c._emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_2=n._emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_2,\nkq=c._emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_3=n._emscripten_bind_btDiscreteDynamicsWorld_addCollisionObject_3,lq=c._emscripten_bind_btWheelInfo_set_m_suspensionStiffness_1=n._emscripten_bind_btWheelInfo_set_m_suspensionStiffness_1,mq=c._emscripten_bind_RaycastInfo_set_m_suspensionLength_1=n._emscripten_bind_RaycastInfo_set_m_suspensionLength_1,nq=c._emscripten_bind_btDispatcher_getManifoldByIndexInternal_1=n._emscripten_bind_btDispatcher_getManifoldByIndexInternal_1,oq=c._emscripten_bind_btSliderConstraint_setBreakingImpulseThreshold_1=\nn._emscripten_bind_btSliderConstraint_setBreakingImpulseThreshold_1,pq=c._emscripten_bind_btSoftBodyWorldInfo___destroy___0=n._emscripten_bind_btSoftBodyWorldInfo___destroy___0,qq=c._emscripten_bind_btConvexTriangleMeshShape_getMargin_0=n._emscripten_bind_btConvexTriangleMeshShape_getMargin_0,rq=c._emscripten_bind_btSoftBodySolver___destroy___0=n._emscripten_bind_btSoftBodySolver___destroy___0,gb=c._bitshift64Lshr=n._bitshift64Lshr,sq=c._emscripten_bind_btWheelInfo_set_m_steering_1=n._emscripten_bind_btWheelInfo_set_m_steering_1,\ntq=c._emscripten_bind_Node_set_m_x_1=n._emscripten_bind_Node_set_m_x_1,uq=c._emscripten_bind_btPairCachingGhostObject_setWorldTransform_1=n._emscripten_bind_btPairCachingGhostObject_setWorldTransform_1,vq=c._emscripten_bind_btHingeConstraint_getBreakingImpulseThreshold_0=n._emscripten_bind_btHingeConstraint_getBreakingImpulseThreshold_0,wq=c._emscripten_bind_btDefaultCollisionConstructionInfo___destroy___0=n._emscripten_bind_btDefaultCollisionConstructionInfo___destroy___0,xq=c._emscripten_bind_btConeShape___destroy___0=\nn._emscripten_bind_btConeShape___destroy___0,yq=c._emscripten_bind_btGhostObject_setCcdSweptSphereRadius_1=n._emscripten_bind_btGhostObject_setCcdSweptSphereRadius_1,zq=c._emscripten_bind_btPoint2PointConstraint_btPoint2PointConstraint_4=n._emscripten_bind_btPoint2PointConstraint_btPoint2PointConstraint_4,Aq=c._emscripten_bind_btRaycastVehicle_updateFriction_1=n._emscripten_bind_btRaycastVehicle_updateFriction_1,Bq=c._emscripten_bind_btPoint2PointConstraint_btPoint2PointConstraint_2=n._emscripten_bind_btPoint2PointConstraint_btPoint2PointConstraint_2,\nCq=c._emscripten_bind_btKinematicCharacterController_setJumpSpeed_1=n._emscripten_bind_btKinematicCharacterController_setJumpSpeed_1,Dq=c._emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration___destroy___0=n._emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration___destroy___0,Eq=c._emscripten_bind_btConeShapeX_calculateLocalInertia_2=n._emscripten_bind_btConeShapeX_calculateLocalInertia_2,Fq=c._emscripten_enum_PHY_ScalarType_PHY_FIXEDPOINT88=n._emscripten_enum_PHY_ScalarType_PHY_FIXEDPOINT88,\nGq=c._emscripten_bind_btPairCachingGhostObject_getOverlappingObject_1=n._emscripten_bind_btPairCachingGhostObject_getOverlappingObject_1,Hq=c._emscripten_bind_btGhostObject_getNumOverlappingObjects_0=n._emscripten_bind_btGhostObject_getNumOverlappingObjects_0,Iq=c._emscripten_bind_btRigidBodyConstructionInfo___destroy___0=n._emscripten_bind_btRigidBodyConstructionInfo___destroy___0,Jq=c._emscripten_bind_btGhostPairCallback___destroy___0=n._emscripten_bind_btGhostPairCallback___destroy___0,Kq=c._emscripten_bind_btRigidBody_getWorldTransform_0=\nn._emscripten_bind_btRigidBody_getWorldTransform_0,zb=c._sbrk=n._sbrk,Lq=c._emscripten_bind_btPoint2PointConstraint_setPivotA_1=n._emscripten_bind_btPoint2PointConstraint_setPivotA_1,Mq=c._emscripten_bind_ClosestConvexResultCallback_set_m_convexToWorld_1=n._emscripten_bind_ClosestConvexResultCallback_set_m_convexToWorld_1,ob=c._memcpy=n._memcpy,Nq=c._emscripten_bind_Config_get_maxvolume_0=n._emscripten_bind_Config_get_maxvolume_0,Oq=c._emscripten_bind_btCapsuleShape_calculateLocalInertia_2=n._emscripten_bind_btCapsuleShape_calculateLocalInertia_2,\nPq=c._emscripten_bind_btSoftRigidDynamicsWorld_getGravity_0=n._emscripten_bind_btSoftRigidDynamicsWorld_getGravity_0,Qq=c._emscripten_bind_btVector3_y_0=n._emscripten_bind_btVector3_y_0,Rq=c._emscripten_bind_btDispatcherInfo_set_m_useEpa_1=n._emscripten_bind_btDispatcherInfo_set_m_useEpa_1,Sq=c._emscripten_bind_btVehicleTuning_get_m_maxSuspensionForce_0=n._emscripten_bind_btVehicleTuning_get_m_maxSuspensionForce_0,Tq=c._emscripten_bind_btBvhTriangleMeshShape_btBvhTriangleMeshShape_2=n._emscripten_bind_btBvhTriangleMeshShape_btBvhTriangleMeshShape_2,\nUq=c._emscripten_bind_btBvhTriangleMeshShape_btBvhTriangleMeshShape_3=n._emscripten_bind_btBvhTriangleMeshShape_btBvhTriangleMeshShape_3,Vq=c._emscripten_bind_LocalShapeInfo_get_m_triangleIndex_0=n._emscripten_bind_LocalShapeInfo_get_m_triangleIndex_0,Wq=c._emscripten_bind_Config_set_kDF_1=n._emscripten_bind_Config_set_kDF_1,Xq=c._emscripten_bind_btHeightfieldTerrainShape_btHeightfieldTerrainShape_9=n._emscripten_bind_btHeightfieldTerrainShape_btHeightfieldTerrainShape_9,Yq=c._emscripten_bind_btSoftBody_activate_1=\nn._emscripten_bind_btSoftBody_activate_1,Zq=c._emscripten_bind_btWheelInfoConstructionInfo_set_m_frictionSlip_1=n._emscripten_bind_btWheelInfoConstructionInfo_set_m_frictionSlip_1,$q=c._emscripten_bind_btGhostObject_setCollisionShape_1=n._emscripten_bind_btGhostObject_setCollisionShape_1,ar=c._emscripten_bind_btDispatcherInfo_set_m_allowedCcdPenetration_1=n._emscripten_bind_btDispatcherInfo_set_m_allowedCcdPenetration_1,br=c._emscripten_bind_btRigidBody_setRollingFriction_1=n._emscripten_bind_btRigidBody_setRollingFriction_1,\ncr=c._emscripten_bind_btPairCachingGhostObject_setRollingFriction_1=n._emscripten_bind_btPairCachingGhostObject_setRollingFriction_1,dr=c._emscripten_bind_btDiscreteDynamicsWorld_setGravity_1=n._emscripten_bind_btDiscreteDynamicsWorld_setGravity_1;c._emscripten_get_global_libc=n._emscripten_get_global_libc;\nvar er=c._emscripten_bind_btVehicleTuning_set_m_suspensionStiffness_1=n._emscripten_bind_btVehicleTuning_set_m_suspensionStiffness_1,fr=c._emscripten_bind_btVector4_z_0=n._emscripten_bind_btVector4_z_0,gr=c._emscripten_bind_btCollisionObject_forceActivationState_1=n._emscripten_bind_btCollisionObject_forceActivationState_1,hr=c._emscripten_bind_btKinematicCharacterController_onGround_0=n._emscripten_bind_btKinematicCharacterController_onGround_0,ir=c._emscripten_bind_btRaycastVehicle_getWheelInfo_1=\nn._emscripten_bind_btRaycastVehicle_getWheelInfo_1,jr=c._emscripten_bind_btGeneric6DofConstraint_getBreakingImpulseThreshold_0=n._emscripten_bind_btGeneric6DofConstraint_getBreakingImpulseThreshold_0,kr=c._emscripten_bind_btVector3_length_0=n._emscripten_bind_btVector3_length_0,lr=c._emscripten_bind_ClosestConvexResultCallback_set_m_collisionFilterMask_1=n._emscripten_bind_ClosestConvexResultCallback_set_m_collisionFilterMask_1,mr=c._emscripten_bind_btSoftBodyWorldInfo_get_water_normal_0=n._emscripten_bind_btSoftBodyWorldInfo_get_water_normal_0,\nnr=c._emscripten_bind_btVector3_normalize_0=n._emscripten_bind_btVector3_normalize_0,or=c._emscripten_bind_btConeTwistConstraint_setLimit_2=n._emscripten_bind_btConeTwistConstraint_setLimit_2,pr=c._emscripten_bind_btSoftBody_setFriction_1=n._emscripten_bind_btSoftBody_setFriction_1;c.runPostSets=n.runPostSets;\nvar qr=c._emscripten_bind_btRigidBody_setSleepingThresholds_2=n._emscripten_bind_btRigidBody_setSleepingThresholds_2,rr=c._emscripten_bind_btSoftBody_upcast_1=n._emscripten_bind_btSoftBody_upcast_1,sr=c._emscripten_bind_btCollisionObject_setWorldTransform_1=n._emscripten_bind_btCollisionObject_setWorldTransform_1,tr=c._emscripten_bind_LocalConvexResult_get_m_localShapeInfo_0=n._emscripten_bind_LocalConvexResult_get_m_localShapeInfo_0,ur=c._emscripten_bind_btSoftBodyWorldInfo_set_m_dispatcher_1=n._emscripten_bind_btSoftBodyWorldInfo_set_m_dispatcher_1,\nvr=c._emscripten_bind_btConvexHullShape_setLocalScaling_1=n._emscripten_bind_btConvexHullShape_setLocalScaling_1,wr=c._emscripten_bind_btStridingMeshInterface___destroy___0=n._emscripten_bind_btStridingMeshInterface___destroy___0,xr=c._emscripten_bind_btSoftBody_setActivationState_1=n._emscripten_bind_btSoftBody_setActivationState_1,yr=c._emscripten_bind_btRigidBody_getUserIndex_0=n._emscripten_bind_btRigidBody_getUserIndex_0,zr=c._emscripten_bind_btRigidBodyConstructionInfo_get_m_linearDamping_0=\nn._emscripten_bind_btRigidBodyConstructionInfo_get_m_linearDamping_0,Ar=c._emscripten_bind_btSoftBodyHelpers_CreatePatch_9=n._emscripten_bind_btSoftBodyHelpers_CreatePatch_9,Br=c._emscripten_bind_btDispatcher_getNumManifolds_0=n._emscripten_bind_btDispatcher_getNumManifolds_0,Cr=c._emscripten_bind_btConvexShape_setMargin_1=n._emscripten_bind_btConvexShape_setMargin_1,Dr=c._emscripten_bind_btSoftBody_get_m_nodes_0=n._emscripten_bind_btSoftBody_get_m_nodes_0,Er=c._emscripten_bind_btSoftBody___destroy___0=\nn._emscripten_bind_btSoftBody___destroy___0,Fr=c._emscripten_bind_btRigidBodyConstructionInfo_get_m_linearSleepingThreshold_0=n._emscripten_bind_btRigidBodyConstructionInfo_get_m_linearSleepingThreshold_0,Gr=c._emscripten_bind_btRigidBody_activate_1=n._emscripten_bind_btRigidBody_activate_1,Hr=c._emscripten_bind_btRaycastVehicle_updateWheelTransform_2=n._emscripten_bind_btRaycastVehicle_updateWheelTransform_2,Ir=c._emscripten_bind_btWheelInfoConstructionInfo_set_m_maxSuspensionForce_1=n._emscripten_bind_btWheelInfoConstructionInfo_set_m_maxSuspensionForce_1,\nJr=c._emscripten_bind_btSoftBodyWorldInfo_get_m_gravity_0=n._emscripten_bind_btSoftBodyWorldInfo_get_m_gravity_0,Kr=c._emscripten_bind_Material_set_m_kVST_1=n._emscripten_bind_Material_set_m_kVST_1,Lr=c._emscripten_bind_btGhostObject_setActivationState_1=n._emscripten_bind_btGhostObject_setActivationState_1,Mr=c._emscripten_bind_Material_set_m_kLST_1=n._emscripten_bind_Material_set_m_kLST_1,Nr=c._emscripten_bind_btCollisionWorld_contactPairTest_3=n._emscripten_bind_btCollisionWorld_contactPairTest_3,\nOr=c._emscripten_bind_btDispatcherInfo_get_m_useContinuous_0=n._emscripten_bind_btDispatcherInfo_get_m_useContinuous_0,Pr=c._emscripten_bind_btHingeConstraint_setMaxMotorImpulse_1=n._emscripten_bind_btHingeConstraint_setMaxMotorImpulse_1,Qr=c._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelsDampingRelaxation_0=n._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelsDampingRelaxation_0,Rr=c._emscripten_bind_Config_get_kSS_SPLT_CL_0=n._emscripten_bind_Config_get_kSS_SPLT_CL_0,Sr=c._emscripten_bind_btCylinderShapeX___destroy___0=\nn._emscripten_bind_btCylinderShapeX___destroy___0,Tr=c._emscripten_bind_btRigidBodyConstructionInfo_set_m_linearSleepingThreshold_1=n._emscripten_bind_btRigidBodyConstructionInfo_set_m_linearSleepingThreshold_1,Ur=c._emscripten_bind_btRigidBody_updateInertiaTensor_0=n._emscripten_bind_btRigidBody_updateInertiaTensor_0,Vr=c._emscripten_bind_ContactResultCallback___destroy___0=n._emscripten_bind_ContactResultCallback___destroy___0,Wr=c._emscripten_bind_btDispatcherInfo_get_m_useConvexConservativeDistanceUtil_0=\nn._emscripten_bind_btDispatcherInfo_get_m_useConvexConservativeDistanceUtil_0,Xr=c._emscripten_bind_btSoftBody_setAnisotropicFriction_2=n._emscripten_bind_btSoftBody_setAnisotropicFriction_2,Yr=c._emscripten_bind_btPairCachingGhostObject_setCollisionFlags_1=n._emscripten_bind_btPairCachingGhostObject_setCollisionFlags_1,Zr=c._emscripten_bind_btRigidBody_getMotionState_0=n._emscripten_bind_btRigidBody_getMotionState_0,$r=c._emscripten_bind_btKinematicCharacterController_getGhostObject_0=n._emscripten_bind_btKinematicCharacterController_getGhostObject_0,\nas=c._emscripten_bind_btRigidBody_btRigidBody_1=n._emscripten_bind_btRigidBody_btRigidBody_1,bs=c._emscripten_bind_btTriangleMeshShape___destroy___0=n._emscripten_bind_btTriangleMeshShape___destroy___0,tb=c._llvm_cttz_i32=n._llvm_cttz_i32,cs=c._emscripten_bind_btDynamicsWorld_removeAction_1=n._emscripten_bind_btDynamicsWorld_removeAction_1,ds=c._emscripten_bind_btRigidBody_applyTorque_1=n._emscripten_bind_btRigidBody_applyTorque_1,es=c._emscripten_bind_btManifoldPoint_get_m_localPointA_0=n._emscripten_bind_btManifoldPoint_get_m_localPointA_0,\ngs=c._emscripten_bind_btDefaultCollisionConstructionInfo_btDefaultCollisionConstructionInfo_0=n._emscripten_bind_btDefaultCollisionConstructionInfo_btDefaultCollisionConstructionInfo_0,hs=c._emscripten_bind_btVehicleTuning_get_m_suspensionStiffness_0=n._emscripten_bind_btVehicleTuning_get_m_suspensionStiffness_0,is=c._emscripten_bind_btManifoldPoint_set_m_normalWorldOnB_1=n._emscripten_bind_btManifoldPoint_set_m_normalWorldOnB_1,js=c._emscripten_bind_btGhostObject_setUserPointer_1=n._emscripten_bind_btGhostObject_setUserPointer_1,\nks=c._emscripten_bind_btConvexHullShape_addPoint_2=n._emscripten_bind_btConvexHullShape_addPoint_2,ls=c._emscripten_bind_btKinematicCharacterController_getGravity_0=n._emscripten_bind_btKinematicCharacterController_getGravity_0,ub=c.___udivmoddi4=n.___udivmoddi4,ms=c._emscripten_enum_PHY_ScalarType_PHY_SHORT=n._emscripten_enum_PHY_ScalarType_PHY_SHORT,ns=c._emscripten_bind_btConeTwistConstraint_getBreakingImpulseThreshold_0=n._emscripten_bind_btConeTwistConstraint_getBreakingImpulseThreshold_0,ps=\nc._emscripten_bind_btGeneric6DofConstraint_setAngularLowerLimit_1=n._emscripten_bind_btGeneric6DofConstraint_setAngularLowerLimit_1,qs=c._emscripten_bind_btVehicleRaycasterResult_get_m_distFraction_0=n._emscripten_bind_btVehicleRaycasterResult_get_m_distFraction_0,rs=c._emscripten_bind_btQuaternion_op_sub_1=n._emscripten_bind_btQuaternion_op_sub_1,ss=c._emscripten_bind_btVector4_normalize_0=n._emscripten_bind_btVector4_normalize_0,ts=c._emscripten_bind_btQuaternion_setY_1=n._emscripten_bind_btQuaternion_setY_1,\nus=c._emscripten_bind_btConeShape_calculateLocalInertia_2=n._emscripten_bind_btConeShape_calculateLocalInertia_2,vs=c._emscripten_bind_btCylinderShapeX_calculateLocalInertia_2=n._emscripten_bind_btCylinderShapeX_calculateLocalInertia_2,xs=c._emscripten_bind_ConvexResultCallback_set_m_collisionFilterMask_1=n._emscripten_bind_ConvexResultCallback_set_m_collisionFilterMask_1,Eb=c._llvm_bswap_i32=n._llvm_bswap_i32,ys=c._emscripten_bind_btRaycastVehicle_getForwardVector_0=n._emscripten_bind_btRaycastVehicle_getForwardVector_0,\nzs=c._emscripten_bind_btKinematicCharacterController_setVelocityForTimeInterval_2=n._emscripten_bind_btKinematicCharacterController_setVelocityForTimeInterval_2,As=c._emscripten_bind_btWheelInfo_set_m_suspensionRelativeVelocity_1=n._emscripten_bind_btWheelInfo_set_m_suspensionRelativeVelocity_1,Bs=c._emscripten_bind_btSphereShape_setLocalScaling_1=n._emscripten_bind_btSphereShape_setLocalScaling_1,Cs=c._emscripten_bind_btRigidBody_applyCentralLocalForce_1=n._emscripten_bind_btRigidBody_applyCentralLocalForce_1,\nDs=c._emscripten_bind_btDiscreteDynamicsWorld_removeAction_1=n._emscripten_bind_btDiscreteDynamicsWorld_removeAction_1,Es=c._emscripten_bind_btVector4_w_0=n._emscripten_bind_btVector4_w_0,Fs=c._emscripten_bind_btWheelInfo_get_m_worldTransform_0=n._emscripten_bind_btWheelInfo_get_m_worldTransform_0,Gs=c._emscripten_bind_btManifoldPoint_get_m_normalWorldOnB_0=n._emscripten_bind_btManifoldPoint_get_m_normalWorldOnB_0,Hs=c._emscripten_bind_btBvhTriangleMeshShape___destroy___0=n._emscripten_bind_btBvhTriangleMeshShape___destroy___0,\nIs=c._emscripten_bind_Config_set_citerations_1=n._emscripten_bind_Config_set_citerations_1,Js=c._emscripten_bind_btSoftBody_checkFace_3=n._emscripten_bind_btSoftBody_checkFace_3,Ks=c._emscripten_bind_Config_get_kSKHR_CL_0=n._emscripten_bind_Config_get_kSKHR_CL_0,Ls=c._emscripten_bind_btDispatcherInfo_get_m_enableSatConvex_0=n._emscripten_bind_btDispatcherInfo_get_m_enableSatConvex_0,Ms=c._emscripten_bind_btDefaultVehicleRaycaster_castRay_3=n._emscripten_bind_btDefaultVehicleRaycaster_castRay_3,Ns=\nc._emscripten_bind_LocalConvexResult_LocalConvexResult_5=n._emscripten_bind_LocalConvexResult_LocalConvexResult_5,Os=c._emscripten_bind_btContactSolverInfo_get_m_numIterations_0=n._emscripten_bind_btContactSolverInfo_get_m_numIterations_0,Ps=c._emscripten_bind_btWheelInfoConstructionInfo_get_m_maxSuspensionTravelCm_0=n._emscripten_bind_btWheelInfoConstructionInfo_get_m_maxSuspensionTravelCm_0,Qs=c._emscripten_bind_ClosestConvexResultCallback_set_m_closestHitFraction_1=n._emscripten_bind_ClosestConvexResultCallback_set_m_closestHitFraction_1,\nRs=c._emscripten_bind_btDiscreteDynamicsWorld_removeConstraint_1=n._emscripten_bind_btDiscreteDynamicsWorld_removeConstraint_1,Ss=c._emscripten_bind_ConcreteContactResultCallback_ConcreteContactResultCallback_0=n._emscripten_bind_ConcreteContactResultCallback_ConcreteContactResultCallback_0,Ts=c._emscripten_bind_Config_set_diterations_1=n._emscripten_bind_Config_set_diterations_1,Us=c._emscripten_bind_btRaycastVehicle_getUserConstraintType_0=n._emscripten_bind_btRaycastVehicle_getUserConstraintType_0,\nVs=c._emscripten_bind_btGeneric6DofConstraint___destroy___0=n._emscripten_bind_btGeneric6DofConstraint___destroy___0,Ws=c._emscripten_bind_btSoftRigidDynamicsWorld_addRigidBody_1=n._emscripten_bind_btSoftRigidDynamicsWorld_addRigidBody_1,Xs=c._emscripten_bind_btSoftRigidDynamicsWorld_addRigidBody_3=n._emscripten_bind_btSoftRigidDynamicsWorld_addRigidBody_3,Ys=c._emscripten_bind_Config_set_kDP_1=n._emscripten_bind_Config_set_kDP_1,Zs=c._emscripten_bind_btVehicleTuning_get_m_maxSuspensionTravelCm_0=\nn._emscripten_bind_btVehicleTuning_get_m_maxSuspensionTravelCm_0,$s=c._emscripten_bind_btConvexHullShape_addPoint_1=n._emscripten_bind_btConvexHullShape_addPoint_1,at=c._emscripten_bind_btQuaternion_length2_0=n._emscripten_bind_btQuaternion_length2_0,bt=c._emscripten_bind_btRaycastVehicle_resetSuspension_0=n._emscripten_bind_btRaycastVehicle_resetSuspension_0,ct=c._emscripten_bind_btPoint2PointConstraint_getBreakingImpulseThreshold_0=n._emscripten_bind_btPoint2PointConstraint_getBreakingImpulseThreshold_0,\ndt=c._emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration_btSoftBodyRigidBodyCollisionConfiguration_1=n._emscripten_bind_btSoftBodyRigidBodyCollisionConfiguration_btSoftBodyRigidBodyCollisionConfiguration_1,et=c._emscripten_bind_btTransform_getOrigin_0=n._emscripten_bind_btTransform_getOrigin_0,ft=c._emscripten_bind_Config_get_kKHR_0=n._emscripten_bind_Config_get_kKHR_0,gt=c._emscripten_bind_Material_get_m_kLST_0=n._emscripten_bind_Material_get_m_kLST_0,ht=c._emscripten_bind_btHingeConstraint___destroy___0=\nn._emscripten_bind_btHingeConstraint___destroy___0,it=c._emscripten_bind_btPairCachingGhostObject_getUserPointer_0=n._emscripten_bind_btPairCachingGhostObject_getUserPointer_0,jt=c._emscripten_bind_btSoftBody_set_m_nodes_1=n._emscripten_bind_btSoftBody_set_m_nodes_1,kt=c._emscripten_bind_btSoftBodyWorldInfo_set_air_density_1=n._emscripten_bind_btSoftBodyWorldInfo_set_air_density_1,lt=c._emscripten_bind_btDbvtBroadphase___destroy___0=n._emscripten_bind_btDbvtBroadphase___destroy___0,mt=c._emscripten_bind_Config_set_viterations_1=\nn._emscripten_bind_Config_set_viterations_1,nt=c._emscripten_bind_btConvexShape_calculateLocalInertia_2=n._emscripten_bind_btConvexShape_calculateLocalInertia_2,fb=c._memset=n._memset,ot=c._emscripten_bind_btGeneric6DofConstraint_setLinearLowerLimit_1=n._emscripten_bind_btGeneric6DofConstraint_setLinearLowerLimit_1,pt=c._emscripten_bind_ClosestRayResultCallback_get_m_hitNormalWorld_0=n._emscripten_bind_ClosestRayResultCallback_get_m_hitNormalWorld_0,qt=c._emscripten_bind_btTriangleMesh_btTriangleMesh_0=\nn._emscripten_bind_btTriangleMesh_btTriangleMesh_0,rt=c._emscripten_bind_btTriangleMesh_btTriangleMesh_1=n._emscripten_bind_btTriangleMesh_btTriangleMesh_1,st=c._emscripten_bind_btTriangleMesh_btTriangleMesh_2=n._emscripten_bind_btTriangleMesh_btTriangleMesh_2,tt=c._emscripten_bind_btWheelInfo_set_m_frictionSlip_1=n._emscripten_bind_btWheelInfo_set_m_frictionSlip_1,ut=c._emscripten_bind_btSoftBodyHelpers___destroy___0=n._emscripten_bind_btSoftBodyHelpers___destroy___0,vt=c._emscripten_bind_btRigidBody_getCollisionShape_0=\nn._emscripten_bind_btRigidBody_getCollisionShape_0,wt=c._emscripten_bind_btManifoldPoint_set_m_positionWorldOnA_1=n._emscripten_bind_btManifoldPoint_set_m_positionWorldOnA_1,xt=c._emscripten_bind_btWheelInfo_get_m_wheelsDampingRelaxation_0=n._emscripten_bind_btWheelInfo_get_m_wheelsDampingRelaxation_0,yt=c._emscripten_bind_btManifoldPoint_get_m_localPointB_0=n._emscripten_bind_btManifoldPoint_get_m_localPointB_0,zt=c._emscripten_bind_btQuaternion_inverse_0=n._emscripten_bind_btQuaternion_inverse_0,\nAt=c._emscripten_bind_btDiscreteDynamicsWorld_contactPairTest_3=n._emscripten_bind_btDiscreteDynamicsWorld_contactPairTest_3,Bt=c._emscripten_bind_btSliderConstraint_setLowerLinLimit_1=n._emscripten_bind_btSliderConstraint_setLowerLinLimit_1,Ct=c._emscripten_bind_btRigidBody_getAngularVelocity_0=n._emscripten_bind_btRigidBody_getAngularVelocity_0,Dt=c._emscripten_bind_btCollisionObject_setCcdSweptSphereRadius_1=n._emscripten_bind_btCollisionObject_setCcdSweptSphereRadius_1,Et=c._emscripten_bind_btWheelInfo_get_m_wheelsRadius_0=\nn._emscripten_bind_btWheelInfo_get_m_wheelsRadius_0,Ft=c._emscripten_bind_btRigidBody_setLinearVelocity_1=n._emscripten_bind_btRigidBody_setLinearVelocity_1,Gt=c._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelDirectionCS_0=n._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelDirectionCS_0,Ht=c._emscripten_bind_btVehicleTuning_btVehicleTuning_0=n._emscripten_bind_btVehicleTuning_btVehicleTuning_0,It=c._emscripten_bind_RayResultCallback_set_m_collisionObject_1=n._emscripten_bind_RayResultCallback_set_m_collisionObject_1,\nJt=c._emscripten_bind_btDefaultSoftBodySolver___destroy___0=n._emscripten_bind_btDefaultSoftBodySolver___destroy___0,Kt=c._emscripten_bind_ClosestRayResultCallback_set_m_rayToWorld_1=n._emscripten_bind_ClosestRayResultCallback_set_m_rayToWorld_1,Lt=c._emscripten_bind_ClosestRayResultCallback_get_m_collisionFilterGroup_0=n._emscripten_bind_ClosestRayResultCallback_get_m_collisionFilterGroup_0,Mt=c._emscripten_bind_btWheelInfo_set_m_wheelsDampingRelaxation_1=n._emscripten_bind_btWheelInfo_set_m_wheelsDampingRelaxation_1,\nNt=c._emscripten_bind_btWheelInfo_get_m_clippedInvContactDotSuspension_0=n._emscripten_bind_btWheelInfo_get_m_clippedInvContactDotSuspension_0,Ot=c._emscripten_bind_btDynamicsWorld_addAction_1=n._emscripten_bind_btDynamicsWorld_addAction_1,Pt=c._emscripten_bind_btSoftBody_appendMaterial_0=n._emscripten_bind_btSoftBody_appendMaterial_0,Qt=c._emscripten_bind_btSoftBodyWorldInfo_set_m_maxDisplacement_1=n._emscripten_bind_btSoftBodyWorldInfo_set_m_maxDisplacement_1,Rt=c._emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_2=\nn._emscripten_bind_btSoftRigidDynamicsWorld_stepSimulation_2,St=c._emscripten_bind_btPairCachingGhostObject_getCollisionFlags_0=n._emscripten_bind_btPairCachingGhostObject_getCollisionFlags_0,Tt=c._emscripten_bind_btSoftBodyWorldInfo_get_air_density_0=n._emscripten_bind_btSoftBodyWorldInfo_get_air_density_0,Ut=c._emscripten_bind_btSoftBody_setRestitution_1=n._emscripten_bind_btSoftBody_setRestitution_1,Vt=c._emscripten_bind_Config_set_kLF_1=n._emscripten_bind_Config_set_kLF_1,Wt=c._emscripten_bind_btWheelInfo_get_m_rotation_0=\nn._emscripten_bind_btWheelInfo_get_m_rotation_0,Xt=c._emscripten_enum_PHY_ScalarType_PHY_FLOAT=n._emscripten_enum_PHY_ScalarType_PHY_FLOAT,Yt=c._emscripten_bind_btWheelInfo_set_m_skidInfo_1=n._emscripten_bind_btWheelInfo_set_m_skidInfo_1,Zt=c._emscripten_bind_Config_set_kSS_SPLT_CL_1=n._emscripten_bind_Config_set_kSS_SPLT_CL_1,$t=c._emscripten_bind_btGhostObject_isActive_0=n._emscripten_bind_btGhostObject_isActive_0,au=c._emscripten_bind_btWheelInfoConstructionInfo_set_m_suspensionRestLength_1=n._emscripten_bind_btWheelInfoConstructionInfo_set_m_suspensionRestLength_1,\nbu=c._emscripten_bind_btKinematicCharacterController_setFallSpeed_1=n._emscripten_bind_btKinematicCharacterController_setFallSpeed_1,cu=c._emscripten_bind_btRigidBody_setActivationState_1=n._emscripten_bind_btRigidBody_setActivationState_1,du=c._emscripten_bind_btWheelInfo_get_m_wheelsDampingCompression_0=n._emscripten_bind_btWheelInfo_get_m_wheelsDampingCompression_0,eu=c._emscripten_bind_ClosestConvexResultCallback_hasHit_0=n._emscripten_bind_ClosestConvexResultCallback_hasHit_0,fu=c._emscripten_bind_btCapsuleShapeZ___destroy___0=\nn._emscripten_bind_btCapsuleShapeZ___destroy___0,gu=c._emscripten_bind_btRaycastVehicle_getRigidBody_0=n._emscripten_bind_btRaycastVehicle_getRigidBody_0,hu=c._emscripten_bind_btWheelInfo_get_m_maxSuspensionForce_0=n._emscripten_bind_btWheelInfo_get_m_maxSuspensionForce_0,iu=c._emscripten_bind_btSoftBody_get_m_materials_0=n._emscripten_bind_btSoftBody_get_m_materials_0,ju=c._emscripten_bind_btTriangleMesh_addTriangle_3=n._emscripten_bind_btTriangleMesh_addTriangle_3,ku=c._emscripten_bind_btGhostObject_getOverlappingObject_1=\nn._emscripten_bind_btGhostObject_getOverlappingObject_1,lu=c._emscripten_bind_btTriangleMesh_addTriangle_4=n._emscripten_bind_btTriangleMesh_addTriangle_4,mu=c._emscripten_bind_btSoftRigidDynamicsWorld_getDispatchInfo_0=n._emscripten_bind_btSoftRigidDynamicsWorld_getDispatchInfo_0,nu=c._emscripten_bind_btSoftBodyWorldInfo_set_water_normal_1=n._emscripten_bind_btSoftBodyWorldInfo_set_water_normal_1,ou=c._emscripten_bind_btSoftRigidDynamicsWorld_addConstraint_2=n._emscripten_bind_btSoftRigidDynamicsWorld_addConstraint_2,\npu=c._emscripten_bind_Config_get_kDF_0=n._emscripten_bind_Config_get_kDF_0,qu=c._emscripten_bind_btRigidBody_applyTorqueImpulse_1=n._emscripten_bind_btRigidBody_applyTorqueImpulse_1,ru=c._emscripten_bind_btVector3_op_add_1=n._emscripten_bind_btVector3_op_add_1,su=c._emscripten_bind_btRigidBody_setCollisionFlags_1=n._emscripten_bind_btRigidBody_setCollisionFlags_1,tu=c._emscripten_bind_btWheelInfo_get_m_steering_0=n._emscripten_bind_btWheelInfo_get_m_steering_0,uu=c._emscripten_bind_btRigidBody___destroy___0=\nn._emscripten_bind_btRigidBody___destroy___0,vu=c._emscripten_bind_btWheelInfo_set_m_suspensionRestLength1_1=n._emscripten_bind_btWheelInfo_set_m_suspensionRestLength1_1,wu=c._emscripten_bind_Config_set_kCHR_1=n._emscripten_bind_Config_set_kCHR_1,xu=c._emscripten_bind_btRaycastVehicle_setUserConstraintType_1=n._emscripten_bind_btRaycastVehicle_setUserConstraintType_1,yu=c._emscripten_bind_btSoftRigidDynamicsWorld_contactTest_2=n._emscripten_bind_btSoftRigidDynamicsWorld_contactTest_2,zu=c._emscripten_bind_btCapsuleShapeZ_btCapsuleShapeZ_2=\nn._emscripten_bind_btCapsuleShapeZ_btCapsuleShapeZ_2,Au=c._emscripten_bind_btDispatcherInfo_get_m_enableSPU_0=n._emscripten_bind_btDispatcherInfo_get_m_enableSPU_0,Bu=c._emscripten_bind_btSoftRigidDynamicsWorld_getWorldInfo_0=n._emscripten_bind_btSoftRigidDynamicsWorld_getWorldInfo_0,Cu=c._emscripten_bind_btSliderConstraint_btSliderConstraint_3=n._emscripten_bind_btSliderConstraint_btSliderConstraint_3,Du=c._emscripten_bind_btTransform___destroy___0=n._emscripten_bind_btTransform___destroy___0,Eu=\nc._emscripten_bind_btWheelInfo_get_m_wheelAxleCS_0=n._emscripten_bind_btWheelInfo_get_m_wheelAxleCS_0,Fu=c._emscripten_bind_btDynamicsWorld_convexSweepTest_5=n._emscripten_bind_btDynamicsWorld_convexSweepTest_5,Gu=c._emscripten_bind_btSliderConstraint___destroy___0=n._emscripten_bind_btSliderConstraint___destroy___0,Hu=c._emscripten_bind_btRigidBody_forceActivationState_1=n._emscripten_bind_btRigidBody_forceActivationState_1,Iu=c._emscripten_bind_btPoint2PointConstraint_setPivotB_1=n._emscripten_bind_btPoint2PointConstraint_setPivotB_1,\nJu=c._emscripten_bind_btManifoldPoint_getDistance_0=n._emscripten_bind_btManifoldPoint_getDistance_0,Ku=c._emscripten_bind_btWheelInfo_set_m_wheelAxleCS_1=n._emscripten_bind_btWheelInfo_set_m_wheelAxleCS_1,Lu=c._emscripten_bind_btTransform_setFromOpenGLMatrix_1=n._emscripten_bind_btTransform_setFromOpenGLMatrix_1,Mu=c._emscripten_bind_btKinematicCharacterController_getMaxSlope_0=n._emscripten_bind_btKinematicCharacterController_getMaxSlope_0,Nu=c._emscripten_bind_btManifoldPoint_getPositionWorldOnA_0=\nn._emscripten_bind_btManifoldPoint_getPositionWorldOnA_0,Ou=c._emscripten_bind_btRaycastVehicle_addWheel_7=n._emscripten_bind_btRaycastVehicle_addWheel_7,Pu=c._emscripten_bind_btQuaternion_op_add_1=n._emscripten_bind_btQuaternion_op_add_1,Qu=c._emscripten_bind_ClosestRayResultCallback_set_m_hitNormalWorld_1=n._emscripten_bind_ClosestRayResultCallback_set_m_hitNormalWorld_1,Ru=c._emscripten_bind_btRaycastVehicle_updateWheelTransformsWS_2=n._emscripten_bind_btRaycastVehicle_updateWheelTransformsWS_2,\nSu=c._emscripten_bind_btStaticPlaneShape___destroy___0=n._emscripten_bind_btStaticPlaneShape___destroy___0,Tu=c._emscripten_bind_btHingeConstraint_enableMotor_1=n._emscripten_bind_btHingeConstraint_enableMotor_1,Uu=c._emscripten_bind_btCylinderShapeZ_setLocalScaling_1=n._emscripten_bind_btCylinderShapeZ_setLocalScaling_1,Vu=c._emscripten_bind_btBoxShape_setLocalScaling_1=n._emscripten_bind_btBoxShape_setLocalScaling_1,Wu=c._emscripten_bind_btConeShapeZ___destroy___0=n._emscripten_bind_btConeShapeZ___destroy___0,\nXu=c._emscripten_bind_btDynamicsWorld_getPairCache_0=n._emscripten_bind_btDynamicsWorld_getPairCache_0,Yu=c._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelAxleCS_0=n._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelAxleCS_0,Zu=c._emscripten_bind_btDiscreteDynamicsWorld_convexSweepTest_5=n._emscripten_bind_btDiscreteDynamicsWorld_convexSweepTest_5,$u=c._emscripten_bind_btSoftRigidDynamicsWorld_removeRigidBody_1=n._emscripten_bind_btSoftRigidDynamicsWorld_removeRigidBody_1,av=c._emscripten_bind_btRigidBody_setRestitution_1=\nn._emscripten_bind_btRigidBody_setRestitution_1,bv=c._emscripten_bind_btVector4_btVector4_0=n._emscripten_bind_btVector4_btVector4_0,cv=c._emscripten_bind_btVector4_x_0=n._emscripten_bind_btVector4_x_0,dv=c._emscripten_bind_btVector4_btVector4_4=n._emscripten_bind_btVector4_btVector4_4,ev=c._emscripten_bind_btKinematicCharacterController___destroy___0=n._emscripten_bind_btKinematicCharacterController___destroy___0,fv=c._emscripten_bind_btGeneric6DofSpringConstraint_setLinearLowerLimit_1=n._emscripten_bind_btGeneric6DofSpringConstraint_setLinearLowerLimit_1,\ngv=c._emscripten_bind_tMaterialArray_at_1=n._emscripten_bind_tMaterialArray_at_1,hv=c._emscripten_bind_LocalConvexResult_set_m_hitCollisionObject_1=n._emscripten_bind_LocalConvexResult_set_m_hitCollisionObject_1,iv=c._emscripten_bind_btVector4_op_sub_1=n._emscripten_bind_btVector4_op_sub_1,jv=c._emscripten_bind_btGeneric6DofSpringConstraint_setAngularLowerLimit_1=n._emscripten_bind_btGeneric6DofSpringConstraint_setAngularLowerLimit_1,kv=c._emscripten_bind_btSoftBodyWorldInfo_get_water_offset_0=n._emscripten_bind_btSoftBodyWorldInfo_get_water_offset_0,\nlv=c._emscripten_bind_btDiscreteDynamicsWorld_rayTest_3=n._emscripten_bind_btDiscreteDynamicsWorld_rayTest_3,mv=c._emscripten_bind_btWheelInfo_get_m_raycastInfo_0=n._emscripten_bind_btWheelInfo_get_m_raycastInfo_0,nv=c._emscripten_bind_btContactSolverInfo_get_m_splitImpulse_0=n._emscripten_bind_btContactSolverInfo_get_m_splitImpulse_0,ov=c._emscripten_bind_btConvexShape_getMargin_0=n._emscripten_bind_btConvexShape_getMargin_0,pv=c._emscripten_bind_btRaycastVehicle_getSteeringValue_1=n._emscripten_bind_btRaycastVehicle_getSteeringValue_1,\nqv=c._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelRadius_0=n._emscripten_bind_btWheelInfoConstructionInfo_get_m_wheelRadius_0,rv=c._emscripten_bind_btKinematicCharacterController_setMaxJumpHeight_1=n._emscripten_bind_btKinematicCharacterController_setMaxJumpHeight_1,sv=c._emscripten_bind_btPairCachingGhostObject_isActive_0=n._emscripten_bind_btPairCachingGhostObject_isActive_0,tv=c._emscripten_bind_btWheelInfo_set_m_wheelDirectionCS_1=n._emscripten_bind_btWheelInfo_set_m_wheelDirectionCS_1,\nuv=c._emscripten_bind_btVehicleTuning_get_m_frictionSlip_0=n._emscripten_bind_btVehicleTuning_get_m_frictionSlip_0;c.dynCall_viiiii=n.dynCall_viiiii;c.dynCall_vid=n.dynCall_vid;c.dynCall_vi=n.dynCall_vi;c.dynCall_viiidii=n.dynCall_viiidii;c.dynCall_vii=n.dynCall_vii;c.dynCall_iiiiiiiiiii=n.dynCall_iiiiiiiiiii;c.dynCall_ii=n.dynCall_ii;c.dynCall_viidi=n.dynCall_viidi;c.dynCall_viddiii=n.dynCall_viddiii;c.dynCall_vidii=n.dynCall_vidii;c.dynCall_iiiii=n.dynCall_iiiii;c.dynCall_vidi=n.dynCall_vidi;\nc.dynCall_diiiiiiii=n.dynCall_diiiiiiii;c.dynCall_viiiiddddiid=n.dynCall_viiiiddddiid;c.dynCall_diiiii=n.dynCall_diiiii;c.dynCall_vidd=n.dynCall_vidd;c.dynCall_iiii=n.dynCall_iiii;c.dynCall_viiiiid=n.dynCall_viiiiid;c.dynCall_viiiiii=n.dynCall_viiiiii;c.dynCall_iiid=n.dynCall_iiid;c.dynCall_di=n.dynCall_di;c.dynCall_iiiiiii=n.dynCall_iiiiiii;c.dynCall_diiidii=n.dynCall_diiidii;c.dynCall_viidii=n.dynCall_viidii;c.dynCall_viiiiiii=n.dynCall_viiiiiii;c.dynCall_viiiiiiiii=n.dynCall_viiiiiiiii;\nc.dynCall_viiiiiiiiii=n.dynCall_viiiiiiiiii;c.dynCall_iii=n.dynCall_iii;c.dynCall_diii=n.dynCall_diii;c.dynCall_diiiiiiiiii=n.dynCall_diiiiiiiiii;c.dynCall_viiiid=n.dynCall_viiiid;c.dynCall_diiiiiiiii=n.dynCall_diiiiiiiii;c.dynCall_did=n.dynCall_did;c.dynCall_viiiidddddidi=n.dynCall_viiiidddddidi;c.dynCall_diidii=n.dynCall_diidii;c.dynCall_diiii=n.dynCall_diiii;c.dynCall_iiiiiiiiii=n.dynCall_iiiiiiiiii;c.dynCall_viiid=n.dynCall_viiid;c.dynCall_viii=n.dynCall_viii;c.dynCall_v=n.dynCall_v;\nc.dynCall_viid=n.dynCall_viid;c.dynCall_iidid=n.dynCall_iidid;c.dynCall_viiii=n.dynCall_viiii;d.t=c.stackAlloc;d.N=c.stackSave;d.M=c.stackRestore;d.S=c.establishStackSpace;d.e=c.setTempRet0;d.J=c.getTempRet0;c.asm=n;c.then=function(a){if(c.calledRun)a(c);else{var b=c.onRuntimeInitialized;c.onRuntimeInitialized=function(){b&&b();a(c)}}return c};function ja(a){this.name=\"ExitStatus\";this.message=\"Program terminated with exit(\"+a+\")\"}ja.prototype=Error();ja.prototype.constructor=ja;var vv=null;\nc.callMain=c.Q=function(a){function b(){for(var a=0;3>a;a++)f.push(0)}a=a||[];Xa||(Xa=!0,Ra(Ta));var e=a.length+1,f=[wa(Za(c.thisProgram),\"i8\",0)];b();for(var g=0;g<e-1;g+=1)f.push(wa(Za(a[g]),\"i8\",0)),b();f.push(0);f=wa(f,\"i32\",0);try{var h=c._main(e,f,0);wv(h,!0)}catch(k){k instanceof ja||(\"SimulateInfiniteLoop\"==k?c.noExitRuntime=!0:((a=k)&&\"object\"===typeof k&&k.stack&&(a=[k,k.stack]),c.i(\"exception thrown: \"+a),c.quit(1,k)))}finally{}};\nfunction xv(a){function b(){if(!c.calledRun&&(c.calledRun=!0,!pa)){Xa||(Xa=!0,Ra(Ta));Ra(Ua);if(c.onRuntimeInitialized)c.onRuntimeInitialized();c._main&&yv&&c.callMain(a);if(c.postRun)for(\"function\"==typeof c.postRun&&(c.postRun=[c.postRun]);c.postRun.length;){var b=c.postRun.shift();Wa.unshift(b)}Ra(Wa)}}a=a||c.arguments;null===vv&&(vv=Date.now());if(c.preRun)for(\"function\"==typeof c.preRun&&(c.preRun=[c.preRun]);c.preRun.length;)Ya();Ra(Sa);c.calledRun||(c.setStatus?(c.setStatus(\"Running...\"),setTimeout(function(){setTimeout(function(){c.setStatus(\"\")},\n1);b()},1)):b())}c.run=c.run=xv;function wv(a,b){if(!b||!c.noExitRuntime){if(!c.noExitRuntime&&(pa=!0,ka=void 0,Ra(Va),c.onExit))c.onExit(a);ea&&process.exit(a);c.quit(a,new ja(a))}}c.exit=c.exit=wv;var zv=[];function qa(a){void 0!==a?(c.print(a),c.i(a),a=JSON.stringify(a)):a=\"\";pa=!0;var b=\"abort(\"+a+\") at \"+Ja()+\"\\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.\";zv&&zv.forEach(function(e){b=e(b,a)});throw b;}c.abort=c.abort=qa;\nif(c.preInit)for(\"function\"==typeof c.preInit&&(c.preInit=[c.preInit]);0<c.preInit.length;)c.preInit.pop()();var yv=!0;c.noInitialRun&&(yv=!1);c.noExitRuntime=!0;xv();function p(){}p.prototype=Object.create(p.prototype);p.prototype.constructor=p;p.prototype.b=p;p.c={};c.WrapperObject=p;function q(a){return(a||p).c}c.getCache=q;function r(a,b){var e=q(b),f=e[a];if(f)return f;f=Object.create((b||p).prototype);f.a=a;return e[a]=f}c.wrapPointer=r;c.castObject=function(a,b){return r(a.a,b)};c.NULL=r(0);\nc.destroy=function(a){if(!a.__destroy__)throw\"Error: Cannot destroy object. (Did you create it yourself?)\";a.__destroy__();delete q(a.b)[a.a]};c.compare=function(a,b){return a.a===b.a};c.getPointer=function(a){return a.a};c.getClass=function(a){return a.b};var Av=0,Bv=0,Cv=0,Dv=[],Ev=0;function Fv(){if(Ev){for(var a=0;a<Dv.length;a++)c._free(Dv[a]);Dv.length=0;c._free(Av);Av=0;Bv+=Ev;Ev=0}Av||(Bv+=128,Av=c._malloc(Bv),assert(Av));Cv=0}\nfunction Gv(a,b){assert(Av);var e=a.length*b.BYTES_PER_ELEMENT,e=e+7&-8,f;Cv+e>=Bv?(assert(0<e),Ev+=e,f=c._malloc(e),Dv.push(f)):(f=Av+Cv,Cv+=e);return f}function Hv(a,b,e){switch(b.BYTES_PER_ELEMENT){case 2:e>>=1;break;case 4:e>>=2;break;case 8:e>>=3}for(var f=0;f<a.length;f++)b[e+f]=a[f]}function Iv(a){if(\"object\"===typeof a){var b=Gv(a,ua);Hv(a,ua,b);return b}return a}function Jv(){throw\"cannot construct a btCollisionWorld, no constructor in IDL\";}Jv.prototype=Object.create(p.prototype);\nJv.prototype.constructor=Jv;Jv.prototype.b=Jv;Jv.c={};c.btCollisionWorld=Jv;Jv.prototype.getDispatcher=function(){return r(hj(this.a),Kv)};Jv.prototype.rayTest=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);Tf(f,a,b,e)};Jv.prototype.getPairCache=function(){return r(Ln(this.a),Lv)};Jv.prototype.getDispatchInfo=function(){return r(ti(this.a),t)};\nJv.prototype.addCollisionObject=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);void 0===b?xl(f,a):void 0===e?yl(f,a,b):Vi(f,a,b,e)};Jv.prototype.getBroadphase=function(){return r($h(this.a),Mv)};\nJv.prototype.convexSweepTest=function(a,b,e,f,g){var h=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);wf(h,a,b,e,f,g)};Jv.prototype.contactPairTest=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);Nr(f,a,b,e)};\nJv.prototype.contactTest=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);jg(e,a,b)};Jv.prototype.__destroy__=function(){Md(this.a)};function u(){throw\"cannot construct a btCollisionShape, no constructor in IDL\";}u.prototype=Object.create(p.prototype);u.prototype.constructor=u;u.prototype.b=u;u.c={};c.btCollisionShape=u;u.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Xi(b,a)};\nu.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);tf(e,a,b)};u.prototype.setMargin=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Oe(b,a)};u.prototype.getMargin=function(){return To(this.a)};u.prototype.__destroy__=function(){mo(this.a)};function w(){throw\"cannot construct a btCollisionObject, no constructor in IDL\";}w.prototype=Object.create(p.prototype);w.prototype.constructor=w;w.prototype.b=w;w.c={};\nc.btCollisionObject=w;w.prototype.setAnisotropicFriction=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);sn(e,a,b)};w.prototype.getCollisionShape=function(){return r(Km(this.a),u)};w.prototype.setContactProcessingThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ni(b,a)};w.prototype.setActivationState=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);kf(b,a)};\nw.prototype.forceActivationState=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);gr(b,a)};w.prototype.activate=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);void 0===a?ad(b):$c(b,a)};w.prototype.isActive=function(){return!!Ob(this.a)};w.prototype.isKinematicObject=function(){return!!Mc(this.a)};w.prototype.setRestitution=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Rk(b,a)};w.prototype.setFriction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);cm(b,a)};\nw.prototype.setRollingFriction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);kj(b,a)};w.prototype.getWorldTransform=function(){return r(Dk(this.a),x)};w.prototype.getCollisionFlags=function(){return xi(this.a)};w.prototype.setCollisionFlags=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);gq(b,a)};w.prototype.setWorldTransform=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);sr(b,a)};\nw.prototype.setCollisionShape=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);lo(b,a)};w.prototype.setCcdMotionThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ip(b,a)};w.prototype.setCcdSweptSphereRadius=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Dt(b,a)};w.prototype.getUserIndex=function(){return ec(this.a)};w.prototype.setUserIndex=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Hn(b,a)};\nw.prototype.getUserPointer=function(){return r(hg(this.a),Nv)};w.prototype.setUserPointer=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ll(b,a)};w.prototype.__destroy__=function(){Fo(this.a)};function y(){throw\"cannot construct a btDynamicsWorld, no constructor in IDL\";}y.prototype=Object.create(Jv.prototype);y.prototype.constructor=y;y.prototype.b=y;y.c={};c.btDynamicsWorld=y;y.prototype.addAction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ot(b,a)};\ny.prototype.removeAction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);cs(b,a)};y.prototype.getSolverInfo=function(){return r(Bm(this.a),Ov)};y.prototype.getDispatcher=function(){return r(qj(this.a),Kv)};y.prototype.rayTest=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);Ic(f,a,b,e)};y.prototype.getPairCache=function(){return r(Xu(this.a),Lv)};y.prototype.getDispatchInfo=function(){return r(de(this.a),t)};\ny.prototype.addCollisionObject=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);void 0===b?Zl(f,a):void 0===e?am(f,a,b):ne(f,a,b,e)};y.prototype.getBroadphase=function(){return r(Fm(this.a),Mv)};\ny.prototype.convexSweepTest=function(a,b,e,f,g){var h=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);Fu(h,a,b,e,f,g)};y.prototype.contactPairTest=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);Kn(f,a,b,e)};\ny.prototype.contactTest=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Kl(e,a,b)};y.prototype.__destroy__=function(){$g(this.a)};function Pv(){throw\"cannot construct a btTypedConstraint, no constructor in IDL\";}Pv.prototype=Object.create(p.prototype);Pv.prototype.constructor=Pv;Pv.prototype.b=Pv;Pv.c={};c.btTypedConstraint=Pv;Pv.prototype.enableFeedback=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);np(b,a)};\nPv.prototype.getBreakingImpulseThreshold=function(){return qn(this.a)};Pv.prototype.setBreakingImpulseThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);$b(b,a)};Pv.prototype.__destroy__=function(){ll(this.a)};function Qv(){throw\"cannot construct a btConcaveShape, no constructor in IDL\";}Qv.prototype=Object.create(u.prototype);Qv.prototype.constructor=Qv;Qv.prototype.b=Qv;Qv.c={};c.btConcaveShape=Qv;\nQv.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Kh(b,a)};Qv.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Kj(e,a,b)};Qv.prototype.__destroy__=function(){Ch(this.a)};function Rv(a,b){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);this.a=mp(a,b);q(Rv)[this.a]=this}Rv.prototype=Object.create(u.prototype);Rv.prototype.constructor=Rv;Rv.prototype.b=Rv;Rv.c={};\nc.btCapsuleShape=Rv;Rv.prototype.setMargin=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Il(b,a)};Rv.prototype.getMargin=function(){return Rp(this.a)};Rv.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Hg(b,a)};Rv.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Oq(e,a,b)};Rv.prototype.__destroy__=function(){Yc(this.a)};\nfunction Sv(a){a&&\"object\"===typeof a&&(a=a.a);this.a=void 0===a?Di():Zc(a);q(Sv)[this.a]=this}Sv.prototype=Object.create(p.prototype);Sv.prototype.constructor=Sv;Sv.prototype.b=Sv;Sv.c={};c.btDefaultCollisionConfiguration=Sv;Sv.prototype.__destroy__=function(){Vm(this.a)};function Tv(){throw\"cannot construct a btTriangleMeshShape, no constructor in IDL\";}Tv.prototype=Object.create(Qv.prototype);Tv.prototype.constructor=Tv;Tv.prototype.b=Tv;Tv.c={};c.btTriangleMeshShape=Tv;\nTv.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Io(b,a)};Tv.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Uj(e,a,b)};Tv.prototype.__destroy__=function(){bs(this.a)};function Uv(){throw\"cannot construct a RayResultCallback, no constructor in IDL\";}Uv.prototype=Object.create(p.prototype);Uv.prototype.constructor=Uv;Uv.prototype.b=Uv;Uv.c={};c.RayResultCallback=Uv;Uv.prototype.hasHit=function(){return!!Zj(this.a)};\nUv.prototype.get_m_collisionFilterGroup=function(){return ho(this.a)};Uv.prototype.set_m_collisionFilterGroup=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);mj(b,a)};Uv.prototype.get_m_collisionFilterMask=function(){return gj(this.a)};Uv.prototype.set_m_collisionFilterMask=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);je(b,a)};Uv.prototype.get_m_collisionObject=function(){return r(Rl(this.a),w)};\nUv.prototype.set_m_collisionObject=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);It(b,a)};Uv.prototype.__destroy__=function(){nh(this.a)};function Vv(a,b){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);this.a=Jg(a,b);q(Vv)[this.a]=this}Vv.prototype=Object.create(u.prototype);Vv.prototype.constructor=Vv;Vv.prototype.b=Vv;Vv.c={};c.btConeShape=Vv;Vv.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ko(b,a)};\nVv.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);us(e,a,b)};Vv.prototype.__destroy__=function(){xq(this.a)};function Wv(){throw\"cannot construct a btActionInterface, no constructor in IDL\";}Wv.prototype=Object.create(p.prototype);Wv.prototype.constructor=Wv;Wv.prototype.b=Wv;Wv.c={};c.btActionInterface=Wv;\nWv.prototype.updateAction=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);ld(e,a,b)};Wv.prototype.__destroy__=function(){Nl(this.a)};function A(a,b,e){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);this.a=void 0===a?Oo():void 0===b?_emscripten_bind_btVector3_btVector3_1(a):void 0===e?_emscripten_bind_btVector3_btVector3_2(a,b):No(a,b,e);q(A)[this.a]=this}A.prototype=Object.create(p.prototype);\nA.prototype.constructor=A;A.prototype.b=A;A.c={};c.btVector3=A;A.prototype.length=A.prototype.length=function(){return kr(this.a)};A.prototype.x=function(){return Im(this.a)};A.prototype.y=function(){return Qq(this.a)};A.prototype.z=function(){return Ro(this.a)};A.prototype.setX=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);hd(b,a)};A.prototype.setY=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ah(b,a)};\nA.prototype.setZ=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);qd(b,a)};A.prototype.setValue=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);Xm(f,a,b,e)};A.prototype.normalize=function(){nr(this.a)};A.prototype.rotate=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);return r(em(e,a,b),A)};\nA.prototype.dot=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return Og(b,a)};A.prototype.op_mul=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(Bh(b,a),A)};A.prototype.op_add=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(ru(b,a),A)};A.prototype.op_sub=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(cf(b,a),A)};A.prototype.__destroy__=function(){tm(this.a)};\nfunction Xv(){throw\"cannot construct a btVehicleRaycaster, no constructor in IDL\";}Xv.prototype=Object.create(p.prototype);Xv.prototype.constructor=Xv;Xv.prototype.b=Xv;Xv.c={};c.btVehicleRaycaster=Xv;Xv.prototype.castRay=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);nj(f,a,b,e)};Xv.prototype.__destroy__=function(){vg(this.a)};function Yv(){throw\"cannot construct a btQuadWord, no constructor in IDL\";}Yv.prototype=Object.create(p.prototype);\nYv.prototype.constructor=Yv;Yv.prototype.b=Yv;Yv.c={};c.btQuadWord=Yv;Yv.prototype.x=function(){return Kc(this.a)};Yv.prototype.y=function(){return pg(this.a)};Yv.prototype.z=function(){return kc(this.a)};Yv.prototype.w=function(){return zg(this.a)};Yv.prototype.setX=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);dh(b,a)};Yv.prototype.setY=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);zd(b,a)};Yv.prototype.setZ=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Um(b,a)};\nYv.prototype.setW=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ze(b,a)};Yv.prototype.__destroy__=function(){$o(this.a)};function Zv(a){a&&\"object\"===typeof a&&(a=a.a);this.a=ai(a);q(Zv)[this.a]=this}Zv.prototype=Object.create(u.prototype);Zv.prototype.constructor=Zv;Zv.prototype.b=Zv;Zv.c={};c.btCylinderShape=Zv;Zv.prototype.setMargin=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Kd(b,a)};Zv.prototype.getMargin=function(){return Sp(this.a)};\nZv.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);qi(b,a)};Zv.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Vl(e,a,b)};Zv.prototype.__destroy__=function(){Gb(this.a)};function C(a,b,e,f){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);this.a=Sb(a,b,e,f);q(C)[this.a]=this}C.prototype=Object.create(y.prototype);\nC.prototype.constructor=C;C.prototype.b=C;C.c={};c.btDiscreteDynamicsWorld=C;C.prototype.setGravity=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);dr(b,a)};C.prototype.getGravity=function(){return r(Qo(this.a),A)};C.prototype.addRigidBody=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);void 0===b?pl(f,a):void 0===e?_emscripten_bind_btDiscreteDynamicsWorld_addRigidBody_2(f,a,b):ol(f,a,b,e)};\nC.prototype.removeRigidBody=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);bg(b,a)};C.prototype.addConstraint=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);void 0===b?Re(e,a):Qe(e,a,b)};C.prototype.removeConstraint=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Rs(b,a)};\nC.prototype.stepSimulation=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);return void 0===b?Ec(f,a):void 0===e?Gc(f,a,b):Fc(f,a,b,e)};C.prototype.getDispatcher=function(){return r(bm(this.a),Kv)};C.prototype.rayTest=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);lv(f,a,b,e)};C.prototype.getPairCache=function(){return r(Zp(this.a),Lv)};\nC.prototype.getDispatchInfo=function(){return r(Lh(this.a),t)};C.prototype.addCollisionObject=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);void 0===b?iq(f,a):void 0===e?jq(f,a,b):kq(f,a,b,e)};C.prototype.getBroadphase=function(){return r(dg(this.a),Mv)};\nC.prototype.convexSweepTest=function(a,b,e,f,g){var h=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);Zu(h,a,b,e,f,g)};C.prototype.contactPairTest=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);At(f,a,b,e)};\nC.prototype.contactTest=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Cg(e,a,b)};C.prototype.addAction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);eg(b,a)};C.prototype.removeAction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ds(b,a)};C.prototype.getSolverInfo=function(){return r(Jd(this.a),Ov)};C.prototype.__destroy__=function(){Ik(this.a)};function $v(){throw\"cannot construct a btConvexShape, no constructor in IDL\";}\n$v.prototype=Object.create(u.prototype);$v.prototype.constructor=$v;$v.prototype.b=$v;$v.c={};c.btConvexShape=$v;$v.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Rj(b,a)};$v.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);nt(e,a,b)};$v.prototype.setMargin=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Cr(b,a)};$v.prototype.getMargin=function(){return ov(this.a)};\n$v.prototype.__destroy__=function(){Jk(this.a)};function Kv(){throw\"cannot construct a btDispatcher, no constructor in IDL\";}Kv.prototype=Object.create(p.prototype);Kv.prototype.constructor=Kv;Kv.prototype.b=Kv;Kv.c={};c.btDispatcher=Kv;Kv.prototype.getNumManifolds=function(){return Br(this.a)};Kv.prototype.getManifoldByIndexInternal=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(nq(b,a),aw)};Kv.prototype.__destroy__=function(){Gk(this.a)};\nfunction bw(a,b,e,f,g){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);this.a=void 0===f?Vd(a,b,e):void 0===g?_emscripten_bind_btGeneric6DofConstraint_btGeneric6DofConstraint_4(a,b,e,f):Ud(a,b,e,f,g);q(bw)[this.a]=this}bw.prototype=Object.create(Pv.prototype);bw.prototype.constructor=bw;bw.prototype.b=bw;bw.c={};c.btGeneric6DofConstraint=bw;\nbw.prototype.setLinearLowerLimit=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ot(b,a)};bw.prototype.setLinearUpperLimit=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Xj(b,a)};bw.prototype.setAngularLowerLimit=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ps(b,a)};bw.prototype.setAngularUpperLimit=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Pe(b,a)};bw.prototype.enableFeedback=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Hb(b,a)};\nbw.prototype.getBreakingImpulseThreshold=function(){return jr(this.a)};bw.prototype.setBreakingImpulseThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Qn(b,a)};bw.prototype.__destroy__=function(){Vs(this.a)};function cw(){throw\"cannot construct a btStridingMeshInterface, no constructor in IDL\";}cw.prototype=Object.create(p.prototype);cw.prototype.constructor=cw;cw.prototype.b=cw;cw.c={};c.btStridingMeshInterface=cw;cw.prototype.__destroy__=function(){wr(this.a)};\nfunction dw(){throw\"cannot construct a btMotionState, no constructor in IDL\";}dw.prototype=Object.create(p.prototype);dw.prototype.constructor=dw;dw.prototype.b=dw;dw.c={};c.btMotionState=dw;dw.prototype.getWorldTransform=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Am(b,a)};dw.prototype.setWorldTransform=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);vd(b,a)};dw.prototype.__destroy__=function(){fq(this.a)};\nfunction ew(){throw\"cannot construct a ConvexResultCallback, no constructor in IDL\";}ew.prototype=Object.create(p.prototype);ew.prototype.constructor=ew;ew.prototype.b=ew;ew.c={};c.ConvexResultCallback=ew;ew.prototype.hasHit=function(){return!!sf(this.a)};ew.prototype.get_m_collisionFilterGroup=function(){return Xk(this.a)};ew.prototype.set_m_collisionFilterGroup=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);xn(b,a)};ew.prototype.get_m_collisionFilterMask=function(){return Ap(this.a)};\new.prototype.set_m_collisionFilterMask=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);xs(b,a)};ew.prototype.get_m_closestHitFraction=function(){return oo(this.a)};ew.prototype.set_m_closestHitFraction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);xp(b,a)};ew.prototype.__destroy__=function(){Hi(this.a)};function fw(){throw\"cannot construct a ContactResultCallback, no constructor in IDL\";}fw.prototype=Object.create(p.prototype);fw.prototype.constructor=fw;fw.prototype.b=fw;\nfw.c={};c.ContactResultCallback=fw;fw.prototype.addSingleResult=function(a,b,e,f,g,h,k){var m=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);h&&\"object\"===typeof h&&(h=h.a);k&&\"object\"===typeof k&&(k=k.a);return Bd(m,a,b,e,f,g,h,k)};fw.prototype.__destroy__=function(){Vr(this.a)};function gw(){throw\"cannot construct a btSoftBodySolver, no constructor in IDL\";}gw.prototype=Object.create(p.prototype);\ngw.prototype.constructor=gw;gw.prototype.b=gw;gw.c={};c.btSoftBodySolver=gw;gw.prototype.__destroy__=function(){rq(this.a)};function D(){this.a=Ig();q(D)[this.a]=this}D.prototype=Object.create(w.prototype);D.prototype.constructor=D;D.prototype.b=D;D.c={};c.btGhostObject=D;D.prototype.getNumOverlappingObjects=function(){return Hq(this.a)};D.prototype.getOverlappingObject=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(ku(b,a),w)};\nD.prototype.setAnisotropicFriction=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);jp(e,a,b)};D.prototype.getCollisionShape=function(){return r(rn(this.a),u)};D.prototype.setContactProcessingThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Yh(b,a)};D.prototype.setActivationState=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Lr(b,a)};\nD.prototype.forceActivationState=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Tn(b,a)};D.prototype.activate=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);void 0===a?pp(b):zn(b,a)};D.prototype.isActive=function(){return!!$t(this.a)};D.prototype.isKinematicObject=function(){return!!Vc(this.a)};D.prototype.setRestitution=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Sm(b,a)};D.prototype.setFriction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Sf(b,a)};\nD.prototype.setRollingFriction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ok(b,a)};D.prototype.getWorldTransform=function(){return r(Yp(this.a),x)};D.prototype.getCollisionFlags=function(){return $m(this.a)};D.prototype.setCollisionFlags=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);rj(b,a)};D.prototype.setWorldTransform=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Yf(b,a)};\nD.prototype.setCollisionShape=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);$q(b,a)};D.prototype.setCcdMotionThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Pn(b,a)};D.prototype.setCcdSweptSphereRadius=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);yq(b,a)};D.prototype.getUserIndex=function(){return qm(this.a)};D.prototype.setUserIndex=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Pm(b,a)};\nD.prototype.getUserPointer=function(){return r(Pg(this.a),Nv)};D.prototype.setUserPointer=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);js(b,a)};D.prototype.__destroy__=function(){Ib(this.a)};function hw(){throw\"cannot construct a btMatrix3x3, no constructor in IDL\";}hw.prototype=Object.create(p.prototype);hw.prototype.constructor=hw;hw.prototype.b=hw;hw.c={};c.btMatrix3x3=hw;\nhw.prototype.setEulerZYX=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);$i(f,a,b,e)};hw.prototype.getRotation=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);sj(b,a)};hw.prototype.getRow=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(no(b,a),A)};hw.prototype.__destroy__=function(){pf(this.a)};function t(){throw\"cannot construct a btDispatcherInfo, no constructor in IDL\";}t.prototype=Object.create(p.prototype);\nt.prototype.constructor=t;t.prototype.b=t;t.c={};c.btDispatcherInfo=t;t.prototype.get_m_timeStep=function(){return bq(this.a)};t.prototype.set_m_timeStep=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Mo(b,a)};t.prototype.get_m_stepCount=function(){return xe(this.a)};t.prototype.set_m_stepCount=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);bi(b,a)};t.prototype.get_m_dispatchFunc=function(){return qo(this.a)};\nt.prototype.set_m_dispatchFunc=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);td(b,a)};t.prototype.get_m_timeOfImpact=function(){return cc(this.a)};t.prototype.set_m_timeOfImpact=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);fd(b,a)};t.prototype.get_m_useContinuous=function(){return!!Or(this.a)};t.prototype.set_m_useContinuous=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Mb(b,a)};t.prototype.get_m_enableSatConvex=function(){return!!Ls(this.a)};\nt.prototype.set_m_enableSatConvex=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);yi(b,a)};t.prototype.get_m_enableSPU=function(){return!!Au(this.a)};t.prototype.set_m_enableSPU=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ff(b,a)};t.prototype.get_m_useEpa=function(){return!!Xe(this.a)};t.prototype.set_m_useEpa=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Rq(b,a)};t.prototype.get_m_allowedCcdPenetration=function(){return fc(this.a)};\nt.prototype.set_m_allowedCcdPenetration=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ar(b,a)};t.prototype.get_m_useConvexConservativeDistanceUtil=function(){return!!Wr(this.a)};t.prototype.set_m_useConvexConservativeDistanceUtil=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Fe(b,a)};t.prototype.get_m_convexConservativeDistanceThreshold=function(){return bj(this.a)};\nt.prototype.set_m_convexConservativeDistanceThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);vk(b,a)};t.prototype.__destroy__=function(){Qp(this.a)};function iw(){throw\"cannot construct a Material, no constructor in IDL\";}iw.prototype=Object.create(p.prototype);iw.prototype.constructor=iw;iw.prototype.b=iw;iw.c={};c.Material=iw;iw.prototype.get_m_kLST=function(){return gt(this.a)};iw.prototype.set_m_kLST=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Mr(b,a)};\niw.prototype.get_m_kAST=function(){return kh(this.a)};iw.prototype.set_m_kAST=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);nk(b,a)};iw.prototype.get_m_kVST=function(){return nm(this.a)};iw.prototype.set_m_kVST=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Kr(b,a)};iw.prototype.get_m_flags=function(){return dn(this.a)};iw.prototype.set_m_flags=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);fi(b,a)};iw.prototype.__destroy__=function(){nc(this.a)};\nfunction E(){throw\"cannot construct a btWheelInfoConstructionInfo, no constructor in IDL\";}E.prototype=Object.create(p.prototype);E.prototype.constructor=E;E.prototype.b=E;E.c={};c.btWheelInfoConstructionInfo=E;E.prototype.get_m_chassisConnectionCS=function(){return r(kl(this.a),A)};E.prototype.set_m_chassisConnectionCS=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Cl(b,a)};E.prototype.get_m_wheelDirectionCS=function(){return r(Gt(this.a),A)};\nE.prototype.set_m_wheelDirectionCS=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);lm(b,a)};E.prototype.get_m_wheelAxleCS=function(){return r(Yu(this.a),A)};E.prototype.set_m_wheelAxleCS=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);mm(b,a)};E.prototype.get_m_suspensionRestLength=function(){return Id(this.a)};E.prototype.set_m_suspensionRestLength=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);au(b,a)};E.prototype.get_m_maxSuspensionTravelCm=function(){return Ps(this.a)};\nE.prototype.set_m_maxSuspensionTravelCm=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);il(b,a)};E.prototype.get_m_wheelRadius=function(){return qv(this.a)};E.prototype.set_m_wheelRadius=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Wl(b,a)};E.prototype.get_m_suspensionStiffness=function(){return Ue(this.a)};E.prototype.set_m_suspensionStiffness=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);qe(b,a)};E.prototype.get_m_wheelsDampingCompression=function(){return gf(this.a)};\nE.prototype.set_m_wheelsDampingCompression=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);cn(b,a)};E.prototype.get_m_wheelsDampingRelaxation=function(){return Qr(this.a)};E.prototype.set_m_wheelsDampingRelaxation=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Qb(b,a)};E.prototype.get_m_frictionSlip=function(){return op(this.a)};E.prototype.set_m_frictionSlip=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Zq(b,a)};E.prototype.get_m_maxSuspensionForce=function(){return ed(this.a)};\nE.prototype.set_m_maxSuspensionForce=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ir(b,a)};E.prototype.get_m_bIsFrontWheel=function(){return!!Aj(this.a)};E.prototype.set_m_bIsFrontWheel=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Wp(b,a)};E.prototype.__destroy__=function(){Xc(this.a)};function jw(a,b){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);this.a=void 0===b?he(a):ge(a,b);q(jw)[this.a]=this}jw.prototype=Object.create($v.prototype);\njw.prototype.constructor=jw;jw.prototype.b=jw;jw.c={};c.btConvexTriangleMeshShape=jw;jw.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);lg(b,a)};jw.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Vp(e,a,b)};jw.prototype.setMargin=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ho(b,a)};jw.prototype.getMargin=function(){return qq(this.a)};jw.prototype.__destroy__=function(){Jm(this.a)};\nfunction Mv(){throw\"cannot construct a btBroadphaseInterface, no constructor in IDL\";}Mv.prototype=Object.create(p.prototype);Mv.prototype.constructor=Mv;Mv.prototype.b=Mv;Mv.c={};c.btBroadphaseInterface=Mv;Mv.prototype.__destroy__=function(){Vo(this.a)};function F(a,b,e,f){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);this.a=void 0===f?wp(a,b,e):Lm(a,b,e,f);q(F)[this.a]=this}F.prototype=Object.create(p.prototype);\nF.prototype.constructor=F;F.prototype.b=F;F.c={};c.btRigidBodyConstructionInfo=F;F.prototype.get_m_linearDamping=function(){return zr(this.a)};F.prototype.set_m_linearDamping=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);zk(b,a)};F.prototype.get_m_angularDamping=function(){return zc(this.a)};F.prototype.set_m_angularDamping=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ye(b,a)};F.prototype.get_m_friction=function(){return Ae(this.a)};\nF.prototype.set_m_friction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Po(b,a)};F.prototype.get_m_rollingFriction=function(){return ro(this.a)};F.prototype.set_m_rollingFriction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Nm(b,a)};F.prototype.get_m_restitution=function(){return ic(this.a)};F.prototype.set_m_restitution=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Cd(b,a)};F.prototype.get_m_linearSleepingThreshold=function(){return Fr(this.a)};\nF.prototype.set_m_linearSleepingThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Tr(b,a)};F.prototype.get_m_angularSleepingThreshold=function(){return Mp(this.a)};F.prototype.set_m_angularSleepingThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Se(b,a)};F.prototype.get_m_additionalDamping=function(){return!!zj(this.a)};F.prototype.set_m_additionalDamping=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Dn(b,a)};\nF.prototype.get_m_additionalDampingFactor=function(){return sp(this.a)};F.prototype.set_m_additionalDampingFactor=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Li(b,a)};F.prototype.get_m_additionalLinearDampingThresholdSqr=function(){return gh(this.a)};F.prototype.set_m_additionalLinearDampingThresholdSqr=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);fh(b,a)};F.prototype.get_m_additionalAngularDampingThresholdSqr=function(){return Hp(this.a)};\nF.prototype.set_m_additionalAngularDampingThresholdSqr=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);fl(b,a)};F.prototype.get_m_additionalAngularDampingFactor=function(){return Qi(this.a)};F.prototype.set_m_additionalAngularDampingFactor=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Kg(b,a)};F.prototype.__destroy__=function(){Iq(this.a)};function kw(){throw\"cannot construct a btCollisionConfiguration, no constructor in IDL\";}kw.prototype=Object.create(p.prototype);\nkw.prototype.constructor=kw;kw.prototype.b=kw;kw.c={};c.btCollisionConfiguration=kw;kw.prototype.__destroy__=function(){id(this.a)};function aw(){this.a=zp();q(aw)[this.a]=this}aw.prototype=Object.create(p.prototype);aw.prototype.constructor=aw;aw.prototype.b=aw;aw.c={};c.btPersistentManifold=aw;aw.prototype.getBody0=function(){return r(qh(this.a),w)};aw.prototype.getBody1=function(){return r(Qd(this.a),w)};aw.prototype.getNumContacts=function(){return vj(this.a)};\naw.prototype.getContactPoint=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(vn(b,a),G)};aw.prototype.__destroy__=function(){mf(this.a)};function lw(a){a&&\"object\"===typeof a&&(a=a.a);this.a=void 0===a?rk():sk(a);q(lw)[this.a]=this}lw.prototype=Object.create(u.prototype);lw.prototype.constructor=lw;lw.prototype.b=lw;lw.c={};c.btCompoundShape=lw;lw.prototype.addChildShape=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Fk(e,a,b)};\nlw.prototype.removeChildShapeByIndex=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ee(b,a)};lw.prototype.getNumChildShapes=function(){return Fg(this.a)};lw.prototype.getChildShape=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(Ee(b,a),u)};lw.prototype.setMargin=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Eg(b,a)};lw.prototype.getMargin=function(){return Vb(this.a)};\nlw.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);zl(b,a)};lw.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);si(e,a,b)};lw.prototype.__destroy__=function(){Oi(this.a)};function H(a,b){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);this.a=bo(a,b);q(H)[this.a]=this}H.prototype=Object.create(ew.prototype);H.prototype.constructor=H;H.prototype.b=H;H.c={};\nc.ClosestConvexResultCallback=H;H.prototype.hasHit=function(){return!!eu(this.a)};H.prototype.get_m_convexFromWorld=function(){return r(xg(this.a),A)};H.prototype.set_m_convexFromWorld=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Nn(b,a)};H.prototype.get_m_convexToWorld=function(){return r(Xp(this.a),A)};H.prototype.set_m_convexToWorld=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Mq(b,a)};H.prototype.get_m_hitNormalWorld=function(){return r(jl(this.a),A)};\nH.prototype.set_m_hitNormalWorld=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Rc(b,a)};H.prototype.get_m_hitPointWorld=function(){return r(So(this.a),A)};H.prototype.set_m_hitPointWorld=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ie(b,a)};H.prototype.get_m_collisionFilterGroup=function(){return Hl(this.a)};H.prototype.set_m_collisionFilterGroup=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Al(b,a)};H.prototype.get_m_collisionFilterMask=function(){return $l(this.a)};\nH.prototype.set_m_collisionFilterMask=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);lr(b,a)};H.prototype.get_m_closestHitFraction=function(){return Yi(this.a)};H.prototype.set_m_closestHitFraction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Qs(b,a)};H.prototype.__destroy__=function(){Xl(this.a)};function mw(){throw\"cannot construct a tMaterialArray, no constructor in IDL\";}mw.prototype=Object.create(p.prototype);mw.prototype.constructor=mw;mw.prototype.b=mw;mw.c={};\nc.tMaterialArray=mw;mw.prototype.size=function(){return Zf(this.a)};mw.prototype.at=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(gv(b,a),iw)};mw.prototype.__destroy__=function(){eh(this.a)};function nw(a){a&&\"object\"===typeof a&&(a=a.a);this.a=Jl(a);q(nw)[this.a]=this}nw.prototype=Object.create(Xv.prototype);nw.prototype.constructor=nw;nw.prototype.b=nw;nw.c={};c.btDefaultVehicleRaycaster=nw;\nnw.prototype.castRay=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);Ms(f,a,b,e)};nw.prototype.__destroy__=function(){Ak(this.a)};function ow(){this.a=qp();q(ow)[this.a]=this}ow.prototype=Object.create(p.prototype);ow.prototype.constructor=ow;ow.prototype.b=ow;ow.c={};c.btConstraintSetting=ow;ow.prototype.get_m_tau=function(){return jo(this.a)};\now.prototype.set_m_tau=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Hf(b,a)};ow.prototype.get_m_damping=function(){return Rh(this.a)};ow.prototype.set_m_damping=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Bf(b,a)};ow.prototype.get_m_impulseClamp=function(){return nf(this.a)};ow.prototype.set_m_impulseClamp=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);eq(b,a)};ow.prototype.__destroy__=function(){lh(this.a)};\nfunction pw(){throw\"cannot construct a LocalShapeInfo, no constructor in IDL\";}pw.prototype=Object.create(p.prototype);pw.prototype.constructor=pw;pw.prototype.b=pw;pw.c={};c.LocalShapeInfo=pw;pw.prototype.get_m_shapePart=function(){return Wd(this.a)};pw.prototype.set_m_shapePart=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ce(b,a)};pw.prototype.get_m_triangleIndex=function(){return Vq(this.a)};\npw.prototype.set_m_triangleIndex=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);zm(b,a)};pw.prototype.__destroy__=function(){wd(this.a)};function I(a){a&&\"object\"===typeof a&&(a=a.a);this.a=as(a);q(I)[this.a]=this}I.prototype=Object.create(w.prototype);I.prototype.constructor=I;I.prototype.b=I;I.c={};c.btRigidBody=I;I.prototype.getCenterOfMassTransform=function(){return r(Tc(this.a),x)};I.prototype.setCenterOfMassTransform=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);fp(b,a)};\nI.prototype.setSleepingThresholds=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);qr(e,a,b)};I.prototype.setDamping=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);pj(e,a,b)};I.prototype.setMassProps=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Wm(e,a,b)};I.prototype.setLinearFactor=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);De(b,a)};\nI.prototype.applyTorque=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ds(b,a)};I.prototype.applyLocalTorque=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ak(b,a)};I.prototype.applyForce=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Ff(e,a,b)};I.prototype.applyCentralForce=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Sk(b,a)};\nI.prototype.applyCentralLocalForce=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Cs(b,a)};I.prototype.applyTorqueImpulse=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);qu(b,a)};I.prototype.applyImpulse=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Jj(e,a,b)};I.prototype.applyCentralImpulse=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Bc(b,a)};I.prototype.updateInertiaTensor=function(){Ur(this.a)};\nI.prototype.getLinearVelocity=function(){return r(Ij(this.a),A)};I.prototype.getAngularVelocity=function(){return r(Ct(this.a),A)};I.prototype.setLinearVelocity=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ft(b,a)};I.prototype.setAngularVelocity=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Oj(b,a)};I.prototype.getMotionState=function(){return r(Zr(this.a),dw)};I.prototype.setMotionState=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);fj(b,a)};\nI.prototype.setAngularFactor=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);wm(b,a)};I.prototype.upcast=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(mg(b,a),I)};I.prototype.setAnisotropicFriction=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);tp(e,a,b)};I.prototype.getCollisionShape=function(){return r(vt(this.a),u)};I.prototype.setContactProcessingThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Hj(b,a)};\nI.prototype.setActivationState=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);cu(b,a)};I.prototype.forceActivationState=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Hu(b,a)};I.prototype.activate=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);void 0===a?Zd(b):Gr(b,a)};I.prototype.isActive=function(){return!!mi(this.a)};I.prototype.isKinematicObject=function(){return!!Ad(this.a)};\nI.prototype.setRestitution=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);av(b,a)};I.prototype.setFriction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Wf(b,a)};I.prototype.setRollingFriction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);br(b,a)};I.prototype.getWorldTransform=function(){return r(Kq(this.a),x)};I.prototype.getCollisionFlags=function(){return Wi(this.a)};I.prototype.setCollisionFlags=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);su(b,a)};\nI.prototype.setWorldTransform=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Mj(b,a)};I.prototype.setCollisionShape=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ui(b,a)};I.prototype.setCcdMotionThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Df(b,a)};I.prototype.setCcdSweptSphereRadius=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Uf(b,a)};I.prototype.getUserIndex=function(){return yr(this.a)};\nI.prototype.setUserIndex=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);jh(b,a)};I.prototype.getUserPointer=function(){return r(cj(this.a),Nv)};I.prototype.setUserPointer=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Yb(b,a)};I.prototype.__destroy__=function(){uu(this.a)};function qw(){this.a=xj();q(qw)[this.a]=this}qw.prototype=Object.create(p.prototype);qw.prototype.constructor=qw;qw.prototype.b=qw;qw.c={};c.btDbvtBroadphase=qw;qw.prototype.__destroy__=function(){lt(this.a)};\nfunction rw(){this.a=En();q(rw)[this.a]=this}rw.prototype=Object.create(gw.prototype);rw.prototype.constructor=rw;rw.prototype.b=rw;rw.c={};c.btDefaultSoftBodySolver=rw;rw.prototype.__destroy__=function(){Jt(this.a)};function sw(a){a&&\"object\"===typeof a&&(a=a.a);this.a=gd(a);q(sw)[this.a]=this}sw.prototype=Object.create(Kv.prototype);sw.prototype.constructor=sw;sw.prototype.b=sw;sw.c={};c.btCollisionDispatcher=sw;sw.prototype.getNumManifolds=function(){return ug(this.a)};\nsw.prototype.getManifoldByIndexInternal=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(Pf(b,a),aw)};sw.prototype.__destroy__=function(){Ac(this.a)};function tw(a,b,e,f,g){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);this.a=void 0===e?Yg(a,b):void 0===f?Zg(a,b,e):void 0===g?bh(a,b,e,f):ch(a,b,e,f,g);q(tw)[this.a]=this}tw.prototype=Object.create(p.prototype);\ntw.prototype.constructor=tw;tw.prototype.b=tw;tw.c={};c.btAxisSweep3=tw;tw.prototype.__destroy__=function(){Bg(this.a)};function Nv(){throw\"cannot construct a VoidPtr, no constructor in IDL\";}Nv.prototype=Object.create(p.prototype);Nv.prototype.constructor=Nv;Nv.prototype.b=Nv;Nv.c={};c.VoidPtr=Nv;Nv.prototype.__destroy__=function(){Xn(this.a)};function J(){this.a=kn();q(J)[this.a]=this}J.prototype=Object.create(p.prototype);J.prototype.constructor=J;J.prototype.b=J;J.c={};c.btSoftBodyWorldInfo=J;\nJ.prototype.get_air_density=function(){return Tt(this.a)};J.prototype.set_air_density=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);kt(b,a)};J.prototype.get_water_density=function(){return ph(this.a)};J.prototype.set_water_density=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);hc(b,a)};J.prototype.get_water_offset=function(){return kv(this.a)};J.prototype.set_water_offset=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Uo(b,a)};J.prototype.get_m_maxDisplacement=function(){return dl(this.a)};\nJ.prototype.set_m_maxDisplacement=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Qt(b,a)};J.prototype.get_water_normal=function(){return r(mr(this.a),A)};J.prototype.set_water_normal=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);nu(b,a)};J.prototype.get_m_broadphase=function(){return r(Nd(this.a),Mv)};J.prototype.set_m_broadphase=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Gg(b,a)};J.prototype.get_m_dispatcher=function(){return r(jk(this.a),Kv)};\nJ.prototype.set_m_dispatcher=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ur(b,a)};J.prototype.get_m_gravity=function(){return r(Jr(this.a),A)};J.prototype.set_m_gravity=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Tk(b,a)};J.prototype.__destroy__=function(){pq(this.a)};\nfunction K(a,b,e,f){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);this.a=void 0===e?Ah(a,b):void 0===f?_emscripten_bind_btConeTwistConstraint_btConeTwistConstraint_3(a,b,e):Eh(a,b,e,f);q(K)[this.a]=this}K.prototype=Object.create(Pv.prototype);K.prototype.constructor=K;K.prototype.b=K;K.c={};c.btConeTwistConstraint=K;\nK.prototype.setLimit=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);or(e,a,b)};K.prototype.setAngularOnly=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Tm(b,a)};K.prototype.setDamping=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Gd(b,a)};K.prototype.enableMotor=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);zi(b,a)};K.prototype.setMaxMotorImpulse=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);uj(b,a)};\nK.prototype.setMaxMotorImpulseNormalized=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);kg(b,a)};K.prototype.setMotorTarget=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Mn(b,a)};K.prototype.setMotorTargetInConstraintSpace=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ko(b,a)};K.prototype.enableFeedback=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);th(b,a)};K.prototype.getBreakingImpulseThreshold=function(){return ns(this.a)};\nK.prototype.setBreakingImpulseThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Bl(b,a)};K.prototype.__destroy__=function(){Zo(this.a)};\nfunction uw(a,b,e,f,g,h,k){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);h&&\"object\"===typeof h&&(h=h.a);k&&\"object\"===typeof k&&(k=k.a);this.a=void 0===e?oc(a,b):void 0===f?el(a,b,e):void 0===g?Tg(a,b,e,f):void 0===h?cl(a,b,e,f,g):void 0===k?$k(a,b,e,f,g,h):al(a,b,e,f,g,h,k);q(uw)[this.a]=this}uw.prototype=Object.create(Pv.prototype);uw.prototype.constructor=uw;uw.prototype.b=uw;\nuw.c={};c.btHingeConstraint=uw;uw.prototype.setLimit=function(a,b,e,f,g){var h=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);void 0===g?hn(h,a,b,e,f):jn(h,a,b,e,f,g)};uw.prototype.enableAngularMotor=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);Gj(f,a,b,e)};\nuw.prototype.setAngularOnly=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);cq(b,a)};uw.prototype.enableMotor=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Tu(b,a)};uw.prototype.setMaxMotorImpulse=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Pr(b,a)};uw.prototype.setMotorTarget=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Pi(e,a,b)};\nuw.prototype.enableFeedback=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);kd(b,a)};uw.prototype.getBreakingImpulseThreshold=function(){return vq(this.a)};uw.prototype.setBreakingImpulseThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Vk(b,a)};uw.prototype.__destroy__=function(){ht(this.a)};function vw(a,b){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);this.a=ym(a,b);q(vw)[this.a]=this}vw.prototype=Object.create(Vv.prototype);\nvw.prototype.constructor=vw;vw.prototype.b=vw;vw.c={};c.btConeShapeZ=vw;vw.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ik(b,a)};vw.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Gf(e,a,b)};vw.prototype.__destroy__=function(){Wu(this.a)};function ww(a,b){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);this.a=rh(a,b);q(ww)[this.a]=this}ww.prototype=Object.create(Vv.prototype);\nww.prototype.constructor=ww;ww.prototype.b=ww;ww.c={};c.btConeShapeX=ww;ww.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Mh(b,a)};ww.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Eq(e,a,b)};ww.prototype.__destroy__=function(){wi(this.a)};function xw(a,b){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);this.a=void 0===a?qt():void 0===b?rt(a):st(a,b);q(xw)[this.a]=this}\nxw.prototype=Object.create(cw.prototype);xw.prototype.constructor=xw;xw.prototype.b=xw;xw.c={};c.btTriangleMesh=xw;xw.prototype.addTriangle=function(a,b,e,f){var g=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);void 0===f?ju(g,a,b,e):lu(g,a,b,e,f)};xw.prototype.__destroy__=function(){xo(this.a)};function yw(){this.a=Ph();q(yw)[this.a]=this}yw.prototype=Object.create(u.prototype);yw.prototype.constructor=yw;\nyw.prototype.b=yw;yw.c={};c.btConvexHullShape=yw;yw.prototype.addPoint=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);void 0===b?$s(e,a):ks(e,a,b)};yw.prototype.setMargin=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ef(b,a)};yw.prototype.getMargin=function(){return Cc(this.a)};yw.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);vr(b,a)};\nyw.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);If(e,a,b)};yw.prototype.__destroy__=function(){cg(this.a)};function L(){this.a=Ht();q(L)[this.a]=this}L.prototype=Object.create(p.prototype);L.prototype.constructor=L;L.prototype.b=L;L.c={};c.btVehicleTuning=L;L.prototype.get_m_suspensionStiffness=function(){return hs(this.a)};\nL.prototype.set_m_suspensionStiffness=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);er(b,a)};L.prototype.get_m_suspensionCompression=function(){return Hk(this.a)};L.prototype.set_m_suspensionCompression=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);dq(b,a)};L.prototype.get_m_suspensionDamping=function(){return dk(this.a)};L.prototype.set_m_suspensionDamping=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Go(b,a)};L.prototype.get_m_maxSuspensionTravelCm=function(){return Zs(this.a)};\nL.prototype.set_m_maxSuspensionTravelCm=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);mk(b,a)};L.prototype.get_m_frictionSlip=function(){return uv(this.a)};L.prototype.set_m_frictionSlip=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Rb(b,a)};L.prototype.get_m_maxSuspensionForce=function(){return Sq(this.a)};L.prototype.set_m_maxSuspensionForce=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ck(b,a)};\nfunction zw(){throw\"cannot construct a btCollisionObjectWrapper, no constructor in IDL\";}zw.prototype=Object.create(p.prototype);zw.prototype.constructor=zw;zw.prototype.b=zw;zw.c={};c.btCollisionObjectWrapper=zw;function Aw(a,b){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);this.a=void 0===a?gi():void 0===b?hi(a):ei(a,b);q(Aw)[this.a]=this}Aw.prototype=Object.create(dw.prototype);Aw.prototype.constructor=Aw;Aw.prototype.b=Aw;Aw.c={};c.btDefaultMotionState=Aw;\nAw.prototype.getWorldTransform=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Dc(b,a)};Aw.prototype.setWorldTransform=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Pl(b,a)};Aw.prototype.get_m_graphicsWorldTrans=function(){return r(Ed(this.a),x)};Aw.prototype.set_m_graphicsWorldTrans=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Rm(b,a)};Aw.prototype.__destroy__=function(){we(this.a)};function M(a){a&&\"object\"===typeof a&&(a=a.a);this.a=mh(a);q(M)[this.a]=this}\nM.prototype=Object.create(p.prototype);M.prototype.constructor=M;M.prototype.b=M;M.c={};c.btWheelInfo=M;M.prototype.getSuspensionRestLength=function(){return Qm(this.a)};M.prototype.updateWheel=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Wo(e,a,b)};M.prototype.get_m_suspensionStiffness=function(){return rc(this.a)};M.prototype.set_m_suspensionStiffness=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);lq(b,a)};M.prototype.get_m_frictionSlip=function(){return hk(this.a)};\nM.prototype.set_m_frictionSlip=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);tt(b,a)};M.prototype.get_m_engineForce=function(){return Je(this.a)};M.prototype.set_m_engineForce=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);tj(b,a)};M.prototype.get_m_rollInfluence=function(){return Yd(this.a)};M.prototype.set_m_rollInfluence=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);On(b,a)};M.prototype.get_m_suspensionRestLength1=function(){return qc(this.a)};\nM.prototype.set_m_suspensionRestLength1=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);vu(b,a)};M.prototype.get_m_wheelsRadius=function(){return Et(this.a)};M.prototype.set_m_wheelsRadius=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);df(b,a)};M.prototype.get_m_wheelsDampingCompression=function(){return du(this.a)};M.prototype.set_m_wheelsDampingCompression=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ci(b,a)};M.prototype.get_m_wheelsDampingRelaxation=function(){return xt(this.a)};\nM.prototype.set_m_wheelsDampingRelaxation=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Mt(b,a)};M.prototype.get_m_steering=function(){return tu(this.a)};M.prototype.set_m_steering=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);sq(b,a)};M.prototype.get_m_maxSuspensionForce=function(){return hu(this.a)};M.prototype.set_m_maxSuspensionForce=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Qh(b,a)};M.prototype.get_m_maxSuspensionTravelCm=function(){return gm(this.a)};\nM.prototype.set_m_maxSuspensionTravelCm=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);mn(b,a)};M.prototype.get_m_wheelsSuspensionForce=function(){return vl(this.a)};M.prototype.set_m_wheelsSuspensionForce=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);nn(b,a)};M.prototype.get_m_bIsFrontWheel=function(){return!!un(this.a)};M.prototype.set_m_bIsFrontWheel=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Cf(b,a)};\nM.prototype.get_m_raycastInfo=function(){return r(mv(this.a),N)};M.prototype.set_m_raycastInfo=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ig(b,a)};M.prototype.get_m_chassisConnectionPointCS=function(){return r(hp(this.a),A)};M.prototype.set_m_chassisConnectionPointCS=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ai(b,a)};M.prototype.get_m_worldTransform=function(){return r(Fs(this.a),x)};\nM.prototype.set_m_worldTransform=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Mk(b,a)};M.prototype.get_m_wheelDirectionCS=function(){return r(bn(this.a),A)};M.prototype.set_m_wheelDirectionCS=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);tv(b,a)};M.prototype.get_m_wheelAxleCS=function(){return r(Eu(this.a),A)};M.prototype.set_m_wheelAxleCS=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ku(b,a)};M.prototype.get_m_rotation=function(){return Wt(this.a)};\nM.prototype.set_m_rotation=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);tl(b,a)};M.prototype.get_m_deltaRotation=function(){return Np(this.a)};M.prototype.set_m_deltaRotation=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);sm(b,a)};M.prototype.get_m_brake=function(){return Lp(this.a)};M.prototype.set_m_brake=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Lk(b,a)};M.prototype.get_m_clippedInvContactDotSuspension=function(){return Nt(this.a)};\nM.prototype.set_m_clippedInvContactDotSuspension=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);rp(b,a)};M.prototype.get_m_suspensionRelativeVelocity=function(){return Cj(this.a)};M.prototype.set_m_suspensionRelativeVelocity=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);As(b,a)};M.prototype.get_m_skidInfo=function(){return Fl(this.a)};M.prototype.set_m_skidInfo=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Yt(b,a)};M.prototype.__destroy__=function(){Rg(this.a)};\nfunction O(a,b,e,f){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);this.a=void 0===a?bv():void 0===b?_emscripten_bind_btVector4_btVector4_1(a):void 0===e?_emscripten_bind_btVector4_btVector4_2(a,b):void 0===f?_emscripten_bind_btVector4_btVector4_3(a,b,e):dv(a,b,e,f);q(O)[this.a]=this}O.prototype=Object.create(A.prototype);O.prototype.constructor=O;O.prototype.b=O;O.c={};c.btVector4=O;O.prototype.w=function(){return Es(this.a)};\nO.prototype.setValue=function(a,b,e,f){var g=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);$d(g,a,b,e,f)};O.prototype.length=O.prototype.length=function(){return Om(this.a)};O.prototype.x=function(){return cv(this.a)};O.prototype.y=function(){return Wn(this.a)};O.prototype.z=function(){return fr(this.a)};O.prototype.setX=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);fg(b,a)};\nO.prototype.setY=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);sc(b,a)};O.prototype.setZ=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);og(b,a)};O.prototype.normalize=function(){ss(this.a)};O.prototype.rotate=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);return r(Dd(e,a,b),A)};O.prototype.dot=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return ij(b,a)};\nO.prototype.op_mul=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(Sh(b,a),A)};O.prototype.op_add=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(Qg(b,a),A)};O.prototype.op_sub=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(iv(b,a),A)};O.prototype.__destroy__=function(){Cp(this.a)};function Bw(){this.a=gs();q(Bw)[this.a]=this}Bw.prototype=Object.create(p.prototype);Bw.prototype.constructor=Bw;Bw.prototype.b=Bw;Bw.c={};\nc.btDefaultCollisionConstructionInfo=Bw;Bw.prototype.__destroy__=function(){wq(this.a)};function Cw(){throw\"cannot construct a btVehicleRaycasterResult, no constructor in IDL\";}Cw.prototype=Object.create(p.prototype);Cw.prototype.constructor=Cw;Cw.prototype.b=Cw;Cw.c={};c.btVehicleRaycasterResult=Cw;Cw.prototype.get_m_hitPointInWorld=function(){return r(Bi(this.a),A)};Cw.prototype.set_m_hitPointInWorld=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);im(b,a)};\nCw.prototype.get_m_hitNormalInWorld=function(){return r(Xb(this.a),A)};Cw.prototype.set_m_hitNormalInWorld=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Cm(b,a)};Cw.prototype.get_m_distFraction=function(){return qs(this.a)};Cw.prototype.set_m_distFraction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Hh(b,a)};Cw.prototype.__destroy__=function(){zf(this.a)};function Dw(){throw\"cannot construct a btConstraintSolver, no constructor in IDL\";}Dw.prototype=Object.create(p.prototype);\nDw.prototype.constructor=Dw;Dw.prototype.b=Dw;Dw.c={};c.btConstraintSolver=Dw;Dw.prototype.__destroy__=function(){kp(this.a)};function P(a,b,e){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);this.a=ni(a,b,e);q(P)[this.a]=this}P.prototype=Object.create(Wv.prototype);P.prototype.constructor=P;P.prototype.b=P;P.c={};c.btRaycastVehicle=P;\nP.prototype.applyEngineForce=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);zo(e,a,b)};P.prototype.setSteeringValue=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Le(e,a,b)};P.prototype.getWheelTransformWS=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(ek(b,a),x)};\nP.prototype.updateWheelTransform=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Hr(e,a,b)};P.prototype.addWheel=function(a,b,e,f,g,h,k){var m=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);h&&\"object\"===typeof h&&(h=h.a);k&&\"object\"===typeof k&&(k=k.a);return r(Ou(m,a,b,e,f,g,h,k),M)};P.prototype.getNumWheels=function(){return lk(this.a)};\nP.prototype.getRigidBody=function(){return r(gu(this.a),I)};P.prototype.getWheelInfo=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(ir(b,a),M)};P.prototype.setBrake=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Bo(e,a,b)};P.prototype.setCoordinateSystem=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);hf(f,a,b,e)};P.prototype.getCurrentSpeedKmHour=function(){return Ie(this.a)};\nP.prototype.getChassisWorldTransform=function(){return r(Qk(this.a),x)};P.prototype.rayCast=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return Ld(b,a)};P.prototype.updateVehicle=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Eo(b,a)};P.prototype.resetSuspension=function(){bt(this.a)};P.prototype.getSteeringValue=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return pv(b,a)};\nP.prototype.updateWheelTransformsWS=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);void 0===b?Kk(e,a):Ru(e,a,b)};P.prototype.setPitchControl=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);uh(b,a)};P.prototype.updateSuspension=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);od(b,a)};P.prototype.updateFriction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Aq(b,a)};P.prototype.getRightAxis=function(){return Ve(this.a)};\nP.prototype.getUpAxis=function(){return He(this.a)};P.prototype.getForwardAxis=function(){return An(this.a)};P.prototype.getForwardVector=function(){return r(ys(this.a),A)};P.prototype.getUserConstraintType=function(){return Us(this.a)};P.prototype.setUserConstraintType=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);xu(b,a)};P.prototype.setUserConstraintId=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Vj(b,a)};P.prototype.getUserConstraintId=function(){return fn(this.a)};\nP.prototype.updateAction=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);gn(e,a,b)};P.prototype.__destroy__=function(){Ui(this.a)};function Ew(a){a&&\"object\"===typeof a&&(a=a.a);this.a=ml(a);q(Ew)[this.a]=this}Ew.prototype=Object.create(Zv.prototype);Ew.prototype.constructor=Ew;Ew.prototype.b=Ew;Ew.c={};c.btCylinderShapeX=Ew;Ew.prototype.setMargin=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);yg(b,a)};Ew.prototype.getMargin=function(){return oj(this.a)};\nEw.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);wj(b,a)};Ew.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);vs(e,a,b)};Ew.prototype.__destroy__=function(){Sr(this.a)};function Fw(a){a&&\"object\"===typeof a&&(a=a.a);this.a=pk(a);q(Fw)[this.a]=this}Fw.prototype=Object.create(Zv.prototype);Fw.prototype.constructor=Fw;Fw.prototype.b=Fw;Fw.c={};c.btCylinderShapeZ=Fw;\nFw.prototype.setMargin=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Vf(b,a)};Fw.prototype.getMargin=function(){return bc(this.a)};Fw.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Uu(b,a)};Fw.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);xm(e,a,b)};Fw.prototype.__destroy__=function(){of(this.a)};function Gw(){this.a=Ml();q(Gw)[this.a]=this}Gw.prototype=Object.create(p.prototype);\nGw.prototype.constructor=Gw;Gw.prototype.b=Gw;Gw.c={};c.btSequentialImpulseConstraintSolver=Gw;Gw.prototype.__destroy__=function(){Si(this.a)};function N(){throw\"cannot construct a RaycastInfo, no constructor in IDL\";}N.prototype=Object.create(p.prototype);N.prototype.constructor=N;N.prototype.b=N;N.c={};c.RaycastInfo=N;N.prototype.get_m_contactNormalWS=function(){return r(oh(this.a),A)};N.prototype.set_m_contactNormalWS=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Yn(b,a)};\nN.prototype.get_m_contactPointWS=function(){return r(Kf(this.a),A)};N.prototype.set_m_contactPointWS=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ao(b,a)};N.prototype.get_m_suspensionLength=function(){return Zm(this.a)};N.prototype.set_m_suspensionLength=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);mq(b,a)};N.prototype.get_m_hardPointWS=function(){return r(Yo(this.a),A)};N.prototype.set_m_hardPointWS=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);$f(b,a)};\nN.prototype.get_m_wheelDirectionWS=function(){return r(ep(this.a),A)};N.prototype.set_m_wheelDirectionWS=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Wb(b,a)};N.prototype.get_m_wheelAxleWS=function(){return r(xc(this.a),A)};N.prototype.set_m_wheelAxleWS=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Do(b,a)};N.prototype.get_m_isInContact=function(){return!!El(this.a)};N.prototype.set_m_isInContact=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Sd(b,a)};\nN.prototype.get_m_groundObject=function(){return Lj(this.a)};N.prototype.set_m_groundObject=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);yn(b,a)};N.prototype.__destroy__=function(){um(this.a)};function Hw(){throw\"cannot construct a tNodeArray, no constructor in IDL\";}Hw.prototype=Object.create(p.prototype);Hw.prototype.constructor=Hw;Hw.prototype.b=Hw;Hw.c={};c.tNodeArray=Hw;Hw.prototype.size=function(){return be(this.a)};\nHw.prototype.at=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(Fp(b,a),Node)};Hw.prototype.__destroy__=function(){Ej(this.a)};function Q(a,b,e,f){Fv();a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);\"object\"==typeof f&&(f=Iv(f));this.a=up(a,b,e,f);q(Q)[this.a]=this}Q.prototype=Object.create(w.prototype);Q.prototype.constructor=Q;Q.prototype.b=Q;Q.c={};c.btSoftBody=Q;\nQ.prototype.checkLink=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);return!!wk(e,a,b)};Q.prototype.checkFace=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);return!!Js(f,a,b,e)};Q.prototype.appendMaterial=function(){return r(Pt(this.a),iw)};Q.prototype.appendNode=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);jf(e,a,b)};\nQ.prototype.appendLink=function(a,b,e,f){var g=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);Nh(g,a,b,e,f)};Q.prototype.appendFace=function(a,b,e,f){var g=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);fe(g,a,b,e,f)};\nQ.prototype.appendTetra=function(a,b,e,f,g){var h=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);vi(h,a,b,e,f,g)};Q.prototype.appendAnchor=function(a,b,e,f){var g=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);xd(g,a,b,e,f)};Q.prototype.getTotalMass=function(){return aj(this.a)};\nQ.prototype.setTotalMass=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Qf(e,a,b)};Q.prototype.setMass=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);te(e,a,b)};Q.prototype.transform=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);oi(b,a)};Q.prototype.translate=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);yh(b,a)};\nQ.prototype.rotate=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);pc(b,a)};Q.prototype.scale=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);on(b,a)};Q.prototype.generateClusters=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);return void 0===b?Ql(e,a):Ol(e,a,b)};Q.prototype.upcast=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(rr(b,a),Q)};\nQ.prototype.setAnisotropicFriction=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Xr(e,a,b)};Q.prototype.getCollisionShape=function(){return r(xk(this.a),u)};Q.prototype.setContactProcessingThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);eo(b,a)};Q.prototype.setActivationState=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);xr(b,a)};\nQ.prototype.forceActivationState=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);jj(b,a)};Q.prototype.activate=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);void 0===a?vp(b):Yq(b,a)};Q.prototype.isActive=function(){return!!lp(this.a)};Q.prototype.isKinematicObject=function(){return!!Sc(this.a)};Q.prototype.setRestitution=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ut(b,a)};Q.prototype.setFriction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);pr(b,a)};\nQ.prototype.setRollingFriction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);sg(b,a)};Q.prototype.getWorldTransform=function(){return r(wo(this.a),x)};Q.prototype.getCollisionFlags=function(){return Pk(this.a)};Q.prototype.setCollisionFlags=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Lf(b,a)};Q.prototype.setWorldTransform=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);gl(b,a)};\nQ.prototype.setCollisionShape=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ip(b,a)};Q.prototype.setCcdMotionThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);mc(b,a)};Q.prototype.setCcdSweptSphereRadius=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);sh(b,a)};Q.prototype.getUserIndex=function(){return so(this.a)};Q.prototype.setUserIndex=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);gp(b,a)};\nQ.prototype.getUserPointer=function(){return r(Ne(this.a),Nv)};Q.prototype.setUserPointer=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);se(b,a)};Q.prototype.get_m_cfg=function(){return r(Gn(this.a),R)};Q.prototype.set_m_cfg=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Kp(b,a)};Q.prototype.get_m_nodes=function(){return r(Dr(this.a),Hw)};Q.prototype.set_m_nodes=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);jt(b,a)};\nQ.prototype.get_m_materials=function(){return r(iu(this.a),mw)};Q.prototype.set_m_materials=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);xf(b,a)};Q.prototype.__destroy__=function(){Er(this.a)};\nfunction Iw(a,b,e,f,g,h,k,m,v){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);h&&\"object\"===typeof h&&(h=h.a);k&&\"object\"===typeof k&&(k=k.a);m&&\"object\"===typeof m&&(m=m.a);v&&\"object\"===typeof v&&(v=v.a);this.a=Xq(a,b,e,f,g,h,k,m,v);q(Iw)[this.a]=this}Iw.prototype=Object.create(Qv.prototype);Iw.prototype.constructor=Iw;Iw.prototype.b=Iw;Iw.c={};c.btHeightfieldTerrainShape=Iw;\nIw.prototype.setMargin=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Gl(b,a)};Iw.prototype.getMargin=function(){return Gi(this.a)};Iw.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);md(b,a)};Iw.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);ej(e,a,b)};Iw.prototype.__destroy__=function(){fm(this.a)};function R(){throw\"cannot construct a Config, no constructor in IDL\";}\nR.prototype=Object.create(p.prototype);R.prototype.constructor=R;R.prototype.b=R;R.c={};c.Config=R;R.prototype.get_kVCF=function(){return Te(this.a)};R.prototype.set_kVCF=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);om(b,a)};R.prototype.get_kDP=function(){return Qj(this.a)};R.prototype.set_kDP=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ys(b,a)};R.prototype.get_kDG=function(){return yk(this.a)};\nR.prototype.set_kDG=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ln(b,a)};R.prototype.get_kLF=function(){return Uh(this.a)};R.prototype.set_kLF=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Vt(b,a)};R.prototype.get_kPR=function(){return hq(this.a)};R.prototype.set_kPR=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);vf(b,a)};R.prototype.get_kVC=function(){return hm(this.a)};R.prototype.set_kVC=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);af(b,a)};\nR.prototype.get_kDF=function(){return pu(this.a)};R.prototype.set_kDF=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Wq(b,a)};R.prototype.get_kMT=function(){return Em(this.a)};R.prototype.set_kMT=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ng(b,a)};R.prototype.get_kCHR=function(){return ue(this.a)};R.prototype.set_kCHR=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);wu(b,a)};R.prototype.get_kKHR=function(){return ft(this.a)};\nR.prototype.set_kKHR=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);rf(b,a)};R.prototype.get_kSHR=function(){return dj(this.a)};R.prototype.set_kSHR=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Vg(b,a)};R.prototype.get_kAHR=function(){return Tl(this.a)};R.prototype.set_kAHR=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Fi(b,a)};R.prototype.get_kSRHR_CL=function(){return Jb(this.a)};\nR.prototype.set_kSRHR_CL=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);tg(b,a)};R.prototype.get_kSKHR_CL=function(){return Ks(this.a)};R.prototype.set_kSKHR_CL=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Zk(b,a)};R.prototype.get_kSSHR_CL=function(){return Jo(this.a)};R.prototype.set_kSSHR_CL=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);dd(b,a)};R.prototype.get_kSR_SPLT_CL=function(){return Ke(this.a)};\nR.prototype.set_kSR_SPLT_CL=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Jc(b,a)};R.prototype.get_kSK_SPLT_CL=function(){return Dh(this.a)};R.prototype.set_kSK_SPLT_CL=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);lj(b,a)};R.prototype.get_kSS_SPLT_CL=function(){return Rr(this.a)};R.prototype.set_kSS_SPLT_CL=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Zt(b,a)};R.prototype.get_maxvolume=function(){return Nq(this.a)};\nR.prototype.set_maxvolume=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Nf(b,a)};R.prototype.get_timescale=function(){return Hm(this.a)};R.prototype.set_timescale=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ih(b,a)};R.prototype.get_viterations=function(){return ii(this.a)};R.prototype.set_viterations=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);mt(b,a)};R.prototype.get_piterations=function(){return xh(this.a)};\nR.prototype.set_piterations=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);hh(b,a)};R.prototype.get_diterations=function(){return Lc(this.a)};R.prototype.set_diterations=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ts(b,a)};R.prototype.get_citerations=function(){return pn(this.a)};R.prototype.set_citerations=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Is(b,a)};R.prototype.get_collisions=function(){return Sj(this.a)};\nR.prototype.set_collisions=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ql(b,a)};R.prototype.__destroy__=function(){bk(this.a)};function Node(){throw\"cannot construct a Node, no constructor in IDL\";}Node.prototype=Object.create(p.prototype);Node.prototype.constructor=Node;Node.prototype.b=Node;Node.c={};c.Node=Node;Node.prototype.get_m_x=function(){return r(Ck(this.a),A)};Node.prototype.set_m_x=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);tq(b,a)};\nNode.prototype.get_m_n=function(){return r(Tj(this.a),A)};Node.prototype.set_m_n=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ub(b,a)};Node.prototype.__destroy__=function(){Ag(this.a)};function Jw(){this.a=Un();q(Jw)[this.a]=this}Jw.prototype=Object.create(p.prototype);Jw.prototype.constructor=Jw;Jw.prototype.b=Jw;Jw.c={};c.btGhostPairCallback=Jw;Jw.prototype.__destroy__=function(){Jq(this.a)};function Kw(){throw\"cannot construct a btOverlappingPairCallback, no constructor in IDL\";}\nKw.prototype=Object.create(p.prototype);Kw.prototype.constructor=Kw;Kw.prototype.b=Kw;Kw.c={};c.btOverlappingPairCallback=Kw;Kw.prototype.__destroy__=function(){Bj(this.a)};function S(a,b,e,f){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);this.a=void 0===f?Mi(a,b,e):Jp(a,b,e,f);q(S)[this.a]=this}S.prototype=Object.create(Wv.prototype);S.prototype.constructor=S;S.prototype.b=S;S.c={};\nc.btKinematicCharacterController=S;S.prototype.setUpAxis=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);bd(b,a)};S.prototype.setWalkDirection=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Nb(b,a)};S.prototype.setVelocityForTimeInterval=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);zs(e,a,b)};S.prototype.warp=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);uo(b,a)};\nS.prototype.preStep=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);yo(b,a)};S.prototype.playerStep=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Pp(e,a,b)};S.prototype.setFallSpeed=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);bu(b,a)};S.prototype.setJumpSpeed=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Cq(b,a)};S.prototype.setMaxJumpHeight=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);rv(b,a)};\nS.prototype.canJump=function(){return!!ji(this.a)};S.prototype.jump=function(){gg(this.a)};S.prototype.setGravity=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Td(b,a)};S.prototype.getGravity=function(){return ls(this.a)};S.prototype.setMaxSlope=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);jc(b,a)};S.prototype.getMaxSlope=function(){return Mu(this.a)};S.prototype.getGhostObject=function(){return r($r(this.a),U)};\nS.prototype.setUseGhostSweepTest=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);rd(b,a)};S.prototype.onGround=function(){return!!hr(this.a)};S.prototype.updateAction=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);di(e,a,b)};S.prototype.__destroy__=function(){ev(this.a)};function Lw(){throw\"cannot construct a btSoftBodyArray, no constructor in IDL\";}Lw.prototype=Object.create(p.prototype);Lw.prototype.constructor=Lw;Lw.prototype.b=Lw;Lw.c={};\nc.btSoftBodyArray=Lw;Lw.prototype.size=function(){return Tp(this.a)};Lw.prototype.at=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(ki(b,a),Q)};Lw.prototype.__destroy__=function(){qk(this.a)};function Mw(a,b){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);this.a=uk(a,b);q(Mw)[this.a]=this}Mw.prototype=Object.create(Qv.prototype);Mw.prototype.constructor=Mw;Mw.prototype.b=Mw;Mw.c={};c.btStaticPlaneShape=Mw;\nMw.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Up(b,a)};Mw.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Gp(e,a,b)};Mw.prototype.__destroy__=function(){Su(this.a)};function Lv(){throw\"cannot construct a btOverlappingPairCache, no constructor in IDL\";}Lv.prototype=Object.create(p.prototype);Lv.prototype.constructor=Lv;Lv.prototype.b=Lv;Lv.c={};c.btOverlappingPairCache=Lv;\nLv.prototype.setInternalGhostPairCallback=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);tk(b,a)};Lv.prototype.__destroy__=function(){ih(this.a)};function V(a,b,e,f,g){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);this.a=Gh(a,b,e,f,g);q(V)[this.a]=this}V.prototype=Object.create(C.prototype);V.prototype.constructor=V;V.prototype.b=V;V.c={};c.btSoftRigidDynamicsWorld=V;\nV.prototype.addSoftBody=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);bf(f,a,b,e)};V.prototype.removeSoftBody=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Nc(b,a)};V.prototype.removeCollisionObject=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Th(b,a)};V.prototype.getWorldInfo=function(){return r(Bu(this.a),J)};V.prototype.getSoftBodyArray=function(){return r(Sg(this.a),Lw)};\nV.prototype.getDispatcher=function(){return r(pi(this.a),Kv)};V.prototype.rayTest=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);Ii(f,a,b,e)};V.prototype.getPairCache=function(){return r(po(this.a),Lv)};V.prototype.getDispatchInfo=function(){return r(mu(this.a),t)};\nV.prototype.addCollisionObject=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);void 0===b?Xh(f,a):void 0===e?Wh(f,a,b):Vh(f,a,b,e)};V.prototype.getBroadphase=function(){return r(sl(this.a),Mv)};\nV.prototype.convexSweepTest=function(a,b,e,f,g){var h=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);Dm(h,a,b,e,f,g)};V.prototype.contactPairTest=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);ap(f,a,b,e)};\nV.prototype.contactTest=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);yu(e,a,b)};V.prototype.setGravity=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ge(b,a)};V.prototype.getGravity=function(){return r(Pq(this.a),A)};\nV.prototype.addRigidBody=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);void 0===b?Ws(f,a):void 0===e?_emscripten_bind_btSoftRigidDynamicsWorld_addRigidBody_2(f,a,b):Xs(f,a,b,e)};V.prototype.removeRigidBody=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);$u(b,a)};V.prototype.addConstraint=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);void 0===b?cd(e,a):ou(e,a,b)};\nV.prototype.removeConstraint=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);wc(b,a)};V.prototype.stepSimulation=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);return void 0===b?rm(f,a):void 0===e?Rt(f,a,b):pm(f,a,b,e)};V.prototype.addAction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Hc(b,a)};V.prototype.removeAction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Xd(b,a)};\nV.prototype.getSolverInfo=function(){return r(Of(this.a),Ov)};V.prototype.__destroy__=function(){vc(this.a)};function x(a,b){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);this.a=void 0===a?Ze():void 0===b?_emscripten_bind_btTransform_btTransform_1(a):Ye(a,b);q(x)[this.a]=this}x.prototype=Object.create(p.prototype);x.prototype.constructor=x;x.prototype.b=x;x.c={};c.btTransform=x;x.prototype.setIdentity=function(){Uc(this.a)};\nx.prototype.setOrigin=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ng(b,a)};x.prototype.setRotation=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ug(b,a)};x.prototype.getOrigin=function(){return r(et(this.a),A)};x.prototype.getRotation=function(){return r(Yk(this.a),W)};x.prototype.getBasis=function(){return r(qg(this.a),hw)};x.prototype.setFromOpenGLMatrix=function(a){var b=this.a;Fv();\"object\"==typeof a&&(a=Iv(a));Lu(b,a)};x.prototype.__destroy__=function(){Du(this.a)};\nfunction X(a,b){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);this.a=Bp(a,b);q(X)[this.a]=this}X.prototype=Object.create(Uv.prototype);X.prototype.constructor=X;X.prototype.b=X;X.c={};c.ClosestRayResultCallback=X;X.prototype.hasHit=function(){return!!Ek(this.a)};X.prototype.get_m_rayFromWorld=function(){return r(co(this.a),A)};X.prototype.set_m_rayFromWorld=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);cp(b,a)};\nX.prototype.get_m_rayToWorld=function(){return r(Rf(this.a),A)};X.prototype.set_m_rayToWorld=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Kt(b,a)};X.prototype.get_m_hitNormalWorld=function(){return r(pt(this.a),A)};X.prototype.set_m_hitNormalWorld=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Qu(b,a)};X.prototype.get_m_hitPointWorld=function(){return r(Zb(this.a),A)};X.prototype.set_m_hitPointWorld=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);yf(b,a)};\nX.prototype.get_m_collisionFilterGroup=function(){return Lt(this.a)};X.prototype.set_m_collisionFilterGroup=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Xg(b,a)};X.prototype.get_m_collisionFilterMask=function(){return Yj(this.a)};X.prototype.set_m_collisionFilterMask=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ep(b,a)};X.prototype.get_m_collisionObject=function(){return r($n(this.a),w)};\nX.prototype.set_m_collisionObject=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Rd(b,a)};X.prototype.__destroy__=function(){wg(this.a)};function Nw(a){a&&\"object\"===typeof a&&(a=a.a);this.a=void 0===a?vh():dt(a);q(Nw)[this.a]=this}Nw.prototype=Object.create(Sv.prototype);Nw.prototype.constructor=Nw;Nw.prototype.b=Nw;Nw.c={};c.btSoftBodyRigidBodyCollisionConfiguration=Nw;Nw.prototype.__destroy__=function(){Dq(this.a)};function Ow(){this.a=Ss();q(Ow)[this.a]=this}Ow.prototype=Object.create(fw.prototype);\nOw.prototype.constructor=Ow;Ow.prototype.b=Ow;Ow.c={};c.ConcreteContactResultCallback=Ow;Ow.prototype.addSingleResult=function(a,b,e,f,g,h,k){var m=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);h&&\"object\"===typeof h&&(h=h.a);k&&\"object\"===typeof k&&(k=k.a);return Xo(m,a,b,e,f,g,h,k)};Ow.prototype.__destroy__=function(){Co(this.a)};\nfunction Pw(a,b,e){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);this.a=void 0===e?Tq(a,b):Uq(a,b,e);q(Pw)[this.a]=this}Pw.prototype=Object.create(Tv.prototype);Pw.prototype.constructor=Pw;Pw.prototype.b=Pw;Pw.c={};c.btBvhTriangleMeshShape=Pw;Pw.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ae(b,a)};\nPw.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Dg(e,a,b)};Pw.prototype.__destroy__=function(){Hs(this.a)};\nfunction Qw(a,b,e,f,g){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);this.a=void 0===f?Cu(a,b,e):void 0===g?_emscripten_bind_btSliderConstraint_btSliderConstraint_4(a,b,e,f):Fd(a,b,e,f,g);q(Qw)[this.a]=this}Qw.prototype=Object.create(Pv.prototype);Qw.prototype.constructor=Qw;Qw.prototype.b=Qw;Qw.c={};c.btSliderConstraint=Qw;\nQw.prototype.setLowerLinLimit=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Bt(b,a)};Qw.prototype.setUpperLinLimit=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);zh(b,a)};Qw.prototype.setLowerAngLimit=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Zn(b,a)};Qw.prototype.setUpperAngLimit=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Jn(b,a)};Qw.prototype.enableFeedback=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);go(b,a)};\nQw.prototype.getBreakingImpulseThreshold=function(){return Ki(this.a)};Qw.prototype.setBreakingImpulseThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);oq(b,a)};Qw.prototype.__destroy__=function(){Gu(this.a)};function U(){this.a=Hd();q(U)[this.a]=this}U.prototype=Object.create(D.prototype);U.prototype.constructor=U;U.prototype.b=U;U.c={};c.btPairCachingGhostObject=U;\nU.prototype.setAnisotropicFriction=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Bk(e,a,b)};U.prototype.getCollisionShape=function(){return r(Ok(this.a),u)};U.prototype.setContactProcessingThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Wj(b,a)};U.prototype.setActivationState=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);km(b,a)};\nU.prototype.forceActivationState=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ve(b,a)};U.prototype.activate=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);void 0===a?oe(b):pe(b,a)};U.prototype.isActive=function(){return!!sv(this.a)};U.prototype.isKinematicObject=function(){return!!Dp(this.a)};U.prototype.setRestitution=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ei(b,a)};U.prototype.setFriction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);rg(b,a)};\nU.prototype.setRollingFriction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);cr(b,a)};U.prototype.getWorldTransform=function(){return r(ri(this.a),x)};U.prototype.getCollisionFlags=function(){return St(this.a)};U.prototype.setCollisionFlags=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Yr(b,a)};U.prototype.setWorldTransform=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);uq(b,a)};\nU.prototype.setCollisionShape=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);to(b,a)};U.prototype.setCcdMotionThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Ym(b,a)};U.prototype.setCcdSweptSphereRadius=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Fj(b,a)};U.prototype.getUserIndex=function(){return $e(this.a)};U.prototype.setUserIndex=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);li(b,a)};\nU.prototype.getUserPointer=function(){return r(it(this.a),Nv)};U.prototype.setUserPointer=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);me(b,a)};U.prototype.getNumOverlappingObjects=function(){return fo(this.a)};U.prototype.getOverlappingObject=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(Gq(b,a),w)};U.prototype.__destroy__=function(){le(this.a)};function G(){throw\"cannot construct a btManifoldPoint, no constructor in IDL\";}G.prototype=Object.create(p.prototype);\nG.prototype.constructor=G;G.prototype.b=G;G.c={};c.btManifoldPoint=G;G.prototype.getPositionWorldOnA=function(){return r(Nu(this.a),A)};G.prototype.getPositionWorldOnB=function(){return r(Bn(this.a),A)};G.prototype.getAppliedImpulse=function(){return ag(this.a)};G.prototype.getDistance=function(){return Ju(this.a)};G.prototype.get_m_localPointA=function(){return r(es(this.a),A)};G.prototype.set_m_localPointA=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Lg(b,a)};\nG.prototype.get_m_localPointB=function(){return r(yt(this.a),A)};G.prototype.set_m_localPointB=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);pd(b,a)};G.prototype.get_m_positionWorldOnB=function(){return r(Dj(this.a),A)};G.prototype.set_m_positionWorldOnB=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);nd(b,a)};G.prototype.get_m_positionWorldOnA=function(){return r(Cn(this.a),A)};G.prototype.set_m_positionWorldOnA=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);wt(b,a)};\nG.prototype.get_m_normalWorldOnB=function(){return r(Gs(this.a),A)};G.prototype.set_m_normalWorldOnB=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);is(b,a)};G.prototype.__destroy__=function(){Mm(this.a)};\nfunction Rw(a,b,e,f){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);this.a=void 0===e?Bq(a,b):void 0===f?_emscripten_bind_btPoint2PointConstraint_btPoint2PointConstraint_3(a,b,e):zq(a,b,e,f);q(Rw)[this.a]=this}Rw.prototype=Object.create(Pv.prototype);Rw.prototype.constructor=Rw;Rw.prototype.b=Rw;Rw.c={};c.btPoint2PointConstraint=Rw;Rw.prototype.setPivotA=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Lq(b,a)};\nRw.prototype.setPivotB=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Iu(b,a)};Rw.prototype.getPivotInA=function(){return r(Sl(this.a),A)};Rw.prototype.getPivotInB=function(){return r(Op(this.a),A)};Rw.prototype.enableFeedback=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Wg(b,a)};Rw.prototype.getBreakingImpulseThreshold=function(){return ct(this.a)};Rw.prototype.setBreakingImpulseThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ce(b,a)};\nRw.prototype.get_m_setting=function(){return r(yd(this.a),ow)};Rw.prototype.set_m_setting=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Kb(b,a)};Rw.prototype.__destroy__=function(){Me(this.a)};function Sw(){this.a=yj();q(Sw)[this.a]=this}Sw.prototype=Object.create(p.prototype);Sw.prototype.constructor=Sw;Sw.prototype.b=Sw;Sw.c={};c.btSoftBodyHelpers=Sw;\nSw.prototype.CreateRope=function(a,b,e,f,g){var h=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);return r(Ti(h,a,b,e,f,g),Q)};\nSw.prototype.CreatePatch=function(a,b,e,f,g,h,k,m,v){var B=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);h&&\"object\"===typeof h&&(h=h.a);k&&\"object\"===typeof k&&(k=k.a);m&&\"object\"===typeof m&&(m=m.a);v&&\"object\"===typeof v&&(v=v.a);return r(Ar(B,a,b,e,f,g,h,k,m,v),Q)};\nSw.prototype.CreatePatchUV=function(a,b,e,f,g,h,k,m,v,B){var z=this.a;Fv();a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);h&&\"object\"===typeof h&&(h=h.a);k&&\"object\"===typeof k&&(k=k.a);m&&\"object\"===typeof m&&(m=m.a);v&&\"object\"===typeof v&&(v=v.a);\"object\"==typeof B&&(B=Iv(B));return r(Sn(z,a,b,e,f,g,h,k,m,v,B),Q)};\nSw.prototype.CreateEllipsoid=function(a,b,e,f){var g=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);return r(Dl(g,a,b,e,f),Q)};\nSw.prototype.CreateFromTriMesh=function(a,b,e,f,g){var h=this.a;Fv();a&&\"object\"===typeof a&&(a=a.a);\"object\"==typeof b&&(b=Iv(b));if(\"object\"==typeof e&&\"object\"===typeof e){var k=Gv(e,l);Hv(e,l,k);e=k}f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);return r(Vn(h,a,b,e,f,g),Q)};\nSw.prototype.CreateFromConvexHull=function(a,b,e,f){var g=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);return r(Zh(g,a,b,e,f),Q)};Sw.prototype.__destroy__=function(){ut(this.a)};function Tw(a){a&&\"object\"===typeof a&&(a=a.a);this.a=Pd(a);q(Tw)[this.a]=this}Tw.prototype=Object.create(u.prototype);Tw.prototype.constructor=Tw;Tw.prototype.b=Tw;Tw.c={};c.btBoxShape=Tw;\nTw.prototype.setMargin=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);hl(b,a)};Tw.prototype.getMargin=function(){return ke(this.a)};Tw.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Vu(b,a)};Tw.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Ao(e,a,b)};Tw.prototype.__destroy__=function(){tn(this.a)};\nfunction Uw(a,b){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);this.a=Be(a,b);q(Uw)[this.a]=this}Uw.prototype=Object.create(Rv.prototype);Uw.prototype.constructor=Uw;Uw.prototype.b=Uw;Uw.c={};c.btCapsuleShapeX=Uw;Uw.prototype.setMargin=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Mg(b,a)};Uw.prototype.getMargin=function(){return Tb(this.a)};Uw.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Nk(b,a)};\nUw.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Af(e,a,b)};Uw.prototype.__destroy__=function(){an(this.a)};function W(a,b,e,f){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);this.a=rl(a,b,e,f);q(W)[this.a]=this}W.prototype=Object.create(Yv.prototype);W.prototype.constructor=W;W.prototype.b=W;W.c={};c.btQuaternion=W;\nW.prototype.setValue=function(a,b,e,f){var g=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);sd(g,a,b,e,f)};W.prototype.setEulerZYX=function(a,b,e){var f=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);bp(f,a,b,e)};W.prototype.setRotation=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);ud(e,a,b)};\nW.prototype.normalize=function(){fk(this.a)};W.prototype.length2=function(){return at(this.a)};W.prototype.length=W.prototype.length=function(){return ef(this.a)};W.prototype.dot=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return Lb(b,a)};W.prototype.normalized=function(){return r(Yl(this.a),W)};W.prototype.getAxis=function(){return r(en(this.a),A)};W.prototype.inverse=function(){return r(zt(this.a),W)};W.prototype.getAngle=function(){return Ji(this.a)};\nW.prototype.getAngleShortestPath=function(){return Qc(this.a)};W.prototype.angle=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return lf(b,a)};W.prototype.angleShortestPath=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return qf(b,a)};W.prototype.op_add=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(Pu(b,a),W)};W.prototype.op_sub=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(rs(b,a),W)};\nW.prototype.op_mul=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(Lo(b,a),W)};W.prototype.op_mulq=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(jm(b,a),W)};W.prototype.op_div=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);return r(Jf(b,a),W)};W.prototype.x=function(){return Fh(this.a)};W.prototype.y=function(){return wl(this.a)};W.prototype.z=function(){return Oh(this.a)};W.prototype.w=function(){return Wk(this.a)};\nW.prototype.setX=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ac(b,a)};W.prototype.setY=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ts(b,a)};W.prototype.setZ=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);dc(b,a)};W.prototype.setW=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);uc(b,a)};W.prototype.__destroy__=function(){gk(this.a)};function Vw(a,b){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);this.a=zu(a,b);q(Vw)[this.a]=this}\nVw.prototype=Object.create(Rv.prototype);Vw.prototype.constructor=Vw;Vw.prototype.b=Vw;Vw.c={};c.btCapsuleShapeZ=Vw;Vw.prototype.setMargin=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);jd(b,a)};Vw.prototype.getMargin=function(){return bl(this.a)};Vw.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);wh(b,a)};Vw.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);aq(e,a,b)};\nVw.prototype.__destroy__=function(){fu(this.a)};function Ov(){throw\"cannot construct a btContactSolverInfo, no constructor in IDL\";}Ov.prototype=Object.create(p.prototype);Ov.prototype.constructor=Ov;Ov.prototype.b=Ov;Ov.c={};c.btContactSolverInfo=Ov;Ov.prototype.get_m_splitImpulse=function(){return!!nv(this.a)};Ov.prototype.set_m_splitImpulse=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);ci(b,a)};Ov.prototype.get_m_splitImpulsePenetrationThreshold=function(){return re(this.a)};\nOv.prototype.set_m_splitImpulsePenetrationThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);In(b,a)};Ov.prototype.get_m_numIterations=function(){return Os(this.a)};Ov.prototype.set_m_numIterations=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);We(b,a)};Ov.prototype.__destroy__=function(){vo(this.a)};\nfunction Y(a,b,e,f,g){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);this.a=void 0===f?Pj(a,b,e):void 0===g?_emscripten_bind_btGeneric6DofSpringConstraint_btGeneric6DofSpringConstraint_4(a,b,e,f):Wc(a,b,e,f,g);q(Y)[this.a]=this}Y.prototype=Object.create(bw.prototype);Y.prototype.constructor=Y;Y.prototype.b=Y;Y.c={};c.btGeneric6DofSpringConstraint=Y;\nY.prototype.enableSpring=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);yp(e,a,b)};Y.prototype.setStiffness=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Ul(e,a,b)};Y.prototype.setDamping=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);dp(e,a,b)};Y.prototype.setLinearLowerLimit=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);fv(b,a)};\nY.prototype.setLinearUpperLimit=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Pc(b,a)};Y.prototype.setAngularLowerLimit=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);jv(b,a)};Y.prototype.setAngularUpperLimit=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);nl(b,a)};Y.prototype.enableFeedback=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);dm(b,a)};Y.prototype.getBreakingImpulseThreshold=function(){return wn(this.a)};\nY.prototype.setBreakingImpulseThreshold=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);uf(b,a)};Y.prototype.__destroy__=function(){kk(this.a)};function Ww(a){a&&\"object\"===typeof a&&(a=a.a);this.a=ul(a);q(Ww)[this.a]=this}Ww.prototype=Object.create(u.prototype);Ww.prototype.constructor=Ww;Ww.prototype.b=Ww;Ww.c={};c.btSphereShape=Ww;Ww.prototype.setMargin=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Fn(b,a)};Ww.prototype.getMargin=function(){return Gm(this.a)};\nWw.prototype.setLocalScaling=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Bs(b,a)};Ww.prototype.calculateLocalInertia=function(a,b){var e=this.a;a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);Mf(e,a,b)};Ww.prototype.__destroy__=function(){Oc(this.a)};\nfunction Z(a,b,e,f,g){a&&\"object\"===typeof a&&(a=a.a);b&&\"object\"===typeof b&&(b=b.a);e&&\"object\"===typeof e&&(e=e.a);f&&\"object\"===typeof f&&(f=f.a);g&&\"object\"===typeof g&&(g=g.a);this.a=Ns(a,b,e,f,g);q(Z)[this.a]=this}Z.prototype=Object.create(p.prototype);Z.prototype.constructor=Z;Z.prototype.b=Z;Z.c={};c.LocalConvexResult=Z;Z.prototype.get_m_hitCollisionObject=function(){return r(Zi(this.a),w)};\nZ.prototype.set_m_hitCollisionObject=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);hv(b,a)};Z.prototype.get_m_localShapeInfo=function(){return r(tr(this.a),pw)};Z.prototype.set_m_localShapeInfo=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Nj(b,a)};Z.prototype.get_m_hitNormalLocal=function(){return r(gc(this.a),A)};Z.prototype.set_m_hitNormalLocal=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Jh(b,a)};\nZ.prototype.get_m_hitPointLocal=function(){return r(Od(this.a),A)};Z.prototype.set_m_hitPointLocal=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);Xf(b,a)};Z.prototype.get_m_hitFraction=function(){return Uk(this.a)};Z.prototype.set_m_hitFraction=function(a){var b=this.a;a&&\"object\"===typeof a&&(a=a.a);$p(b,a)};Z.prototype.__destroy__=function(){Ri(this.a)};\n(function(){function a(){c.PHY_FLOAT=Xt();c.PHY_DOUBLE=io();c.PHY_INTEGER=Rn();c.PHY_SHORT=ms();c.PHY_FIXEDPOINT88=Fq();c.PHY_UCHAR=tc()}c.calledRun?a():Ua.unshift(a)})();this.Ammo=c;\n\n\n  return Ammo;\n};\n"
  },
  {
    "path": "libs/gl-matrix.js",
    "content": "/**\r\n * @fileoverview gl-matrix - High performance matrix and vector operations\r\n * @author Brandon Jones\r\n * @author Colin MacKenzie IV\r\n * @version 2.3.2\r\n */\r\n\r\n/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in\r\nall copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\nTHE SOFTWARE. */\r\n\r\n(function webpackUniversalModuleDefinition(root, factory) {\r\n\tif(typeof exports === 'object' && typeof module === 'object')\r\n\t\tmodule.exports = factory();\r\n\telse if(typeof define === 'function' && define.amd)\r\n\t\tdefine([], factory);\r\n\telse {\r\n\t\tvar a = factory();\r\n\t\tfor(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\r\n\t}\r\n})(this, function() {\r\nreturn /******/ (function(modules) { // webpackBootstrap\r\n/******/ \t// The module cache\r\n/******/ \tvar installedModules = {};\r\n\r\n/******/ \t// The require function\r\n/******/ \tfunction __webpack_require__(moduleId) {\r\n\r\n/******/ \t\t// Check if module is in cache\r\n/******/ \t\tif(installedModules[moduleId])\r\n/******/ \t\t\treturn installedModules[moduleId].exports;\r\n\r\n/******/ \t\t// Create a new module (and put it into the cache)\r\n/******/ \t\tvar module = installedModules[moduleId] = {\r\n/******/ \t\t\texports: {},\r\n/******/ \t\t\tid: moduleId,\r\n/******/ \t\t\tloaded: false\r\n/******/ \t\t};\r\n\r\n/******/ \t\t// Execute the module function\r\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\r\n\r\n/******/ \t\t// Flag the module as loaded\r\n/******/ \t\tmodule.loaded = true;\r\n\r\n/******/ \t\t// Return the exports of the module\r\n/******/ \t\treturn module.exports;\r\n/******/ \t}\r\n\r\n\r\n/******/ \t// expose the modules object (__webpack_modules__)\r\n/******/ \t__webpack_require__.m = modules;\r\n\r\n/******/ \t// expose the module cache\r\n/******/ \t__webpack_require__.c = installedModules;\r\n\r\n/******/ \t// __webpack_public_path__\r\n/******/ \t__webpack_require__.p = \"\";\r\n\r\n/******/ \t// Load entry module and return exports\r\n/******/ \treturn __webpack_require__(0);\r\n/******/ })\r\n/************************************************************************/\r\n/******/ ([\r\n/* 0 */\r\n/***/ function(module, exports, __webpack_require__) {\r\n\r\n\t/**\r\n\t * @fileoverview gl-matrix - High performance matrix and vector operations\r\n\t * @author Brandon Jones\r\n\t * @author Colin MacKenzie IV\r\n\t * @version 2.3.2\r\n\t */\r\n\r\n\t/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\n\tPermission is hereby granted, free of charge, to any person obtaining a copy\r\n\tof this software and associated documentation files (the \"Software\"), to deal\r\n\tin the Software without restriction, including without limitation the rights\r\n\tto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n\tcopies of the Software, and to permit persons to whom the Software is\r\n\tfurnished to do so, subject to the following conditions:\r\n\r\n\tThe above copyright notice and this permission notice shall be included in\r\n\tall copies or substantial portions of the Software.\r\n\r\n\tTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n\tIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n\tFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n\tAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n\tLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n\tOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\n\tTHE SOFTWARE. */\r\n\t// END HEADER\r\n\r\n\texports.glMatrix = __webpack_require__(1);\r\n\texports.mat2 = __webpack_require__(2);\r\n\texports.mat2d = __webpack_require__(3);\r\n\texports.mat3 = __webpack_require__(4);\r\n\texports.mat4 = __webpack_require__(5);\r\n\texports.quat = __webpack_require__(6);\r\n\texports.vec2 = __webpack_require__(9);\r\n\texports.vec3 = __webpack_require__(7);\r\n\texports.vec4 = __webpack_require__(8);\r\n\r\n/***/ },\r\n/* 1 */\r\n/***/ function(module, exports) {\r\n\r\n\t/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\n\tPermission is hereby granted, free of charge, to any person obtaining a copy\r\n\tof this software and associated documentation files (the \"Software\"), to deal\r\n\tin the Software without restriction, including without limitation the rights\r\n\tto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n\tcopies of the Software, and to permit persons to whom the Software is\r\n\tfurnished to do so, subject to the following conditions:\r\n\r\n\tThe above copyright notice and this permission notice shall be included in\r\n\tall copies or substantial portions of the Software.\r\n\r\n\tTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n\tIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n\tFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n\tAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n\tLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n\tOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\n\tTHE SOFTWARE. */\r\n\r\n\t/**\r\n\t * @class Common utilities\r\n\t * @name glMatrix\r\n\t */\r\n\tvar glMatrix = {};\r\n\r\n\t// Configuration Constants\r\n\tglMatrix.EPSILON = 0.000001;\r\n\tglMatrix.ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array;\r\n\tglMatrix.RANDOM = Math.random;\r\n\tglMatrix.ENABLE_SIMD = false;\r\n\r\n\t// Capability detection\r\n\tglMatrix.SIMD_AVAILABLE = (glMatrix.ARRAY_TYPE === this.Float32Array) && ('SIMD' in this);\r\n\tglMatrix.USE_SIMD = glMatrix.ENABLE_SIMD && glMatrix.SIMD_AVAILABLE;\r\n\r\n\t/**\r\n\t * Sets the type of array used when creating new vectors and matrices\r\n\t *\r\n\t * @param {Type} type Array type, such as Float32Array or Array\r\n\t */\r\n\tglMatrix.setMatrixArrayType = function(type) {\r\n\t    glMatrix.ARRAY_TYPE = type;\r\n\t}\r\n\r\n\tvar degree = Math.PI / 180;\r\n\r\n\t/**\r\n\t* Convert Degree To Radian\r\n\t*\r\n\t* @param {Number} a Angle in Degrees\r\n\t*/\r\n\tglMatrix.toRadian = function(a){\r\n\t     return a * degree;\r\n\t}\r\n\r\n\t/**\r\n\t * Tests whether or not the arguments have approximately the same value, within an absolute\r\n\t * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less \r\n\t * than or equal to 1.0, and a relative tolerance is used for larger values)\r\n\t * \r\n\t * @param {Number} a The first number to test.\r\n\t * @param {Number} b The second number to test.\r\n\t * @returns {Boolean} True if the numbers are approximately equal, false otherwise.\r\n\t */\r\n\tglMatrix.equals = function(a, b) {\r\n\t\treturn Math.abs(a - b) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a), Math.abs(b));\r\n\t}\r\n\r\n\tmodule.exports = glMatrix;\r\n\r\n\r\n/***/ },\r\n/* 2 */\r\n/***/ function(module, exports, __webpack_require__) {\r\n\r\n\t/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\n\tPermission is hereby granted, free of charge, to any person obtaining a copy\r\n\tof this software and associated documentation files (the \"Software\"), to deal\r\n\tin the Software without restriction, including without limitation the rights\r\n\tto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n\tcopies of the Software, and to permit persons to whom the Software is\r\n\tfurnished to do so, subject to the following conditions:\r\n\r\n\tThe above copyright notice and this permission notice shall be included in\r\n\tall copies or substantial portions of the Software.\r\n\r\n\tTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n\tIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n\tFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n\tAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n\tLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n\tOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\n\tTHE SOFTWARE. */\r\n\r\n\tvar glMatrix = __webpack_require__(1);\r\n\r\n\t/**\r\n\t * @class 2x2 Matrix\r\n\t * @name mat2\r\n\t */\r\n\tvar mat2 = {};\r\n\r\n\t/**\r\n\t * Creates a new identity mat2\r\n\t *\r\n\t * @returns {mat2} a new 2x2 matrix\r\n\t */\r\n\tmat2.create = function() {\r\n\t    var out = new glMatrix.ARRAY_TYPE(4);\r\n\t    out[0] = 1;\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = 1;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Creates a new mat2 initialized with values from an existing matrix\r\n\t *\r\n\t * @param {mat2} a matrix to clone\r\n\t * @returns {mat2} a new 2x2 matrix\r\n\t */\r\n\tmat2.clone = function(a) {\r\n\t    var out = new glMatrix.ARRAY_TYPE(4);\r\n\t    out[0] = a[0];\r\n\t    out[1] = a[1];\r\n\t    out[2] = a[2];\r\n\t    out[3] = a[3];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Copy the values from one mat2 to another\r\n\t *\r\n\t * @param {mat2} out the receiving matrix\r\n\t * @param {mat2} a the source matrix\r\n\t * @returns {mat2} out\r\n\t */\r\n\tmat2.copy = function(out, a) {\r\n\t    out[0] = a[0];\r\n\t    out[1] = a[1];\r\n\t    out[2] = a[2];\r\n\t    out[3] = a[3];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Set a mat2 to the identity matrix\r\n\t *\r\n\t * @param {mat2} out the receiving matrix\r\n\t * @returns {mat2} out\r\n\t */\r\n\tmat2.identity = function(out) {\r\n\t    out[0] = 1;\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = 1;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Create a new mat2 with the given values\r\n\t *\r\n\t * @param {Number} m00 Component in column 0, row 0 position (index 0)\r\n\t * @param {Number} m01 Component in column 0, row 1 position (index 1)\r\n\t * @param {Number} m10 Component in column 1, row 0 position (index 2)\r\n\t * @param {Number} m11 Component in column 1, row 1 position (index 3)\r\n\t * @returns {mat2} out A new 2x2 matrix\r\n\t */\r\n\tmat2.fromValues = function(m00, m01, m10, m11) {\r\n\t    var out = new glMatrix.ARRAY_TYPE(4);\r\n\t    out[0] = m00;\r\n\t    out[1] = m01;\r\n\t    out[2] = m10;\r\n\t    out[3] = m11;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Set the components of a mat2 to the given values\r\n\t *\r\n\t * @param {mat2} out the receiving matrix\r\n\t * @param {Number} m00 Component in column 0, row 0 position (index 0)\r\n\t * @param {Number} m01 Component in column 0, row 1 position (index 1)\r\n\t * @param {Number} m10 Component in column 1, row 0 position (index 2)\r\n\t * @param {Number} m11 Component in column 1, row 1 position (index 3)\r\n\t * @returns {mat2} out\r\n\t */\r\n\tmat2.set = function(out, m00, m01, m10, m11) {\r\n\t    out[0] = m00;\r\n\t    out[1] = m01;\r\n\t    out[2] = m10;\r\n\t    out[3] = m11;\r\n\t    return out;\r\n\t};\r\n\r\n\r\n\t/**\r\n\t * Transpose the values of a mat2\r\n\t *\r\n\t * @param {mat2} out the receiving matrix\r\n\t * @param {mat2} a the source matrix\r\n\t * @returns {mat2} out\r\n\t */\r\n\tmat2.transpose = function(out, a) {\r\n\t    // If we are transposing ourselves we can skip a few steps but have to cache some values\r\n\t    if (out === a) {\r\n\t        var a1 = a[1];\r\n\t        out[1] = a[2];\r\n\t        out[2] = a1;\r\n\t    } else {\r\n\t        out[0] = a[0];\r\n\t        out[1] = a[2];\r\n\t        out[2] = a[1];\r\n\t        out[3] = a[3];\r\n\t    }\r\n\t    \r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Inverts a mat2\r\n\t *\r\n\t * @param {mat2} out the receiving matrix\r\n\t * @param {mat2} a the source matrix\r\n\t * @returns {mat2} out\r\n\t */\r\n\tmat2.invert = function(out, a) {\r\n\t    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],\r\n\r\n\t        // Calculate the determinant\r\n\t        det = a0 * a3 - a2 * a1;\r\n\r\n\t    if (!det) {\r\n\t        return null;\r\n\t    }\r\n\t    det = 1.0 / det;\r\n\t    \r\n\t    out[0] =  a3 * det;\r\n\t    out[1] = -a1 * det;\r\n\t    out[2] = -a2 * det;\r\n\t    out[3] =  a0 * det;\r\n\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Calculates the adjugate of a mat2\r\n\t *\r\n\t * @param {mat2} out the receiving matrix\r\n\t * @param {mat2} a the source matrix\r\n\t * @returns {mat2} out\r\n\t */\r\n\tmat2.adjoint = function(out, a) {\r\n\t    // Caching this value is nessecary if out == a\r\n\t    var a0 = a[0];\r\n\t    out[0] =  a[3];\r\n\t    out[1] = -a[1];\r\n\t    out[2] = -a[2];\r\n\t    out[3] =  a0;\r\n\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Calculates the determinant of a mat2\r\n\t *\r\n\t * @param {mat2} a the source matrix\r\n\t * @returns {Number} determinant of a\r\n\t */\r\n\tmat2.determinant = function (a) {\r\n\t    return a[0] * a[3] - a[2] * a[1];\r\n\t};\r\n\r\n\t/**\r\n\t * Multiplies two mat2's\r\n\t *\r\n\t * @param {mat2} out the receiving matrix\r\n\t * @param {mat2} a the first operand\r\n\t * @param {mat2} b the second operand\r\n\t * @returns {mat2} out\r\n\t */\r\n\tmat2.multiply = function (out, a, b) {\r\n\t    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\r\n\t    var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\r\n\t    out[0] = a0 * b0 + a2 * b1;\r\n\t    out[1] = a1 * b0 + a3 * b1;\r\n\t    out[2] = a0 * b2 + a2 * b3;\r\n\t    out[3] = a1 * b2 + a3 * b3;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link mat2.multiply}\r\n\t * @function\r\n\t */\r\n\tmat2.mul = mat2.multiply;\r\n\r\n\t/**\r\n\t * Rotates a mat2 by the given angle\r\n\t *\r\n\t * @param {mat2} out the receiving matrix\r\n\t * @param {mat2} a the matrix to rotate\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @returns {mat2} out\r\n\t */\r\n\tmat2.rotate = function (out, a, rad) {\r\n\t    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],\r\n\t        s = Math.sin(rad),\r\n\t        c = Math.cos(rad);\r\n\t    out[0] = a0 *  c + a2 * s;\r\n\t    out[1] = a1 *  c + a3 * s;\r\n\t    out[2] = a0 * -s + a2 * c;\r\n\t    out[3] = a1 * -s + a3 * c;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Scales the mat2 by the dimensions in the given vec2\r\n\t *\r\n\t * @param {mat2} out the receiving matrix\r\n\t * @param {mat2} a the matrix to rotate\r\n\t * @param {vec2} v the vec2 to scale the matrix by\r\n\t * @returns {mat2} out\r\n\t **/\r\n\tmat2.scale = function(out, a, v) {\r\n\t    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],\r\n\t        v0 = v[0], v1 = v[1];\r\n\t    out[0] = a0 * v0;\r\n\t    out[1] = a1 * v0;\r\n\t    out[2] = a2 * v1;\r\n\t    out[3] = a3 * v1;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Creates a matrix from a given angle\r\n\t * This is equivalent to (but much faster than):\r\n\t *\r\n\t *     mat2.identity(dest);\r\n\t *     mat2.rotate(dest, dest, rad);\r\n\t *\r\n\t * @param {mat2} out mat2 receiving operation result\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @returns {mat2} out\r\n\t */\r\n\tmat2.fromRotation = function(out, rad) {\r\n\t    var s = Math.sin(rad),\r\n\t        c = Math.cos(rad);\r\n\t    out[0] = c;\r\n\t    out[1] = s;\r\n\t    out[2] = -s;\r\n\t    out[3] = c;\r\n\t    return out;\r\n\t}\r\n\r\n\t/**\r\n\t * Creates a matrix from a vector scaling\r\n\t * This is equivalent to (but much faster than):\r\n\t *\r\n\t *     mat2.identity(dest);\r\n\t *     mat2.scale(dest, dest, vec);\r\n\t *\r\n\t * @param {mat2} out mat2 receiving operation result\r\n\t * @param {vec2} v Scaling vector\r\n\t * @returns {mat2} out\r\n\t */\r\n\tmat2.fromScaling = function(out, v) {\r\n\t    out[0] = v[0];\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = v[1];\r\n\t    return out;\r\n\t}\r\n\r\n\t/**\r\n\t * Returns a string representation of a mat2\r\n\t *\r\n\t * @param {mat2} a matrix to represent as a string\r\n\t * @returns {String} string representation of the matrix\r\n\t */\r\n\tmat2.str = function (a) {\r\n\t    return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';\r\n\t};\r\n\r\n\t/**\r\n\t * Returns Frobenius norm of a mat2\r\n\t *\r\n\t * @param {mat2} a the matrix to calculate Frobenius norm of\r\n\t * @returns {Number} Frobenius norm\r\n\t */\r\n\tmat2.frob = function (a) {\r\n\t    return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2)))\r\n\t};\r\n\r\n\t/**\r\n\t * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix\r\n\t * @param {mat2} L the lower triangular matrix \r\n\t * @param {mat2} D the diagonal matrix \r\n\t * @param {mat2} U the upper triangular matrix \r\n\t * @param {mat2} a the input matrix to factorize\r\n\t */\r\n\r\n\tmat2.LDU = function (L, D, U, a) { \r\n\t    L[2] = a[2]/a[0]; \r\n\t    U[0] = a[0]; \r\n\t    U[1] = a[1]; \r\n\t    U[3] = a[3] - L[2] * U[1]; \r\n\t    return [L, D, U];       \r\n\t}; \r\n\r\n\t/**\r\n\t * Adds two mat2's\r\n\t *\r\n\t * @param {mat2} out the receiving matrix\r\n\t * @param {mat2} a the first operand\r\n\t * @param {mat2} b the second operand\r\n\t * @returns {mat2} out\r\n\t */\r\n\tmat2.add = function(out, a, b) {\r\n\t    out[0] = a[0] + b[0];\r\n\t    out[1] = a[1] + b[1];\r\n\t    out[2] = a[2] + b[2];\r\n\t    out[3] = a[3] + b[3];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Subtracts matrix b from matrix a\r\n\t *\r\n\t * @param {mat2} out the receiving matrix\r\n\t * @param {mat2} a the first operand\r\n\t * @param {mat2} b the second operand\r\n\t * @returns {mat2} out\r\n\t */\r\n\tmat2.subtract = function(out, a, b) {\r\n\t    out[0] = a[0] - b[0];\r\n\t    out[1] = a[1] - b[1];\r\n\t    out[2] = a[2] - b[2];\r\n\t    out[3] = a[3] - b[3];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link mat2.subtract}\r\n\t * @function\r\n\t */\r\n\tmat2.sub = mat2.subtract;\r\n\r\n\t/**\r\n\t * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)\r\n\t *\r\n\t * @param {mat2} a The first matrix.\r\n\t * @param {mat2} b The second matrix.\r\n\t * @returns {Boolean} True if the matrices are equal, false otherwise.\r\n\t */\r\n\tmat2.exactEquals = function (a, b) {\r\n\t    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];\r\n\t};\r\n\r\n\t/**\r\n\t * Returns whether or not the matrices have approximately the same elements in the same position.\r\n\t *\r\n\t * @param {mat2} a The first matrix.\r\n\t * @param {mat2} b The second matrix.\r\n\t * @returns {Boolean} True if the matrices are equal, false otherwise.\r\n\t */\r\n\tmat2.equals = function (a, b) {\r\n\t    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\r\n\t    var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\r\n\t    return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\r\n\t            Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\r\n\t            Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\r\n\t            Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)));\r\n\t};\r\n\r\n\t/**\r\n\t * Multiply each element of the matrix by a scalar.\r\n\t *\r\n\t * @param {mat2} out the receiving matrix\r\n\t * @param {mat2} a the matrix to scale\r\n\t * @param {Number} b amount to scale the matrix's elements by\r\n\t * @returns {mat2} out\r\n\t */\r\n\tmat2.multiplyScalar = function(out, a, b) {\r\n\t    out[0] = a[0] * b;\r\n\t    out[1] = a[1] * b;\r\n\t    out[2] = a[2] * b;\r\n\t    out[3] = a[3] * b;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Adds two mat2's after multiplying each element of the second operand by a scalar value.\r\n\t *\r\n\t * @param {mat2} out the receiving vector\r\n\t * @param {mat2} a the first operand\r\n\t * @param {mat2} b the second operand\r\n\t * @param {Number} scale the amount to scale b's elements by before adding\r\n\t * @returns {mat2} out\r\n\t */\r\n\tmat2.multiplyScalarAndAdd = function(out, a, b, scale) {\r\n\t    out[0] = a[0] + (b[0] * scale);\r\n\t    out[1] = a[1] + (b[1] * scale);\r\n\t    out[2] = a[2] + (b[2] * scale);\r\n\t    out[3] = a[3] + (b[3] * scale);\r\n\t    return out;\r\n\t};\r\n\r\n\tmodule.exports = mat2;\r\n\r\n\r\n/***/ },\r\n/* 3 */\r\n/***/ function(module, exports, __webpack_require__) {\r\n\r\n\t/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\n\tPermission is hereby granted, free of charge, to any person obtaining a copy\r\n\tof this software and associated documentation files (the \"Software\"), to deal\r\n\tin the Software without restriction, including without limitation the rights\r\n\tto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n\tcopies of the Software, and to permit persons to whom the Software is\r\n\tfurnished to do so, subject to the following conditions:\r\n\r\n\tThe above copyright notice and this permission notice shall be included in\r\n\tall copies or substantial portions of the Software.\r\n\r\n\tTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n\tIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n\tFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n\tAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n\tLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n\tOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\n\tTHE SOFTWARE. */\r\n\r\n\tvar glMatrix = __webpack_require__(1);\r\n\r\n\t/**\r\n\t * @class 2x3 Matrix\r\n\t * @name mat2d\r\n\t * \r\n\t * @description \r\n\t * A mat2d contains six elements defined as:\r\n\t * <pre>\r\n\t * [a, c, tx,\r\n\t *  b, d, ty]\r\n\t * </pre>\r\n\t * This is a short form for the 3x3 matrix:\r\n\t * <pre>\r\n\t * [a, c, tx,\r\n\t *  b, d, ty,\r\n\t *  0, 0, 1]\r\n\t * </pre>\r\n\t * The last row is ignored so the array is shorter and operations are faster.\r\n\t */\r\n\tvar mat2d = {};\r\n\r\n\t/**\r\n\t * Creates a new identity mat2d\r\n\t *\r\n\t * @returns {mat2d} a new 2x3 matrix\r\n\t */\r\n\tmat2d.create = function() {\r\n\t    var out = new glMatrix.ARRAY_TYPE(6);\r\n\t    out[0] = 1;\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = 1;\r\n\t    out[4] = 0;\r\n\t    out[5] = 0;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Creates a new mat2d initialized with values from an existing matrix\r\n\t *\r\n\t * @param {mat2d} a matrix to clone\r\n\t * @returns {mat2d} a new 2x3 matrix\r\n\t */\r\n\tmat2d.clone = function(a) {\r\n\t    var out = new glMatrix.ARRAY_TYPE(6);\r\n\t    out[0] = a[0];\r\n\t    out[1] = a[1];\r\n\t    out[2] = a[2];\r\n\t    out[3] = a[3];\r\n\t    out[4] = a[4];\r\n\t    out[5] = a[5];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Copy the values from one mat2d to another\r\n\t *\r\n\t * @param {mat2d} out the receiving matrix\r\n\t * @param {mat2d} a the source matrix\r\n\t * @returns {mat2d} out\r\n\t */\r\n\tmat2d.copy = function(out, a) {\r\n\t    out[0] = a[0];\r\n\t    out[1] = a[1];\r\n\t    out[2] = a[2];\r\n\t    out[3] = a[3];\r\n\t    out[4] = a[4];\r\n\t    out[5] = a[5];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Set a mat2d to the identity matrix\r\n\t *\r\n\t * @param {mat2d} out the receiving matrix\r\n\t * @returns {mat2d} out\r\n\t */\r\n\tmat2d.identity = function(out) {\r\n\t    out[0] = 1;\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = 1;\r\n\t    out[4] = 0;\r\n\t    out[5] = 0;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Create a new mat2d with the given values\r\n\t *\r\n\t * @param {Number} a Component A (index 0)\r\n\t * @param {Number} b Component B (index 1)\r\n\t * @param {Number} c Component C (index 2)\r\n\t * @param {Number} d Component D (index 3)\r\n\t * @param {Number} tx Component TX (index 4)\r\n\t * @param {Number} ty Component TY (index 5)\r\n\t * @returns {mat2d} A new mat2d\r\n\t */\r\n\tmat2d.fromValues = function(a, b, c, d, tx, ty) {\r\n\t    var out = new glMatrix.ARRAY_TYPE(6);\r\n\t    out[0] = a;\r\n\t    out[1] = b;\r\n\t    out[2] = c;\r\n\t    out[3] = d;\r\n\t    out[4] = tx;\r\n\t    out[5] = ty;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Set the components of a mat2d to the given values\r\n\t *\r\n\t * @param {mat2d} out the receiving matrix\r\n\t * @param {Number} a Component A (index 0)\r\n\t * @param {Number} b Component B (index 1)\r\n\t * @param {Number} c Component C (index 2)\r\n\t * @param {Number} d Component D (index 3)\r\n\t * @param {Number} tx Component TX (index 4)\r\n\t * @param {Number} ty Component TY (index 5)\r\n\t * @returns {mat2d} out\r\n\t */\r\n\tmat2d.set = function(out, a, b, c, d, tx, ty) {\r\n\t    out[0] = a;\r\n\t    out[1] = b;\r\n\t    out[2] = c;\r\n\t    out[3] = d;\r\n\t    out[4] = tx;\r\n\t    out[5] = ty;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Inverts a mat2d\r\n\t *\r\n\t * @param {mat2d} out the receiving matrix\r\n\t * @param {mat2d} a the source matrix\r\n\t * @returns {mat2d} out\r\n\t */\r\n\tmat2d.invert = function(out, a) {\r\n\t    var aa = a[0], ab = a[1], ac = a[2], ad = a[3],\r\n\t        atx = a[4], aty = a[5];\r\n\r\n\t    var det = aa * ad - ab * ac;\r\n\t    if(!det){\r\n\t        return null;\r\n\t    }\r\n\t    det = 1.0 / det;\r\n\r\n\t    out[0] = ad * det;\r\n\t    out[1] = -ab * det;\r\n\t    out[2] = -ac * det;\r\n\t    out[3] = aa * det;\r\n\t    out[4] = (ac * aty - ad * atx) * det;\r\n\t    out[5] = (ab * atx - aa * aty) * det;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Calculates the determinant of a mat2d\r\n\t *\r\n\t * @param {mat2d} a the source matrix\r\n\t * @returns {Number} determinant of a\r\n\t */\r\n\tmat2d.determinant = function (a) {\r\n\t    return a[0] * a[3] - a[1] * a[2];\r\n\t};\r\n\r\n\t/**\r\n\t * Multiplies two mat2d's\r\n\t *\r\n\t * @param {mat2d} out the receiving matrix\r\n\t * @param {mat2d} a the first operand\r\n\t * @param {mat2d} b the second operand\r\n\t * @returns {mat2d} out\r\n\t */\r\n\tmat2d.multiply = function (out, a, b) {\r\n\t    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5],\r\n\t        b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5];\r\n\t    out[0] = a0 * b0 + a2 * b1;\r\n\t    out[1] = a1 * b0 + a3 * b1;\r\n\t    out[2] = a0 * b2 + a2 * b3;\r\n\t    out[3] = a1 * b2 + a3 * b3;\r\n\t    out[4] = a0 * b4 + a2 * b5 + a4;\r\n\t    out[5] = a1 * b4 + a3 * b5 + a5;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link mat2d.multiply}\r\n\t * @function\r\n\t */\r\n\tmat2d.mul = mat2d.multiply;\r\n\r\n\t/**\r\n\t * Rotates a mat2d by the given angle\r\n\t *\r\n\t * @param {mat2d} out the receiving matrix\r\n\t * @param {mat2d} a the matrix to rotate\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @returns {mat2d} out\r\n\t */\r\n\tmat2d.rotate = function (out, a, rad) {\r\n\t    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5],\r\n\t        s = Math.sin(rad),\r\n\t        c = Math.cos(rad);\r\n\t    out[0] = a0 *  c + a2 * s;\r\n\t    out[1] = a1 *  c + a3 * s;\r\n\t    out[2] = a0 * -s + a2 * c;\r\n\t    out[3] = a1 * -s + a3 * c;\r\n\t    out[4] = a4;\r\n\t    out[5] = a5;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Scales the mat2d by the dimensions in the given vec2\r\n\t *\r\n\t * @param {mat2d} out the receiving matrix\r\n\t * @param {mat2d} a the matrix to translate\r\n\t * @param {vec2} v the vec2 to scale the matrix by\r\n\t * @returns {mat2d} out\r\n\t **/\r\n\tmat2d.scale = function(out, a, v) {\r\n\t    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5],\r\n\t        v0 = v[0], v1 = v[1];\r\n\t    out[0] = a0 * v0;\r\n\t    out[1] = a1 * v0;\r\n\t    out[2] = a2 * v1;\r\n\t    out[3] = a3 * v1;\r\n\t    out[4] = a4;\r\n\t    out[5] = a5;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Translates the mat2d by the dimensions in the given vec2\r\n\t *\r\n\t * @param {mat2d} out the receiving matrix\r\n\t * @param {mat2d} a the matrix to translate\r\n\t * @param {vec2} v the vec2 to translate the matrix by\r\n\t * @returns {mat2d} out\r\n\t **/\r\n\tmat2d.translate = function(out, a, v) {\r\n\t    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5],\r\n\t        v0 = v[0], v1 = v[1];\r\n\t    out[0] = a0;\r\n\t    out[1] = a1;\r\n\t    out[2] = a2;\r\n\t    out[3] = a3;\r\n\t    out[4] = a0 * v0 + a2 * v1 + a4;\r\n\t    out[5] = a1 * v0 + a3 * v1 + a5;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Creates a matrix from a given angle\r\n\t * This is equivalent to (but much faster than):\r\n\t *\r\n\t *     mat2d.identity(dest);\r\n\t *     mat2d.rotate(dest, dest, rad);\r\n\t *\r\n\t * @param {mat2d} out mat2d receiving operation result\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @returns {mat2d} out\r\n\t */\r\n\tmat2d.fromRotation = function(out, rad) {\r\n\t    var s = Math.sin(rad), c = Math.cos(rad);\r\n\t    out[0] = c;\r\n\t    out[1] = s;\r\n\t    out[2] = -s;\r\n\t    out[3] = c;\r\n\t    out[4] = 0;\r\n\t    out[5] = 0;\r\n\t    return out;\r\n\t}\r\n\r\n\t/**\r\n\t * Creates a matrix from a vector scaling\r\n\t * This is equivalent to (but much faster than):\r\n\t *\r\n\t *     mat2d.identity(dest);\r\n\t *     mat2d.scale(dest, dest, vec);\r\n\t *\r\n\t * @param {mat2d} out mat2d receiving operation result\r\n\t * @param {vec2} v Scaling vector\r\n\t * @returns {mat2d} out\r\n\t */\r\n\tmat2d.fromScaling = function(out, v) {\r\n\t    out[0] = v[0];\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = v[1];\r\n\t    out[4] = 0;\r\n\t    out[5] = 0;\r\n\t    return out;\r\n\t}\r\n\r\n\t/**\r\n\t * Creates a matrix from a vector translation\r\n\t * This is equivalent to (but much faster than):\r\n\t *\r\n\t *     mat2d.identity(dest);\r\n\t *     mat2d.translate(dest, dest, vec);\r\n\t *\r\n\t * @param {mat2d} out mat2d receiving operation result\r\n\t * @param {vec2} v Translation vector\r\n\t * @returns {mat2d} out\r\n\t */\r\n\tmat2d.fromTranslation = function(out, v) {\r\n\t    out[0] = 1;\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = 1;\r\n\t    out[4] = v[0];\r\n\t    out[5] = v[1];\r\n\t    return out;\r\n\t}\r\n\r\n\t/**\r\n\t * Returns a string representation of a mat2d\r\n\t *\r\n\t * @param {mat2d} a matrix to represent as a string\r\n\t * @returns {String} string representation of the matrix\r\n\t */\r\n\tmat2d.str = function (a) {\r\n\t    return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + \r\n\t                    a[3] + ', ' + a[4] + ', ' + a[5] + ')';\r\n\t};\r\n\r\n\t/**\r\n\t * Returns Frobenius norm of a mat2d\r\n\t *\r\n\t * @param {mat2d} a the matrix to calculate Frobenius norm of\r\n\t * @returns {Number} Frobenius norm\r\n\t */\r\n\tmat2d.frob = function (a) { \r\n\t    return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + 1))\r\n\t}; \r\n\r\n\t/**\r\n\t * Adds two mat2d's\r\n\t *\r\n\t * @param {mat2d} out the receiving matrix\r\n\t * @param {mat2d} a the first operand\r\n\t * @param {mat2d} b the second operand\r\n\t * @returns {mat2d} out\r\n\t */\r\n\tmat2d.add = function(out, a, b) {\r\n\t    out[0] = a[0] + b[0];\r\n\t    out[1] = a[1] + b[1];\r\n\t    out[2] = a[2] + b[2];\r\n\t    out[3] = a[3] + b[3];\r\n\t    out[4] = a[4] + b[4];\r\n\t    out[5] = a[5] + b[5];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Subtracts matrix b from matrix a\r\n\t *\r\n\t * @param {mat2d} out the receiving matrix\r\n\t * @param {mat2d} a the first operand\r\n\t * @param {mat2d} b the second operand\r\n\t * @returns {mat2d} out\r\n\t */\r\n\tmat2d.subtract = function(out, a, b) {\r\n\t    out[0] = a[0] - b[0];\r\n\t    out[1] = a[1] - b[1];\r\n\t    out[2] = a[2] - b[2];\r\n\t    out[3] = a[3] - b[3];\r\n\t    out[4] = a[4] - b[4];\r\n\t    out[5] = a[5] - b[5];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link mat2d.subtract}\r\n\t * @function\r\n\t */\r\n\tmat2d.sub = mat2d.subtract;\r\n\r\n\t/**\r\n\t * Multiply each element of the matrix by a scalar.\r\n\t *\r\n\t * @param {mat2d} out the receiving matrix\r\n\t * @param {mat2d} a the matrix to scale\r\n\t * @param {Number} b amount to scale the matrix's elements by\r\n\t * @returns {mat2d} out\r\n\t */\r\n\tmat2d.multiplyScalar = function(out, a, b) {\r\n\t    out[0] = a[0] * b;\r\n\t    out[1] = a[1] * b;\r\n\t    out[2] = a[2] * b;\r\n\t    out[3] = a[3] * b;\r\n\t    out[4] = a[4] * b;\r\n\t    out[5] = a[5] * b;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Adds two mat2d's after multiplying each element of the second operand by a scalar value.\r\n\t *\r\n\t * @param {mat2d} out the receiving vector\r\n\t * @param {mat2d} a the first operand\r\n\t * @param {mat2d} b the second operand\r\n\t * @param {Number} scale the amount to scale b's elements by before adding\r\n\t * @returns {mat2d} out\r\n\t */\r\n\tmat2d.multiplyScalarAndAdd = function(out, a, b, scale) {\r\n\t    out[0] = a[0] + (b[0] * scale);\r\n\t    out[1] = a[1] + (b[1] * scale);\r\n\t    out[2] = a[2] + (b[2] * scale);\r\n\t    out[3] = a[3] + (b[3] * scale);\r\n\t    out[4] = a[4] + (b[4] * scale);\r\n\t    out[5] = a[5] + (b[5] * scale);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)\r\n\t *\r\n\t * @param {mat2d} a The first matrix.\r\n\t * @param {mat2d} b The second matrix.\r\n\t * @returns {Boolean} True if the matrices are equal, false otherwise.\r\n\t */\r\n\tmat2d.exactEquals = function (a, b) {\r\n\t    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];\r\n\t};\r\n\r\n\t/**\r\n\t * Returns whether or not the matrices have approximately the same elements in the same position.\r\n\t *\r\n\t * @param {mat2d} a The first matrix.\r\n\t * @param {mat2d} b The second matrix.\r\n\t * @returns {Boolean} True if the matrices are equal, false otherwise.\r\n\t */\r\n\tmat2d.equals = function (a, b) {\r\n\t    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];\r\n\t    var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5];\r\n\t    return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\r\n\t            Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\r\n\t            Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\r\n\t            Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&\r\n\t            Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&\r\n\t            Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)));\r\n\t};\r\n\r\n\tmodule.exports = mat2d;\r\n\r\n\r\n/***/ },\r\n/* 4 */\r\n/***/ function(module, exports, __webpack_require__) {\r\n\r\n\t/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\n\tPermission is hereby granted, free of charge, to any person obtaining a copy\r\n\tof this software and associated documentation files (the \"Software\"), to deal\r\n\tin the Software without restriction, including without limitation the rights\r\n\tto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n\tcopies of the Software, and to permit persons to whom the Software is\r\n\tfurnished to do so, subject to the following conditions:\r\n\r\n\tThe above copyright notice and this permission notice shall be included in\r\n\tall copies or substantial portions of the Software.\r\n\r\n\tTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n\tIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n\tFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n\tAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n\tLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n\tOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\n\tTHE SOFTWARE. */\r\n\r\n\tvar glMatrix = __webpack_require__(1);\r\n\r\n\t/**\r\n\t * @class 3x3 Matrix\r\n\t * @name mat3\r\n\t */\r\n\tvar mat3 = {};\r\n\r\n\t/**\r\n\t * Creates a new identity mat3\r\n\t *\r\n\t * @returns {mat3} a new 3x3 matrix\r\n\t */\r\n\tmat3.create = function() {\r\n\t    var out = new glMatrix.ARRAY_TYPE(9);\r\n\t    out[0] = 1;\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = 0;\r\n\t    out[4] = 1;\r\n\t    out[5] = 0;\r\n\t    out[6] = 0;\r\n\t    out[7] = 0;\r\n\t    out[8] = 1;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Copies the upper-left 3x3 values into the given mat3.\r\n\t *\r\n\t * @param {mat3} out the receiving 3x3 matrix\r\n\t * @param {mat4} a   the source 4x4 matrix\r\n\t * @returns {mat3} out\r\n\t */\r\n\tmat3.fromMat4 = function(out, a) {\r\n\t    out[0] = a[0];\r\n\t    out[1] = a[1];\r\n\t    out[2] = a[2];\r\n\t    out[3] = a[4];\r\n\t    out[4] = a[5];\r\n\t    out[5] = a[6];\r\n\t    out[6] = a[8];\r\n\t    out[7] = a[9];\r\n\t    out[8] = a[10];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Creates a new mat3 initialized with values from an existing matrix\r\n\t *\r\n\t * @param {mat3} a matrix to clone\r\n\t * @returns {mat3} a new 3x3 matrix\r\n\t */\r\n\tmat3.clone = function(a) {\r\n\t    var out = new glMatrix.ARRAY_TYPE(9);\r\n\t    out[0] = a[0];\r\n\t    out[1] = a[1];\r\n\t    out[2] = a[2];\r\n\t    out[3] = a[3];\r\n\t    out[4] = a[4];\r\n\t    out[5] = a[5];\r\n\t    out[6] = a[6];\r\n\t    out[7] = a[7];\r\n\t    out[8] = a[8];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Copy the values from one mat3 to another\r\n\t *\r\n\t * @param {mat3} out the receiving matrix\r\n\t * @param {mat3} a the source matrix\r\n\t * @returns {mat3} out\r\n\t */\r\n\tmat3.copy = function(out, a) {\r\n\t    out[0] = a[0];\r\n\t    out[1] = a[1];\r\n\t    out[2] = a[2];\r\n\t    out[3] = a[3];\r\n\t    out[4] = a[4];\r\n\t    out[5] = a[5];\r\n\t    out[6] = a[6];\r\n\t    out[7] = a[7];\r\n\t    out[8] = a[8];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Create a new mat3 with the given values\r\n\t *\r\n\t * @param {Number} m00 Component in column 0, row 0 position (index 0)\r\n\t * @param {Number} m01 Component in column 0, row 1 position (index 1)\r\n\t * @param {Number} m02 Component in column 0, row 2 position (index 2)\r\n\t * @param {Number} m10 Component in column 1, row 0 position (index 3)\r\n\t * @param {Number} m11 Component in column 1, row 1 position (index 4)\r\n\t * @param {Number} m12 Component in column 1, row 2 position (index 5)\r\n\t * @param {Number} m20 Component in column 2, row 0 position (index 6)\r\n\t * @param {Number} m21 Component in column 2, row 1 position (index 7)\r\n\t * @param {Number} m22 Component in column 2, row 2 position (index 8)\r\n\t * @returns {mat3} A new mat3\r\n\t */\r\n\tmat3.fromValues = function(m00, m01, m02, m10, m11, m12, m20, m21, m22) {\r\n\t    var out = new glMatrix.ARRAY_TYPE(9);\r\n\t    out[0] = m00;\r\n\t    out[1] = m01;\r\n\t    out[2] = m02;\r\n\t    out[3] = m10;\r\n\t    out[4] = m11;\r\n\t    out[5] = m12;\r\n\t    out[6] = m20;\r\n\t    out[7] = m21;\r\n\t    out[8] = m22;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Set the components of a mat3 to the given values\r\n\t *\r\n\t * @param {mat3} out the receiving matrix\r\n\t * @param {Number} m00 Component in column 0, row 0 position (index 0)\r\n\t * @param {Number} m01 Component in column 0, row 1 position (index 1)\r\n\t * @param {Number} m02 Component in column 0, row 2 position (index 2)\r\n\t * @param {Number} m10 Component in column 1, row 0 position (index 3)\r\n\t * @param {Number} m11 Component in column 1, row 1 position (index 4)\r\n\t * @param {Number} m12 Component in column 1, row 2 position (index 5)\r\n\t * @param {Number} m20 Component in column 2, row 0 position (index 6)\r\n\t * @param {Number} m21 Component in column 2, row 1 position (index 7)\r\n\t * @param {Number} m22 Component in column 2, row 2 position (index 8)\r\n\t * @returns {mat3} out\r\n\t */\r\n\tmat3.set = function(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {\r\n\t    out[0] = m00;\r\n\t    out[1] = m01;\r\n\t    out[2] = m02;\r\n\t    out[3] = m10;\r\n\t    out[4] = m11;\r\n\t    out[5] = m12;\r\n\t    out[6] = m20;\r\n\t    out[7] = m21;\r\n\t    out[8] = m22;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Set a mat3 to the identity matrix\r\n\t *\r\n\t * @param {mat3} out the receiving matrix\r\n\t * @returns {mat3} out\r\n\t */\r\n\tmat3.identity = function(out) {\r\n\t    out[0] = 1;\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = 0;\r\n\t    out[4] = 1;\r\n\t    out[5] = 0;\r\n\t    out[6] = 0;\r\n\t    out[7] = 0;\r\n\t    out[8] = 1;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Transpose the values of a mat3\r\n\t *\r\n\t * @param {mat3} out the receiving matrix\r\n\t * @param {mat3} a the source matrix\r\n\t * @returns {mat3} out\r\n\t */\r\n\tmat3.transpose = function(out, a) {\r\n\t    // If we are transposing ourselves we can skip a few steps but have to cache some values\r\n\t    if (out === a) {\r\n\t        var a01 = a[1], a02 = a[2], a12 = a[5];\r\n\t        out[1] = a[3];\r\n\t        out[2] = a[6];\r\n\t        out[3] = a01;\r\n\t        out[5] = a[7];\r\n\t        out[6] = a02;\r\n\t        out[7] = a12;\r\n\t    } else {\r\n\t        out[0] = a[0];\r\n\t        out[1] = a[3];\r\n\t        out[2] = a[6];\r\n\t        out[3] = a[1];\r\n\t        out[4] = a[4];\r\n\t        out[5] = a[7];\r\n\t        out[6] = a[2];\r\n\t        out[7] = a[5];\r\n\t        out[8] = a[8];\r\n\t    }\r\n\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Inverts a mat3\r\n\t *\r\n\t * @param {mat3} out the receiving matrix\r\n\t * @param {mat3} a the source matrix\r\n\t * @returns {mat3} out\r\n\t */\r\n\tmat3.invert = function(out, a) {\r\n\t    var a00 = a[0], a01 = a[1], a02 = a[2],\r\n\t        a10 = a[3], a11 = a[4], a12 = a[5],\r\n\t        a20 = a[6], a21 = a[7], a22 = a[8],\r\n\r\n\t        b01 = a22 * a11 - a12 * a21,\r\n\t        b11 = -a22 * a10 + a12 * a20,\r\n\t        b21 = a21 * a10 - a11 * a20,\r\n\r\n\t        // Calculate the determinant\r\n\t        det = a00 * b01 + a01 * b11 + a02 * b21;\r\n\r\n\t    if (!det) {\r\n\t        return null;\r\n\t    }\r\n\t    det = 1.0 / det;\r\n\r\n\t    out[0] = b01 * det;\r\n\t    out[1] = (-a22 * a01 + a02 * a21) * det;\r\n\t    out[2] = (a12 * a01 - a02 * a11) * det;\r\n\t    out[3] = b11 * det;\r\n\t    out[4] = (a22 * a00 - a02 * a20) * det;\r\n\t    out[5] = (-a12 * a00 + a02 * a10) * det;\r\n\t    out[6] = b21 * det;\r\n\t    out[7] = (-a21 * a00 + a01 * a20) * det;\r\n\t    out[8] = (a11 * a00 - a01 * a10) * det;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Calculates the adjugate of a mat3\r\n\t *\r\n\t * @param {mat3} out the receiving matrix\r\n\t * @param {mat3} a the source matrix\r\n\t * @returns {mat3} out\r\n\t */\r\n\tmat3.adjoint = function(out, a) {\r\n\t    var a00 = a[0], a01 = a[1], a02 = a[2],\r\n\t        a10 = a[3], a11 = a[4], a12 = a[5],\r\n\t        a20 = a[6], a21 = a[7], a22 = a[8];\r\n\r\n\t    out[0] = (a11 * a22 - a12 * a21);\r\n\t    out[1] = (a02 * a21 - a01 * a22);\r\n\t    out[2] = (a01 * a12 - a02 * a11);\r\n\t    out[3] = (a12 * a20 - a10 * a22);\r\n\t    out[4] = (a00 * a22 - a02 * a20);\r\n\t    out[5] = (a02 * a10 - a00 * a12);\r\n\t    out[6] = (a10 * a21 - a11 * a20);\r\n\t    out[7] = (a01 * a20 - a00 * a21);\r\n\t    out[8] = (a00 * a11 - a01 * a10);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Calculates the determinant of a mat3\r\n\t *\r\n\t * @param {mat3} a the source matrix\r\n\t * @returns {Number} determinant of a\r\n\t */\r\n\tmat3.determinant = function (a) {\r\n\t    var a00 = a[0], a01 = a[1], a02 = a[2],\r\n\t        a10 = a[3], a11 = a[4], a12 = a[5],\r\n\t        a20 = a[6], a21 = a[7], a22 = a[8];\r\n\r\n\t    return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);\r\n\t};\r\n\r\n\t/**\r\n\t * Multiplies two mat3's\r\n\t *\r\n\t * @param {mat3} out the receiving matrix\r\n\t * @param {mat3} a the first operand\r\n\t * @param {mat3} b the second operand\r\n\t * @returns {mat3} out\r\n\t */\r\n\tmat3.multiply = function (out, a, b) {\r\n\t    var a00 = a[0], a01 = a[1], a02 = a[2],\r\n\t        a10 = a[3], a11 = a[4], a12 = a[5],\r\n\t        a20 = a[6], a21 = a[7], a22 = a[8],\r\n\r\n\t        b00 = b[0], b01 = b[1], b02 = b[2],\r\n\t        b10 = b[3], b11 = b[4], b12 = b[5],\r\n\t        b20 = b[6], b21 = b[7], b22 = b[8];\r\n\r\n\t    out[0] = b00 * a00 + b01 * a10 + b02 * a20;\r\n\t    out[1] = b00 * a01 + b01 * a11 + b02 * a21;\r\n\t    out[2] = b00 * a02 + b01 * a12 + b02 * a22;\r\n\r\n\t    out[3] = b10 * a00 + b11 * a10 + b12 * a20;\r\n\t    out[4] = b10 * a01 + b11 * a11 + b12 * a21;\r\n\t    out[5] = b10 * a02 + b11 * a12 + b12 * a22;\r\n\r\n\t    out[6] = b20 * a00 + b21 * a10 + b22 * a20;\r\n\t    out[7] = b20 * a01 + b21 * a11 + b22 * a21;\r\n\t    out[8] = b20 * a02 + b21 * a12 + b22 * a22;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link mat3.multiply}\r\n\t * @function\r\n\t */\r\n\tmat3.mul = mat3.multiply;\r\n\r\n\t/**\r\n\t * Translate a mat3 by the given vector\r\n\t *\r\n\t * @param {mat3} out the receiving matrix\r\n\t * @param {mat3} a the matrix to translate\r\n\t * @param {vec2} v vector to translate by\r\n\t * @returns {mat3} out\r\n\t */\r\n\tmat3.translate = function(out, a, v) {\r\n\t    var a00 = a[0], a01 = a[1], a02 = a[2],\r\n\t        a10 = a[3], a11 = a[4], a12 = a[5],\r\n\t        a20 = a[6], a21 = a[7], a22 = a[8],\r\n\t        x = v[0], y = v[1];\r\n\r\n\t    out[0] = a00;\r\n\t    out[1] = a01;\r\n\t    out[2] = a02;\r\n\r\n\t    out[3] = a10;\r\n\t    out[4] = a11;\r\n\t    out[5] = a12;\r\n\r\n\t    out[6] = x * a00 + y * a10 + a20;\r\n\t    out[7] = x * a01 + y * a11 + a21;\r\n\t    out[8] = x * a02 + y * a12 + a22;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Rotates a mat3 by the given angle\r\n\t *\r\n\t * @param {mat3} out the receiving matrix\r\n\t * @param {mat3} a the matrix to rotate\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @returns {mat3} out\r\n\t */\r\n\tmat3.rotate = function (out, a, rad) {\r\n\t    var a00 = a[0], a01 = a[1], a02 = a[2],\r\n\t        a10 = a[3], a11 = a[4], a12 = a[5],\r\n\t        a20 = a[6], a21 = a[7], a22 = a[8],\r\n\r\n\t        s = Math.sin(rad),\r\n\t        c = Math.cos(rad);\r\n\r\n\t    out[0] = c * a00 + s * a10;\r\n\t    out[1] = c * a01 + s * a11;\r\n\t    out[2] = c * a02 + s * a12;\r\n\r\n\t    out[3] = c * a10 - s * a00;\r\n\t    out[4] = c * a11 - s * a01;\r\n\t    out[5] = c * a12 - s * a02;\r\n\r\n\t    out[6] = a20;\r\n\t    out[7] = a21;\r\n\t    out[8] = a22;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Scales the mat3 by the dimensions in the given vec2\r\n\t *\r\n\t * @param {mat3} out the receiving matrix\r\n\t * @param {mat3} a the matrix to rotate\r\n\t * @param {vec2} v the vec2 to scale the matrix by\r\n\t * @returns {mat3} out\r\n\t **/\r\n\tmat3.scale = function(out, a, v) {\r\n\t    var x = v[0], y = v[1];\r\n\r\n\t    out[0] = x * a[0];\r\n\t    out[1] = x * a[1];\r\n\t    out[2] = x * a[2];\r\n\r\n\t    out[3] = y * a[3];\r\n\t    out[4] = y * a[4];\r\n\t    out[5] = y * a[5];\r\n\r\n\t    out[6] = a[6];\r\n\t    out[7] = a[7];\r\n\t    out[8] = a[8];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Creates a matrix from a vector translation\r\n\t * This is equivalent to (but much faster than):\r\n\t *\r\n\t *     mat3.identity(dest);\r\n\t *     mat3.translate(dest, dest, vec);\r\n\t *\r\n\t * @param {mat3} out mat3 receiving operation result\r\n\t * @param {vec2} v Translation vector\r\n\t * @returns {mat3} out\r\n\t */\r\n\tmat3.fromTranslation = function(out, v) {\r\n\t    out[0] = 1;\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = 0;\r\n\t    out[4] = 1;\r\n\t    out[5] = 0;\r\n\t    out[6] = v[0];\r\n\t    out[7] = v[1];\r\n\t    out[8] = 1;\r\n\t    return out;\r\n\t}\r\n\r\n\t/**\r\n\t * Creates a matrix from a given angle\r\n\t * This is equivalent to (but much faster than):\r\n\t *\r\n\t *     mat3.identity(dest);\r\n\t *     mat3.rotate(dest, dest, rad);\r\n\t *\r\n\t * @param {mat3} out mat3 receiving operation result\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @returns {mat3} out\r\n\t */\r\n\tmat3.fromRotation = function(out, rad) {\r\n\t    var s = Math.sin(rad), c = Math.cos(rad);\r\n\r\n\t    out[0] = c;\r\n\t    out[1] = s;\r\n\t    out[2] = 0;\r\n\r\n\t    out[3] = -s;\r\n\t    out[4] = c;\r\n\t    out[5] = 0;\r\n\r\n\t    out[6] = 0;\r\n\t    out[7] = 0;\r\n\t    out[8] = 1;\r\n\t    return out;\r\n\t}\r\n\r\n\t/**\r\n\t * Creates a matrix from a vector scaling\r\n\t * This is equivalent to (but much faster than):\r\n\t *\r\n\t *     mat3.identity(dest);\r\n\t *     mat3.scale(dest, dest, vec);\r\n\t *\r\n\t * @param {mat3} out mat3 receiving operation result\r\n\t * @param {vec2} v Scaling vector\r\n\t * @returns {mat3} out\r\n\t */\r\n\tmat3.fromScaling = function(out, v) {\r\n\t    out[0] = v[0];\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\r\n\t    out[3] = 0;\r\n\t    out[4] = v[1];\r\n\t    out[5] = 0;\r\n\r\n\t    out[6] = 0;\r\n\t    out[7] = 0;\r\n\t    out[8] = 1;\r\n\t    return out;\r\n\t}\r\n\r\n\t/**\r\n\t * Copies the values from a mat2d into a mat3\r\n\t *\r\n\t * @param {mat3} out the receiving matrix\r\n\t * @param {mat2d} a the matrix to copy\r\n\t * @returns {mat3} out\r\n\t **/\r\n\tmat3.fromMat2d = function(out, a) {\r\n\t    out[0] = a[0];\r\n\t    out[1] = a[1];\r\n\t    out[2] = 0;\r\n\r\n\t    out[3] = a[2];\r\n\t    out[4] = a[3];\r\n\t    out[5] = 0;\r\n\r\n\t    out[6] = a[4];\r\n\t    out[7] = a[5];\r\n\t    out[8] = 1;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t* Calculates a 3x3 matrix from the given quaternion\r\n\t*\r\n\t* @param {mat3} out mat3 receiving operation result\r\n\t* @param {quat} q Quaternion to create matrix from\r\n\t*\r\n\t* @returns {mat3} out\r\n\t*/\r\n\tmat3.fromQuat = function (out, q) {\r\n\t    var x = q[0], y = q[1], z = q[2], w = q[3],\r\n\t        x2 = x + x,\r\n\t        y2 = y + y,\r\n\t        z2 = z + z,\r\n\r\n\t        xx = x * x2,\r\n\t        yx = y * x2,\r\n\t        yy = y * y2,\r\n\t        zx = z * x2,\r\n\t        zy = z * y2,\r\n\t        zz = z * z2,\r\n\t        wx = w * x2,\r\n\t        wy = w * y2,\r\n\t        wz = w * z2;\r\n\r\n\t    out[0] = 1 - yy - zz;\r\n\t    out[3] = yx - wz;\r\n\t    out[6] = zx + wy;\r\n\r\n\t    out[1] = yx + wz;\r\n\t    out[4] = 1 - xx - zz;\r\n\t    out[7] = zy - wx;\r\n\r\n\t    out[2] = zx - wy;\r\n\t    out[5] = zy + wx;\r\n\t    out[8] = 1 - xx - yy;\r\n\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix\r\n\t*\r\n\t* @param {mat3} out mat3 receiving operation result\r\n\t* @param {mat4} a Mat4 to derive the normal matrix from\r\n\t*\r\n\t* @returns {mat3} out\r\n\t*/\r\n\tmat3.normalFromMat4 = function (out, a) {\r\n\t    var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],\r\n\t        a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],\r\n\t        a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],\r\n\t        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],\r\n\r\n\t        b00 = a00 * a11 - a01 * a10,\r\n\t        b01 = a00 * a12 - a02 * a10,\r\n\t        b02 = a00 * a13 - a03 * a10,\r\n\t        b03 = a01 * a12 - a02 * a11,\r\n\t        b04 = a01 * a13 - a03 * a11,\r\n\t        b05 = a02 * a13 - a03 * a12,\r\n\t        b06 = a20 * a31 - a21 * a30,\r\n\t        b07 = a20 * a32 - a22 * a30,\r\n\t        b08 = a20 * a33 - a23 * a30,\r\n\t        b09 = a21 * a32 - a22 * a31,\r\n\t        b10 = a21 * a33 - a23 * a31,\r\n\t        b11 = a22 * a33 - a23 * a32,\r\n\r\n\t        // Calculate the determinant\r\n\t        det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\r\n\r\n\t    if (!det) {\r\n\t        return null;\r\n\t    }\r\n\t    det = 1.0 / det;\r\n\r\n\t    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;\r\n\t    out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;\r\n\t    out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;\r\n\r\n\t    out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;\r\n\t    out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;\r\n\t    out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;\r\n\r\n\t    out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;\r\n\t    out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;\r\n\t    out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;\r\n\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Returns a string representation of a mat3\r\n\t *\r\n\t * @param {mat3} a matrix to represent as a string\r\n\t * @returns {String} string representation of the matrix\r\n\t */\r\n\tmat3.str = function (a) {\r\n\t    return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +\r\n\t                    a[3] + ', ' + a[4] + ', ' + a[5] + ', ' +\r\n\t                    a[6] + ', ' + a[7] + ', ' + a[8] + ')';\r\n\t};\r\n\r\n\t/**\r\n\t * Returns Frobenius norm of a mat3\r\n\t *\r\n\t * @param {mat3} a the matrix to calculate Frobenius norm of\r\n\t * @returns {Number} Frobenius norm\r\n\t */\r\n\tmat3.frob = function (a) {\r\n\t    return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2)))\r\n\t};\r\n\r\n\t/**\r\n\t * Adds two mat3's\r\n\t *\r\n\t * @param {mat3} out the receiving matrix\r\n\t * @param {mat3} a the first operand\r\n\t * @param {mat3} b the second operand\r\n\t * @returns {mat3} out\r\n\t */\r\n\tmat3.add = function(out, a, b) {\r\n\t    out[0] = a[0] + b[0];\r\n\t    out[1] = a[1] + b[1];\r\n\t    out[2] = a[2] + b[2];\r\n\t    out[3] = a[3] + b[3];\r\n\t    out[4] = a[4] + b[4];\r\n\t    out[5] = a[5] + b[5];\r\n\t    out[6] = a[6] + b[6];\r\n\t    out[7] = a[7] + b[7];\r\n\t    out[8] = a[8] + b[8];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Subtracts matrix b from matrix a\r\n\t *\r\n\t * @param {mat3} out the receiving matrix\r\n\t * @param {mat3} a the first operand\r\n\t * @param {mat3} b the second operand\r\n\t * @returns {mat3} out\r\n\t */\r\n\tmat3.subtract = function(out, a, b) {\r\n\t    out[0] = a[0] - b[0];\r\n\t    out[1] = a[1] - b[1];\r\n\t    out[2] = a[2] - b[2];\r\n\t    out[3] = a[3] - b[3];\r\n\t    out[4] = a[4] - b[4];\r\n\t    out[5] = a[5] - b[5];\r\n\t    out[6] = a[6] - b[6];\r\n\t    out[7] = a[7] - b[7];\r\n\t    out[8] = a[8] - b[8];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link mat3.subtract}\r\n\t * @function\r\n\t */\r\n\tmat3.sub = mat3.subtract;\r\n\r\n\t/**\r\n\t * Multiply each element of the matrix by a scalar.\r\n\t *\r\n\t * @param {mat3} out the receiving matrix\r\n\t * @param {mat3} a the matrix to scale\r\n\t * @param {Number} b amount to scale the matrix's elements by\r\n\t * @returns {mat3} out\r\n\t */\r\n\tmat3.multiplyScalar = function(out, a, b) {\r\n\t    out[0] = a[0] * b;\r\n\t    out[1] = a[1] * b;\r\n\t    out[2] = a[2] * b;\r\n\t    out[3] = a[3] * b;\r\n\t    out[4] = a[4] * b;\r\n\t    out[5] = a[5] * b;\r\n\t    out[6] = a[6] * b;\r\n\t    out[7] = a[7] * b;\r\n\t    out[8] = a[8] * b;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Adds two mat3's after multiplying each element of the second operand by a scalar value.\r\n\t *\r\n\t * @param {mat3} out the receiving vector\r\n\t * @param {mat3} a the first operand\r\n\t * @param {mat3} b the second operand\r\n\t * @param {Number} scale the amount to scale b's elements by before adding\r\n\t * @returns {mat3} out\r\n\t */\r\n\tmat3.multiplyScalarAndAdd = function(out, a, b, scale) {\r\n\t    out[0] = a[0] + (b[0] * scale);\r\n\t    out[1] = a[1] + (b[1] * scale);\r\n\t    out[2] = a[2] + (b[2] * scale);\r\n\t    out[3] = a[3] + (b[3] * scale);\r\n\t    out[4] = a[4] + (b[4] * scale);\r\n\t    out[5] = a[5] + (b[5] * scale);\r\n\t    out[6] = a[6] + (b[6] * scale);\r\n\t    out[7] = a[7] + (b[7] * scale);\r\n\t    out[8] = a[8] + (b[8] * scale);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)\r\n\t *\r\n\t * @param {mat3} a The first matrix.\r\n\t * @param {mat3} b The second matrix.\r\n\t * @returns {Boolean} True if the matrices are equal, false otherwise.\r\n\t */\r\n\tmat3.exactEquals = function (a, b) {\r\n\t    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] &&\r\n\t           a[3] === b[3] && a[4] === b[4] && a[5] === b[5] &&\r\n\t           a[6] === b[6] && a[7] === b[7] && a[8] === b[8];\r\n\t};\r\n\r\n\t/**\r\n\t * Returns whether or not the matrices have approximately the same elements in the same position.\r\n\t *\r\n\t * @param {mat3} a The first matrix.\r\n\t * @param {mat3} b The second matrix.\r\n\t * @returns {Boolean} True if the matrices are equal, false otherwise.\r\n\t */\r\n\tmat3.equals = function (a, b) {\r\n\t    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7], a8 = a[8];\r\n\t    var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5], b6 = a[6], b7 = b[7], b8 = b[8];\r\n\t    return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\r\n\t            Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\r\n\t            Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\r\n\t            Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&\r\n\t            Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&\r\n\t            Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&\r\n\t            Math.abs(a6 - b6) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&\r\n\t            Math.abs(a7 - b7) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&\r\n\t            Math.abs(a8 - b8) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a8), Math.abs(b8)));\r\n\t};\r\n\r\n\r\n\tmodule.exports = mat3;\r\n\r\n\r\n/***/ },\r\n/* 5 */\r\n/***/ function(module, exports, __webpack_require__) {\r\n\r\n\t/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\n\tPermission is hereby granted, free of charge, to any person obtaining a copy\r\n\tof this software and associated documentation files (the \"Software\"), to deal\r\n\tin the Software without restriction, including without limitation the rights\r\n\tto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n\tcopies of the Software, and to permit persons to whom the Software is\r\n\tfurnished to do so, subject to the following conditions:\r\n\r\n\tThe above copyright notice and this permission notice shall be included in\r\n\tall copies or substantial portions of the Software.\r\n\r\n\tTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n\tIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n\tFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n\tAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n\tLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n\tOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\n\tTHE SOFTWARE. */\r\n\r\n\tvar glMatrix = __webpack_require__(1);\r\n\r\n\t/**\r\n\t * @class 4x4 Matrix\r\n\t * @name mat4\r\n\t */\r\n\tvar mat4 = {\r\n\t  scalar: {},\r\n\t  SIMD: {}\r\n\t};\r\n\r\n\t/**\r\n\t * Creates a new identity mat4\r\n\t *\r\n\t * @returns {mat4} a new 4x4 matrix\r\n\t */\r\n\tmat4.create = function() {\r\n\t    var out = new glMatrix.ARRAY_TYPE(16);\r\n\t    out[0] = 1;\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = 0;\r\n\t    out[4] = 0;\r\n\t    out[5] = 1;\r\n\t    out[6] = 0;\r\n\t    out[7] = 0;\r\n\t    out[8] = 0;\r\n\t    out[9] = 0;\r\n\t    out[10] = 1;\r\n\t    out[11] = 0;\r\n\t    out[12] = 0;\r\n\t    out[13] = 0;\r\n\t    out[14] = 0;\r\n\t    out[15] = 1;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Creates a new mat4 initialized with values from an existing matrix\r\n\t *\r\n\t * @param {mat4} a matrix to clone\r\n\t * @returns {mat4} a new 4x4 matrix\r\n\t */\r\n\tmat4.clone = function(a) {\r\n\t    var out = new glMatrix.ARRAY_TYPE(16);\r\n\t    out[0] = a[0];\r\n\t    out[1] = a[1];\r\n\t    out[2] = a[2];\r\n\t    out[3] = a[3];\r\n\t    out[4] = a[4];\r\n\t    out[5] = a[5];\r\n\t    out[6] = a[6];\r\n\t    out[7] = a[7];\r\n\t    out[8] = a[8];\r\n\t    out[9] = a[9];\r\n\t    out[10] = a[10];\r\n\t    out[11] = a[11];\r\n\t    out[12] = a[12];\r\n\t    out[13] = a[13];\r\n\t    out[14] = a[14];\r\n\t    out[15] = a[15];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Copy the values from one mat4 to another\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the source matrix\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.copy = function(out, a) {\r\n\t    out[0] = a[0];\r\n\t    out[1] = a[1];\r\n\t    out[2] = a[2];\r\n\t    out[3] = a[3];\r\n\t    out[4] = a[4];\r\n\t    out[5] = a[5];\r\n\t    out[6] = a[6];\r\n\t    out[7] = a[7];\r\n\t    out[8] = a[8];\r\n\t    out[9] = a[9];\r\n\t    out[10] = a[10];\r\n\t    out[11] = a[11];\r\n\t    out[12] = a[12];\r\n\t    out[13] = a[13];\r\n\t    out[14] = a[14];\r\n\t    out[15] = a[15];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Create a new mat4 with the given values\r\n\t *\r\n\t * @param {Number} m00 Component in column 0, row 0 position (index 0)\r\n\t * @param {Number} m01 Component in column 0, row 1 position (index 1)\r\n\t * @param {Number} m02 Component in column 0, row 2 position (index 2)\r\n\t * @param {Number} m03 Component in column 0, row 3 position (index 3)\r\n\t * @param {Number} m10 Component in column 1, row 0 position (index 4)\r\n\t * @param {Number} m11 Component in column 1, row 1 position (index 5)\r\n\t * @param {Number} m12 Component in column 1, row 2 position (index 6)\r\n\t * @param {Number} m13 Component in column 1, row 3 position (index 7)\r\n\t * @param {Number} m20 Component in column 2, row 0 position (index 8)\r\n\t * @param {Number} m21 Component in column 2, row 1 position (index 9)\r\n\t * @param {Number} m22 Component in column 2, row 2 position (index 10)\r\n\t * @param {Number} m23 Component in column 2, row 3 position (index 11)\r\n\t * @param {Number} m30 Component in column 3, row 0 position (index 12)\r\n\t * @param {Number} m31 Component in column 3, row 1 position (index 13)\r\n\t * @param {Number} m32 Component in column 3, row 2 position (index 14)\r\n\t * @param {Number} m33 Component in column 3, row 3 position (index 15)\r\n\t * @returns {mat4} A new mat4\r\n\t */\r\n\tmat4.fromValues = function(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {\r\n\t    var out = new glMatrix.ARRAY_TYPE(16);\r\n\t    out[0] = m00;\r\n\t    out[1] = m01;\r\n\t    out[2] = m02;\r\n\t    out[3] = m03;\r\n\t    out[4] = m10;\r\n\t    out[5] = m11;\r\n\t    out[6] = m12;\r\n\t    out[7] = m13;\r\n\t    out[8] = m20;\r\n\t    out[9] = m21;\r\n\t    out[10] = m22;\r\n\t    out[11] = m23;\r\n\t    out[12] = m30;\r\n\t    out[13] = m31;\r\n\t    out[14] = m32;\r\n\t    out[15] = m33;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Set the components of a mat4 to the given values\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {Number} m00 Component in column 0, row 0 position (index 0)\r\n\t * @param {Number} m01 Component in column 0, row 1 position (index 1)\r\n\t * @param {Number} m02 Component in column 0, row 2 position (index 2)\r\n\t * @param {Number} m03 Component in column 0, row 3 position (index 3)\r\n\t * @param {Number} m10 Component in column 1, row 0 position (index 4)\r\n\t * @param {Number} m11 Component in column 1, row 1 position (index 5)\r\n\t * @param {Number} m12 Component in column 1, row 2 position (index 6)\r\n\t * @param {Number} m13 Component in column 1, row 3 position (index 7)\r\n\t * @param {Number} m20 Component in column 2, row 0 position (index 8)\r\n\t * @param {Number} m21 Component in column 2, row 1 position (index 9)\r\n\t * @param {Number} m22 Component in column 2, row 2 position (index 10)\r\n\t * @param {Number} m23 Component in column 2, row 3 position (index 11)\r\n\t * @param {Number} m30 Component in column 3, row 0 position (index 12)\r\n\t * @param {Number} m31 Component in column 3, row 1 position (index 13)\r\n\t * @param {Number} m32 Component in column 3, row 2 position (index 14)\r\n\t * @param {Number} m33 Component in column 3, row 3 position (index 15)\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.set = function(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {\r\n\t    out[0] = m00;\r\n\t    out[1] = m01;\r\n\t    out[2] = m02;\r\n\t    out[3] = m03;\r\n\t    out[4] = m10;\r\n\t    out[5] = m11;\r\n\t    out[6] = m12;\r\n\t    out[7] = m13;\r\n\t    out[8] = m20;\r\n\t    out[9] = m21;\r\n\t    out[10] = m22;\r\n\t    out[11] = m23;\r\n\t    out[12] = m30;\r\n\t    out[13] = m31;\r\n\t    out[14] = m32;\r\n\t    out[15] = m33;\r\n\t    return out;\r\n\t};\r\n\r\n\r\n\t/**\r\n\t * Set a mat4 to the identity matrix\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.identity = function(out) {\r\n\t    out[0] = 1;\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = 0;\r\n\t    out[4] = 0;\r\n\t    out[5] = 1;\r\n\t    out[6] = 0;\r\n\t    out[7] = 0;\r\n\t    out[8] = 0;\r\n\t    out[9] = 0;\r\n\t    out[10] = 1;\r\n\t    out[11] = 0;\r\n\t    out[12] = 0;\r\n\t    out[13] = 0;\r\n\t    out[14] = 0;\r\n\t    out[15] = 1;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Transpose the values of a mat4 not using SIMD\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the source matrix\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.scalar.transpose = function(out, a) {\r\n\t    // If we are transposing ourselves we can skip a few steps but have to cache some values\r\n\t    if (out === a) {\r\n\t        var a01 = a[1], a02 = a[2], a03 = a[3],\r\n\t            a12 = a[6], a13 = a[7],\r\n\t            a23 = a[11];\r\n\r\n\t        out[1] = a[4];\r\n\t        out[2] = a[8];\r\n\t        out[3] = a[12];\r\n\t        out[4] = a01;\r\n\t        out[6] = a[9];\r\n\t        out[7] = a[13];\r\n\t        out[8] = a02;\r\n\t        out[9] = a12;\r\n\t        out[11] = a[14];\r\n\t        out[12] = a03;\r\n\t        out[13] = a13;\r\n\t        out[14] = a23;\r\n\t    } else {\r\n\t        out[0] = a[0];\r\n\t        out[1] = a[4];\r\n\t        out[2] = a[8];\r\n\t        out[3] = a[12];\r\n\t        out[4] = a[1];\r\n\t        out[5] = a[5];\r\n\t        out[6] = a[9];\r\n\t        out[7] = a[13];\r\n\t        out[8] = a[2];\r\n\t        out[9] = a[6];\r\n\t        out[10] = a[10];\r\n\t        out[11] = a[14];\r\n\t        out[12] = a[3];\r\n\t        out[13] = a[7];\r\n\t        out[14] = a[11];\r\n\t        out[15] = a[15];\r\n\t    }\r\n\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Transpose the values of a mat4 using SIMD\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the source matrix\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.SIMD.transpose = function(out, a) {\r\n\t    var a0, a1, a2, a3,\r\n\t        tmp01, tmp23,\r\n\t        out0, out1, out2, out3;\r\n\r\n\t    a0 = SIMD.Float32x4.load(a, 0);\r\n\t    a1 = SIMD.Float32x4.load(a, 4);\r\n\t    a2 = SIMD.Float32x4.load(a, 8);\r\n\t    a3 = SIMD.Float32x4.load(a, 12);\r\n\r\n\t    tmp01 = SIMD.Float32x4.shuffle(a0, a1, 0, 1, 4, 5);\r\n\t    tmp23 = SIMD.Float32x4.shuffle(a2, a3, 0, 1, 4, 5);\r\n\t    out0  = SIMD.Float32x4.shuffle(tmp01, tmp23, 0, 2, 4, 6);\r\n\t    out1  = SIMD.Float32x4.shuffle(tmp01, tmp23, 1, 3, 5, 7);\r\n\t    SIMD.Float32x4.store(out, 0,  out0);\r\n\t    SIMD.Float32x4.store(out, 4,  out1);\r\n\r\n\t    tmp01 = SIMD.Float32x4.shuffle(a0, a1, 2, 3, 6, 7);\r\n\t    tmp23 = SIMD.Float32x4.shuffle(a2, a3, 2, 3, 6, 7);\r\n\t    out2  = SIMD.Float32x4.shuffle(tmp01, tmp23, 0, 2, 4, 6);\r\n\t    out3  = SIMD.Float32x4.shuffle(tmp01, tmp23, 1, 3, 5, 7);\r\n\t    SIMD.Float32x4.store(out, 8,  out2);\r\n\t    SIMD.Float32x4.store(out, 12, out3);\r\n\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Transpse a mat4 using SIMD if available and enabled\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the source matrix\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.transpose = glMatrix.USE_SIMD ? mat4.SIMD.transpose : mat4.scalar.transpose;\r\n\r\n\t/**\r\n\t * Inverts a mat4 not using SIMD\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the source matrix\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.scalar.invert = function(out, a) {\r\n\t    var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],\r\n\t        a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],\r\n\t        a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],\r\n\t        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],\r\n\r\n\t        b00 = a00 * a11 - a01 * a10,\r\n\t        b01 = a00 * a12 - a02 * a10,\r\n\t        b02 = a00 * a13 - a03 * a10,\r\n\t        b03 = a01 * a12 - a02 * a11,\r\n\t        b04 = a01 * a13 - a03 * a11,\r\n\t        b05 = a02 * a13 - a03 * a12,\r\n\t        b06 = a20 * a31 - a21 * a30,\r\n\t        b07 = a20 * a32 - a22 * a30,\r\n\t        b08 = a20 * a33 - a23 * a30,\r\n\t        b09 = a21 * a32 - a22 * a31,\r\n\t        b10 = a21 * a33 - a23 * a31,\r\n\t        b11 = a22 * a33 - a23 * a32,\r\n\r\n\t        // Calculate the determinant\r\n\t        det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\r\n\r\n\t    if (!det) {\r\n\t        return null;\r\n\t    }\r\n\t    det = 1.0 / det;\r\n\r\n\t    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;\r\n\t    out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;\r\n\t    out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;\r\n\t    out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;\r\n\t    out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;\r\n\t    out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;\r\n\t    out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;\r\n\t    out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;\r\n\t    out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;\r\n\t    out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;\r\n\t    out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;\r\n\t    out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;\r\n\t    out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;\r\n\t    out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;\r\n\t    out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;\r\n\t    out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;\r\n\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Inverts a mat4 using SIMD\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the source matrix\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.SIMD.invert = function(out, a) {\r\n\t  var row0, row1, row2, row3,\r\n\t      tmp1,\r\n\t      minor0, minor1, minor2, minor3,\r\n\t      det,\r\n\t      a0 = SIMD.Float32x4.load(a, 0),\r\n\t      a1 = SIMD.Float32x4.load(a, 4),\r\n\t      a2 = SIMD.Float32x4.load(a, 8),\r\n\t      a3 = SIMD.Float32x4.load(a, 12);\r\n\r\n\t  // Compute matrix adjugate\r\n\t  tmp1 = SIMD.Float32x4.shuffle(a0, a1, 0, 1, 4, 5);\r\n\t  row1 = SIMD.Float32x4.shuffle(a2, a3, 0, 1, 4, 5);\r\n\t  row0 = SIMD.Float32x4.shuffle(tmp1, row1, 0, 2, 4, 6);\r\n\t  row1 = SIMD.Float32x4.shuffle(row1, tmp1, 1, 3, 5, 7);\r\n\t  tmp1 = SIMD.Float32x4.shuffle(a0, a1, 2, 3, 6, 7);\r\n\t  row3 = SIMD.Float32x4.shuffle(a2, a3, 2, 3, 6, 7);\r\n\t  row2 = SIMD.Float32x4.shuffle(tmp1, row3, 0, 2, 4, 6);\r\n\t  row3 = SIMD.Float32x4.shuffle(row3, tmp1, 1, 3, 5, 7);\r\n\r\n\t  tmp1   = SIMD.Float32x4.mul(row2, row3);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);\r\n\t  minor0 = SIMD.Float32x4.mul(row1, tmp1);\r\n\t  minor1 = SIMD.Float32x4.mul(row0, tmp1);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);\r\n\t  minor0 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row1, tmp1), minor0);\r\n\t  minor1 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row0, tmp1), minor1);\r\n\t  minor1 = SIMD.Float32x4.swizzle(minor1, 2, 3, 0, 1);\r\n\r\n\t  tmp1   = SIMD.Float32x4.mul(row1, row2);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);\r\n\t  minor0 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row3, tmp1), minor0);\r\n\t  minor3 = SIMD.Float32x4.mul(row0, tmp1);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);\r\n\t  minor0 = SIMD.Float32x4.sub(minor0, SIMD.Float32x4.mul(row3, tmp1));\r\n\t  minor3 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row0, tmp1), minor3);\r\n\t  minor3 = SIMD.Float32x4.swizzle(minor3, 2, 3, 0, 1);\r\n\r\n\t  tmp1   = SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(row1, 2, 3, 0, 1), row3);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);\r\n\t  row2   = SIMD.Float32x4.swizzle(row2, 2, 3, 0, 1);\r\n\t  minor0 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row2, tmp1), minor0);\r\n\t  minor2 = SIMD.Float32x4.mul(row0, tmp1);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);\r\n\t  minor0 = SIMD.Float32x4.sub(minor0, SIMD.Float32x4.mul(row2, tmp1));\r\n\t  minor2 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row0, tmp1), minor2);\r\n\t  minor2 = SIMD.Float32x4.swizzle(minor2, 2, 3, 0, 1);\r\n\r\n\t  tmp1   = SIMD.Float32x4.mul(row0, row1);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);\r\n\t  minor2 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row3, tmp1), minor2);\r\n\t  minor3 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row2, tmp1), minor3);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);\r\n\t  minor2 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row3, tmp1), minor2);\r\n\t  minor3 = SIMD.Float32x4.sub(minor3, SIMD.Float32x4.mul(row2, tmp1));\r\n\r\n\t  tmp1   = SIMD.Float32x4.mul(row0, row3);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);\r\n\t  minor1 = SIMD.Float32x4.sub(minor1, SIMD.Float32x4.mul(row2, tmp1));\r\n\t  minor2 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row1, tmp1), minor2);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);\r\n\t  minor1 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row2, tmp1), minor1);\r\n\t  minor2 = SIMD.Float32x4.sub(minor2, SIMD.Float32x4.mul(row1, tmp1));\r\n\r\n\t  tmp1   = SIMD.Float32x4.mul(row0, row2);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);\r\n\t  minor1 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row3, tmp1), minor1);\r\n\t  minor3 = SIMD.Float32x4.sub(minor3, SIMD.Float32x4.mul(row1, tmp1));\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);\r\n\t  minor1 = SIMD.Float32x4.sub(minor1, SIMD.Float32x4.mul(row3, tmp1));\r\n\t  minor3 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row1, tmp1), minor3);\r\n\r\n\t  // Compute matrix determinant\r\n\t  det   = SIMD.Float32x4.mul(row0, minor0);\r\n\t  det   = SIMD.Float32x4.add(SIMD.Float32x4.swizzle(det, 2, 3, 0, 1), det);\r\n\t  det   = SIMD.Float32x4.add(SIMD.Float32x4.swizzle(det, 1, 0, 3, 2), det);\r\n\t  tmp1  = SIMD.Float32x4.reciprocalApproximation(det);\r\n\t  det   = SIMD.Float32x4.sub(\r\n\t               SIMD.Float32x4.add(tmp1, tmp1),\r\n\t               SIMD.Float32x4.mul(det, SIMD.Float32x4.mul(tmp1, tmp1)));\r\n\t  det   = SIMD.Float32x4.swizzle(det, 0, 0, 0, 0);\r\n\t  if (!det) {\r\n\t      return null;\r\n\t  }\r\n\r\n\t  // Compute matrix inverse\r\n\t  SIMD.Float32x4.store(out, 0,  SIMD.Float32x4.mul(det, minor0));\r\n\t  SIMD.Float32x4.store(out, 4,  SIMD.Float32x4.mul(det, minor1));\r\n\t  SIMD.Float32x4.store(out, 8,  SIMD.Float32x4.mul(det, minor2));\r\n\t  SIMD.Float32x4.store(out, 12, SIMD.Float32x4.mul(det, minor3));\r\n\t  return out;\r\n\t}\r\n\r\n\t/**\r\n\t * Inverts a mat4 using SIMD if available and enabled\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the source matrix\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.invert = glMatrix.USE_SIMD ? mat4.SIMD.invert : mat4.scalar.invert;\r\n\r\n\t/**\r\n\t * Calculates the adjugate of a mat4 not using SIMD\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the source matrix\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.scalar.adjoint = function(out, a) {\r\n\t    var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],\r\n\t        a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],\r\n\t        a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],\r\n\t        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];\r\n\r\n\t    out[0]  =  (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));\r\n\t    out[1]  = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));\r\n\t    out[2]  =  (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));\r\n\t    out[3]  = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));\r\n\t    out[4]  = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));\r\n\t    out[5]  =  (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));\r\n\t    out[6]  = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));\r\n\t    out[7]  =  (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));\r\n\t    out[8]  =  (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));\r\n\t    out[9]  = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));\r\n\t    out[10] =  (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));\r\n\t    out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));\r\n\t    out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));\r\n\t    out[13] =  (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));\r\n\t    out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));\r\n\t    out[15] =  (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Calculates the adjugate of a mat4 using SIMD\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the source matrix\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.SIMD.adjoint = function(out, a) {\r\n\t  var a0, a1, a2, a3;\r\n\t  var row0, row1, row2, row3;\r\n\t  var tmp1;\r\n\t  var minor0, minor1, minor2, minor3;\r\n\r\n\t  a0 = SIMD.Float32x4.load(a, 0);\r\n\t  a1 = SIMD.Float32x4.load(a, 4);\r\n\t  a2 = SIMD.Float32x4.load(a, 8);\r\n\t  a3 = SIMD.Float32x4.load(a, 12);\r\n\r\n\t  // Transpose the source matrix.  Sort of.  Not a true transpose operation\r\n\t  tmp1 = SIMD.Float32x4.shuffle(a0, a1, 0, 1, 4, 5);\r\n\t  row1 = SIMD.Float32x4.shuffle(a2, a3, 0, 1, 4, 5);\r\n\t  row0 = SIMD.Float32x4.shuffle(tmp1, row1, 0, 2, 4, 6);\r\n\t  row1 = SIMD.Float32x4.shuffle(row1, tmp1, 1, 3, 5, 7);\r\n\r\n\t  tmp1 = SIMD.Float32x4.shuffle(a0, a1, 2, 3, 6, 7);\r\n\t  row3 = SIMD.Float32x4.shuffle(a2, a3, 2, 3, 6, 7);\r\n\t  row2 = SIMD.Float32x4.shuffle(tmp1, row3, 0, 2, 4, 6);\r\n\t  row3 = SIMD.Float32x4.shuffle(row3, tmp1, 1, 3, 5, 7);\r\n\r\n\t  tmp1   = SIMD.Float32x4.mul(row2, row3);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);\r\n\t  minor0 = SIMD.Float32x4.mul(row1, tmp1);\r\n\t  minor1 = SIMD.Float32x4.mul(row0, tmp1);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);\r\n\t  minor0 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row1, tmp1), minor0);\r\n\t  minor1 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row0, tmp1), minor1);\r\n\t  minor1 = SIMD.Float32x4.swizzle(minor1, 2, 3, 0, 1);\r\n\r\n\t  tmp1   = SIMD.Float32x4.mul(row1, row2);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);\r\n\t  minor0 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row3, tmp1), minor0);\r\n\t  minor3 = SIMD.Float32x4.mul(row0, tmp1);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);\r\n\t  minor0 = SIMD.Float32x4.sub(minor0, SIMD.Float32x4.mul(row3, tmp1));\r\n\t  minor3 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row0, tmp1), minor3);\r\n\t  minor3 = SIMD.Float32x4.swizzle(minor3, 2, 3, 0, 1);\r\n\r\n\t  tmp1   = SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(row1, 2, 3, 0, 1), row3);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);\r\n\t  row2   = SIMD.Float32x4.swizzle(row2, 2, 3, 0, 1);\r\n\t  minor0 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row2, tmp1), minor0);\r\n\t  minor2 = SIMD.Float32x4.mul(row0, tmp1);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);\r\n\t  minor0 = SIMD.Float32x4.sub(minor0, SIMD.Float32x4.mul(row2, tmp1));\r\n\t  minor2 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row0, tmp1), minor2);\r\n\t  minor2 = SIMD.Float32x4.swizzle(minor2, 2, 3, 0, 1);\r\n\r\n\t  tmp1   = SIMD.Float32x4.mul(row0, row1);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);\r\n\t  minor2 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row3, tmp1), minor2);\r\n\t  minor3 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row2, tmp1), minor3);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);\r\n\t  minor2 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row3, tmp1), minor2);\r\n\t  minor3 = SIMD.Float32x4.sub(minor3, SIMD.Float32x4.mul(row2, tmp1));\r\n\r\n\t  tmp1   = SIMD.Float32x4.mul(row0, row3);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);\r\n\t  minor1 = SIMD.Float32x4.sub(minor1, SIMD.Float32x4.mul(row2, tmp1));\r\n\t  minor2 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row1, tmp1), minor2);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);\r\n\t  minor1 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row2, tmp1), minor1);\r\n\t  minor2 = SIMD.Float32x4.sub(minor2, SIMD.Float32x4.mul(row1, tmp1));\r\n\r\n\t  tmp1   = SIMD.Float32x4.mul(row0, row2);\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);\r\n\t  minor1 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row3, tmp1), minor1);\r\n\t  minor3 = SIMD.Float32x4.sub(minor3, SIMD.Float32x4.mul(row1, tmp1));\r\n\t  tmp1   = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);\r\n\t  minor1 = SIMD.Float32x4.sub(minor1, SIMD.Float32x4.mul(row3, tmp1));\r\n\t  minor3 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row1, tmp1), minor3);\r\n\r\n\t  SIMD.Float32x4.store(out, 0,  minor0);\r\n\t  SIMD.Float32x4.store(out, 4,  minor1);\r\n\t  SIMD.Float32x4.store(out, 8,  minor2);\r\n\t  SIMD.Float32x4.store(out, 12, minor3);\r\n\t  return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Calculates the adjugate of a mat4 using SIMD if available and enabled\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the source matrix\r\n\t * @returns {mat4} out\r\n\t */\r\n\t mat4.adjoint = glMatrix.USE_SIMD ? mat4.SIMD.adjoint : mat4.scalar.adjoint;\r\n\r\n\t/**\r\n\t * Calculates the determinant of a mat4\r\n\t *\r\n\t * @param {mat4} a the source matrix\r\n\t * @returns {Number} determinant of a\r\n\t */\r\n\tmat4.determinant = function (a) {\r\n\t    var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],\r\n\t        a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],\r\n\t        a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],\r\n\t        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],\r\n\r\n\t        b00 = a00 * a11 - a01 * a10,\r\n\t        b01 = a00 * a12 - a02 * a10,\r\n\t        b02 = a00 * a13 - a03 * a10,\r\n\t        b03 = a01 * a12 - a02 * a11,\r\n\t        b04 = a01 * a13 - a03 * a11,\r\n\t        b05 = a02 * a13 - a03 * a12,\r\n\t        b06 = a20 * a31 - a21 * a30,\r\n\t        b07 = a20 * a32 - a22 * a30,\r\n\t        b08 = a20 * a33 - a23 * a30,\r\n\t        b09 = a21 * a32 - a22 * a31,\r\n\t        b10 = a21 * a33 - a23 * a31,\r\n\t        b11 = a22 * a33 - a23 * a32;\r\n\r\n\t    // Calculate the determinant\r\n\t    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\r\n\t};\r\n\r\n\t/**\r\n\t * Multiplies two mat4's explicitly using SIMD\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the first operand, must be a Float32Array\r\n\t * @param {mat4} b the second operand, must be a Float32Array\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.SIMD.multiply = function (out, a, b) {\r\n\t    var a0 = SIMD.Float32x4.load(a, 0);\r\n\t    var a1 = SIMD.Float32x4.load(a, 4);\r\n\t    var a2 = SIMD.Float32x4.load(a, 8);\r\n\t    var a3 = SIMD.Float32x4.load(a, 12);\r\n\r\n\t    var b0 = SIMD.Float32x4.load(b, 0);\r\n\t    var out0 = SIMD.Float32x4.add(\r\n\t                   SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b0, 0, 0, 0, 0), a0),\r\n\t                   SIMD.Float32x4.add(\r\n\t                       SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b0, 1, 1, 1, 1), a1),\r\n\t                       SIMD.Float32x4.add(\r\n\t                           SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b0, 2, 2, 2, 2), a2),\r\n\t                           SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b0, 3, 3, 3, 3), a3))));\r\n\t    SIMD.Float32x4.store(out, 0, out0);\r\n\r\n\t    var b1 = SIMD.Float32x4.load(b, 4);\r\n\t    var out1 = SIMD.Float32x4.add(\r\n\t                   SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b1, 0, 0, 0, 0), a0),\r\n\t                   SIMD.Float32x4.add(\r\n\t                       SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b1, 1, 1, 1, 1), a1),\r\n\t                       SIMD.Float32x4.add(\r\n\t                           SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b1, 2, 2, 2, 2), a2),\r\n\t                           SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b1, 3, 3, 3, 3), a3))));\r\n\t    SIMD.Float32x4.store(out, 4, out1);\r\n\r\n\t    var b2 = SIMD.Float32x4.load(b, 8);\r\n\t    var out2 = SIMD.Float32x4.add(\r\n\t                   SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b2, 0, 0, 0, 0), a0),\r\n\t                   SIMD.Float32x4.add(\r\n\t                       SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b2, 1, 1, 1, 1), a1),\r\n\t                       SIMD.Float32x4.add(\r\n\t                               SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b2, 2, 2, 2, 2), a2),\r\n\t                               SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b2, 3, 3, 3, 3), a3))));\r\n\t    SIMD.Float32x4.store(out, 8, out2);\r\n\r\n\t    var b3 = SIMD.Float32x4.load(b, 12);\r\n\t    var out3 = SIMD.Float32x4.add(\r\n\t                   SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b3, 0, 0, 0, 0), a0),\r\n\t                   SIMD.Float32x4.add(\r\n\t                        SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b3, 1, 1, 1, 1), a1),\r\n\t                        SIMD.Float32x4.add(\r\n\t                            SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b3, 2, 2, 2, 2), a2),\r\n\t                            SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b3, 3, 3, 3, 3), a3))));\r\n\t    SIMD.Float32x4.store(out, 12, out3);\r\n\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Multiplies two mat4's explicitly not using SIMD\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the first operand\r\n\t * @param {mat4} b the second operand\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.scalar.multiply = function (out, a, b) {\r\n\t    var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],\r\n\t        a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],\r\n\t        a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],\r\n\t        a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];\r\n\r\n\t    // Cache only the current line of the second matrix\r\n\t    var b0  = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\r\n\t    out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;\r\n\t    out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;\r\n\t    out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;\r\n\t    out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;\r\n\r\n\t    b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];\r\n\t    out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;\r\n\t    out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;\r\n\t    out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;\r\n\t    out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;\r\n\r\n\t    b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];\r\n\t    out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;\r\n\t    out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;\r\n\t    out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;\r\n\t    out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;\r\n\r\n\t    b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];\r\n\t    out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;\r\n\t    out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;\r\n\t    out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;\r\n\t    out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Multiplies two mat4's using SIMD if available and enabled\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the first operand\r\n\t * @param {mat4} b the second operand\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.multiply = glMatrix.USE_SIMD ? mat4.SIMD.multiply : mat4.scalar.multiply;\r\n\r\n\t/**\r\n\t * Alias for {@link mat4.multiply}\r\n\t * @function\r\n\t */\r\n\tmat4.mul = mat4.multiply;\r\n\r\n\t/**\r\n\t * Translate a mat4 by the given vector not using SIMD\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the matrix to translate\r\n\t * @param {vec3} v vector to translate by\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.scalar.translate = function (out, a, v) {\r\n\t    var x = v[0], y = v[1], z = v[2],\r\n\t        a00, a01, a02, a03,\r\n\t        a10, a11, a12, a13,\r\n\t        a20, a21, a22, a23;\r\n\r\n\t    if (a === out) {\r\n\t        out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];\r\n\t        out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];\r\n\t        out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];\r\n\t        out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];\r\n\t    } else {\r\n\t        a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];\r\n\t        a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];\r\n\t        a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];\r\n\r\n\t        out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03;\r\n\t        out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13;\r\n\t        out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23;\r\n\r\n\t        out[12] = a00 * x + a10 * y + a20 * z + a[12];\r\n\t        out[13] = a01 * x + a11 * y + a21 * z + a[13];\r\n\t        out[14] = a02 * x + a12 * y + a22 * z + a[14];\r\n\t        out[15] = a03 * x + a13 * y + a23 * z + a[15];\r\n\t    }\r\n\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Translates a mat4 by the given vector using SIMD\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the matrix to translate\r\n\t * @param {vec3} v vector to translate by\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.SIMD.translate = function (out, a, v) {\r\n\t    var a0 = SIMD.Float32x4.load(a, 0),\r\n\t        a1 = SIMD.Float32x4.load(a, 4),\r\n\t        a2 = SIMD.Float32x4.load(a, 8),\r\n\t        a3 = SIMD.Float32x4.load(a, 12),\r\n\t        vec = SIMD.Float32x4(v[0], v[1], v[2] , 0);\r\n\r\n\t    if (a !== out) {\r\n\t        out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3];\r\n\t        out[4] = a[4]; out[5] = a[5]; out[6] = a[6]; out[7] = a[7];\r\n\t        out[8] = a[8]; out[9] = a[9]; out[10] = a[10]; out[11] = a[11];\r\n\t    }\r\n\r\n\t    a0 = SIMD.Float32x4.mul(a0, SIMD.Float32x4.swizzle(vec, 0, 0, 0, 0));\r\n\t    a1 = SIMD.Float32x4.mul(a1, SIMD.Float32x4.swizzle(vec, 1, 1, 1, 1));\r\n\t    a2 = SIMD.Float32x4.mul(a2, SIMD.Float32x4.swizzle(vec, 2, 2, 2, 2));\r\n\r\n\t    var t0 = SIMD.Float32x4.add(a0, SIMD.Float32x4.add(a1, SIMD.Float32x4.add(a2, a3)));\r\n\t    SIMD.Float32x4.store(out, 12, t0);\r\n\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Translates a mat4 by the given vector using SIMD if available and enabled\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the matrix to translate\r\n\t * @param {vec3} v vector to translate by\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.translate = glMatrix.USE_SIMD ? mat4.SIMD.translate : mat4.scalar.translate;\r\n\r\n\t/**\r\n\t * Scales the mat4 by the dimensions in the given vec3 not using vectorization\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the matrix to scale\r\n\t * @param {vec3} v the vec3 to scale the matrix by\r\n\t * @returns {mat4} out\r\n\t **/\r\n\tmat4.scalar.scale = function(out, a, v) {\r\n\t    var x = v[0], y = v[1], z = v[2];\r\n\r\n\t    out[0] = a[0] * x;\r\n\t    out[1] = a[1] * x;\r\n\t    out[2] = a[2] * x;\r\n\t    out[3] = a[3] * x;\r\n\t    out[4] = a[4] * y;\r\n\t    out[5] = a[5] * y;\r\n\t    out[6] = a[6] * y;\r\n\t    out[7] = a[7] * y;\r\n\t    out[8] = a[8] * z;\r\n\t    out[9] = a[9] * z;\r\n\t    out[10] = a[10] * z;\r\n\t    out[11] = a[11] * z;\r\n\t    out[12] = a[12];\r\n\t    out[13] = a[13];\r\n\t    out[14] = a[14];\r\n\t    out[15] = a[15];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Scales the mat4 by the dimensions in the given vec3 using vectorization\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the matrix to scale\r\n\t * @param {vec3} v the vec3 to scale the matrix by\r\n\t * @returns {mat4} out\r\n\t **/\r\n\tmat4.SIMD.scale = function(out, a, v) {\r\n\t    var a0, a1, a2;\r\n\t    var vec = SIMD.Float32x4(v[0], v[1], v[2], 0);\r\n\r\n\t    a0 = SIMD.Float32x4.load(a, 0);\r\n\t    SIMD.Float32x4.store(\r\n\t        out, 0, SIMD.Float32x4.mul(a0, SIMD.Float32x4.swizzle(vec, 0, 0, 0, 0)));\r\n\r\n\t    a1 = SIMD.Float32x4.load(a, 4);\r\n\t    SIMD.Float32x4.store(\r\n\t        out, 4, SIMD.Float32x4.mul(a1, SIMD.Float32x4.swizzle(vec, 1, 1, 1, 1)));\r\n\r\n\t    a2 = SIMD.Float32x4.load(a, 8);\r\n\t    SIMD.Float32x4.store(\r\n\t        out, 8, SIMD.Float32x4.mul(a2, SIMD.Float32x4.swizzle(vec, 2, 2, 2, 2)));\r\n\r\n\t    out[12] = a[12];\r\n\t    out[13] = a[13];\r\n\t    out[14] = a[14];\r\n\t    out[15] = a[15];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Scales the mat4 by the dimensions in the given vec3 using SIMD if available and enabled\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the matrix to scale\r\n\t * @param {vec3} v the vec3 to scale the matrix by\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.scale = glMatrix.USE_SIMD ? mat4.SIMD.scale : mat4.scalar.scale;\r\n\r\n\t/**\r\n\t * Rotates a mat4 by the given angle around the given axis\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the matrix to rotate\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @param {vec3} axis the axis to rotate around\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.rotate = function (out, a, rad, axis) {\r\n\t    var x = axis[0], y = axis[1], z = axis[2],\r\n\t        len = Math.sqrt(x * x + y * y + z * z),\r\n\t        s, c, t,\r\n\t        a00, a01, a02, a03,\r\n\t        a10, a11, a12, a13,\r\n\t        a20, a21, a22, a23,\r\n\t        b00, b01, b02,\r\n\t        b10, b11, b12,\r\n\t        b20, b21, b22;\r\n\r\n\t    if (Math.abs(len) < glMatrix.EPSILON) { return null; }\r\n\r\n\t    len = 1 / len;\r\n\t    x *= len;\r\n\t    y *= len;\r\n\t    z *= len;\r\n\r\n\t    s = Math.sin(rad);\r\n\t    c = Math.cos(rad);\r\n\t    t = 1 - c;\r\n\r\n\t    a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];\r\n\t    a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];\r\n\t    a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];\r\n\r\n\t    // Construct the elements of the rotation matrix\r\n\t    b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;\r\n\t    b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;\r\n\t    b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;\r\n\r\n\t    // Perform rotation-specific matrix multiplication\r\n\t    out[0] = a00 * b00 + a10 * b01 + a20 * b02;\r\n\t    out[1] = a01 * b00 + a11 * b01 + a21 * b02;\r\n\t    out[2] = a02 * b00 + a12 * b01 + a22 * b02;\r\n\t    out[3] = a03 * b00 + a13 * b01 + a23 * b02;\r\n\t    out[4] = a00 * b10 + a10 * b11 + a20 * b12;\r\n\t    out[5] = a01 * b10 + a11 * b11 + a21 * b12;\r\n\t    out[6] = a02 * b10 + a12 * b11 + a22 * b12;\r\n\t    out[7] = a03 * b10 + a13 * b11 + a23 * b12;\r\n\t    out[8] = a00 * b20 + a10 * b21 + a20 * b22;\r\n\t    out[9] = a01 * b20 + a11 * b21 + a21 * b22;\r\n\t    out[10] = a02 * b20 + a12 * b21 + a22 * b22;\r\n\t    out[11] = a03 * b20 + a13 * b21 + a23 * b22;\r\n\r\n\t    if (a !== out) { // If the source and destination differ, copy the unchanged last row\r\n\t        out[12] = a[12];\r\n\t        out[13] = a[13];\r\n\t        out[14] = a[14];\r\n\t        out[15] = a[15];\r\n\t    }\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Rotates a matrix by the given angle around the X axis not using SIMD\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the matrix to rotate\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.scalar.rotateX = function (out, a, rad) {\r\n\t    var s = Math.sin(rad),\r\n\t        c = Math.cos(rad),\r\n\t        a10 = a[4],\r\n\t        a11 = a[5],\r\n\t        a12 = a[6],\r\n\t        a13 = a[7],\r\n\t        a20 = a[8],\r\n\t        a21 = a[9],\r\n\t        a22 = a[10],\r\n\t        a23 = a[11];\r\n\r\n\t    if (a !== out) { // If the source and destination differ, copy the unchanged rows\r\n\t        out[0]  = a[0];\r\n\t        out[1]  = a[1];\r\n\t        out[2]  = a[2];\r\n\t        out[3]  = a[3];\r\n\t        out[12] = a[12];\r\n\t        out[13] = a[13];\r\n\t        out[14] = a[14];\r\n\t        out[15] = a[15];\r\n\t    }\r\n\r\n\t    // Perform axis-specific matrix multiplication\r\n\t    out[4] = a10 * c + a20 * s;\r\n\t    out[5] = a11 * c + a21 * s;\r\n\t    out[6] = a12 * c + a22 * s;\r\n\t    out[7] = a13 * c + a23 * s;\r\n\t    out[8] = a20 * c - a10 * s;\r\n\t    out[9] = a21 * c - a11 * s;\r\n\t    out[10] = a22 * c - a12 * s;\r\n\t    out[11] = a23 * c - a13 * s;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Rotates a matrix by the given angle around the X axis using SIMD\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the matrix to rotate\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.SIMD.rotateX = function (out, a, rad) {\r\n\t    var s = SIMD.Float32x4.splat(Math.sin(rad)),\r\n\t        c = SIMD.Float32x4.splat(Math.cos(rad));\r\n\r\n\t    if (a !== out) { // If the source and destination differ, copy the unchanged rows\r\n\t      out[0]  = a[0];\r\n\t      out[1]  = a[1];\r\n\t      out[2]  = a[2];\r\n\t      out[3]  = a[3];\r\n\t      out[12] = a[12];\r\n\t      out[13] = a[13];\r\n\t      out[14] = a[14];\r\n\t      out[15] = a[15];\r\n\t    }\r\n\r\n\t    // Perform axis-specific matrix multiplication\r\n\t    var a_1 = SIMD.Float32x4.load(a, 4);\r\n\t    var a_2 = SIMD.Float32x4.load(a, 8);\r\n\t    SIMD.Float32x4.store(out, 4,\r\n\t                         SIMD.Float32x4.add(SIMD.Float32x4.mul(a_1, c), SIMD.Float32x4.mul(a_2, s)));\r\n\t    SIMD.Float32x4.store(out, 8,\r\n\t                         SIMD.Float32x4.sub(SIMD.Float32x4.mul(a_2, c), SIMD.Float32x4.mul(a_1, s)));\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Rotates a matrix by the given angle around the X axis using SIMD if availabe and enabled\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the matrix to rotate\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.rotateX = glMatrix.USE_SIMD ? mat4.SIMD.rotateX : mat4.scalar.rotateX;\r\n\r\n\t/**\r\n\t * Rotates a matrix by the given angle around the Y axis not using SIMD\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the matrix to rotate\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.scalar.rotateY = function (out, a, rad) {\r\n\t    var s = Math.sin(rad),\r\n\t        c = Math.cos(rad),\r\n\t        a00 = a[0],\r\n\t        a01 = a[1],\r\n\t        a02 = a[2],\r\n\t        a03 = a[3],\r\n\t        a20 = a[8],\r\n\t        a21 = a[9],\r\n\t        a22 = a[10],\r\n\t        a23 = a[11];\r\n\r\n\t    if (a !== out) { // If the source and destination differ, copy the unchanged rows\r\n\t        out[4]  = a[4];\r\n\t        out[5]  = a[5];\r\n\t        out[6]  = a[6];\r\n\t        out[7]  = a[7];\r\n\t        out[12] = a[12];\r\n\t        out[13] = a[13];\r\n\t        out[14] = a[14];\r\n\t        out[15] = a[15];\r\n\t    }\r\n\r\n\t    // Perform axis-specific matrix multiplication\r\n\t    out[0] = a00 * c - a20 * s;\r\n\t    out[1] = a01 * c - a21 * s;\r\n\t    out[2] = a02 * c - a22 * s;\r\n\t    out[3] = a03 * c - a23 * s;\r\n\t    out[8] = a00 * s + a20 * c;\r\n\t    out[9] = a01 * s + a21 * c;\r\n\t    out[10] = a02 * s + a22 * c;\r\n\t    out[11] = a03 * s + a23 * c;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Rotates a matrix by the given angle around the Y axis using SIMD\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the matrix to rotate\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.SIMD.rotateY = function (out, a, rad) {\r\n\t    var s = SIMD.Float32x4.splat(Math.sin(rad)),\r\n\t        c = SIMD.Float32x4.splat(Math.cos(rad));\r\n\r\n\t    if (a !== out) { // If the source and destination differ, copy the unchanged rows\r\n\t        out[4]  = a[4];\r\n\t        out[5]  = a[5];\r\n\t        out[6]  = a[6];\r\n\t        out[7]  = a[7];\r\n\t        out[12] = a[12];\r\n\t        out[13] = a[13];\r\n\t        out[14] = a[14];\r\n\t        out[15] = a[15];\r\n\t    }\r\n\r\n\t    // Perform axis-specific matrix multiplication\r\n\t    var a_0 = SIMD.Float32x4.load(a, 0);\r\n\t    var a_2 = SIMD.Float32x4.load(a, 8);\r\n\t    SIMD.Float32x4.store(out, 0,\r\n\t                         SIMD.Float32x4.sub(SIMD.Float32x4.mul(a_0, c), SIMD.Float32x4.mul(a_2, s)));\r\n\t    SIMD.Float32x4.store(out, 8,\r\n\t                         SIMD.Float32x4.add(SIMD.Float32x4.mul(a_0, s), SIMD.Float32x4.mul(a_2, c)));\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Rotates a matrix by the given angle around the Y axis if SIMD available and enabled\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the matrix to rotate\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @returns {mat4} out\r\n\t */\r\n\t mat4.rotateY = glMatrix.USE_SIMD ? mat4.SIMD.rotateY : mat4.scalar.rotateY;\r\n\r\n\t/**\r\n\t * Rotates a matrix by the given angle around the Z axis not using SIMD\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the matrix to rotate\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.scalar.rotateZ = function (out, a, rad) {\r\n\t    var s = Math.sin(rad),\r\n\t        c = Math.cos(rad),\r\n\t        a00 = a[0],\r\n\t        a01 = a[1],\r\n\t        a02 = a[2],\r\n\t        a03 = a[3],\r\n\t        a10 = a[4],\r\n\t        a11 = a[5],\r\n\t        a12 = a[6],\r\n\t        a13 = a[7];\r\n\r\n\t    if (a !== out) { // If the source and destination differ, copy the unchanged last row\r\n\t        out[8]  = a[8];\r\n\t        out[9]  = a[9];\r\n\t        out[10] = a[10];\r\n\t        out[11] = a[11];\r\n\t        out[12] = a[12];\r\n\t        out[13] = a[13];\r\n\t        out[14] = a[14];\r\n\t        out[15] = a[15];\r\n\t    }\r\n\r\n\t    // Perform axis-specific matrix multiplication\r\n\t    out[0] = a00 * c + a10 * s;\r\n\t    out[1] = a01 * c + a11 * s;\r\n\t    out[2] = a02 * c + a12 * s;\r\n\t    out[3] = a03 * c + a13 * s;\r\n\t    out[4] = a10 * c - a00 * s;\r\n\t    out[5] = a11 * c - a01 * s;\r\n\t    out[6] = a12 * c - a02 * s;\r\n\t    out[7] = a13 * c - a03 * s;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Rotates a matrix by the given angle around the Z axis using SIMD\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the matrix to rotate\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.SIMD.rotateZ = function (out, a, rad) {\r\n\t    var s = SIMD.Float32x4.splat(Math.sin(rad)),\r\n\t        c = SIMD.Float32x4.splat(Math.cos(rad));\r\n\r\n\t    if (a !== out) { // If the source and destination differ, copy the unchanged last row\r\n\t        out[8]  = a[8];\r\n\t        out[9]  = a[9];\r\n\t        out[10] = a[10];\r\n\t        out[11] = a[11];\r\n\t        out[12] = a[12];\r\n\t        out[13] = a[13];\r\n\t        out[14] = a[14];\r\n\t        out[15] = a[15];\r\n\t    }\r\n\r\n\t    // Perform axis-specific matrix multiplication\r\n\t    var a_0 = SIMD.Float32x4.load(a, 0);\r\n\t    var a_1 = SIMD.Float32x4.load(a, 4);\r\n\t    SIMD.Float32x4.store(out, 0,\r\n\t                         SIMD.Float32x4.add(SIMD.Float32x4.mul(a_0, c), SIMD.Float32x4.mul(a_1, s)));\r\n\t    SIMD.Float32x4.store(out, 4,\r\n\t                         SIMD.Float32x4.sub(SIMD.Float32x4.mul(a_1, c), SIMD.Float32x4.mul(a_0, s)));\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Rotates a matrix by the given angle around the Z axis if SIMD available and enabled\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the matrix to rotate\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @returns {mat4} out\r\n\t */\r\n\t mat4.rotateZ = glMatrix.USE_SIMD ? mat4.SIMD.rotateZ : mat4.scalar.rotateZ;\r\n\r\n\t/**\r\n\t * Creates a matrix from a vector translation\r\n\t * This is equivalent to (but much faster than):\r\n\t *\r\n\t *     mat4.identity(dest);\r\n\t *     mat4.translate(dest, dest, vec);\r\n\t *\r\n\t * @param {mat4} out mat4 receiving operation result\r\n\t * @param {vec3} v Translation vector\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.fromTranslation = function(out, v) {\r\n\t    out[0] = 1;\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = 0;\r\n\t    out[4] = 0;\r\n\t    out[5] = 1;\r\n\t    out[6] = 0;\r\n\t    out[7] = 0;\r\n\t    out[8] = 0;\r\n\t    out[9] = 0;\r\n\t    out[10] = 1;\r\n\t    out[11] = 0;\r\n\t    out[12] = v[0];\r\n\t    out[13] = v[1];\r\n\t    out[14] = v[2];\r\n\t    out[15] = 1;\r\n\t    return out;\r\n\t}\r\n\r\n\t/**\r\n\t * Creates a matrix from a vector scaling\r\n\t * This is equivalent to (but much faster than):\r\n\t *\r\n\t *     mat4.identity(dest);\r\n\t *     mat4.scale(dest, dest, vec);\r\n\t *\r\n\t * @param {mat4} out mat4 receiving operation result\r\n\t * @param {vec3} v Scaling vector\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.fromScaling = function(out, v) {\r\n\t    out[0] = v[0];\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = 0;\r\n\t    out[4] = 0;\r\n\t    out[5] = v[1];\r\n\t    out[6] = 0;\r\n\t    out[7] = 0;\r\n\t    out[8] = 0;\r\n\t    out[9] = 0;\r\n\t    out[10] = v[2];\r\n\t    out[11] = 0;\r\n\t    out[12] = 0;\r\n\t    out[13] = 0;\r\n\t    out[14] = 0;\r\n\t    out[15] = 1;\r\n\t    return out;\r\n\t}\r\n\r\n\t/**\r\n\t * Creates a matrix from a given angle around a given axis\r\n\t * This is equivalent to (but much faster than):\r\n\t *\r\n\t *     mat4.identity(dest);\r\n\t *     mat4.rotate(dest, dest, rad, axis);\r\n\t *\r\n\t * @param {mat4} out mat4 receiving operation result\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @param {vec3} axis the axis to rotate around\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.fromRotation = function(out, rad, axis) {\r\n\t    var x = axis[0], y = axis[1], z = axis[2],\r\n\t        len = Math.sqrt(x * x + y * y + z * z),\r\n\t        s, c, t;\r\n\r\n\t    if (Math.abs(len) < glMatrix.EPSILON) { return null; }\r\n\r\n\t    len = 1 / len;\r\n\t    x *= len;\r\n\t    y *= len;\r\n\t    z *= len;\r\n\r\n\t    s = Math.sin(rad);\r\n\t    c = Math.cos(rad);\r\n\t    t = 1 - c;\r\n\r\n\t    // Perform rotation-specific matrix multiplication\r\n\t    out[0] = x * x * t + c;\r\n\t    out[1] = y * x * t + z * s;\r\n\t    out[2] = z * x * t - y * s;\r\n\t    out[3] = 0;\r\n\t    out[4] = x * y * t - z * s;\r\n\t    out[5] = y * y * t + c;\r\n\t    out[6] = z * y * t + x * s;\r\n\t    out[7] = 0;\r\n\t    out[8] = x * z * t + y * s;\r\n\t    out[9] = y * z * t - x * s;\r\n\t    out[10] = z * z * t + c;\r\n\t    out[11] = 0;\r\n\t    out[12] = 0;\r\n\t    out[13] = 0;\r\n\t    out[14] = 0;\r\n\t    out[15] = 1;\r\n\t    return out;\r\n\t}\r\n\r\n\t/**\r\n\t * Creates a matrix from the given angle around the X axis\r\n\t * This is equivalent to (but much faster than):\r\n\t *\r\n\t *     mat4.identity(dest);\r\n\t *     mat4.rotateX(dest, dest, rad);\r\n\t *\r\n\t * @param {mat4} out mat4 receiving operation result\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.fromXRotation = function(out, rad) {\r\n\t    var s = Math.sin(rad),\r\n\t        c = Math.cos(rad);\r\n\r\n\t    // Perform axis-specific matrix multiplication\r\n\t    out[0]  = 1;\r\n\t    out[1]  = 0;\r\n\t    out[2]  = 0;\r\n\t    out[3]  = 0;\r\n\t    out[4] = 0;\r\n\t    out[5] = c;\r\n\t    out[6] = s;\r\n\t    out[7] = 0;\r\n\t    out[8] = 0;\r\n\t    out[9] = -s;\r\n\t    out[10] = c;\r\n\t    out[11] = 0;\r\n\t    out[12] = 0;\r\n\t    out[13] = 0;\r\n\t    out[14] = 0;\r\n\t    out[15] = 1;\r\n\t    return out;\r\n\t}\r\n\r\n\t/**\r\n\t * Creates a matrix from the given angle around the Y axis\r\n\t * This is equivalent to (but much faster than):\r\n\t *\r\n\t *     mat4.identity(dest);\r\n\t *     mat4.rotateY(dest, dest, rad);\r\n\t *\r\n\t * @param {mat4} out mat4 receiving operation result\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.fromYRotation = function(out, rad) {\r\n\t    var s = Math.sin(rad),\r\n\t        c = Math.cos(rad);\r\n\r\n\t    // Perform axis-specific matrix multiplication\r\n\t    out[0]  = c;\r\n\t    out[1]  = 0;\r\n\t    out[2]  = -s;\r\n\t    out[3]  = 0;\r\n\t    out[4] = 0;\r\n\t    out[5] = 1;\r\n\t    out[6] = 0;\r\n\t    out[7] = 0;\r\n\t    out[8] = s;\r\n\t    out[9] = 0;\r\n\t    out[10] = c;\r\n\t    out[11] = 0;\r\n\t    out[12] = 0;\r\n\t    out[13] = 0;\r\n\t    out[14] = 0;\r\n\t    out[15] = 1;\r\n\t    return out;\r\n\t}\r\n\r\n\t/**\r\n\t * Creates a matrix from the given angle around the Z axis\r\n\t * This is equivalent to (but much faster than):\r\n\t *\r\n\t *     mat4.identity(dest);\r\n\t *     mat4.rotateZ(dest, dest, rad);\r\n\t *\r\n\t * @param {mat4} out mat4 receiving operation result\r\n\t * @param {Number} rad the angle to rotate the matrix by\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.fromZRotation = function(out, rad) {\r\n\t    var s = Math.sin(rad),\r\n\t        c = Math.cos(rad);\r\n\r\n\t    // Perform axis-specific matrix multiplication\r\n\t    out[0]  = c;\r\n\t    out[1]  = s;\r\n\t    out[2]  = 0;\r\n\t    out[3]  = 0;\r\n\t    out[4] = -s;\r\n\t    out[5] = c;\r\n\t    out[6] = 0;\r\n\t    out[7] = 0;\r\n\t    out[8] = 0;\r\n\t    out[9] = 0;\r\n\t    out[10] = 1;\r\n\t    out[11] = 0;\r\n\t    out[12] = 0;\r\n\t    out[13] = 0;\r\n\t    out[14] = 0;\r\n\t    out[15] = 1;\r\n\t    return out;\r\n\t}\r\n\r\n\t/**\r\n\t * Creates a matrix from a quaternion rotation and vector translation\r\n\t * This is equivalent to (but much faster than):\r\n\t *\r\n\t *     mat4.identity(dest);\r\n\t *     mat4.translate(dest, vec);\r\n\t *     var quatMat = mat4.create();\r\n\t *     quat4.toMat4(quat, quatMat);\r\n\t *     mat4.multiply(dest, quatMat);\r\n\t *\r\n\t * @param {mat4} out mat4 receiving operation result\r\n\t * @param {quat4} q Rotation quaternion\r\n\t * @param {vec3} v Translation vector\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.fromRotationTranslation = function (out, q, v) {\r\n\t    // Quaternion math\r\n\t    var x = q[0], y = q[1], z = q[2], w = q[3],\r\n\t        x2 = x + x,\r\n\t        y2 = y + y,\r\n\t        z2 = z + z,\r\n\r\n\t        xx = x * x2,\r\n\t        xy = x * y2,\r\n\t        xz = x * z2,\r\n\t        yy = y * y2,\r\n\t        yz = y * z2,\r\n\t        zz = z * z2,\r\n\t        wx = w * x2,\r\n\t        wy = w * y2,\r\n\t        wz = w * z2;\r\n\r\n\t    out[0] = 1 - (yy + zz);\r\n\t    out[1] = xy + wz;\r\n\t    out[2] = xz - wy;\r\n\t    out[3] = 0;\r\n\t    out[4] = xy - wz;\r\n\t    out[5] = 1 - (xx + zz);\r\n\t    out[6] = yz + wx;\r\n\t    out[7] = 0;\r\n\t    out[8] = xz + wy;\r\n\t    out[9] = yz - wx;\r\n\t    out[10] = 1 - (xx + yy);\r\n\t    out[11] = 0;\r\n\t    out[12] = v[0];\r\n\t    out[13] = v[1];\r\n\t    out[14] = v[2];\r\n\t    out[15] = 1;\r\n\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Returns the translation vector component of a transformation\r\n\t *  matrix. If a matrix is built with fromRotationTranslation,\r\n\t *  the returned vector will be the same as the translation vector\r\n\t *  originally supplied.\r\n\t * @param  {vec3} out Vector to receive translation component\r\n\t * @param  {mat4} mat Matrix to be decomposed (input)\r\n\t * @return {vec3} out\r\n\t */\r\n\tmat4.getTranslation = function (out, mat) {\r\n\t  out[0] = mat[12];\r\n\t  out[1] = mat[13];\r\n\t  out[2] = mat[14];\r\n\r\n\t  return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Returns a quaternion representing the rotational component\r\n\t *  of a transformation matrix. If a matrix is built with\r\n\t *  fromRotationTranslation, the returned quaternion will be the\r\n\t *  same as the quaternion originally supplied.\r\n\t * @param {quat} out Quaternion to receive the rotation component\r\n\t * @param {mat4} mat Matrix to be decomposed (input)\r\n\t * @return {quat} out\r\n\t */\r\n\tmat4.getRotation = function (out, mat) {\r\n\t  // Algorithm taken from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm\r\n\t  var trace = mat[0] + mat[5] + mat[10];\r\n\t  var S = 0;\r\n\r\n\t  if (trace > 0) { \r\n\t    S = Math.sqrt(trace + 1.0) * 2;\r\n\t    out[3] = 0.25 * S;\r\n\t    out[0] = (mat[6] - mat[9]) / S;\r\n\t    out[1] = (mat[8] - mat[2]) / S; \r\n\t    out[2] = (mat[1] - mat[4]) / S; \r\n\t  } else if ((mat[0] > mat[5])&(mat[0] > mat[10])) { \r\n\t    S = Math.sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2;\r\n\t    out[3] = (mat[6] - mat[9]) / S;\r\n\t    out[0] = 0.25 * S;\r\n\t    out[1] = (mat[1] + mat[4]) / S; \r\n\t    out[2] = (mat[8] + mat[2]) / S; \r\n\t  } else if (mat[5] > mat[10]) { \r\n\t    S = Math.sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2;\r\n\t    out[3] = (mat[8] - mat[2]) / S;\r\n\t    out[0] = (mat[1] + mat[4]) / S; \r\n\t    out[1] = 0.25 * S;\r\n\t    out[2] = (mat[6] + mat[9]) / S; \r\n\t  } else { \r\n\t    S = Math.sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2;\r\n\t    out[3] = (mat[1] - mat[4]) / S;\r\n\t    out[0] = (mat[8] + mat[2]) / S;\r\n\t    out[1] = (mat[6] + mat[9]) / S;\r\n\t    out[2] = 0.25 * S;\r\n\t  }\r\n\r\n\t  return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Creates a matrix from a quaternion rotation, vector translation and vector scale\r\n\t * This is equivalent to (but much faster than):\r\n\t *\r\n\t *     mat4.identity(dest);\r\n\t *     mat4.translate(dest, vec);\r\n\t *     var quatMat = mat4.create();\r\n\t *     quat4.toMat4(quat, quatMat);\r\n\t *     mat4.multiply(dest, quatMat);\r\n\t *     mat4.scale(dest, scale)\r\n\t *\r\n\t * @param {mat4} out mat4 receiving operation result\r\n\t * @param {quat4} q Rotation quaternion\r\n\t * @param {vec3} v Translation vector\r\n\t * @param {vec3} s Scaling vector\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.fromRotationTranslationScale = function (out, q, v, s) {\r\n\t    // Quaternion math\r\n\t    var x = q[0], y = q[1], z = q[2], w = q[3],\r\n\t        x2 = x + x,\r\n\t        y2 = y + y,\r\n\t        z2 = z + z,\r\n\r\n\t        xx = x * x2,\r\n\t        xy = x * y2,\r\n\t        xz = x * z2,\r\n\t        yy = y * y2,\r\n\t        yz = y * z2,\r\n\t        zz = z * z2,\r\n\t        wx = w * x2,\r\n\t        wy = w * y2,\r\n\t        wz = w * z2,\r\n\t        sx = s[0],\r\n\t        sy = s[1],\r\n\t        sz = s[2];\r\n\r\n\t    out[0] = (1 - (yy + zz)) * sx;\r\n\t    out[1] = (xy + wz) * sx;\r\n\t    out[2] = (xz - wy) * sx;\r\n\t    out[3] = 0;\r\n\t    out[4] = (xy - wz) * sy;\r\n\t    out[5] = (1 - (xx + zz)) * sy;\r\n\t    out[6] = (yz + wx) * sy;\r\n\t    out[7] = 0;\r\n\t    out[8] = (xz + wy) * sz;\r\n\t    out[9] = (yz - wx) * sz;\r\n\t    out[10] = (1 - (xx + yy)) * sz;\r\n\t    out[11] = 0;\r\n\t    out[12] = v[0];\r\n\t    out[13] = v[1];\r\n\t    out[14] = v[2];\r\n\t    out[15] = 1;\r\n\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin\r\n\t * This is equivalent to (but much faster than):\r\n\t *\r\n\t *     mat4.identity(dest);\r\n\t *     mat4.translate(dest, vec);\r\n\t *     mat4.translate(dest, origin);\r\n\t *     var quatMat = mat4.create();\r\n\t *     quat4.toMat4(quat, quatMat);\r\n\t *     mat4.multiply(dest, quatMat);\r\n\t *     mat4.scale(dest, scale)\r\n\t *     mat4.translate(dest, negativeOrigin);\r\n\t *\r\n\t * @param {mat4} out mat4 receiving operation result\r\n\t * @param {quat4} q Rotation quaternion\r\n\t * @param {vec3} v Translation vector\r\n\t * @param {vec3} s Scaling vector\r\n\t * @param {vec3} o The origin vector around which to scale and rotate\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.fromRotationTranslationScaleOrigin = function (out, q, v, s, o) {\r\n\t  // Quaternion math\r\n\t  var x = q[0], y = q[1], z = q[2], w = q[3],\r\n\t      x2 = x + x,\r\n\t      y2 = y + y,\r\n\t      z2 = z + z,\r\n\r\n\t      xx = x * x2,\r\n\t      xy = x * y2,\r\n\t      xz = x * z2,\r\n\t      yy = y * y2,\r\n\t      yz = y * z2,\r\n\t      zz = z * z2,\r\n\t      wx = w * x2,\r\n\t      wy = w * y2,\r\n\t      wz = w * z2,\r\n\r\n\t      sx = s[0],\r\n\t      sy = s[1],\r\n\t      sz = s[2],\r\n\r\n\t      ox = o[0],\r\n\t      oy = o[1],\r\n\t      oz = o[2];\r\n\r\n\t  out[0] = (1 - (yy + zz)) * sx;\r\n\t  out[1] = (xy + wz) * sx;\r\n\t  out[2] = (xz - wy) * sx;\r\n\t  out[3] = 0;\r\n\t  out[4] = (xy - wz) * sy;\r\n\t  out[5] = (1 - (xx + zz)) * sy;\r\n\t  out[6] = (yz + wx) * sy;\r\n\t  out[7] = 0;\r\n\t  out[8] = (xz + wy) * sz;\r\n\t  out[9] = (yz - wx) * sz;\r\n\t  out[10] = (1 - (xx + yy)) * sz;\r\n\t  out[11] = 0;\r\n\t  out[12] = v[0] + ox - (out[0] * ox + out[4] * oy + out[8] * oz);\r\n\t  out[13] = v[1] + oy - (out[1] * ox + out[5] * oy + out[9] * oz);\r\n\t  out[14] = v[2] + oz - (out[2] * ox + out[6] * oy + out[10] * oz);\r\n\t  out[15] = 1;\r\n\r\n\t  return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Calculates a 4x4 matrix from the given quaternion\r\n\t *\r\n\t * @param {mat4} out mat4 receiving operation result\r\n\t * @param {quat} q Quaternion to create matrix from\r\n\t *\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.fromQuat = function (out, q) {\r\n\t    var x = q[0], y = q[1], z = q[2], w = q[3],\r\n\t        x2 = x + x,\r\n\t        y2 = y + y,\r\n\t        z2 = z + z,\r\n\r\n\t        xx = x * x2,\r\n\t        yx = y * x2,\r\n\t        yy = y * y2,\r\n\t        zx = z * x2,\r\n\t        zy = z * y2,\r\n\t        zz = z * z2,\r\n\t        wx = w * x2,\r\n\t        wy = w * y2,\r\n\t        wz = w * z2;\r\n\r\n\t    out[0] = 1 - yy - zz;\r\n\t    out[1] = yx + wz;\r\n\t    out[2] = zx - wy;\r\n\t    out[3] = 0;\r\n\r\n\t    out[4] = yx - wz;\r\n\t    out[5] = 1 - xx - zz;\r\n\t    out[6] = zy + wx;\r\n\t    out[7] = 0;\r\n\r\n\t    out[8] = zx + wy;\r\n\t    out[9] = zy - wx;\r\n\t    out[10] = 1 - xx - yy;\r\n\t    out[11] = 0;\r\n\r\n\t    out[12] = 0;\r\n\t    out[13] = 0;\r\n\t    out[14] = 0;\r\n\t    out[15] = 1;\r\n\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Generates a frustum matrix with the given bounds\r\n\t *\r\n\t * @param {mat4} out mat4 frustum matrix will be written into\r\n\t * @param {Number} left Left bound of the frustum\r\n\t * @param {Number} right Right bound of the frustum\r\n\t * @param {Number} bottom Bottom bound of the frustum\r\n\t * @param {Number} top Top bound of the frustum\r\n\t * @param {Number} near Near bound of the frustum\r\n\t * @param {Number} far Far bound of the frustum\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.frustum = function (out, left, right, bottom, top, near, far) {\r\n\t    var rl = 1 / (right - left),\r\n\t        tb = 1 / (top - bottom),\r\n\t        nf = 1 / (near - far);\r\n\t    out[0] = (near * 2) * rl;\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = 0;\r\n\t    out[4] = 0;\r\n\t    out[5] = (near * 2) * tb;\r\n\t    out[6] = 0;\r\n\t    out[7] = 0;\r\n\t    out[8] = (right + left) * rl;\r\n\t    out[9] = (top + bottom) * tb;\r\n\t    out[10] = (far + near) * nf;\r\n\t    out[11] = -1;\r\n\t    out[12] = 0;\r\n\t    out[13] = 0;\r\n\t    out[14] = (far * near * 2) * nf;\r\n\t    out[15] = 0;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Generates a perspective projection matrix with the given bounds\r\n\t *\r\n\t * @param {mat4} out mat4 frustum matrix will be written into\r\n\t * @param {number} fovy Vertical field of view in radians\r\n\t * @param {number} aspect Aspect ratio. typically viewport width/height\r\n\t * @param {number} near Near bound of the frustum\r\n\t * @param {number} far Far bound of the frustum\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.perspective = function (out, fovy, aspect, near, far) {\r\n\t    var f = 1.0 / Math.tan(fovy / 2),\r\n\t        nf = 1 / (near - far);\r\n\t    out[0] = f / aspect;\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = 0;\r\n\t    out[4] = 0;\r\n\t    out[5] = f;\r\n\t    out[6] = 0;\r\n\t    out[7] = 0;\r\n\t    out[8] = 0;\r\n\t    out[9] = 0;\r\n\t    out[10] = (far + near) * nf;\r\n\t    out[11] = -1;\r\n\t    out[12] = 0;\r\n\t    out[13] = 0;\r\n\t    out[14] = (2 * far * near) * nf;\r\n\t    out[15] = 0;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Generates a perspective projection matrix with the given field of view.\r\n\t * This is primarily useful for generating projection matrices to be used\r\n\t * with the still experiemental WebVR API.\r\n\t *\r\n\t * @param {mat4} out mat4 frustum matrix will be written into\r\n\t * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees\r\n\t * @param {number} near Near bound of the frustum\r\n\t * @param {number} far Far bound of the frustum\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.perspectiveFromFieldOfView = function (out, fov, near, far) {\r\n\t    var upTan = Math.tan(fov.upDegrees * Math.PI/180.0),\r\n\t        downTan = Math.tan(fov.downDegrees * Math.PI/180.0),\r\n\t        leftTan = Math.tan(fov.leftDegrees * Math.PI/180.0),\r\n\t        rightTan = Math.tan(fov.rightDegrees * Math.PI/180.0),\r\n\t        xScale = 2.0 / (leftTan + rightTan),\r\n\t        yScale = 2.0 / (upTan + downTan);\r\n\r\n\t    out[0] = xScale;\r\n\t    out[1] = 0.0;\r\n\t    out[2] = 0.0;\r\n\t    out[3] = 0.0;\r\n\t    out[4] = 0.0;\r\n\t    out[5] = yScale;\r\n\t    out[6] = 0.0;\r\n\t    out[7] = 0.0;\r\n\t    out[8] = -((leftTan - rightTan) * xScale * 0.5);\r\n\t    out[9] = ((upTan - downTan) * yScale * 0.5);\r\n\t    out[10] = far / (near - far);\r\n\t    out[11] = -1.0;\r\n\t    out[12] = 0.0;\r\n\t    out[13] = 0.0;\r\n\t    out[14] = (far * near) / (near - far);\r\n\t    out[15] = 0.0;\r\n\t    return out;\r\n\t}\r\n\r\n\t/**\r\n\t * Generates a orthogonal projection matrix with the given bounds\r\n\t *\r\n\t * @param {mat4} out mat4 frustum matrix will be written into\r\n\t * @param {number} left Left bound of the frustum\r\n\t * @param {number} right Right bound of the frustum\r\n\t * @param {number} bottom Bottom bound of the frustum\r\n\t * @param {number} top Top bound of the frustum\r\n\t * @param {number} near Near bound of the frustum\r\n\t * @param {number} far Far bound of the frustum\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.ortho = function (out, left, right, bottom, top, near, far) {\r\n\t    var lr = 1 / (left - right),\r\n\t        bt = 1 / (bottom - top),\r\n\t        nf = 1 / (near - far);\r\n\t    out[0] = -2 * lr;\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = 0;\r\n\t    out[4] = 0;\r\n\t    out[5] = -2 * bt;\r\n\t    out[6] = 0;\r\n\t    out[7] = 0;\r\n\t    out[8] = 0;\r\n\t    out[9] = 0;\r\n\t    out[10] = 2 * nf;\r\n\t    out[11] = 0;\r\n\t    out[12] = (left + right) * lr;\r\n\t    out[13] = (top + bottom) * bt;\r\n\t    out[14] = (far + near) * nf;\r\n\t    out[15] = 1;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Generates a look-at matrix with the given eye position, focal point, and up axis\r\n\t *\r\n\t * @param {mat4} out mat4 frustum matrix will be written into\r\n\t * @param {vec3} eye Position of the viewer\r\n\t * @param {vec3} center Point the viewer is looking at\r\n\t * @param {vec3} up vec3 pointing up\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.lookAt = function (out, eye, center, up) {\r\n\t    var x0, x1, x2, y0, y1, y2, z0, z1, z2, len,\r\n\t        eyex = eye[0],\r\n\t        eyey = eye[1],\r\n\t        eyez = eye[2],\r\n\t        upx = up[0],\r\n\t        upy = up[1],\r\n\t        upz = up[2],\r\n\t        centerx = center[0],\r\n\t        centery = center[1],\r\n\t        centerz = center[2];\r\n\r\n\t    if (Math.abs(eyex - centerx) < glMatrix.EPSILON &&\r\n\t        Math.abs(eyey - centery) < glMatrix.EPSILON &&\r\n\t        Math.abs(eyez - centerz) < glMatrix.EPSILON) {\r\n\t        return mat4.identity(out);\r\n\t    }\r\n\r\n\t    z0 = eyex - centerx;\r\n\t    z1 = eyey - centery;\r\n\t    z2 = eyez - centerz;\r\n\r\n\t    len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);\r\n\t    z0 *= len;\r\n\t    z1 *= len;\r\n\t    z2 *= len;\r\n\r\n\t    x0 = upy * z2 - upz * z1;\r\n\t    x1 = upz * z0 - upx * z2;\r\n\t    x2 = upx * z1 - upy * z0;\r\n\t    len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);\r\n\t    if (!len) {\r\n\t        x0 = 0;\r\n\t        x1 = 0;\r\n\t        x2 = 0;\r\n\t    } else {\r\n\t        len = 1 / len;\r\n\t        x0 *= len;\r\n\t        x1 *= len;\r\n\t        x2 *= len;\r\n\t    }\r\n\r\n\t    y0 = z1 * x2 - z2 * x1;\r\n\t    y1 = z2 * x0 - z0 * x2;\r\n\t    y2 = z0 * x1 - z1 * x0;\r\n\r\n\t    len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);\r\n\t    if (!len) {\r\n\t        y0 = 0;\r\n\t        y1 = 0;\r\n\t        y2 = 0;\r\n\t    } else {\r\n\t        len = 1 / len;\r\n\t        y0 *= len;\r\n\t        y1 *= len;\r\n\t        y2 *= len;\r\n\t    }\r\n\r\n\t    out[0] = x0;\r\n\t    out[1] = y0;\r\n\t    out[2] = z0;\r\n\t    out[3] = 0;\r\n\t    out[4] = x1;\r\n\t    out[5] = y1;\r\n\t    out[6] = z1;\r\n\t    out[7] = 0;\r\n\t    out[8] = x2;\r\n\t    out[9] = y2;\r\n\t    out[10] = z2;\r\n\t    out[11] = 0;\r\n\t    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);\r\n\t    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);\r\n\t    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);\r\n\t    out[15] = 1;\r\n\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Returns a string representation of a mat4\r\n\t *\r\n\t * @param {mat4} a matrix to represent as a string\r\n\t * @returns {String} string representation of the matrix\r\n\t */\r\n\tmat4.str = function (a) {\r\n\t    return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +\r\n\t                    a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' +\r\n\t                    a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' +\r\n\t                    a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';\r\n\t};\r\n\r\n\t/**\r\n\t * Returns Frobenius norm of a mat4\r\n\t *\r\n\t * @param {mat4} a the matrix to calculate Frobenius norm of\r\n\t * @returns {Number} Frobenius norm\r\n\t */\r\n\tmat4.frob = function (a) {\r\n\t    return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2) ))\r\n\t};\r\n\r\n\t/**\r\n\t * Adds two mat4's\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the first operand\r\n\t * @param {mat4} b the second operand\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.add = function(out, a, b) {\r\n\t    out[0] = a[0] + b[0];\r\n\t    out[1] = a[1] + b[1];\r\n\t    out[2] = a[2] + b[2];\r\n\t    out[3] = a[3] + b[3];\r\n\t    out[4] = a[4] + b[4];\r\n\t    out[5] = a[5] + b[5];\r\n\t    out[6] = a[6] + b[6];\r\n\t    out[7] = a[7] + b[7];\r\n\t    out[8] = a[8] + b[8];\r\n\t    out[9] = a[9] + b[9];\r\n\t    out[10] = a[10] + b[10];\r\n\t    out[11] = a[11] + b[11];\r\n\t    out[12] = a[12] + b[12];\r\n\t    out[13] = a[13] + b[13];\r\n\t    out[14] = a[14] + b[14];\r\n\t    out[15] = a[15] + b[15];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Subtracts matrix b from matrix a\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the first operand\r\n\t * @param {mat4} b the second operand\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.subtract = function(out, a, b) {\r\n\t    out[0] = a[0] - b[0];\r\n\t    out[1] = a[1] - b[1];\r\n\t    out[2] = a[2] - b[2];\r\n\t    out[3] = a[3] - b[3];\r\n\t    out[4] = a[4] - b[4];\r\n\t    out[5] = a[5] - b[5];\r\n\t    out[6] = a[6] - b[6];\r\n\t    out[7] = a[7] - b[7];\r\n\t    out[8] = a[8] - b[8];\r\n\t    out[9] = a[9] - b[9];\r\n\t    out[10] = a[10] - b[10];\r\n\t    out[11] = a[11] - b[11];\r\n\t    out[12] = a[12] - b[12];\r\n\t    out[13] = a[13] - b[13];\r\n\t    out[14] = a[14] - b[14];\r\n\t    out[15] = a[15] - b[15];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link mat4.subtract}\r\n\t * @function\r\n\t */\r\n\tmat4.sub = mat4.subtract;\r\n\r\n\t/**\r\n\t * Multiply each element of the matrix by a scalar.\r\n\t *\r\n\t * @param {mat4} out the receiving matrix\r\n\t * @param {mat4} a the matrix to scale\r\n\t * @param {Number} b amount to scale the matrix's elements by\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.multiplyScalar = function(out, a, b) {\r\n\t    out[0] = a[0] * b;\r\n\t    out[1] = a[1] * b;\r\n\t    out[2] = a[2] * b;\r\n\t    out[3] = a[3] * b;\r\n\t    out[4] = a[4] * b;\r\n\t    out[5] = a[5] * b;\r\n\t    out[6] = a[6] * b;\r\n\t    out[7] = a[7] * b;\r\n\t    out[8] = a[8] * b;\r\n\t    out[9] = a[9] * b;\r\n\t    out[10] = a[10] * b;\r\n\t    out[11] = a[11] * b;\r\n\t    out[12] = a[12] * b;\r\n\t    out[13] = a[13] * b;\r\n\t    out[14] = a[14] * b;\r\n\t    out[15] = a[15] * b;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Adds two mat4's after multiplying each element of the second operand by a scalar value.\r\n\t *\r\n\t * @param {mat4} out the receiving vector\r\n\t * @param {mat4} a the first operand\r\n\t * @param {mat4} b the second operand\r\n\t * @param {Number} scale the amount to scale b's elements by before adding\r\n\t * @returns {mat4} out\r\n\t */\r\n\tmat4.multiplyScalarAndAdd = function(out, a, b, scale) {\r\n\t    out[0] = a[0] + (b[0] * scale);\r\n\t    out[1] = a[1] + (b[1] * scale);\r\n\t    out[2] = a[2] + (b[2] * scale);\r\n\t    out[3] = a[3] + (b[3] * scale);\r\n\t    out[4] = a[4] + (b[4] * scale);\r\n\t    out[5] = a[5] + (b[5] * scale);\r\n\t    out[6] = a[6] + (b[6] * scale);\r\n\t    out[7] = a[7] + (b[7] * scale);\r\n\t    out[8] = a[8] + (b[8] * scale);\r\n\t    out[9] = a[9] + (b[9] * scale);\r\n\t    out[10] = a[10] + (b[10] * scale);\r\n\t    out[11] = a[11] + (b[11] * scale);\r\n\t    out[12] = a[12] + (b[12] * scale);\r\n\t    out[13] = a[13] + (b[13] * scale);\r\n\t    out[14] = a[14] + (b[14] * scale);\r\n\t    out[15] = a[15] + (b[15] * scale);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)\r\n\t *\r\n\t * @param {mat4} a The first matrix.\r\n\t * @param {mat4} b The second matrix.\r\n\t * @returns {Boolean} True if the matrices are equal, false otherwise.\r\n\t */\r\n\tmat4.exactEquals = function (a, b) {\r\n\t    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && \r\n\t           a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && \r\n\t           a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] &&\r\n\t           a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];\r\n\t};\r\n\r\n\t/**\r\n\t * Returns whether or not the matrices have approximately the same elements in the same position.\r\n\t *\r\n\t * @param {mat4} a The first matrix.\r\n\t * @param {mat4} b The second matrix.\r\n\t * @returns {Boolean} True if the matrices are equal, false otherwise.\r\n\t */\r\n\tmat4.equals = function (a, b) {\r\n\t    var a0  = a[0],  a1  = a[1],  a2  = a[2],  a3  = a[3],\r\n\t        a4  = a[4],  a5  = a[5],  a6  = a[6],  a7  = a[7], \r\n\t        a8  = a[8],  a9  = a[9],  a10 = a[10], a11 = a[11], \r\n\t        a12 = a[12], a13 = a[13], a14 = a[14], a15 = a[15];\r\n\r\n\t    var b0  = b[0],  b1  = b[1],  b2  = b[2],  b3  = b[3],\r\n\t        b4  = b[4],  b5  = b[5],  b6  = b[6],  b7  = b[7], \r\n\t        b8  = b[8],  b9  = b[9],  b10 = b[10], b11 = b[11], \r\n\t        b12 = b[12], b13 = b[13], b14 = b[14], b15 = b[15];\r\n\r\n\t    return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\r\n\t            Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\r\n\t            Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\r\n\t            Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&\r\n\t            Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&\r\n\t            Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&\r\n\t            Math.abs(a6 - b6) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&\r\n\t            Math.abs(a7 - b7) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&\r\n\t            Math.abs(a8 - b8) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a8), Math.abs(b8)) &&\r\n\t            Math.abs(a9 - b9) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a9), Math.abs(b9)) &&\r\n\t            Math.abs(a10 - b10) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a10), Math.abs(b10)) &&\r\n\t            Math.abs(a11 - b11) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a11), Math.abs(b11)) &&\r\n\t            Math.abs(a12 - b12) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a12), Math.abs(b12)) &&\r\n\t            Math.abs(a13 - b13) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a13), Math.abs(b13)) &&\r\n\t            Math.abs(a14 - b14) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a14), Math.abs(b14)) &&\r\n\t            Math.abs(a15 - b15) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a15), Math.abs(b15)));\r\n\t};\r\n\r\n\r\n\r\n\tmodule.exports = mat4;\r\n\r\n\r\n/***/ },\r\n/* 6 */\r\n/***/ function(module, exports, __webpack_require__) {\r\n\r\n\t/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\n\tPermission is hereby granted, free of charge, to any person obtaining a copy\r\n\tof this software and associated documentation files (the \"Software\"), to deal\r\n\tin the Software without restriction, including without limitation the rights\r\n\tto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n\tcopies of the Software, and to permit persons to whom the Software is\r\n\tfurnished to do so, subject to the following conditions:\r\n\r\n\tThe above copyright notice and this permission notice shall be included in\r\n\tall copies or substantial portions of the Software.\r\n\r\n\tTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n\tIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n\tFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n\tAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n\tLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n\tOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\n\tTHE SOFTWARE. */\r\n\r\n\tvar glMatrix = __webpack_require__(1);\r\n\tvar mat3 = __webpack_require__(4);\r\n\tvar vec3 = __webpack_require__(7);\r\n\tvar vec4 = __webpack_require__(8);\r\n\r\n\t/**\r\n\t * @class Quaternion\r\n\t * @name quat\r\n\t */\r\n\tvar quat = {};\r\n\r\n\t/**\r\n\t * Creates a new identity quat\r\n\t *\r\n\t * @returns {quat} a new quaternion\r\n\t */\r\n\tquat.create = function() {\r\n\t    var out = new glMatrix.ARRAY_TYPE(4);\r\n\t    out[0] = 0;\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = 1;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Sets a quaternion to represent the shortest rotation from one\r\n\t * vector to another.\r\n\t *\r\n\t * Both vectors are assumed to be unit length.\r\n\t *\r\n\t * @param {quat} out the receiving quaternion.\r\n\t * @param {vec3} a the initial vector\r\n\t * @param {vec3} b the destination vector\r\n\t * @returns {quat} out\r\n\t */\r\n\tquat.rotationTo = (function() {\r\n\t    var tmpvec3 = vec3.create();\r\n\t    var xUnitVec3 = vec3.fromValues(1,0,0);\r\n\t    var yUnitVec3 = vec3.fromValues(0,1,0);\r\n\r\n\t    return function(out, a, b) {\r\n\t        var dot = vec3.dot(a, b);\r\n\t        if (dot < -0.999999) {\r\n\t            vec3.cross(tmpvec3, xUnitVec3, a);\r\n\t            if (vec3.length(tmpvec3) < 0.000001)\r\n\t                vec3.cross(tmpvec3, yUnitVec3, a);\r\n\t            vec3.normalize(tmpvec3, tmpvec3);\r\n\t            quat.setAxisAngle(out, tmpvec3, Math.PI);\r\n\t            return out;\r\n\t        } else if (dot > 0.999999) {\r\n\t            out[0] = 0;\r\n\t            out[1] = 0;\r\n\t            out[2] = 0;\r\n\t            out[3] = 1;\r\n\t            return out;\r\n\t        } else {\r\n\t            vec3.cross(tmpvec3, a, b);\r\n\t            out[0] = tmpvec3[0];\r\n\t            out[1] = tmpvec3[1];\r\n\t            out[2] = tmpvec3[2];\r\n\t            out[3] = 1 + dot;\r\n\t            return quat.normalize(out, out);\r\n\t        }\r\n\t    };\r\n\t})();\r\n\r\n\t/**\r\n\t * Sets the specified quaternion with values corresponding to the given\r\n\t * axes. Each axis is a vec3 and is expected to be unit length and\r\n\t * perpendicular to all other specified axes.\r\n\t *\r\n\t * @param {vec3} view  the vector representing the viewing direction\r\n\t * @param {vec3} right the vector representing the local \"right\" direction\r\n\t * @param {vec3} up    the vector representing the local \"up\" direction\r\n\t * @returns {quat} out\r\n\t */\r\n\tquat.setAxes = (function() {\r\n\t    var matr = mat3.create();\r\n\r\n\t    return function(out, view, right, up) {\r\n\t        matr[0] = right[0];\r\n\t        matr[3] = right[1];\r\n\t        matr[6] = right[2];\r\n\r\n\t        matr[1] = up[0];\r\n\t        matr[4] = up[1];\r\n\t        matr[7] = up[2];\r\n\r\n\t        matr[2] = -view[0];\r\n\t        matr[5] = -view[1];\r\n\t        matr[8] = -view[2];\r\n\r\n\t        return quat.normalize(out, quat.fromMat3(out, matr));\r\n\t    };\r\n\t})();\r\n\r\n\t/**\r\n\t * Creates a new quat initialized with values from an existing quaternion\r\n\t *\r\n\t * @param {quat} a quaternion to clone\r\n\t * @returns {quat} a new quaternion\r\n\t * @function\r\n\t */\r\n\tquat.clone = vec4.clone;\r\n\r\n\t/**\r\n\t * Creates a new quat initialized with the given values\r\n\t *\r\n\t * @param {Number} x X component\r\n\t * @param {Number} y Y component\r\n\t * @param {Number} z Z component\r\n\t * @param {Number} w W component\r\n\t * @returns {quat} a new quaternion\r\n\t * @function\r\n\t */\r\n\tquat.fromValues = vec4.fromValues;\r\n\r\n\t/**\r\n\t * Copy the values from one quat to another\r\n\t *\r\n\t * @param {quat} out the receiving quaternion\r\n\t * @param {quat} a the source quaternion\r\n\t * @returns {quat} out\r\n\t * @function\r\n\t */\r\n\tquat.copy = vec4.copy;\r\n\r\n\t/**\r\n\t * Set the components of a quat to the given values\r\n\t *\r\n\t * @param {quat} out the receiving quaternion\r\n\t * @param {Number} x X component\r\n\t * @param {Number} y Y component\r\n\t * @param {Number} z Z component\r\n\t * @param {Number} w W component\r\n\t * @returns {quat} out\r\n\t * @function\r\n\t */\r\n\tquat.set = vec4.set;\r\n\r\n\t/**\r\n\t * Set a quat to the identity quaternion\r\n\t *\r\n\t * @param {quat} out the receiving quaternion\r\n\t * @returns {quat} out\r\n\t */\r\n\tquat.identity = function(out) {\r\n\t    out[0] = 0;\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = 1;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Sets a quat from the given angle and rotation axis,\r\n\t * then returns it.\r\n\t *\r\n\t * @param {quat} out the receiving quaternion\r\n\t * @param {vec3} axis the axis around which to rotate\r\n\t * @param {Number} rad the angle in radians\r\n\t * @returns {quat} out\r\n\t **/\r\n\tquat.setAxisAngle = function(out, axis, rad) {\r\n\t    rad = rad * 0.5;\r\n\t    var s = Math.sin(rad);\r\n\t    out[0] = s * axis[0];\r\n\t    out[1] = s * axis[1];\r\n\t    out[2] = s * axis[2];\r\n\t    out[3] = Math.cos(rad);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Gets the rotation axis and angle for a given\r\n\t *  quaternion. If a quaternion is created with\r\n\t *  setAxisAngle, this method will return the same\r\n\t *  values as providied in the original parameter list\r\n\t *  OR functionally equivalent values.\r\n\t * Example: The quaternion formed by axis [0, 0, 1] and\r\n\t *  angle -90 is the same as the quaternion formed by\r\n\t *  [0, 0, 1] and 270. This method favors the latter.\r\n\t * @param  {vec3} out_axis  Vector receiving the axis of rotation\r\n\t * @param  {quat} q     Quaternion to be decomposed\r\n\t * @return {Number}     Angle, in radians, of the rotation\r\n\t */\r\n\tquat.getAxisAngle = function(out_axis, q) {\r\n\t    var rad = Math.acos(q[3]) * 2.0;\r\n\t    var s = Math.sin(rad / 2.0);\r\n\t    if (s != 0.0) {\r\n\t        out_axis[0] = q[0] / s;\r\n\t        out_axis[1] = q[1] / s;\r\n\t        out_axis[2] = q[2] / s;\r\n\t    } else {\r\n\t        // If s is zero, return any axis (no rotation - axis does not matter)\r\n\t        out_axis[0] = 1;\r\n\t        out_axis[1] = 0;\r\n\t        out_axis[2] = 0;\r\n\t    }\r\n\t    return rad;\r\n\t};\r\n\r\n\t/**\r\n\t * Adds two quat's\r\n\t *\r\n\t * @param {quat} out the receiving quaternion\r\n\t * @param {quat} a the first operand\r\n\t * @param {quat} b the second operand\r\n\t * @returns {quat} out\r\n\t * @function\r\n\t */\r\n\tquat.add = vec4.add;\r\n\r\n\t/**\r\n\t * Multiplies two quat's\r\n\t *\r\n\t * @param {quat} out the receiving quaternion\r\n\t * @param {quat} a the first operand\r\n\t * @param {quat} b the second operand\r\n\t * @returns {quat} out\r\n\t */\r\n\tquat.multiply = function(out, a, b) {\r\n\t    var ax = a[0], ay = a[1], az = a[2], aw = a[3],\r\n\t        bx = b[0], by = b[1], bz = b[2], bw = b[3];\r\n\r\n\t    out[0] = ax * bw + aw * bx + ay * bz - az * by;\r\n\t    out[1] = ay * bw + aw * by + az * bx - ax * bz;\r\n\t    out[2] = az * bw + aw * bz + ax * by - ay * bx;\r\n\t    out[3] = aw * bw - ax * bx - ay * by - az * bz;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link quat.multiply}\r\n\t * @function\r\n\t */\r\n\tquat.mul = quat.multiply;\r\n\r\n\t/**\r\n\t * Scales a quat by a scalar number\r\n\t *\r\n\t * @param {quat} out the receiving vector\r\n\t * @param {quat} a the vector to scale\r\n\t * @param {Number} b amount to scale the vector by\r\n\t * @returns {quat} out\r\n\t * @function\r\n\t */\r\n\tquat.scale = vec4.scale;\r\n\r\n\t/**\r\n\t * Rotates a quaternion by the given angle about the X axis\r\n\t *\r\n\t * @param {quat} out quat receiving operation result\r\n\t * @param {quat} a quat to rotate\r\n\t * @param {number} rad angle (in radians) to rotate\r\n\t * @returns {quat} out\r\n\t */\r\n\tquat.rotateX = function (out, a, rad) {\r\n\t    rad *= 0.5; \r\n\r\n\t    var ax = a[0], ay = a[1], az = a[2], aw = a[3],\r\n\t        bx = Math.sin(rad), bw = Math.cos(rad);\r\n\r\n\t    out[0] = ax * bw + aw * bx;\r\n\t    out[1] = ay * bw + az * bx;\r\n\t    out[2] = az * bw - ay * bx;\r\n\t    out[3] = aw * bw - ax * bx;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Rotates a quaternion by the given angle about the Y axis\r\n\t *\r\n\t * @param {quat} out quat receiving operation result\r\n\t * @param {quat} a quat to rotate\r\n\t * @param {number} rad angle (in radians) to rotate\r\n\t * @returns {quat} out\r\n\t */\r\n\tquat.rotateY = function (out, a, rad) {\r\n\t    rad *= 0.5; \r\n\r\n\t    var ax = a[0], ay = a[1], az = a[2], aw = a[3],\r\n\t        by = Math.sin(rad), bw = Math.cos(rad);\r\n\r\n\t    out[0] = ax * bw - az * by;\r\n\t    out[1] = ay * bw + aw * by;\r\n\t    out[2] = az * bw + ax * by;\r\n\t    out[3] = aw * bw - ay * by;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Rotates a quaternion by the given angle about the Z axis\r\n\t *\r\n\t * @param {quat} out quat receiving operation result\r\n\t * @param {quat} a quat to rotate\r\n\t * @param {number} rad angle (in radians) to rotate\r\n\t * @returns {quat} out\r\n\t */\r\n\tquat.rotateZ = function (out, a, rad) {\r\n\t    rad *= 0.5; \r\n\r\n\t    var ax = a[0], ay = a[1], az = a[2], aw = a[3],\r\n\t        bz = Math.sin(rad), bw = Math.cos(rad);\r\n\r\n\t    out[0] = ax * bw + ay * bz;\r\n\t    out[1] = ay * bw - ax * bz;\r\n\t    out[2] = az * bw + aw * bz;\r\n\t    out[3] = aw * bw - az * bz;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Calculates the W component of a quat from the X, Y, and Z components.\r\n\t * Assumes that quaternion is 1 unit in length.\r\n\t * Any existing W component will be ignored.\r\n\t *\r\n\t * @param {quat} out the receiving quaternion\r\n\t * @param {quat} a quat to calculate W component of\r\n\t * @returns {quat} out\r\n\t */\r\n\tquat.calculateW = function (out, a) {\r\n\t    var x = a[0], y = a[1], z = a[2];\r\n\r\n\t    out[0] = x;\r\n\t    out[1] = y;\r\n\t    out[2] = z;\r\n\t    out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Calculates the dot product of two quat's\r\n\t *\r\n\t * @param {quat} a the first operand\r\n\t * @param {quat} b the second operand\r\n\t * @returns {Number} dot product of a and b\r\n\t * @function\r\n\t */\r\n\tquat.dot = vec4.dot;\r\n\r\n\t/**\r\n\t * Performs a linear interpolation between two quat's\r\n\t *\r\n\t * @param {quat} out the receiving quaternion\r\n\t * @param {quat} a the first operand\r\n\t * @param {quat} b the second operand\r\n\t * @param {Number} t interpolation amount between the two inputs\r\n\t * @returns {quat} out\r\n\t * @function\r\n\t */\r\n\tquat.lerp = vec4.lerp;\r\n\r\n\t/**\r\n\t * Performs a spherical linear interpolation between two quat\r\n\t *\r\n\t * @param {quat} out the receiving quaternion\r\n\t * @param {quat} a the first operand\r\n\t * @param {quat} b the second operand\r\n\t * @param {Number} t interpolation amount between the two inputs\r\n\t * @returns {quat} out\r\n\t */\r\n\tquat.slerp = function (out, a, b, t) {\r\n\t    // benchmarks:\r\n\t    //    http://jsperf.com/quaternion-slerp-implementations\r\n\r\n\t    var ax = a[0], ay = a[1], az = a[2], aw = a[3],\r\n\t        bx = b[0], by = b[1], bz = b[2], bw = b[3];\r\n\r\n\t    var        omega, cosom, sinom, scale0, scale1;\r\n\r\n\t    // calc cosine\r\n\t    cosom = ax * bx + ay * by + az * bz + aw * bw;\r\n\t    // adjust signs (if necessary)\r\n\t    if ( cosom < 0.0 ) {\r\n\t        cosom = -cosom;\r\n\t        bx = - bx;\r\n\t        by = - by;\r\n\t        bz = - bz;\r\n\t        bw = - bw;\r\n\t    }\r\n\t    // calculate coefficients\r\n\t    if ( (1.0 - cosom) > 0.000001 ) {\r\n\t        // standard case (slerp)\r\n\t        omega  = Math.acos(cosom);\r\n\t        sinom  = Math.sin(omega);\r\n\t        scale0 = Math.sin((1.0 - t) * omega) / sinom;\r\n\t        scale1 = Math.sin(t * omega) / sinom;\r\n\t    } else {        \r\n\t        // \"from\" and \"to\" quaternions are very close \r\n\t        //  ... so we can do a linear interpolation\r\n\t        scale0 = 1.0 - t;\r\n\t        scale1 = t;\r\n\t    }\r\n\t    // calculate final values\r\n\t    out[0] = scale0 * ax + scale1 * bx;\r\n\t    out[1] = scale0 * ay + scale1 * by;\r\n\t    out[2] = scale0 * az + scale1 * bz;\r\n\t    out[3] = scale0 * aw + scale1 * bw;\r\n\t    \r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Performs a spherical linear interpolation with two control points\r\n\t *\r\n\t * @param {quat} out the receiving quaternion\r\n\t * @param {quat} a the first operand\r\n\t * @param {quat} b the second operand\r\n\t * @param {quat} c the third operand\r\n\t * @param {quat} d the fourth operand\r\n\t * @param {Number} t interpolation amount\r\n\t * @returns {quat} out\r\n\t */\r\n\tquat.sqlerp = (function () {\r\n\t  var temp1 = quat.create();\r\n\t  var temp2 = quat.create();\r\n\t  \r\n\t  return function (out, a, b, c, d, t) {\r\n\t    quat.slerp(temp1, a, d, t);\r\n\t    quat.slerp(temp2, b, c, t);\r\n\t    quat.slerp(out, temp1, temp2, 2 * t * (1 - t));\r\n\t    \r\n\t    return out;\r\n\t  };\r\n\t}());\r\n\r\n\t/**\r\n\t * Calculates the inverse of a quat\r\n\t *\r\n\t * @param {quat} out the receiving quaternion\r\n\t * @param {quat} a quat to calculate inverse of\r\n\t * @returns {quat} out\r\n\t */\r\n\tquat.invert = function(out, a) {\r\n\t    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],\r\n\t        dot = a0*a0 + a1*a1 + a2*a2 + a3*a3,\r\n\t        invDot = dot ? 1.0/dot : 0;\r\n\t    \r\n\t    // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0\r\n\r\n\t    out[0] = -a0*invDot;\r\n\t    out[1] = -a1*invDot;\r\n\t    out[2] = -a2*invDot;\r\n\t    out[3] = a3*invDot;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Calculates the conjugate of a quat\r\n\t * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.\r\n\t *\r\n\t * @param {quat} out the receiving quaternion\r\n\t * @param {quat} a quat to calculate conjugate of\r\n\t * @returns {quat} out\r\n\t */\r\n\tquat.conjugate = function (out, a) {\r\n\t    out[0] = -a[0];\r\n\t    out[1] = -a[1];\r\n\t    out[2] = -a[2];\r\n\t    out[3] = a[3];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Calculates the length of a quat\r\n\t *\r\n\t * @param {quat} a vector to calculate length of\r\n\t * @returns {Number} length of a\r\n\t * @function\r\n\t */\r\n\tquat.length = vec4.length;\r\n\r\n\t/**\r\n\t * Alias for {@link quat.length}\r\n\t * @function\r\n\t */\r\n\tquat.len = quat.length;\r\n\r\n\t/**\r\n\t * Calculates the squared length of a quat\r\n\t *\r\n\t * @param {quat} a vector to calculate squared length of\r\n\t * @returns {Number} squared length of a\r\n\t * @function\r\n\t */\r\n\tquat.squaredLength = vec4.squaredLength;\r\n\r\n\t/**\r\n\t * Alias for {@link quat.squaredLength}\r\n\t * @function\r\n\t */\r\n\tquat.sqrLen = quat.squaredLength;\r\n\r\n\t/**\r\n\t * Normalize a quat\r\n\t *\r\n\t * @param {quat} out the receiving quaternion\r\n\t * @param {quat} a quaternion to normalize\r\n\t * @returns {quat} out\r\n\t * @function\r\n\t */\r\n\tquat.normalize = vec4.normalize;\r\n\r\n\t/**\r\n\t * Creates a quaternion from the given 3x3 rotation matrix.\r\n\t *\r\n\t * NOTE: The resultant quaternion is not normalized, so you should be sure\r\n\t * to renormalize the quaternion yourself where necessary.\r\n\t *\r\n\t * @param {quat} out the receiving quaternion\r\n\t * @param {mat3} m rotation matrix\r\n\t * @returns {quat} out\r\n\t * @function\r\n\t */\r\n\tquat.fromMat3 = function(out, m) {\r\n\t    // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes\r\n\t    // article \"Quaternion Calculus and Fast Animation\".\r\n\t    var fTrace = m[0] + m[4] + m[8];\r\n\t    var fRoot;\r\n\r\n\t    if ( fTrace > 0.0 ) {\r\n\t        // |w| > 1/2, may as well choose w > 1/2\r\n\t        fRoot = Math.sqrt(fTrace + 1.0);  // 2w\r\n\t        out[3] = 0.5 * fRoot;\r\n\t        fRoot = 0.5/fRoot;  // 1/(4w)\r\n\t        out[0] = (m[5]-m[7])*fRoot;\r\n\t        out[1] = (m[6]-m[2])*fRoot;\r\n\t        out[2] = (m[1]-m[3])*fRoot;\r\n\t    } else {\r\n\t        // |w| <= 1/2\r\n\t        var i = 0;\r\n\t        if ( m[4] > m[0] )\r\n\t          i = 1;\r\n\t        if ( m[8] > m[i*3+i] )\r\n\t          i = 2;\r\n\t        var j = (i+1)%3;\r\n\t        var k = (i+2)%3;\r\n\t        \r\n\t        fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);\r\n\t        out[i] = 0.5 * fRoot;\r\n\t        fRoot = 0.5 / fRoot;\r\n\t        out[3] = (m[j*3+k] - m[k*3+j]) * fRoot;\r\n\t        out[j] = (m[j*3+i] + m[i*3+j]) * fRoot;\r\n\t        out[k] = (m[k*3+i] + m[i*3+k]) * fRoot;\r\n\t    }\r\n\t    \r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Returns a string representation of a quatenion\r\n\t *\r\n\t * @param {quat} a vector to represent as a string\r\n\t * @returns {String} string representation of the vector\r\n\t */\r\n\tquat.str = function (a) {\r\n\t    return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';\r\n\t};\r\n\r\n\t/**\r\n\t * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)\r\n\t *\r\n\t * @param {quat} a The first quaternion.\r\n\t * @param {quat} b The second quaternion.\r\n\t * @returns {Boolean} True if the vectors are equal, false otherwise.\r\n\t */\r\n\tquat.exactEquals = vec4.exactEquals;\r\n\r\n\t/**\r\n\t * Returns whether or not the quaternions have approximately the same elements in the same position.\r\n\t *\r\n\t * @param {quat} a The first vector.\r\n\t * @param {quat} b The second vector.\r\n\t * @returns {Boolean} True if the vectors are equal, false otherwise.\r\n\t */\r\n\tquat.equals = vec4.equals;\r\n\r\n\tmodule.exports = quat;\r\n\r\n\r\n/***/ },\r\n/* 7 */\r\n/***/ function(module, exports, __webpack_require__) {\r\n\r\n\t/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\n\tPermission is hereby granted, free of charge, to any person obtaining a copy\r\n\tof this software and associated documentation files (the \"Software\"), to deal\r\n\tin the Software without restriction, including without limitation the rights\r\n\tto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n\tcopies of the Software, and to permit persons to whom the Software is\r\n\tfurnished to do so, subject to the following conditions:\r\n\r\n\tThe above copyright notice and this permission notice shall be included in\r\n\tall copies or substantial portions of the Software.\r\n\r\n\tTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n\tIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n\tFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n\tAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n\tLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n\tOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\n\tTHE SOFTWARE. */\r\n\r\n\tvar glMatrix = __webpack_require__(1);\r\n\r\n\t/**\r\n\t * @class 3 Dimensional Vector\r\n\t * @name vec3\r\n\t */\r\n\tvar vec3 = {};\r\n\r\n\t/**\r\n\t * Creates a new, empty vec3\r\n\t *\r\n\t * @returns {vec3} a new 3D vector\r\n\t */\r\n\tvec3.create = function() {\r\n\t    var out = new glMatrix.ARRAY_TYPE(3);\r\n\t    out[0] = 0;\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Creates a new vec3 initialized with values from an existing vector\r\n\t *\r\n\t * @param {vec3} a vector to clone\r\n\t * @returns {vec3} a new 3D vector\r\n\t */\r\n\tvec3.clone = function(a) {\r\n\t    var out = new glMatrix.ARRAY_TYPE(3);\r\n\t    out[0] = a[0];\r\n\t    out[1] = a[1];\r\n\t    out[2] = a[2];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Creates a new vec3 initialized with the given values\r\n\t *\r\n\t * @param {Number} x X component\r\n\t * @param {Number} y Y component\r\n\t * @param {Number} z Z component\r\n\t * @returns {vec3} a new 3D vector\r\n\t */\r\n\tvec3.fromValues = function(x, y, z) {\r\n\t    var out = new glMatrix.ARRAY_TYPE(3);\r\n\t    out[0] = x;\r\n\t    out[1] = y;\r\n\t    out[2] = z;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Copy the values from one vec3 to another\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a the source vector\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.copy = function(out, a) {\r\n\t    out[0] = a[0];\r\n\t    out[1] = a[1];\r\n\t    out[2] = a[2];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Set the components of a vec3 to the given values\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {Number} x X component\r\n\t * @param {Number} y Y component\r\n\t * @param {Number} z Z component\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.set = function(out, x, y, z) {\r\n\t    out[0] = x;\r\n\t    out[1] = y;\r\n\t    out[2] = z;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Adds two vec3's\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a the first operand\r\n\t * @param {vec3} b the second operand\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.add = function(out, a, b) {\r\n\t    out[0] = a[0] + b[0];\r\n\t    out[1] = a[1] + b[1];\r\n\t    out[2] = a[2] + b[2];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Subtracts vector b from vector a\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a the first operand\r\n\t * @param {vec3} b the second operand\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.subtract = function(out, a, b) {\r\n\t    out[0] = a[0] - b[0];\r\n\t    out[1] = a[1] - b[1];\r\n\t    out[2] = a[2] - b[2];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec3.subtract}\r\n\t * @function\r\n\t */\r\n\tvec3.sub = vec3.subtract;\r\n\r\n\t/**\r\n\t * Multiplies two vec3's\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a the first operand\r\n\t * @param {vec3} b the second operand\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.multiply = function(out, a, b) {\r\n\t    out[0] = a[0] * b[0];\r\n\t    out[1] = a[1] * b[1];\r\n\t    out[2] = a[2] * b[2];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec3.multiply}\r\n\t * @function\r\n\t */\r\n\tvec3.mul = vec3.multiply;\r\n\r\n\t/**\r\n\t * Divides two vec3's\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a the first operand\r\n\t * @param {vec3} b the second operand\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.divide = function(out, a, b) {\r\n\t    out[0] = a[0] / b[0];\r\n\t    out[1] = a[1] / b[1];\r\n\t    out[2] = a[2] / b[2];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec3.divide}\r\n\t * @function\r\n\t */\r\n\tvec3.div = vec3.divide;\r\n\r\n\t/**\r\n\t * Math.ceil the components of a vec3\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a vector to ceil\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.ceil = function (out, a) {\r\n\t    out[0] = Math.ceil(a[0]);\r\n\t    out[1] = Math.ceil(a[1]);\r\n\t    out[2] = Math.ceil(a[2]);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Math.floor the components of a vec3\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a vector to floor\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.floor = function (out, a) {\r\n\t    out[0] = Math.floor(a[0]);\r\n\t    out[1] = Math.floor(a[1]);\r\n\t    out[2] = Math.floor(a[2]);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Returns the minimum of two vec3's\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a the first operand\r\n\t * @param {vec3} b the second operand\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.min = function(out, a, b) {\r\n\t    out[0] = Math.min(a[0], b[0]);\r\n\t    out[1] = Math.min(a[1], b[1]);\r\n\t    out[2] = Math.min(a[2], b[2]);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Returns the maximum of two vec3's\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a the first operand\r\n\t * @param {vec3} b the second operand\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.max = function(out, a, b) {\r\n\t    out[0] = Math.max(a[0], b[0]);\r\n\t    out[1] = Math.max(a[1], b[1]);\r\n\t    out[2] = Math.max(a[2], b[2]);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Math.round the components of a vec3\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a vector to round\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.round = function (out, a) {\r\n\t    out[0] = Math.round(a[0]);\r\n\t    out[1] = Math.round(a[1]);\r\n\t    out[2] = Math.round(a[2]);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Scales a vec3 by a scalar number\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a the vector to scale\r\n\t * @param {Number} b amount to scale the vector by\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.scale = function(out, a, b) {\r\n\t    out[0] = a[0] * b;\r\n\t    out[1] = a[1] * b;\r\n\t    out[2] = a[2] * b;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Adds two vec3's after scaling the second operand by a scalar value\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a the first operand\r\n\t * @param {vec3} b the second operand\r\n\t * @param {Number} scale the amount to scale b by before adding\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.scaleAndAdd = function(out, a, b, scale) {\r\n\t    out[0] = a[0] + (b[0] * scale);\r\n\t    out[1] = a[1] + (b[1] * scale);\r\n\t    out[2] = a[2] + (b[2] * scale);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Calculates the euclidian distance between two vec3's\r\n\t *\r\n\t * @param {vec3} a the first operand\r\n\t * @param {vec3} b the second operand\r\n\t * @returns {Number} distance between a and b\r\n\t */\r\n\tvec3.distance = function(a, b) {\r\n\t    var x = b[0] - a[0],\r\n\t        y = b[1] - a[1],\r\n\t        z = b[2] - a[2];\r\n\t    return Math.sqrt(x*x + y*y + z*z);\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec3.distance}\r\n\t * @function\r\n\t */\r\n\tvec3.dist = vec3.distance;\r\n\r\n\t/**\r\n\t * Calculates the squared euclidian distance between two vec3's\r\n\t *\r\n\t * @param {vec3} a the first operand\r\n\t * @param {vec3} b the second operand\r\n\t * @returns {Number} squared distance between a and b\r\n\t */\r\n\tvec3.squaredDistance = function(a, b) {\r\n\t    var x = b[0] - a[0],\r\n\t        y = b[1] - a[1],\r\n\t        z = b[2] - a[2];\r\n\t    return x*x + y*y + z*z;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec3.squaredDistance}\r\n\t * @function\r\n\t */\r\n\tvec3.sqrDist = vec3.squaredDistance;\r\n\r\n\t/**\r\n\t * Calculates the length of a vec3\r\n\t *\r\n\t * @param {vec3} a vector to calculate length of\r\n\t * @returns {Number} length of a\r\n\t */\r\n\tvec3.length = function (a) {\r\n\t    var x = a[0],\r\n\t        y = a[1],\r\n\t        z = a[2];\r\n\t    return Math.sqrt(x*x + y*y + z*z);\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec3.length}\r\n\t * @function\r\n\t */\r\n\tvec3.len = vec3.length;\r\n\r\n\t/**\r\n\t * Calculates the squared length of a vec3\r\n\t *\r\n\t * @param {vec3} a vector to calculate squared length of\r\n\t * @returns {Number} squared length of a\r\n\t */\r\n\tvec3.squaredLength = function (a) {\r\n\t    var x = a[0],\r\n\t        y = a[1],\r\n\t        z = a[2];\r\n\t    return x*x + y*y + z*z;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec3.squaredLength}\r\n\t * @function\r\n\t */\r\n\tvec3.sqrLen = vec3.squaredLength;\r\n\r\n\t/**\r\n\t * Negates the components of a vec3\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a vector to negate\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.negate = function(out, a) {\r\n\t    out[0] = -a[0];\r\n\t    out[1] = -a[1];\r\n\t    out[2] = -a[2];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Returns the inverse of the components of a vec3\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a vector to invert\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.inverse = function(out, a) {\r\n\t  out[0] = 1.0 / a[0];\r\n\t  out[1] = 1.0 / a[1];\r\n\t  out[2] = 1.0 / a[2];\r\n\t  return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Normalize a vec3\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a vector to normalize\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.normalize = function(out, a) {\r\n\t    var x = a[0],\r\n\t        y = a[1],\r\n\t        z = a[2];\r\n\t    var len = x*x + y*y + z*z;\r\n\t    if (len > 0) {\r\n\t        //TODO: evaluate use of glm_invsqrt here?\r\n\t        len = 1 / Math.sqrt(len);\r\n\t        out[0] = a[0] * len;\r\n\t        out[1] = a[1] * len;\r\n\t        out[2] = a[2] * len;\r\n\t    }\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Calculates the dot product of two vec3's\r\n\t *\r\n\t * @param {vec3} a the first operand\r\n\t * @param {vec3} b the second operand\r\n\t * @returns {Number} dot product of a and b\r\n\t */\r\n\tvec3.dot = function (a, b) {\r\n\t    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\r\n\t};\r\n\r\n\t/**\r\n\t * Computes the cross product of two vec3's\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a the first operand\r\n\t * @param {vec3} b the second operand\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.cross = function(out, a, b) {\r\n\t    var ax = a[0], ay = a[1], az = a[2],\r\n\t        bx = b[0], by = b[1], bz = b[2];\r\n\r\n\t    out[0] = ay * bz - az * by;\r\n\t    out[1] = az * bx - ax * bz;\r\n\t    out[2] = ax * by - ay * bx;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Performs a linear interpolation between two vec3's\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a the first operand\r\n\t * @param {vec3} b the second operand\r\n\t * @param {Number} t interpolation amount between the two inputs\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.lerp = function (out, a, b, t) {\r\n\t    var ax = a[0],\r\n\t        ay = a[1],\r\n\t        az = a[2];\r\n\t    out[0] = ax + t * (b[0] - ax);\r\n\t    out[1] = ay + t * (b[1] - ay);\r\n\t    out[2] = az + t * (b[2] - az);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Performs a hermite interpolation with two control points\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a the first operand\r\n\t * @param {vec3} b the second operand\r\n\t * @param {vec3} c the third operand\r\n\t * @param {vec3} d the fourth operand\r\n\t * @param {Number} t interpolation amount between the two inputs\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.hermite = function (out, a, b, c, d, t) {\r\n\t  var factorTimes2 = t * t,\r\n\t      factor1 = factorTimes2 * (2 * t - 3) + 1,\r\n\t      factor2 = factorTimes2 * (t - 2) + t,\r\n\t      factor3 = factorTimes2 * (t - 1),\r\n\t      factor4 = factorTimes2 * (3 - 2 * t);\r\n\t  \r\n\t  out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;\r\n\t  out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;\r\n\t  out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;\r\n\t  \r\n\t  return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Performs a bezier interpolation with two control points\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a the first operand\r\n\t * @param {vec3} b the second operand\r\n\t * @param {vec3} c the third operand\r\n\t * @param {vec3} d the fourth operand\r\n\t * @param {Number} t interpolation amount between the two inputs\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.bezier = function (out, a, b, c, d, t) {\r\n\t  var inverseFactor = 1 - t,\r\n\t      inverseFactorTimesTwo = inverseFactor * inverseFactor,\r\n\t      factorTimes2 = t * t,\r\n\t      factor1 = inverseFactorTimesTwo * inverseFactor,\r\n\t      factor2 = 3 * t * inverseFactorTimesTwo,\r\n\t      factor3 = 3 * factorTimes2 * inverseFactor,\r\n\t      factor4 = factorTimes2 * t;\r\n\t  \r\n\t  out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;\r\n\t  out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;\r\n\t  out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;\r\n\t  \r\n\t  return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Generates a random vector with the given scale\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.random = function (out, scale) {\r\n\t    scale = scale || 1.0;\r\n\r\n\t    var r = glMatrix.RANDOM() * 2.0 * Math.PI;\r\n\t    var z = (glMatrix.RANDOM() * 2.0) - 1.0;\r\n\t    var zScale = Math.sqrt(1.0-z*z) * scale;\r\n\r\n\t    out[0] = Math.cos(r) * zScale;\r\n\t    out[1] = Math.sin(r) * zScale;\r\n\t    out[2] = z * scale;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Transforms the vec3 with a mat4.\r\n\t * 4th vector component is implicitly '1'\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a the vector to transform\r\n\t * @param {mat4} m matrix to transform with\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.transformMat4 = function(out, a, m) {\r\n\t    var x = a[0], y = a[1], z = a[2],\r\n\t        w = m[3] * x + m[7] * y + m[11] * z + m[15];\r\n\t    w = w || 1.0;\r\n\t    out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;\r\n\t    out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;\r\n\t    out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Transforms the vec3 with a mat3.\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a the vector to transform\r\n\t * @param {mat4} m the 3x3 matrix to transform with\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.transformMat3 = function(out, a, m) {\r\n\t    var x = a[0], y = a[1], z = a[2];\r\n\t    out[0] = x * m[0] + y * m[3] + z * m[6];\r\n\t    out[1] = x * m[1] + y * m[4] + z * m[7];\r\n\t    out[2] = x * m[2] + y * m[5] + z * m[8];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Transforms the vec3 with a quat\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec3} a the vector to transform\r\n\t * @param {quat} q quaternion to transform with\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.transformQuat = function(out, a, q) {\r\n\t    // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations\r\n\r\n\t    var x = a[0], y = a[1], z = a[2],\r\n\t        qx = q[0], qy = q[1], qz = q[2], qw = q[3],\r\n\r\n\t        // calculate quat * vec\r\n\t        ix = qw * x + qy * z - qz * y,\r\n\t        iy = qw * y + qz * x - qx * z,\r\n\t        iz = qw * z + qx * y - qy * x,\r\n\t        iw = -qx * x - qy * y - qz * z;\r\n\r\n\t    // calculate result * inverse quat\r\n\t    out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;\r\n\t    out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;\r\n\t    out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Rotate a 3D vector around the x-axis\r\n\t * @param {vec3} out The receiving vec3\r\n\t * @param {vec3} a The vec3 point to rotate\r\n\t * @param {vec3} b The origin of the rotation\r\n\t * @param {Number} c The angle of rotation\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.rotateX = function(out, a, b, c){\r\n\t   var p = [], r=[];\r\n\t\t  //Translate point to the origin\r\n\t\t  p[0] = a[0] - b[0];\r\n\t\t  p[1] = a[1] - b[1];\r\n\t  \tp[2] = a[2] - b[2];\r\n\r\n\t\t  //perform rotation\r\n\t\t  r[0] = p[0];\r\n\t\t  r[1] = p[1]*Math.cos(c) - p[2]*Math.sin(c);\r\n\t\t  r[2] = p[1]*Math.sin(c) + p[2]*Math.cos(c);\r\n\r\n\t\t  //translate to correct position\r\n\t\t  out[0] = r[0] + b[0];\r\n\t\t  out[1] = r[1] + b[1];\r\n\t\t  out[2] = r[2] + b[2];\r\n\r\n\t  \treturn out;\r\n\t};\r\n\r\n\t/**\r\n\t * Rotate a 3D vector around the y-axis\r\n\t * @param {vec3} out The receiving vec3\r\n\t * @param {vec3} a The vec3 point to rotate\r\n\t * @param {vec3} b The origin of the rotation\r\n\t * @param {Number} c The angle of rotation\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.rotateY = function(out, a, b, c){\r\n\t  \tvar p = [], r=[];\r\n\t  \t//Translate point to the origin\r\n\t  \tp[0] = a[0] - b[0];\r\n\t  \tp[1] = a[1] - b[1];\r\n\t  \tp[2] = a[2] - b[2];\r\n\t  \r\n\t  \t//perform rotation\r\n\t  \tr[0] = p[2]*Math.sin(c) + p[0]*Math.cos(c);\r\n\t  \tr[1] = p[1];\r\n\t  \tr[2] = p[2]*Math.cos(c) - p[0]*Math.sin(c);\r\n\t  \r\n\t  \t//translate to correct position\r\n\t  \tout[0] = r[0] + b[0];\r\n\t  \tout[1] = r[1] + b[1];\r\n\t  \tout[2] = r[2] + b[2];\r\n\t  \r\n\t  \treturn out;\r\n\t};\r\n\r\n\t/**\r\n\t * Rotate a 3D vector around the z-axis\r\n\t * @param {vec3} out The receiving vec3\r\n\t * @param {vec3} a The vec3 point to rotate\r\n\t * @param {vec3} b The origin of the rotation\r\n\t * @param {Number} c The angle of rotation\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec3.rotateZ = function(out, a, b, c){\r\n\t  \tvar p = [], r=[];\r\n\t  \t//Translate point to the origin\r\n\t  \tp[0] = a[0] - b[0];\r\n\t  \tp[1] = a[1] - b[1];\r\n\t  \tp[2] = a[2] - b[2];\r\n\t  \r\n\t  \t//perform rotation\r\n\t  \tr[0] = p[0]*Math.cos(c) - p[1]*Math.sin(c);\r\n\t  \tr[1] = p[0]*Math.sin(c) + p[1]*Math.cos(c);\r\n\t  \tr[2] = p[2];\r\n\t  \r\n\t  \t//translate to correct position\r\n\t  \tout[0] = r[0] + b[0];\r\n\t  \tout[1] = r[1] + b[1];\r\n\t  \tout[2] = r[2] + b[2];\r\n\t  \r\n\t  \treturn out;\r\n\t};\r\n\r\n\t/**\r\n\t * Perform some operation over an array of vec3s.\r\n\t *\r\n\t * @param {Array} a the array of vectors to iterate over\r\n\t * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed\r\n\t * @param {Number} offset Number of elements to skip at the beginning of the array\r\n\t * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array\r\n\t * @param {Function} fn Function to call for each vector in the array\r\n\t * @param {Object} [arg] additional argument to pass to fn\r\n\t * @returns {Array} a\r\n\t * @function\r\n\t */\r\n\tvec3.forEach = (function() {\r\n\t    var vec = vec3.create();\r\n\r\n\t    return function(a, stride, offset, count, fn, arg) {\r\n\t        var i, l;\r\n\t        if(!stride) {\r\n\t            stride = 3;\r\n\t        }\r\n\r\n\t        if(!offset) {\r\n\t            offset = 0;\r\n\t        }\r\n\t        \r\n\t        if(count) {\r\n\t            l = Math.min((count * stride) + offset, a.length);\r\n\t        } else {\r\n\t            l = a.length;\r\n\t        }\r\n\r\n\t        for(i = offset; i < l; i += stride) {\r\n\t            vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2];\r\n\t            fn(vec, vec, arg);\r\n\t            a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2];\r\n\t        }\r\n\t        \r\n\t        return a;\r\n\t    };\r\n\t})();\r\n\r\n\t/**\r\n\t * Get the angle between two 3D vectors\r\n\t * @param {vec3} a The first operand\r\n\t * @param {vec3} b The second operand\r\n\t * @returns {Number} The angle in radians\r\n\t */\r\n\tvec3.angle = function(a, b) {\r\n\t   \r\n\t    var tempA = vec3.fromValues(a[0], a[1], a[2]);\r\n\t    var tempB = vec3.fromValues(b[0], b[1], b[2]);\r\n\t \r\n\t    vec3.normalize(tempA, tempA);\r\n\t    vec3.normalize(tempB, tempB);\r\n\t \r\n\t    var cosine = vec3.dot(tempA, tempB);\r\n\r\n\t    if(cosine > 1.0){\r\n\t        return 0;\r\n\t    } else {\r\n\t        return Math.acos(cosine);\r\n\t    }     \r\n\t};\r\n\r\n\t/**\r\n\t * Returns a string representation of a vector\r\n\t *\r\n\t * @param {vec3} a vector to represent as a string\r\n\t * @returns {String} string representation of the vector\r\n\t */\r\n\tvec3.str = function (a) {\r\n\t    return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';\r\n\t};\r\n\r\n\t/**\r\n\t * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)\r\n\t *\r\n\t * @param {vec3} a The first vector.\r\n\t * @param {vec3} b The second vector.\r\n\t * @returns {Boolean} True if the vectors are equal, false otherwise.\r\n\t */\r\n\tvec3.exactEquals = function (a, b) {\r\n\t    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];\r\n\t};\r\n\r\n\t/**\r\n\t * Returns whether or not the vectors have approximately the same elements in the same position.\r\n\t *\r\n\t * @param {vec3} a The first vector.\r\n\t * @param {vec3} b The second vector.\r\n\t * @returns {Boolean} True if the vectors are equal, false otherwise.\r\n\t */\r\n\tvec3.equals = function (a, b) {\r\n\t    var a0 = a[0], a1 = a[1], a2 = a[2];\r\n\t    var b0 = b[0], b1 = b[1], b2 = b[2];\r\n\t    return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\r\n\t            Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\r\n\t            Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)));\r\n\t};\r\n\r\n\tmodule.exports = vec3;\r\n\r\n\r\n/***/ },\r\n/* 8 */\r\n/***/ function(module, exports, __webpack_require__) {\r\n\r\n\t/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\n\tPermission is hereby granted, free of charge, to any person obtaining a copy\r\n\tof this software and associated documentation files (the \"Software\"), to deal\r\n\tin the Software without restriction, including without limitation the rights\r\n\tto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n\tcopies of the Software, and to permit persons to whom the Software is\r\n\tfurnished to do so, subject to the following conditions:\r\n\r\n\tThe above copyright notice and this permission notice shall be included in\r\n\tall copies or substantial portions of the Software.\r\n\r\n\tTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n\tIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n\tFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n\tAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n\tLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n\tOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\n\tTHE SOFTWARE. */\r\n\r\n\tvar glMatrix = __webpack_require__(1);\r\n\r\n\t/**\r\n\t * @class 4 Dimensional Vector\r\n\t * @name vec4\r\n\t */\r\n\tvar vec4 = {};\r\n\r\n\t/**\r\n\t * Creates a new, empty vec4\r\n\t *\r\n\t * @returns {vec4} a new 4D vector\r\n\t */\r\n\tvec4.create = function() {\r\n\t    var out = new glMatrix.ARRAY_TYPE(4);\r\n\t    out[0] = 0;\r\n\t    out[1] = 0;\r\n\t    out[2] = 0;\r\n\t    out[3] = 0;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Creates a new vec4 initialized with values from an existing vector\r\n\t *\r\n\t * @param {vec4} a vector to clone\r\n\t * @returns {vec4} a new 4D vector\r\n\t */\r\n\tvec4.clone = function(a) {\r\n\t    var out = new glMatrix.ARRAY_TYPE(4);\r\n\t    out[0] = a[0];\r\n\t    out[1] = a[1];\r\n\t    out[2] = a[2];\r\n\t    out[3] = a[3];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Creates a new vec4 initialized with the given values\r\n\t *\r\n\t * @param {Number} x X component\r\n\t * @param {Number} y Y component\r\n\t * @param {Number} z Z component\r\n\t * @param {Number} w W component\r\n\t * @returns {vec4} a new 4D vector\r\n\t */\r\n\tvec4.fromValues = function(x, y, z, w) {\r\n\t    var out = new glMatrix.ARRAY_TYPE(4);\r\n\t    out[0] = x;\r\n\t    out[1] = y;\r\n\t    out[2] = z;\r\n\t    out[3] = w;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Copy the values from one vec4 to another\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {vec4} a the source vector\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.copy = function(out, a) {\r\n\t    out[0] = a[0];\r\n\t    out[1] = a[1];\r\n\t    out[2] = a[2];\r\n\t    out[3] = a[3];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Set the components of a vec4 to the given values\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {Number} x X component\r\n\t * @param {Number} y Y component\r\n\t * @param {Number} z Z component\r\n\t * @param {Number} w W component\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.set = function(out, x, y, z, w) {\r\n\t    out[0] = x;\r\n\t    out[1] = y;\r\n\t    out[2] = z;\r\n\t    out[3] = w;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Adds two vec4's\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {vec4} a the first operand\r\n\t * @param {vec4} b the second operand\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.add = function(out, a, b) {\r\n\t    out[0] = a[0] + b[0];\r\n\t    out[1] = a[1] + b[1];\r\n\t    out[2] = a[2] + b[2];\r\n\t    out[3] = a[3] + b[3];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Subtracts vector b from vector a\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {vec4} a the first operand\r\n\t * @param {vec4} b the second operand\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.subtract = function(out, a, b) {\r\n\t    out[0] = a[0] - b[0];\r\n\t    out[1] = a[1] - b[1];\r\n\t    out[2] = a[2] - b[2];\r\n\t    out[3] = a[3] - b[3];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec4.subtract}\r\n\t * @function\r\n\t */\r\n\tvec4.sub = vec4.subtract;\r\n\r\n\t/**\r\n\t * Multiplies two vec4's\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {vec4} a the first operand\r\n\t * @param {vec4} b the second operand\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.multiply = function(out, a, b) {\r\n\t    out[0] = a[0] * b[0];\r\n\t    out[1] = a[1] * b[1];\r\n\t    out[2] = a[2] * b[2];\r\n\t    out[3] = a[3] * b[3];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec4.multiply}\r\n\t * @function\r\n\t */\r\n\tvec4.mul = vec4.multiply;\r\n\r\n\t/**\r\n\t * Divides two vec4's\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {vec4} a the first operand\r\n\t * @param {vec4} b the second operand\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.divide = function(out, a, b) {\r\n\t    out[0] = a[0] / b[0];\r\n\t    out[1] = a[1] / b[1];\r\n\t    out[2] = a[2] / b[2];\r\n\t    out[3] = a[3] / b[3];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec4.divide}\r\n\t * @function\r\n\t */\r\n\tvec4.div = vec4.divide;\r\n\r\n\t/**\r\n\t * Math.ceil the components of a vec4\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {vec4} a vector to ceil\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.ceil = function (out, a) {\r\n\t    out[0] = Math.ceil(a[0]);\r\n\t    out[1] = Math.ceil(a[1]);\r\n\t    out[2] = Math.ceil(a[2]);\r\n\t    out[3] = Math.ceil(a[3]);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Math.floor the components of a vec4\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {vec4} a vector to floor\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.floor = function (out, a) {\r\n\t    out[0] = Math.floor(a[0]);\r\n\t    out[1] = Math.floor(a[1]);\r\n\t    out[2] = Math.floor(a[2]);\r\n\t    out[3] = Math.floor(a[3]);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Returns the minimum of two vec4's\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {vec4} a the first operand\r\n\t * @param {vec4} b the second operand\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.min = function(out, a, b) {\r\n\t    out[0] = Math.min(a[0], b[0]);\r\n\t    out[1] = Math.min(a[1], b[1]);\r\n\t    out[2] = Math.min(a[2], b[2]);\r\n\t    out[3] = Math.min(a[3], b[3]);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Returns the maximum of two vec4's\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {vec4} a the first operand\r\n\t * @param {vec4} b the second operand\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.max = function(out, a, b) {\r\n\t    out[0] = Math.max(a[0], b[0]);\r\n\t    out[1] = Math.max(a[1], b[1]);\r\n\t    out[2] = Math.max(a[2], b[2]);\r\n\t    out[3] = Math.max(a[3], b[3]);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Math.round the components of a vec4\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {vec4} a vector to round\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.round = function (out, a) {\r\n\t    out[0] = Math.round(a[0]);\r\n\t    out[1] = Math.round(a[1]);\r\n\t    out[2] = Math.round(a[2]);\r\n\t    out[3] = Math.round(a[3]);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Scales a vec4 by a scalar number\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {vec4} a the vector to scale\r\n\t * @param {Number} b amount to scale the vector by\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.scale = function(out, a, b) {\r\n\t    out[0] = a[0] * b;\r\n\t    out[1] = a[1] * b;\r\n\t    out[2] = a[2] * b;\r\n\t    out[3] = a[3] * b;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Adds two vec4's after scaling the second operand by a scalar value\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {vec4} a the first operand\r\n\t * @param {vec4} b the second operand\r\n\t * @param {Number} scale the amount to scale b by before adding\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.scaleAndAdd = function(out, a, b, scale) {\r\n\t    out[0] = a[0] + (b[0] * scale);\r\n\t    out[1] = a[1] + (b[1] * scale);\r\n\t    out[2] = a[2] + (b[2] * scale);\r\n\t    out[3] = a[3] + (b[3] * scale);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Calculates the euclidian distance between two vec4's\r\n\t *\r\n\t * @param {vec4} a the first operand\r\n\t * @param {vec4} b the second operand\r\n\t * @returns {Number} distance between a and b\r\n\t */\r\n\tvec4.distance = function(a, b) {\r\n\t    var x = b[0] - a[0],\r\n\t        y = b[1] - a[1],\r\n\t        z = b[2] - a[2],\r\n\t        w = b[3] - a[3];\r\n\t    return Math.sqrt(x*x + y*y + z*z + w*w);\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec4.distance}\r\n\t * @function\r\n\t */\r\n\tvec4.dist = vec4.distance;\r\n\r\n\t/**\r\n\t * Calculates the squared euclidian distance between two vec4's\r\n\t *\r\n\t * @param {vec4} a the first operand\r\n\t * @param {vec4} b the second operand\r\n\t * @returns {Number} squared distance between a and b\r\n\t */\r\n\tvec4.squaredDistance = function(a, b) {\r\n\t    var x = b[0] - a[0],\r\n\t        y = b[1] - a[1],\r\n\t        z = b[2] - a[2],\r\n\t        w = b[3] - a[3];\r\n\t    return x*x + y*y + z*z + w*w;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec4.squaredDistance}\r\n\t * @function\r\n\t */\r\n\tvec4.sqrDist = vec4.squaredDistance;\r\n\r\n\t/**\r\n\t * Calculates the length of a vec4\r\n\t *\r\n\t * @param {vec4} a vector to calculate length of\r\n\t * @returns {Number} length of a\r\n\t */\r\n\tvec4.length = function (a) {\r\n\t    var x = a[0],\r\n\t        y = a[1],\r\n\t        z = a[2],\r\n\t        w = a[3];\r\n\t    return Math.sqrt(x*x + y*y + z*z + w*w);\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec4.length}\r\n\t * @function\r\n\t */\r\n\tvec4.len = vec4.length;\r\n\r\n\t/**\r\n\t * Calculates the squared length of a vec4\r\n\t *\r\n\t * @param {vec4} a vector to calculate squared length of\r\n\t * @returns {Number} squared length of a\r\n\t */\r\n\tvec4.squaredLength = function (a) {\r\n\t    var x = a[0],\r\n\t        y = a[1],\r\n\t        z = a[2],\r\n\t        w = a[3];\r\n\t    return x*x + y*y + z*z + w*w;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec4.squaredLength}\r\n\t * @function\r\n\t */\r\n\tvec4.sqrLen = vec4.squaredLength;\r\n\r\n\t/**\r\n\t * Negates the components of a vec4\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {vec4} a vector to negate\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.negate = function(out, a) {\r\n\t    out[0] = -a[0];\r\n\t    out[1] = -a[1];\r\n\t    out[2] = -a[2];\r\n\t    out[3] = -a[3];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Returns the inverse of the components of a vec4\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {vec4} a vector to invert\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.inverse = function(out, a) {\r\n\t  out[0] = 1.0 / a[0];\r\n\t  out[1] = 1.0 / a[1];\r\n\t  out[2] = 1.0 / a[2];\r\n\t  out[3] = 1.0 / a[3];\r\n\t  return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Normalize a vec4\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {vec4} a vector to normalize\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.normalize = function(out, a) {\r\n\t    var x = a[0],\r\n\t        y = a[1],\r\n\t        z = a[2],\r\n\t        w = a[3];\r\n\t    var len = x*x + y*y + z*z + w*w;\r\n\t    if (len > 0) {\r\n\t        len = 1 / Math.sqrt(len);\r\n\t        out[0] = x * len;\r\n\t        out[1] = y * len;\r\n\t        out[2] = z * len;\r\n\t        out[3] = w * len;\r\n\t    }\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Calculates the dot product of two vec4's\r\n\t *\r\n\t * @param {vec4} a the first operand\r\n\t * @param {vec4} b the second operand\r\n\t * @returns {Number} dot product of a and b\r\n\t */\r\n\tvec4.dot = function (a, b) {\r\n\t    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];\r\n\t};\r\n\r\n\t/**\r\n\t * Performs a linear interpolation between two vec4's\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {vec4} a the first operand\r\n\t * @param {vec4} b the second operand\r\n\t * @param {Number} t interpolation amount between the two inputs\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.lerp = function (out, a, b, t) {\r\n\t    var ax = a[0],\r\n\t        ay = a[1],\r\n\t        az = a[2],\r\n\t        aw = a[3];\r\n\t    out[0] = ax + t * (b[0] - ax);\r\n\t    out[1] = ay + t * (b[1] - ay);\r\n\t    out[2] = az + t * (b[2] - az);\r\n\t    out[3] = aw + t * (b[3] - aw);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Generates a random vector with the given scale\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.random = function (out, scale) {\r\n\t    scale = scale || 1.0;\r\n\r\n\t    //TODO: This is a pretty awful way of doing this. Find something better.\r\n\t    out[0] = glMatrix.RANDOM();\r\n\t    out[1] = glMatrix.RANDOM();\r\n\t    out[2] = glMatrix.RANDOM();\r\n\t    out[3] = glMatrix.RANDOM();\r\n\t    vec4.normalize(out, out);\r\n\t    vec4.scale(out, out, scale);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Transforms the vec4 with a mat4.\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {vec4} a the vector to transform\r\n\t * @param {mat4} m matrix to transform with\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.transformMat4 = function(out, a, m) {\r\n\t    var x = a[0], y = a[1], z = a[2], w = a[3];\r\n\t    out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;\r\n\t    out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;\r\n\t    out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;\r\n\t    out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Transforms the vec4 with a quat\r\n\t *\r\n\t * @param {vec4} out the receiving vector\r\n\t * @param {vec4} a the vector to transform\r\n\t * @param {quat} q quaternion to transform with\r\n\t * @returns {vec4} out\r\n\t */\r\n\tvec4.transformQuat = function(out, a, q) {\r\n\t    var x = a[0], y = a[1], z = a[2],\r\n\t        qx = q[0], qy = q[1], qz = q[2], qw = q[3],\r\n\r\n\t        // calculate quat * vec\r\n\t        ix = qw * x + qy * z - qz * y,\r\n\t        iy = qw * y + qz * x - qx * z,\r\n\t        iz = qw * z + qx * y - qy * x,\r\n\t        iw = -qx * x - qy * y - qz * z;\r\n\r\n\t    // calculate result * inverse quat\r\n\t    out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;\r\n\t    out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;\r\n\t    out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;\r\n\t    out[3] = a[3];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Perform some operation over an array of vec4s.\r\n\t *\r\n\t * @param {Array} a the array of vectors to iterate over\r\n\t * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed\r\n\t * @param {Number} offset Number of elements to skip at the beginning of the array\r\n\t * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array\r\n\t * @param {Function} fn Function to call for each vector in the array\r\n\t * @param {Object} [arg] additional argument to pass to fn\r\n\t * @returns {Array} a\r\n\t * @function\r\n\t */\r\n\tvec4.forEach = (function() {\r\n\t    var vec = vec4.create();\r\n\r\n\t    return function(a, stride, offset, count, fn, arg) {\r\n\t        var i, l;\r\n\t        if(!stride) {\r\n\t            stride = 4;\r\n\t        }\r\n\r\n\t        if(!offset) {\r\n\t            offset = 0;\r\n\t        }\r\n\t        \r\n\t        if(count) {\r\n\t            l = Math.min((count * stride) + offset, a.length);\r\n\t        } else {\r\n\t            l = a.length;\r\n\t        }\r\n\r\n\t        for(i = offset; i < l; i += stride) {\r\n\t            vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3];\r\n\t            fn(vec, vec, arg);\r\n\t            a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3];\r\n\t        }\r\n\t        \r\n\t        return a;\r\n\t    };\r\n\t})();\r\n\r\n\t/**\r\n\t * Returns a string representation of a vector\r\n\t *\r\n\t * @param {vec4} a vector to represent as a string\r\n\t * @returns {String} string representation of the vector\r\n\t */\r\n\tvec4.str = function (a) {\r\n\t    return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';\r\n\t};\r\n\r\n\t/**\r\n\t * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)\r\n\t *\r\n\t * @param {vec4} a The first vector.\r\n\t * @param {vec4} b The second vector.\r\n\t * @returns {Boolean} True if the vectors are equal, false otherwise.\r\n\t */\r\n\tvec4.exactEquals = function (a, b) {\r\n\t    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];\r\n\t};\r\n\r\n\t/**\r\n\t * Returns whether or not the vectors have approximately the same elements in the same position.\r\n\t *\r\n\t * @param {vec4} a The first vector.\r\n\t * @param {vec4} b The second vector.\r\n\t * @returns {Boolean} True if the vectors are equal, false otherwise.\r\n\t */\r\n\tvec4.equals = function (a, b) {\r\n\t    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\r\n\t    var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\r\n\t    return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\r\n\t            Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\r\n\t            Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\r\n\t            Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)));\r\n\t};\r\n\r\n\tmodule.exports = vec4;\r\n\r\n\r\n/***/ },\r\n/* 9 */\r\n/***/ function(module, exports, __webpack_require__) {\r\n\r\n\t/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\r\n\r\n\tPermission is hereby granted, free of charge, to any person obtaining a copy\r\n\tof this software and associated documentation files (the \"Software\"), to deal\r\n\tin the Software without restriction, including without limitation the rights\r\n\tto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n\tcopies of the Software, and to permit persons to whom the Software is\r\n\tfurnished to do so, subject to the following conditions:\r\n\r\n\tThe above copyright notice and this permission notice shall be included in\r\n\tall copies or substantial portions of the Software.\r\n\r\n\tTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n\tIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n\tFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n\tAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n\tLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n\tOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\n\tTHE SOFTWARE. */\r\n\r\n\tvar glMatrix = __webpack_require__(1);\r\n\r\n\t/**\r\n\t * @class 2 Dimensional Vector\r\n\t * @name vec2\r\n\t */\r\n\tvar vec2 = {};\r\n\r\n\t/**\r\n\t * Creates a new, empty vec2\r\n\t *\r\n\t * @returns {vec2} a new 2D vector\r\n\t */\r\n\tvec2.create = function() {\r\n\t    var out = new glMatrix.ARRAY_TYPE(2);\r\n\t    out[0] = 0;\r\n\t    out[1] = 0;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Creates a new vec2 initialized with values from an existing vector\r\n\t *\r\n\t * @param {vec2} a vector to clone\r\n\t * @returns {vec2} a new 2D vector\r\n\t */\r\n\tvec2.clone = function(a) {\r\n\t    var out = new glMatrix.ARRAY_TYPE(2);\r\n\t    out[0] = a[0];\r\n\t    out[1] = a[1];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Creates a new vec2 initialized with the given values\r\n\t *\r\n\t * @param {Number} x X component\r\n\t * @param {Number} y Y component\r\n\t * @returns {vec2} a new 2D vector\r\n\t */\r\n\tvec2.fromValues = function(x, y) {\r\n\t    var out = new glMatrix.ARRAY_TYPE(2);\r\n\t    out[0] = x;\r\n\t    out[1] = y;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Copy the values from one vec2 to another\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a the source vector\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.copy = function(out, a) {\r\n\t    out[0] = a[0];\r\n\t    out[1] = a[1];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Set the components of a vec2 to the given values\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {Number} x X component\r\n\t * @param {Number} y Y component\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.set = function(out, x, y) {\r\n\t    out[0] = x;\r\n\t    out[1] = y;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Adds two vec2's\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a the first operand\r\n\t * @param {vec2} b the second operand\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.add = function(out, a, b) {\r\n\t    out[0] = a[0] + b[0];\r\n\t    out[1] = a[1] + b[1];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Subtracts vector b from vector a\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a the first operand\r\n\t * @param {vec2} b the second operand\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.subtract = function(out, a, b) {\r\n\t    out[0] = a[0] - b[0];\r\n\t    out[1] = a[1] - b[1];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec2.subtract}\r\n\t * @function\r\n\t */\r\n\tvec2.sub = vec2.subtract;\r\n\r\n\t/**\r\n\t * Multiplies two vec2's\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a the first operand\r\n\t * @param {vec2} b the second operand\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.multiply = function(out, a, b) {\r\n\t    out[0] = a[0] * b[0];\r\n\t    out[1] = a[1] * b[1];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec2.multiply}\r\n\t * @function\r\n\t */\r\n\tvec2.mul = vec2.multiply;\r\n\r\n\t/**\r\n\t * Divides two vec2's\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a the first operand\r\n\t * @param {vec2} b the second operand\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.divide = function(out, a, b) {\r\n\t    out[0] = a[0] / b[0];\r\n\t    out[1] = a[1] / b[1];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec2.divide}\r\n\t * @function\r\n\t */\r\n\tvec2.div = vec2.divide;\r\n\r\n\t/**\r\n\t * Math.ceil the components of a vec2\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a vector to ceil\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.ceil = function (out, a) {\r\n\t    out[0] = Math.ceil(a[0]);\r\n\t    out[1] = Math.ceil(a[1]);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Math.floor the components of a vec2\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a vector to floor\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.floor = function (out, a) {\r\n\t    out[0] = Math.floor(a[0]);\r\n\t    out[1] = Math.floor(a[1]);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Returns the minimum of two vec2's\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a the first operand\r\n\t * @param {vec2} b the second operand\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.min = function(out, a, b) {\r\n\t    out[0] = Math.min(a[0], b[0]);\r\n\t    out[1] = Math.min(a[1], b[1]);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Returns the maximum of two vec2's\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a the first operand\r\n\t * @param {vec2} b the second operand\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.max = function(out, a, b) {\r\n\t    out[0] = Math.max(a[0], b[0]);\r\n\t    out[1] = Math.max(a[1], b[1]);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Math.round the components of a vec2\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a vector to round\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.round = function (out, a) {\r\n\t    out[0] = Math.round(a[0]);\r\n\t    out[1] = Math.round(a[1]);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Scales a vec2 by a scalar number\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a the vector to scale\r\n\t * @param {Number} b amount to scale the vector by\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.scale = function(out, a, b) {\r\n\t    out[0] = a[0] * b;\r\n\t    out[1] = a[1] * b;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Adds two vec2's after scaling the second operand by a scalar value\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a the first operand\r\n\t * @param {vec2} b the second operand\r\n\t * @param {Number} scale the amount to scale b by before adding\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.scaleAndAdd = function(out, a, b, scale) {\r\n\t    out[0] = a[0] + (b[0] * scale);\r\n\t    out[1] = a[1] + (b[1] * scale);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Calculates the euclidian distance between two vec2's\r\n\t *\r\n\t * @param {vec2} a the first operand\r\n\t * @param {vec2} b the second operand\r\n\t * @returns {Number} distance between a and b\r\n\t */\r\n\tvec2.distance = function(a, b) {\r\n\t    var x = b[0] - a[0],\r\n\t        y = b[1] - a[1];\r\n\t    return Math.sqrt(x*x + y*y);\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec2.distance}\r\n\t * @function\r\n\t */\r\n\tvec2.dist = vec2.distance;\r\n\r\n\t/**\r\n\t * Calculates the squared euclidian distance between two vec2's\r\n\t *\r\n\t * @param {vec2} a the first operand\r\n\t * @param {vec2} b the second operand\r\n\t * @returns {Number} squared distance between a and b\r\n\t */\r\n\tvec2.squaredDistance = function(a, b) {\r\n\t    var x = b[0] - a[0],\r\n\t        y = b[1] - a[1];\r\n\t    return x*x + y*y;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec2.squaredDistance}\r\n\t * @function\r\n\t */\r\n\tvec2.sqrDist = vec2.squaredDistance;\r\n\r\n\t/**\r\n\t * Calculates the length of a vec2\r\n\t *\r\n\t * @param {vec2} a vector to calculate length of\r\n\t * @returns {Number} length of a\r\n\t */\r\n\tvec2.length = function (a) {\r\n\t    var x = a[0],\r\n\t        y = a[1];\r\n\t    return Math.sqrt(x*x + y*y);\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec2.length}\r\n\t * @function\r\n\t */\r\n\tvec2.len = vec2.length;\r\n\r\n\t/**\r\n\t * Calculates the squared length of a vec2\r\n\t *\r\n\t * @param {vec2} a vector to calculate squared length of\r\n\t * @returns {Number} squared length of a\r\n\t */\r\n\tvec2.squaredLength = function (a) {\r\n\t    var x = a[0],\r\n\t        y = a[1];\r\n\t    return x*x + y*y;\r\n\t};\r\n\r\n\t/**\r\n\t * Alias for {@link vec2.squaredLength}\r\n\t * @function\r\n\t */\r\n\tvec2.sqrLen = vec2.squaredLength;\r\n\r\n\t/**\r\n\t * Negates the components of a vec2\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a vector to negate\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.negate = function(out, a) {\r\n\t    out[0] = -a[0];\r\n\t    out[1] = -a[1];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Returns the inverse of the components of a vec2\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a vector to invert\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.inverse = function(out, a) {\r\n\t  out[0] = 1.0 / a[0];\r\n\t  out[1] = 1.0 / a[1];\r\n\t  return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Normalize a vec2\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a vector to normalize\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.normalize = function(out, a) {\r\n\t    var x = a[0],\r\n\t        y = a[1];\r\n\t    var len = x*x + y*y;\r\n\t    if (len > 0) {\r\n\t        //TODO: evaluate use of glm_invsqrt here?\r\n\t        len = 1 / Math.sqrt(len);\r\n\t        out[0] = a[0] * len;\r\n\t        out[1] = a[1] * len;\r\n\t    }\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Calculates the dot product of two vec2's\r\n\t *\r\n\t * @param {vec2} a the first operand\r\n\t * @param {vec2} b the second operand\r\n\t * @returns {Number} dot product of a and b\r\n\t */\r\n\tvec2.dot = function (a, b) {\r\n\t    return a[0] * b[0] + a[1] * b[1];\r\n\t};\r\n\r\n\t/**\r\n\t * Computes the cross product of two vec2's\r\n\t * Note that the cross product must by definition produce a 3D vector\r\n\t *\r\n\t * @param {vec3} out the receiving vector\r\n\t * @param {vec2} a the first operand\r\n\t * @param {vec2} b the second operand\r\n\t * @returns {vec3} out\r\n\t */\r\n\tvec2.cross = function(out, a, b) {\r\n\t    var z = a[0] * b[1] - a[1] * b[0];\r\n\t    out[0] = out[1] = 0;\r\n\t    out[2] = z;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Performs a linear interpolation between two vec2's\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a the first operand\r\n\t * @param {vec2} b the second operand\r\n\t * @param {Number} t interpolation amount between the two inputs\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.lerp = function (out, a, b, t) {\r\n\t    var ax = a[0],\r\n\t        ay = a[1];\r\n\t    out[0] = ax + t * (b[0] - ax);\r\n\t    out[1] = ay + t * (b[1] - ay);\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Generates a random vector with the given scale\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.random = function (out, scale) {\r\n\t    scale = scale || 1.0;\r\n\t    var r = glMatrix.RANDOM() * 2.0 * Math.PI;\r\n\t    out[0] = Math.cos(r) * scale;\r\n\t    out[1] = Math.sin(r) * scale;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Transforms the vec2 with a mat2\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a the vector to transform\r\n\t * @param {mat2} m matrix to transform with\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.transformMat2 = function(out, a, m) {\r\n\t    var x = a[0],\r\n\t        y = a[1];\r\n\t    out[0] = m[0] * x + m[2] * y;\r\n\t    out[1] = m[1] * x + m[3] * y;\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Transforms the vec2 with a mat2d\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a the vector to transform\r\n\t * @param {mat2d} m matrix to transform with\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.transformMat2d = function(out, a, m) {\r\n\t    var x = a[0],\r\n\t        y = a[1];\r\n\t    out[0] = m[0] * x + m[2] * y + m[4];\r\n\t    out[1] = m[1] * x + m[3] * y + m[5];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Transforms the vec2 with a mat3\r\n\t * 3rd vector component is implicitly '1'\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a the vector to transform\r\n\t * @param {mat3} m matrix to transform with\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.transformMat3 = function(out, a, m) {\r\n\t    var x = a[0],\r\n\t        y = a[1];\r\n\t    out[0] = m[0] * x + m[3] * y + m[6];\r\n\t    out[1] = m[1] * x + m[4] * y + m[7];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Transforms the vec2 with a mat4\r\n\t * 3rd vector component is implicitly '0'\r\n\t * 4th vector component is implicitly '1'\r\n\t *\r\n\t * @param {vec2} out the receiving vector\r\n\t * @param {vec2} a the vector to transform\r\n\t * @param {mat4} m matrix to transform with\r\n\t * @returns {vec2} out\r\n\t */\r\n\tvec2.transformMat4 = function(out, a, m) {\r\n\t    var x = a[0], \r\n\t        y = a[1];\r\n\t    out[0] = m[0] * x + m[4] * y + m[12];\r\n\t    out[1] = m[1] * x + m[5] * y + m[13];\r\n\t    return out;\r\n\t};\r\n\r\n\t/**\r\n\t * Perform some operation over an array of vec2s.\r\n\t *\r\n\t * @param {Array} a the array of vectors to iterate over\r\n\t * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed\r\n\t * @param {Number} offset Number of elements to skip at the beginning of the array\r\n\t * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array\r\n\t * @param {Function} fn Function to call for each vector in the array\r\n\t * @param {Object} [arg] additional argument to pass to fn\r\n\t * @returns {Array} a\r\n\t * @function\r\n\t */\r\n\tvec2.forEach = (function() {\r\n\t    var vec = vec2.create();\r\n\r\n\t    return function(a, stride, offset, count, fn, arg) {\r\n\t        var i, l;\r\n\t        if(!stride) {\r\n\t            stride = 2;\r\n\t        }\r\n\r\n\t        if(!offset) {\r\n\t            offset = 0;\r\n\t        }\r\n\t        \r\n\t        if(count) {\r\n\t            l = Math.min((count * stride) + offset, a.length);\r\n\t        } else {\r\n\t            l = a.length;\r\n\t        }\r\n\r\n\t        for(i = offset; i < l; i += stride) {\r\n\t            vec[0] = a[i]; vec[1] = a[i+1];\r\n\t            fn(vec, vec, arg);\r\n\t            a[i] = vec[0]; a[i+1] = vec[1];\r\n\t        }\r\n\t        \r\n\t        return a;\r\n\t    };\r\n\t})();\r\n\r\n\t/**\r\n\t * Returns a string representation of a vector\r\n\t *\r\n\t * @param {vec2} a vector to represent as a string\r\n\t * @returns {String} string representation of the vector\r\n\t */\r\n\tvec2.str = function (a) {\r\n\t    return 'vec2(' + a[0] + ', ' + a[1] + ')';\r\n\t};\r\n\r\n\t/**\r\n\t * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)\r\n\t *\r\n\t * @param {vec2} a The first vector.\r\n\t * @param {vec2} b The second vector.\r\n\t * @returns {Boolean} True if the vectors are equal, false otherwise.\r\n\t */\r\n\tvec2.exactEquals = function (a, b) {\r\n\t    return a[0] === b[0] && a[1] === b[1];\r\n\t};\r\n\r\n\t/**\r\n\t * Returns whether or not the vectors have approximately the same elements in the same position.\r\n\t *\r\n\t * @param {vec2} a The first vector.\r\n\t * @param {vec2} b The second vector.\r\n\t * @returns {Boolean} True if the vectors are equal, false otherwise.\r\n\t */\r\n\tvec2.equals = function (a, b) {\r\n\t    var a0 = a[0], a1 = a[1];\r\n\t    var b0 = b[0], b1 = b[1];\r\n\t    return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\r\n\t            Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)));\r\n\t};\r\n\r\n\tmodule.exports = vec2;\r\n\r\n\r\n/***/ }\r\n/******/ ])\r\n});\r\n;"
  },
  {
    "path": "libs/picogl.js/picogl.js",
    "content": "/*\r\nPicoGL.js v0.6.10\r\n\r\nThe MIT License (MIT)\r\n\r\nCopyright (c) 2017 Tarek Sherif\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy of\r\nthis software and associated documentation files (the \"Software\"), to deal in\r\nthe Software without restriction, including without limitation the rights to\r\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\nthe Software, and to permit persons to whom the Software is furnished to do so,\r\nsubject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n*/\r\n\r\n(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.exports=f()}else if(typeof define===\"function\"&&define.amd){define([],f)}else{var g;if(typeof window!==\"undefined\"){g=window}else if(typeof global!==\"undefined\"){g=global}else if(typeof self!==\"undefined\"){g=self}else{g=this}g.PicoGL = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){\r\n///////////////////////////////////////////////////////////////////////////////////\r\n// The MIT License (MIT)\r\n//\r\n// Copyright (c) 2017 Tarek Sherif\r\n//\r\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n// this software and associated documentation files (the \"Software\"), to deal in\r\n// the Software without restriction, including without limitation the rights to\r\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n// the Software, and to permit persons to whom the Software is furnished to do so,\r\n// subject to the following conditions:\r\n//\r\n// The above copyright notice and this permission notice shall be included in all\r\n// copies or substantial portions of the Software.\r\n//\r\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n///////////////////////////////////////////////////////////////////////////////////\r\n\r\n\"use strict\";\r\nvar CONSTANTS               = require(\"./constants\");\r\nvar TEXTURE_FORMAT_DEFAULTS = require(\"./texture-format-defaults\");\r\nvar Cubemap                 = require(\"./cubemap\");\r\nvar DrawCall                = require(\"./draw-call\");\r\nvar Framebuffer             = require(\"./framebuffer\");\r\nvar Program                 = require(\"./program\");\r\nvar Shader                  = require(\"./shader\");\r\nvar Texture                 = require(\"./texture\");\r\nvar Timer                   = require(\"./timer\");\r\nvar TransformFeedback       = require(\"./transform-feedback\");\r\nvar UniformBuffer           = require(\"./uniform-buffer\");\r\nvar VertexArray             = require(\"./vertex-array\");\r\nvar VertexBuffer            = require(\"./vertex-buffer\");\r\nvar Query                   = require(\"./query\");\r\n\r\n/**\r\n    Primary entry point to PicoGL. An app will store all parts of the WebGL\r\n    state.\r\n\r\n    @class\r\n    @prop {DOMElement} canvas The canvas on which this app drawing.\r\n    @prop {WebGLRenderingContext} gl The WebGL context.\r\n    @prop {number} width The width of the drawing surface.\r\n    @prop {number} height The height of the drawing surface.\r\n    @prop {boolean} floatRenderTargetsEnabled Whether the EXT_color_buffer_float extension is enabled.\r\n    @prop {boolean} linearFloatTexturesEnabled Whether the OES_texture_float_linear extension is enabled.\r\n    @prop {boolean} s3tcTexturesEnabled Whether the WEBGL_compressed_texture_s3tc extension is enabled.\r\n    @prop {boolean} s3tcSRGBTexturesEnabled Whether the WEBGL_compressed_texture_s3tc_srgb extension is enabled.\r\n    @prop {boolean} etcTexturesEnabled Whether the WEBGL_compressed_texture_etc extension is enabled.\r\n    @prop {boolean} astcTexturesEnabled Whether the WEBGL_compressed_texture_astc extension is enabled.\r\n    @prop {boolean} pvrtcTexturesEnabled Whether the WEBGL_compressed_texture_pvrtc extension is enabled.\r\n    @prop {Object} state Tracked GL state.\r\n    @prop {GLEnum} clearBits Current clear mask to use with clear().    \r\n*/\r\nfunction App(canvas, contextAttributes) {\r\n    this.canvas = canvas;\r\n    this.gl = canvas.getContext(\"webgl2\", contextAttributes);\r\n    this.width = this.gl.drawingBufferWidth;\r\n    this.height = this.gl.drawingBufferHeight;\r\n    this.viewportX = 0;\r\n    this.viewportY = 0;\r\n    this.viewportWidth = 0;\r\n    this.viewportHeight = 0;\r\n    this.currentDrawCalls = null;\r\n    this.emptyFragmentShader = null;\r\n\r\n    this.state = {\r\n        program: null,\r\n        vertexArray: null,\r\n        transformFeedback: null,\r\n        activeTexture: -1,\r\n        textures: new Array(CONSTANTS.WEBGL_INFO.MAX_TEXTURE_UNITS),\r\n        // TODO(Tarek): UBO state currently not tracked, due bug\r\n        // with UBO state becoming corrupted between frames in Chrome\r\n        // https://bugs.chromium.org/p/chromium/issues/detail?id=722060\r\n        // Enable UBO state tracking when that's fixed.\r\n        uniformBuffers: new Array(CONSTANTS.WEBGL_INFO.MAX_UNIFORM_BUFFERS),\r\n        uniformBufferCount: 0,\r\n        freeUniformBufferBases: [],\r\n        drawFramebuffer: null,\r\n        readFramebuffer: null\r\n    };\r\n\r\n    this.clearBits = this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT| this.gl.STENCIL_BUFFER_BIT;\r\n\r\n    this.cpuTime = 0;\r\n    this.gpuTime = 0;\r\n\r\n    // Extensions\r\n    this.floatRenderTargetsEnabled = false;\r\n    this.linearFloatTexturesEnabled = false;\r\n    this.s3tcTexturesEnabled = false;\r\n    this.s3tcSRGBTexturesEnabled = false;\r\n    this.etcTexturesEnabled = false;\r\n    this.astcTexturesEnabled = false;\r\n    this.pvrtcTexturesEnabled = false;\r\n\r\n    this.viewport(0, 0, this.width, this.height);\r\n}\r\n\r\n/**\r\n    Set the color mask to selectively enable or disable particular\r\n    color channels while rendering.\r\n\r\n    @method\r\n    @param {boolean} r Red channel.\r\n    @param {boolean} g Green channel.\r\n    @param {boolean} b Blue channel.\r\n    @param {boolean} a Alpha channel.\r\n*/\r\nApp.prototype.colorMask = function(r, g, b, a) {\r\n    this.gl.colorMask(r, g, b, a);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Set the clear color.\r\n\r\n    @method\r\n    @param {number} r Red channel.\r\n    @param {number} g Green channel.\r\n    @param {number} b Blue channel.\r\n    @param {number} a Alpha channel.\r\n*/\r\nApp.prototype.clearColor = function(r, g, b, a) {\r\n    this.gl.clearColor(r, g, b, a);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Set the clear mask bits to use when calling clear().\r\n    E.g. app.clearMask(PicoGL.COLOR_BUFFER_BIT).\r\n\r\n    @method\r\n    @param {GLEnum} mask Bit mask of buffers to clear.\r\n*/\r\nApp.prototype.clearMask = function(mask) {\r\n    this.clearBits = mask;\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Clear the canvas\r\n\r\n    @method\r\n*/\r\nApp.prototype.clear = function() {\r\n    this.gl.clear(this.clearBits);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Bind a draw framebuffer to the WebGL context. Note that \r\n    this method resets the viewport to match the given framebuffer.\r\n\r\n    @method\r\n    @param {Framebuffer} framebuffer The Framebuffer object to bind.\r\n    @see Framebuffer\r\n*/\r\nApp.prototype.drawFramebuffer = function(framebuffer) {\r\n    framebuffer.bindForDraw();\r\n\r\n    this.viewport(0, 0, framebuffer.width, framebuffer.height);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Bind a read framebuffer to the WebGL context.\r\n\r\n    @method\r\n    @param {Framebuffer} framebuffer The Framebuffer object to bind.\r\n    @see Framebuffer\r\n*/\r\nApp.prototype.readFramebuffer = function(framebuffer) {\r\n    framebuffer.bindForRead();\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Switch back to the default framebuffer for drawing (i.e. draw to the screen).\r\n    Note that this method resets the viewport to match the default framebuffer.\r\n\r\n    @method\r\n*/\r\nApp.prototype.defaultDrawFramebuffer = function() {\r\n    if (this.state.drawFramebuffer !== null) {\r\n        this.gl.bindFramebuffer(this.gl.DRAW_FRAMEBUFFER, null);\r\n        this.state.drawFramebuffer = null;\r\n        this.viewport(0, 0, this.width, this.height);\r\n    }\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Switch back to the default framebuffer for reading (i.e. read from the screen).\r\n\r\n    @method\r\n*/\r\nApp.prototype.defaultReadFramebuffer = function() {\r\n    if (this.state.readFramebuffer !== null) {\r\n        this.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER, null);\r\n        this.state.readFramebuffer = null;\r\n    }\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Set the depth range.\r\n\r\n    @method\r\n    @param {number} near Minimum depth value.\r\n    @param {number} far Maximum depth value.\r\n*/\r\nApp.prototype.depthRange = function(near, far) {\r\n    this.gl.depthRange(near, far);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Enable depth testing.\r\n\r\n    @method\r\n*/\r\nApp.prototype.depthTest = function() {\r\n    this.gl.enable(this.gl.DEPTH_TEST);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Disable depth testing.\r\n\r\n    @method\r\n*/\r\nApp.prototype.noDepthTest = function() {\r\n    this.gl.disable(this.gl.DEPTH_TEST);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Enable or disable writing to the depth buffer.\r\n\r\n    @method\r\n    @param {Boolean} mask The depth mask.\r\n*/\r\nApp.prototype.depthMask = function(mask) {\r\n    this.gl.depthMask(mask);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Set the depth test function. E.g. app.depthFunc(PicoGL.LEQUAL).\r\n\r\n    @method\r\n    @param {GLEnum} func The depth testing function to use.\r\n*/\r\nApp.prototype.depthFunc = function(func) {\r\n    this.gl.depthFunc(func);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Enable blending.\r\n\r\n    @method\r\n*/\r\nApp.prototype.blend = function() {\r\n    this.gl.enable(this.gl.BLEND);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Disable blending\r\n\r\n    @method\r\n*/\r\nApp.prototype.noBlend = function() {\r\n    this.gl.disable(this.gl.BLEND);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Set the blend function. E.g. app.blendFunc(PicoGL.ONE, PicoGL.ONE_MINUS_SRC_ALPHA).\r\n\r\n    @method\r\n    @param {GLEnum} src The source blending weight.\r\n    @param {GLEnum} dest The destination blending weight.\r\n*/\r\nApp.prototype.blendFunc = function(src, dest) {\r\n    this.gl.blendFunc(src, dest);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Set the blend function, with separate weighting for color and alpha channels.\r\n    E.g. app.blendFuncSeparate(PicoGL.ONE, PicoGL.ONE_MINUS_SRC_ALPHA, PicoGL.ONE, PicoGL.ONE).\r\n\r\n    @method\r\n    @param {GLEnum} csrc The source blending weight for the RGB channels.\r\n    @param {GLEnum} cdest The destination blending weight for the RGB channels.\r\n    @param {GLEnum} asrc The source blending weight for the alpha channel.\r\n    @param {GLEnum} adest The destination blending weight for the alpha channel.\r\n*/\r\nApp.prototype.blendFuncSeparate = function(csrc, cdest, asrc, adest) {\r\n    this.gl.blendFuncSeparate(csrc, cdest, asrc, adest);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Enable stencil testing.\r\n    NOTE: Only works if { stencil: true } passed as a\r\n    context attribute when creating the App!\r\n\r\n    @method\r\n*/\r\nApp.prototype.stencilTest = function() {\r\n    this.gl.enable(this.gl.STENCIL_TEST);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Disable stencil testing.\r\n\r\n    @method\r\n*/\r\nApp.prototype.noStencilTest = function() {\r\n    this.gl.disable(this.gl.STENCIL_TEST);\r\n\r\n    return this;\r\n};\r\n\r\n\r\n/**\r\n    Enable scissor testing.\r\n\r\n    @method\r\n*/\r\nApp.prototype.scissorTest = function() {\r\n    this.gl.enable(this.gl.SCISSOR_TEST);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Disable scissor testing.\r\n\r\n    @method\r\n*/\r\nApp.prototype.noScissorTest = function() {\r\n    this.gl.disable(this.gl.SCISSOR_TEST);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Define the scissor box.\r\n\r\n    @method\r\n*/\r\nApp.prototype.scissor = function(x, y, width, height) {\r\n    this.gl.scissor(x, y, width, height);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Set the bitmask to use for tested stencil values.\r\n    E.g. app.stencilMask(0xFF).\r\n    NOTE: Only works if { stencil: true } passed as a\r\n    context attribute when creating the App!\r\n\r\n    @method\r\n    @param {number} mask The mask value.\r\n\r\n*/\r\nApp.prototype.stencilMask = function(mask) {\r\n    this.gl.stencilMask(mask);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Set the bitmask to use for tested stencil values for a particular face orientation.\r\n    E.g. app.stencilMaskSeparate(PicoGL.FRONT, 0xFF).\r\n    NOTE: Only works if { stencil: true } passed as a\r\n    context attribute when creating the App!\r\n\r\n    @method\r\n    @param {GLEnum} face The face orientation to apply the mask to.\r\n    @param {number} mask The mask value.\r\n\r\n*/\r\nApp.prototype.stencilMaskSeparate = function(face, mask) {\r\n    this.gl.stencilMaskSeparate(face, mask);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Set the stencil function and reference value.\r\n    E.g. app.stencilFunc(PicoGL.EQUAL, 1, 0xFF).\r\n    NOTE: Only works if { stencil: true } passed as a\r\n    context attribute when creating the App!\r\n\r\n    @method\r\n    @param {GLEnum} func The testing function.\r\n    @param {number} ref The reference value.\r\n    @param {GLEnum} mask The bitmask to use against tested values before applying\r\n        the stencil function.\r\n*/\r\nApp.prototype.stencilFunc = function(func, ref, mask) {\r\n    this.gl.stencilFunc(func, ref, mask);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Set the stencil function and reference value for a particular face orientation.\r\n    E.g. app.stencilFuncSeparate(PicoGL.FRONT, PicoGL.EQUAL, 1, 0xFF).\r\n    NOTE: Only works if { stencil: true } passed as a\r\n    context attribute when creating the App!\r\n\r\n    @method\r\n    @param {GLEnum} face The face orientation to apply the function to.\r\n    @param {GLEnum} func The testing function.\r\n    @param {number} ref The reference value.\r\n    @param {GLEnum} mask The bitmask to use against tested values before applying\r\n        the stencil function.\r\n*/\r\nApp.prototype.stencilFuncSeparate = function(face, func, ref, mask) {\r\n    this.gl.stencilFuncSeparate(face, func, ref, mask);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Set the operations for updating stencil buffer values.\r\n    E.g. app.stencilOp(PicoGL.KEEP, PicoGL.KEEP, PicoGL.REPLACE).\r\n    NOTE: Only works if { stencil: true } passed as a\r\n    context attribute when creating the App!\r\n\r\n    @method\r\n    @param {GLEnum} stencilFail Operation to apply if the stencil test fails.\r\n    @param {GLEnum} depthFail Operation to apply if the depth test fails.\r\n    @param {GLEnum} pass Operation to apply if the both the depth and stencil tests pass.\r\n*/\r\nApp.prototype.stencilOp = function(stencilFail, depthFail, pass) {\r\n    this.gl.stencilOp(stencilFail, depthFail, pass);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Set the operations for updating stencil buffer values for a particular face orientation.\r\n    E.g. app.stencilOpSeparate(PicoGL.FRONT, PicoGL.KEEP, PicoGL.KEEP, PicoGL.REPLACE).\r\n    NOTE: Only works if { stencil: true } passed as a\r\n    context attribute when creating the App!\r\n\r\n    @method\r\n    @param {GLEnum} face The face orientation to apply the operations to.\r\n    @param {GLEnum} stencilFail Operation to apply if the stencil test fails.\r\n    @param {GLEnum} depthFail Operation to apply if the depth test fails.\r\n    @param {GLEnum} pass Operation to apply if the both the depth and stencil tests pass.\r\n*/\r\nApp.prototype.stencilOpSeparate = function(face, stencilFail, depthFail, pass) {\r\n    this.gl.stencilOpSeparate(face, stencilFail, depthFail, pass);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Enable rasterization step.\r\n\r\n    @method\r\n*/\r\nApp.prototype.rasterize = function() {\r\n    this.gl.disable(this.gl.RASTERIZER_DISCARD);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Disable rasterization step.\r\n\r\n    @method\r\n*/\r\nApp.prototype.noRasterize = function() {\r\n    this.gl.enable(this.gl.RASTERIZER_DISCARD);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Enable backface culling.\r\n\r\n    @method\r\n*/\r\nApp.prototype.cullBackfaces = function() {\r\n    this.gl.enable(this.gl.CULL_FACE);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Disable backface culling.\r\n\r\n    @method\r\n*/\r\nApp.prototype.drawBackfaces = function() {\r\n    this.gl.disable(this.gl.CULL_FACE);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Enable the EXT_color_buffer_float extension. Allows for creating float textures as\r\n    render targets on FrameBuffer objects. E.g. app.createFramebuffer().colorTarget(0, PicoGL.FLOAT).\r\n\r\n    @method\r\n    @see Framebuffer\r\n*/\r\nApp.prototype.floatRenderTargets = function() {\r\n    this.floatRenderTargetsEnabled = !!this.gl.getExtension(\"EXT_color_buffer_float\");\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Enable the OES_texture_float_linear extension. Allows for linear blending on float textures.\r\n\r\n    @method\r\n    @see Framebuffer\r\n*/\r\nApp.prototype.linearFloatTextures = function() {\r\n    this.linearFloatTexturesEnabled = !!this.gl.getExtension(\"OES_texture_float_linear\");\r\n\r\n    return this;\r\n};\r\n\r\n\r\n/**\r\n    Enable the WEBGL_compressed_texture_s3tc and WEBGL_compressed_texture_s3tc_srgb extensions, and \r\n    add the following enums, which can be used as texture formats, to the PicoGL object:\r\n\r\n    <ul>\r\n      <li>PicoGL.COMPRESSED_RGB_S3TC_DXT1_EXT\r\n      <li>PicoGL.COMPRESSED_RGBA_S3TC_DXT1_EXT\r\n      <li>PicoGL.COMPRESSED_RGBA_S3TC_DXT3_EXT\r\n      <li>PicoGL.COMPRESSED_RGBA_S3TC_DXT5_EXT\r\n      <li>PicoGL.COMPRESSED_SRGB_S3TC_DXT1_EXT\r\n      <li>PicoGL.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT\r\n      <li>PicoGL.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT\r\n      <li>PicoGL.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT\r\n    </ul>\r\n\r\n    @method\r\n*/\r\nApp.prototype.s3tcTextures = function() {\r\n    var ext = this.gl.getExtension(\"WEBGL_compressed_texture_s3tc\");\r\n    this.s3tcTexturesEnabled = !!ext;\r\n    \r\n    if (this.s3tcTexturesEnabled) {\r\n        CONSTANTS.COMPRESSED_RGB_S3TC_DXT1_EXT  = ext.COMPRESSED_RGB_S3TC_DXT1_EXT;\r\n        CONSTANTS.COMPRESSED_RGBA_S3TC_DXT1_EXT = ext.COMPRESSED_RGBA_S3TC_DXT1_EXT;\r\n        CONSTANTS.COMPRESSED_RGBA_S3TC_DXT3_EXT = ext.COMPRESSED_RGBA_S3TC_DXT3_EXT;\r\n        CONSTANTS.COMPRESSED_RGBA_S3TC_DXT5_EXT = ext.COMPRESSED_RGBA_S3TC_DXT5_EXT;\r\n\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGB_S3TC_DXT1_EXT]  = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA_S3TC_DXT1_EXT] = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA_S3TC_DXT3_EXT] = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA_S3TC_DXT5_EXT] = true;\r\n    }\r\n\r\n    ext = this.gl.getExtension(\"WEBGL_compressed_texture_s3tc_srgb\");\r\n    this.s3tcSRGBTexturesEnabled = !!ext;\r\n    \r\n    if (this.s3tcSRGBTexturesEnabled) {\r\n        CONSTANTS.COMPRESSED_SRGB_S3TC_DXT1_EXT       = ext.COMPRESSED_SRGB_S3TC_DXT1_EXT;\r\n        CONSTANTS.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT = ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;\r\n        CONSTANTS.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT = ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;\r\n        CONSTANTS.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT = ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;\r\n        \r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB_S3TC_DXT1_EXT]       = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT] = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT] = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT] = true;\r\n    }\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Enable the WEBGL_compressed_texture_etc extension  and add the following enums, which can\r\n    be used as texture formats, to the PicoGL object:\r\n    \r\n    <ul>\r\n      <li>PicoGL.COMPRESSED_R11_EAC\r\n      <li>PicoGL.COMPRESSED_SIGNED_R11_EAC\r\n      <li>PicoGL.COMPRESSED_RG11_EAC\r\n      <li>PicoGL.COMPRESSED_SIGNED_RG11_EAC\r\n      <li>PicoGL.COMPRESSED_RGB8_ETC2\r\n      <li>PicoGL.COMPRESSED_SRGB8_ETC2\r\n      <li>PicoGL.COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2\r\n      <li>PicoGL.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2\r\n      <li>PicoGL.COMPRESSED_RGBA8_ETC2_EAC\r\n      <li>PicoGL.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC\r\n    </ul>\r\n\r\n    Note that while WEBGL_compressed_texture_etc1 is not enabled by this method,\r\n    ETC1 textures can be loaded using COMPRESSED_RGB8_ETC2 as the format.\r\n\r\n    @method\r\n*/\r\nApp.prototype.etcTextures = function() {\r\n    var ext = this.gl.getExtension(\"WEBGL_compressed_texture_etc\");\r\n    this.etcTexturesEnabled = !!ext;\r\n\r\n    if (this.etcTexturesEnabled) {\r\n        CONSTANTS.COMPRESSED_R11_EAC                        = ext.COMPRESSED_R11_EAC;\r\n        CONSTANTS.COMPRESSED_SIGNED_R11_EAC                 = ext.COMPRESSED_SIGNED_R11_EAC;\r\n        CONSTANTS.COMPRESSED_RG11_EAC                       = ext.COMPRESSED_RG11_EAC;\r\n        CONSTANTS.COMPRESSED_SIGNED_RG11_EAC                = ext.COMPRESSED_SIGNED_RG11_EAC;\r\n        CONSTANTS.COMPRESSED_RGB8_ETC2                      = ext.COMPRESSED_RGB8_ETC2;\r\n        CONSTANTS.COMPRESSED_SRGB8_ETC2                     = ext.COMPRESSED_SRGB8_ETC2;\r\n        CONSTANTS.COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2  = ext.COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;\r\n        CONSTANTS.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = ext.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2;\r\n        CONSTANTS.COMPRESSED_RGBA8_ETC2_EAC                 = ext.COMPRESSED_RGBA8_ETC2_EAC;\r\n        CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC          = ext.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC;\r\n\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_R11_EAC]                        = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SIGNED_R11_EAC]                 = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RG11_EAC]                       = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SIGNED_RG11_EAC]                = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGB8_ETC2]                      = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB8_ETC2]                     = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2]  = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2] = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA8_ETC2_EAC]                 = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC]          = true;\r\n    }\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Enable the WEBGL_compressed_texture_astc extension and add the following enums, which can\r\n    be used as texture formats, to the PicoGL object:\r\n    \r\n    <ul>\r\n      <li>PicoGL.COMPRESSED_RGBA_ASTC_4x4_KHR\r\n      <li>PicoGL.COMPRESSED_RGBA_ASTC_5x4_KHR\r\n      <li>PicoGL.COMPRESSED_RGBA_ASTC_5x5_KHR\r\n      <li>PicoGL.COMPRESSED_RGBA_ASTC_6x5_KHR\r\n      <li>PicoGL.COMPRESSED_RGBA_ASTC_6x6_KHR\r\n      <li>PicoGL.COMPRESSED_RGBA_ASTC_8x5_KHR\r\n      <li>PicoGL.COMPRESSED_RGBA_ASTC_8x6_KHR\r\n      <li>PicoGL.COMPRESSED_RGBA_ASTC_8x8_KHR\r\n      <li>PicoGL.COMPRESSED_RGBA_ASTC_10x5_KHR\r\n      <li>PicoGL.COMPRESSED_RGBA_ASTC_10x6_KHR\r\n      <li>PicoGL.COMPRESSED_RGBA_ASTC_10x8_KHR\r\n      <li>PicoGL.COMPRESSED_RGBA_ASTC_10x10_KHR\r\n      <li>PicoGL.COMPRESSED_RGBA_ASTC_12x10_KHR\r\n      <li>PicoGL.COMPRESSED_RGBA_ASTC_12x12_KHR\r\n      <li>PicoGL.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR\r\n      <li>PicoGL.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR\r\n      <li>PicoGL.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR\r\n      <li>PicoGL.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR\r\n      <li>PicoGL.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR\r\n      <li>PicoGL.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR\r\n      <li>PicoGL.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR\r\n      <li>PicoGL.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR\r\n      <li>PicoGL.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR\r\n      <li>PicoGL.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR\r\n      <li>PicoGL.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR\r\n      <li>PicoGL.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR\r\n      <li>PicoGL.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR\r\n      <li>PicoGL.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR\r\n    </ul>\r\n\r\n    @method\r\n*/\r\nApp.prototype.astcTextures = function() {\r\n    var ext = this.gl.getExtension(\"WEBGL_compressed_texture_astc\");\r\n    this.astcTexturesEnabled = !!ext;\r\n\r\n    if (this.astcTexturesEnabled) {\r\n        CONSTANTS.COMPRESSED_RGBA_ASTC_4x4_KHR           = ext.COMPRESSED_RGBA_ASTC_4x4_KHR;\r\n        CONSTANTS.COMPRESSED_RGBA_ASTC_5x4_KHR           = ext.COMPRESSED_RGBA_ASTC_5x4_KHR;\r\n        CONSTANTS.COMPRESSED_RGBA_ASTC_5x5_KHR           = ext.COMPRESSED_RGBA_ASTC_5x5_KHR;\r\n        CONSTANTS.COMPRESSED_RGBA_ASTC_6x5_KHR           = ext.COMPRESSED_RGBA_ASTC_6x5_KHR;\r\n        CONSTANTS.COMPRESSED_RGBA_ASTC_6x6_KHR           = ext.COMPRESSED_RGBA_ASTC_6x6_KHR;\r\n        CONSTANTS.COMPRESSED_RGBA_ASTC_8x5_KHR           = ext.COMPRESSED_RGBA_ASTC_8x5_KHR;\r\n        CONSTANTS.COMPRESSED_RGBA_ASTC_8x6_KHR           = ext.COMPRESSED_RGBA_ASTC_8x6_KHR;\r\n        CONSTANTS.COMPRESSED_RGBA_ASTC_8x8_KHR           = ext.COMPRESSED_RGBA_ASTC_8x8_KHR;\r\n        CONSTANTS.COMPRESSED_RGBA_ASTC_10x5_KHR          = ext.COMPRESSED_RGBA_ASTC_10x5_KHR;\r\n        CONSTANTS.COMPRESSED_RGBA_ASTC_10x6_KHR          = ext.COMPRESSED_RGBA_ASTC_10x6_KHR;\r\n        CONSTANTS.COMPRESSED_RGBA_ASTC_10x8_KHR          = ext.COMPRESSED_RGBA_ASTC_10x8_KHR;\r\n        CONSTANTS.COMPRESSED_RGBA_ASTC_10x10_KHR         = ext.COMPRESSED_RGBA_ASTC_10x10_KHR;\r\n        CONSTANTS.COMPRESSED_RGBA_ASTC_12x10_KHR         = ext.COMPRESSED_RGBA_ASTC_12x10_KHR;\r\n        CONSTANTS.COMPRESSED_RGBA_ASTC_12x12_KHR         = ext.COMPRESSED_RGBA_ASTC_12x12_KHR;\r\n        CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR   = ext.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR;\r\n        CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR   = ext.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR;\r\n        CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR   = ext.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR;\r\n        CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR   = ext.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR;\r\n        CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR   = ext.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR;\r\n        CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR   = ext.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR;\r\n        CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR   = ext.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR;\r\n        CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR   = ext.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR;\r\n        CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR  = ext.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR;\r\n        CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR  = ext.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR;\r\n        CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR  = ext.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR;\r\n        CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR = ext.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR;\r\n        CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR = ext.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR;\r\n        CONSTANTS.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = ext.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR;\r\n\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA_ASTC_4x4_KHR]           = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA_ASTC_5x4_KHR]           = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA_ASTC_5x5_KHR]           = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA_ASTC_6x5_KHR]           = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA_ASTC_6x6_KHR]           = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA_ASTC_8x5_KHR]           = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA_ASTC_8x6_KHR]           = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA_ASTC_8x8_KHR]           = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA_ASTC_10x5_KHR]          = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA_ASTC_10x6_KHR]          = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA_ASTC_10x8_KHR]          = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA_ASTC_10x10_KHR]         = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA_ASTC_12x10_KHR]         = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA_ASTC_12x12_KHR]         = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR]   = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR]   = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR]   = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR]   = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR]   = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR]   = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR]   = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR]   = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR]  = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR]  = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR]  = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR] = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR] = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR] = true;\r\n\r\n        // TODO(Tarek): Test for https://bugs.chromium.org/p/chromium/issues/detail?id=757447\r\n        // Remove this when that's fixed\r\n        this.gl.getError();\r\n        this.state.textures[0] = null;\r\n        this.gl.activeTexture(this.gl.TEXTURE0);\r\n        var texture = this.gl.createTexture();\r\n        this.gl.bindTexture(this.gl.TEXTURE_2D, texture);\r\n        this.gl.texStorage2D(this.gl.TEXTURE_2D, 1, ext.COMPRESSED_RGBA_ASTC_4x4_KHR, 4, 4);\r\n\r\n        if (this.gl.getError() !== this.gl.NO_ERROR) {\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_RGBA_ASTC_4x4_KHR]           = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_RGBA_ASTC_5x4_KHR]           = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_RGBA_ASTC_5x5_KHR]           = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_RGBA_ASTC_6x5_KHR]           = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_RGBA_ASTC_6x6_KHR]           = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_RGBA_ASTC_8x5_KHR]           = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_RGBA_ASTC_8x6_KHR]           = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_RGBA_ASTC_8x8_KHR]           = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_RGBA_ASTC_10x5_KHR]          = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_RGBA_ASTC_10x6_KHR]          = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_RGBA_ASTC_10x8_KHR]          = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_RGBA_ASTC_10x10_KHR]         = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_RGBA_ASTC_12x10_KHR]         = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_RGBA_ASTC_12x12_KHR]         = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR]   = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR]   = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR]   = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR]   = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR]   = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR]   = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR]   = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR]   = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR]  = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR]  = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR]  = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR] = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR] = true;\r\n            TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[ext.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR] = true;\r\n        }\r\n\r\n        this.gl.deleteTexture(texture);\r\n    }\r\n    \r\n    return this;\r\n};\r\n\r\n/**\r\n    Enable the WEBGL_compressed_texture_pvrtc extension and add the following enums, which can\r\n    be used as texture formats, to the PicoGL object:\r\n\r\n    <ul>\r\n      <li>PicoGL.COMPRESSED_RGB_PVRTC_4BPPV1_IMG\r\n      <li>PicoGL.COMPRESSED_RGB_PVRTC_2BPPV1_IMG\r\n      <li>PicoGL.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG\r\n      <li>PicoGL.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG\r\n    </ul>\r\n\r\n    @method\r\n*/\r\nApp.prototype.pvrtcTextures = function() {\r\n    var ext = this.gl.getExtension(\"WEBGL_compressed_texture_pvrtc\");\r\n    this.pvrtcTexturesEnabled = !!ext;\r\n    \r\n    if (this.pvrtcTexturesEnabled) {\r\n        CONSTANTS.COMPRESSED_RGB_PVRTC_4BPPV1_IMG = ext.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;\r\n        CONSTANTS.COMPRESSED_RGB_PVRTC_2BPPV1_IMG = ext.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;\r\n        CONSTANTS.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = ext.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;\r\n        CONSTANTS.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = ext.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;\r\n\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGB_PVRTC_4BPPV1_IMG] = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGB_PVRTC_2BPPV1_IMG] = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG] = true;\r\n        TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[ext.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG] = true;\r\n    }\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Read a pixel's color value from the currently-bound framebuffer.\r\n\r\n    @method\r\n    @param {number} x The x coordinate of the pixel.\r\n    @param {number} y The y coordinate of the pixel.\r\n    @param {ArrayBufferView} outColor Typed array to store the pixel's color.\r\n    @param {object} [options] Options.\r\n    @param {GLEnum} [options.type=UNSIGNED_BYTE] Type of data stored in the read framebuffer.\r\n    @param {GLEnum} [options.format=RGBA] Read framebuffer data format.\r\n*/\r\nApp.prototype.readPixel = function(x, y, outColor, options) {\r\n    options = options || CONSTANTS.DUMMY_OBJECT;\r\n    \r\n    var format = options.format || CONSTANTS.RGBA;\r\n    var type = options.type || CONSTANTS.UNSIGNED_BYTE;\r\n\r\n    this.gl.readPixels(x, y, 1, 1, format, type, outColor);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Set the viewport.\r\n\r\n    @method\r\n    @param {number} x Left bound of the viewport rectangle.\r\n    @param {number} y Lower bound of the viewport rectangle.\r\n    @param {number} width Width of the viewport rectangle.\r\n    @param {number} height Height of the viewport rectangle.\r\n*/\r\nApp.prototype.viewport = function(x, y, width, height) {\r\n\r\n    if (this.viewportWidth !== width || this.viewportHeight !== height ||\r\n            this.viewportX !== x || this.viewportY !== y) {\r\n        this.viewportX = x;\r\n        this.viewportY = y;\r\n        this.viewportWidth = width;\r\n        this.viewportHeight = height;\r\n        this.gl.viewport(x, y, this.viewportWidth, this.viewportHeight);\r\n    }\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Resize the drawing surface.\r\n\r\n    @method\r\n    @param {number} width The new canvas width.\r\n    @param {number} height The new canvas height.\r\n*/\r\nApp.prototype.resize = function(width, height) {\r\n    this.canvas.width = width;\r\n    this.canvas.height = height;\r\n\r\n    this.width = this.gl.drawingBufferWidth;\r\n    this.height = this.gl.drawingBufferHeight;\r\n    this.viewport(0, 0, this.width, this.height);\r\n\r\n    return this;\r\n};\r\n/**\r\n    Create a program.\r\n\r\n    @method\r\n    @param {Shader|string} vertexShader Vertex shader object or source code.\r\n    @param {Shader|string} fragmentShader Fragment shader object or source code.\r\n    @param {Array} [xformFeedbackVars] Transform feedback varyings.\r\n*/\r\nApp.prototype.createProgram = function(vsSource, fsSource, xformFeedbackVars) {\r\n    return new Program(this.gl, this.state, vsSource, fsSource, xformFeedbackVars);\r\n};\r\n\r\n/**\r\n    Create a shader. Creating a shader separately from a program allows for\r\n    shader reuse.\r\n\r\n    @method\r\n    @param {GLEnum} type Shader type.\r\n    @param {string} source Shader source.\r\n*/\r\nApp.prototype.createShader = function(type, source) {\r\n    return new Shader(this.gl, type, source);\r\n};\r\n\r\n/**\r\n    Create a vertex array.\r\n\r\n    @method\r\n*/\r\nApp.prototype.createVertexArray = function() {\r\n    return new VertexArray(this.gl, this.state);\r\n};\r\n\r\n/**\r\n    Create a transform feedback object.\r\n\r\n    @method\r\n*/\r\nApp.prototype.createTransformFeedback = function() {\r\n    return new TransformFeedback(this.gl, this.state);\r\n};\r\n\r\n/**\r\n    Create a vertex buffer.\r\n\r\n    @method\r\n    @param {GLEnum} type The data type stored in the vertex buffer.\r\n    @param {number} itemSize Number of elements per vertex.\r\n    @param {ArrayBufferView} data Buffer data.\r\n    @param {GLEnum} [usage=STATIC_DRAW] Buffer usage.\r\n*/\r\nApp.prototype.createVertexBuffer = function(type, itemSize, data, usage) {\r\n    return new VertexBuffer(this.gl, this.state, type, itemSize, data, usage);\r\n};\r\n\r\n/**\r\n    Create a per-vertex matrix buffer. Matrix buffers ensure that columns\r\n    are correctly split across attribute locations.\r\n\r\n    @method\r\n    @param {GLEnum} type The data type stored in the matrix buffer. Valid types\r\n    are FLOAT_MAT4, FLOAT_MAT4x2, FLOAT_MAT4x3, FLOAT_MAT3, FLOAT_MAT3x2,\r\n    FLOAT_MAT3x4, FLOAT_MAT2, FLOAT_MAT2x3, FLOAT_MAT2x4.\r\n    @param {ArrayBufferView} data Matrix buffer data.\r\n    @param {GLEnum} [usage=STATIC_DRAW] Buffer usage.\r\n*/\r\nApp.prototype.createMatrixBuffer = function(type, data, usage) {\r\n    return new VertexBuffer(this.gl, this.state, type, null, data, usage);\r\n};\r\n\r\n/**\r\n    Create an index buffer.\r\n\r\n    @method\r\n    @param {GLEnum} type The data type stored in the index buffer.\r\n    @param {number} itemSize Number of elements per primitive.\r\n    @param {ArrayBufferView} data Index buffer data.\r\n*/\r\nApp.prototype.createIndexBuffer = function(type, itemSize, data) {\r\n    return new VertexBuffer(this.gl, this.state, type, itemSize, data, null, true);\r\n};\r\n\r\n/**\r\n    Create a uniform buffer in std140 layout. NOTE: FLOAT_MAT2, FLOAT_MAT3x2, FLOAT_MAT4x2,\r\n    FLOAT_MAT3, FLOAT_MAT2x3, FLOAT_MAT4x3 are supported, but must be manually padded to\r\n    4-float column alignment by the application!\r\n\r\n    @method\r\n    @param {Array} layout Array indicating the order and types of items to\r\n                    be stored in the buffer.\r\n    @param {GLEnum} [usage=DYNAMIC_DRAW] Buffer usage.\r\n*/\r\nApp.prototype.createUniformBuffer = function(layout, usage) {\r\n    return new UniformBuffer(this.gl, layout, usage);\r\n};\r\n\r\n/**\r\n    Create a 2D texture.\r\n\r\n    @method\r\n    @param {DOMElement|ArrayBufferView|Array} image Image data. An array can be passed to manually set all levels \r\n        of the mipmap chain. If a single level is passed and mipmap filtering is being used,\r\n        generateMipmap() will be called to produce the remaining levels.\r\n    @param {number} [width] Texture width. Required for array data.\r\n    @param {number} [height] Texture height. Required for array data.\r\n    @param {Object} [options] Texture options.\r\n    @param {GLEnum} [options.type=UNSIGNED_BYTE] Type of data stored in the texture.\r\n    @param {GLEnum} [options.format=RGBA] Texture data format.\r\n    @param {GLEnum} [options.internalFormat=RGBA] Texture data internal format.\r\n    @param {boolean} [options.flipY=false] Whether the y-axis be flipped when unpacking the texture.\r\n    @param {GLEnum} [options.minFilter=LINEAR_MIPMAP_NEAREST] Minification filter.\r\n    @param {GLEnum} [options.magFilter=LINEAR] Magnification filter.\r\n    @param {GLEnum} [options.wrapS=REPEAT] Horizontal wrap mode.\r\n    @param {GLEnum} [options.wrapT=REPEAT] Vertical wrap mode.\r\n    @param {GLEnum} [options.compareMode=NONE] Comparison mode.\r\n    @param {GLEnum} [options.compareFunc=LEQUAL] Comparison function.\r\n    @param {GLEnum} [options.baseLevel] Base mipmap level.\r\n    @param {GLEnum} [options.maxLevel] Maximum mipmap level.\r\n    @param {GLEnum} [options.minLOD] Mimimum level of detail.\r\n    @param {GLEnum} [options.maxLOD] Maximum level of detail.\r\n    @param {boolean} [options.generateMipmaps] Should mipmaps be generated.\r\n*/\r\nApp.prototype.createTexture2D = function(image, width, height, options) {\r\n    if (height === undefined) {\r\n        // Passing in a DOM element. Height/width not required.\r\n        options = width;\r\n        width = image.width;\r\n        height = image.height;\r\n    }\r\n\r\n    return new Texture(this.gl, this.state, this.gl.TEXTURE_2D, image, width, height, null, false, options);\r\n};\r\n\r\n/**\r\n    Create a 2D texture array.\r\n\r\n    @method\r\n    @param {ArrayBufferView|Array} image Pixel data. An array can be passed to manually set all levels \r\n        of the mipmap chain. If a single level is passed and mipmap filtering is being used,\r\n        generateMipmap() will be called to produce the remaining levels.\r\n    @param {number} width Texture width.\r\n    @param {number} height Texture height.\r\n    @param {number} size Number of images in the array.\r\n    @param {Object} [options] Texture options.\r\n    @param {GLEnum} [options.type=UNSIGNED_BYTE] Type of data stored in the texture.\r\n    @param {GLEnum} [options.format=RGBA] Texture data format.\r\n    @param {GLEnum} [options.internalFormat=RGBA] Texture data internal format.\r\n    @param {boolean} [options.flipY=false] Whether the y-axis be flipped when unpacking the texture.\r\n    @param {GLEnum} [options.minFilter=LINEAR_MIPMAP_NEAREST] Minification filter.\r\n    @param {GLEnum} [options.magFilter=LINEAR] Magnification filter.\r\n    @param {GLEnum} [options.wrapS=REPEAT] Horizontal wrap mode.\r\n    @param {GLEnum} [options.wrapT=REPEAT] Vertical wrap mode.\r\n    @param {GLEnum} [options.compareMode=NONE] Comparison mode.\r\n    @param {GLEnum} [options.compareFunc=LEQUAL] Comparison function.\r\n    @param {GLEnum} [options.baseLevel] Base mipmap level.\r\n    @param {GLEnum} [options.maxLevel] Maximum mipmap level.\r\n    @param {GLEnum} [options.minLOD] Mimimum level of detail.\r\n    @param {GLEnum} [options.maxLOD] Maximum level of detail.\r\n    @param {boolean} [options.generateMipmaps] Should mipmaps be generated.\r\n*/\r\nApp.prototype.createTextureArray = function(image, width, height, depth, options) {\r\n    return new Texture(this.gl, this.state, this.gl.TEXTURE_2D_ARRAY, image, width, height, depth, true, options);\r\n};\r\n\r\n/**\r\n    Create a 3D texture.\r\n\r\n    @method\r\n    @param {ArrayBufferView|Array} image Pixel data. An array can be passed to manually set all levels \r\n        of the mipmap chain. If a single level is passed and mipmap filtering is being used,\r\n        generateMipmap() will be called to produce the remaining levels.\r\n    @param {number} width Texture width.\r\n    @param {number} height Texture height.\r\n    @param {number} depth Texture depth.\r\n    @param {Object} [options] Texture options.\r\n    @param {GLEnum} [options.type=UNSIGNED_BYTE] Type of data stored in the texture.\r\n    @param {GLEnum} [options.format=RGBA] Texture data format.\r\n    @param {GLEnum} [options.internalFormat=RGBA] Texture data internal format.\r\n    @param {boolean} [options.flipY=false] Whether the y-axis be flipped when unpacking the texture.\r\n    @param {GLEnum} [options.minFilter=LINEAR_MIPMAP_NEAREST] Minification filter.\r\n    @param {GLEnum} [options.magFilter=LINEAR] Magnification filter.\r\n    @param {GLEnum} [options.wrapS=REPEAT] Horizontal wrap mode.\r\n    @param {GLEnum} [options.wrapT=REPEAT] Vertical wrap mode.\r\n    @param {GLEnum} [options.wrapR=REPEAT] Depth wrap mode.\r\n    @param {GLEnum} [options.compareMode=NONE] Comparison mode.\r\n    @param {GLEnum} [options.compareFunc=LEQUAL] Comparison function.\r\n    @param {GLEnum} [options.baseLevel] Base mipmap level.\r\n    @param {GLEnum} [options.maxLevel] Maximum mipmap level.\r\n    @param {GLEnum} [options.minLOD] Mimimum level of detail.\r\n    @param {GLEnum} [options.maxLOD] Maximum level of detail.\r\n    @param {boolean} [options.generateMipmaps] Should mipmaps be generated.\r\n*/\r\nApp.prototype.createTexture3D = function(image, width, height, depth, options) {\r\n    return new Texture(this.gl, this.state, this.gl.TEXTURE_3D, image, width, height, depth, true, options);\r\n};\r\n\r\n/**\r\n    Create a cubemap.\r\n\r\n    @method\r\n    @param {Object} options Texture options.\r\n    @param {DOMElement|ArrayBufferView} options.negX The image data for the negative X direction.\r\n            Can be any format that would be accepted by texImage2D.\r\n    @param {DOMElement|ArrayBufferView} options.posX The image data for the positive X direction.\r\n            Can be any format that would be accepted by texImage2D.\r\n    @param {DOMElement|ArrayBufferView} options.negY The image data for the negative Y direction.\r\n            Can be any format that would be accepted by texImage2D.\r\n    @param {DOMElement|ArrayBufferView} options.posY The image data for the positive Y direction.\r\n            Can be any format that would be accepted by texImage2D.\r\n    @param {DOMElement|ArrayBufferView} options.negZ The image data for the negative Z direction.\r\n            Can be any format that would be accepted by texImage2D.\r\n    @param {DOMElement|ArrayBufferView} options.posZ The image data for the positive Z direction.\r\n            Can be any format that would be accepted by texImage2D.\r\n    @param {GLEnum} [options.type=UNSIGNED_BYTE] Type of data stored in the texture.\r\n    @param {GLEnum} [options.format=RGBA] Texture data format.\r\n    @param {GLEnum} [options.internalFormat=RGBA] Texture data internal format.\r\n    @param {number} [options.width] Texture width. Required when passing array data.\r\n    @param {number} [options.height] Texture height. Required when passing array data.\r\n    @param {boolean} [options.flipY=false] Whether the y-axis be flipped when unpacking the texture.\r\n    @param {GLEnum} [options.minFilter=LINEAR_MIPMAP_NEAREST] Minification filter.\r\n    @param {GLEnum} [options.magFilter=LINEAR] Magnification filter.\r\n    @param {GLEnum} [options.wrapS=REPEAT] Horizontal wrap mode.\r\n    @param {GLEnum} [options.wrapT=REPEAT] Vertical wrap mode.\r\n    @param {GLEnum} [options.compareMode=NONE] Comparison mode.\r\n    @param {GLEnum} [options.compareFunc=LEQUAL] Comparison function.\r\n    @param {boolean} [options.generateMipmaps] Should mipmaps be generated.\r\n*/\r\nApp.prototype.createCubemap = function(options) {\r\n    return new Cubemap(this.gl, this.state, options);\r\n};\r\n\r\n/**\r\n    Create a framebuffer.\r\n\r\n    @method\r\n    @param {number} [width=app.width] Width of the framebuffer.\r\n    @param {number} [height=app.height] Height of the framebuffer.\r\n*/\r\nApp.prototype.createFramebuffer = function(width, height) {\r\n    return new Framebuffer(this.gl, this.state, width, height);\r\n};\r\n\r\n/**\r\n    Create a query.\r\n\r\n    @method\r\n    @param {GLEnum} target Information to query.\r\n*/\r\nApp.prototype.createQuery = function(target) {\r\n    return new Query(this.gl, target);\r\n};\r\n\r\n/**\r\n    Create a timer.\r\n\r\n    @method\r\n*/\r\nApp.prototype.createTimer = function() {\r\n    return new Timer(this.gl);\r\n};\r\n\r\n/**\r\n    Create a DrawCall. A DrawCall manages the state associated with\r\n    a WebGL draw call including a program and associated vertex data, textures,\r\n    uniforms and uniform blocks.\r\n\r\n    @method\r\n    @param {Program} program The program to use for this DrawCall.\r\n    @param {VertexArray} vertexArray Vertex data to use for drawing.\r\n    @param {GLEnum} [primitive=TRIANGLES] Type of primitive to draw.\r\n*/\r\nApp.prototype.createDrawCall = function(program, vertexArray, primitive) {\r\n    return new DrawCall(this.gl, this.state, program, vertexArray, primitive);\r\n};\r\n\r\nmodule.exports = App;\r\n\r\n},{\"./constants\":2,\"./cubemap\":3,\"./draw-call\":4,\"./framebuffer\":5,\"./program\":7,\"./query\":8,\"./shader\":9,\"./texture\":11,\"./texture-format-defaults\":10,\"./timer\":12,\"./transform-feedback\":13,\"./uniform-buffer\":14,\"./vertex-array\":16,\"./vertex-buffer\":17}],2:[function(require,module,exports){\r\n///////////////////////////////////////////////////////////////////////////////////\r\n// The MIT License (MIT)\r\n//\r\n// Copyright (c) 2017 Tarek Sherif\r\n//\r\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n// this software and associated documentation files (the \"Software\"), to deal in\r\n// the Software without restriction, including without limitation the rights to\r\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n// the Software, and to permit persons to whom the Software is furnished to do so,\r\n// subject to the following conditions:\r\n//\r\n// The above copyright notice and this permission notice shall be included in all\r\n// copies or substantial portions of the Software.\r\n//\r\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n///////////////////////////////////////////////////////////////////////////////////\r\n\r\n\"use strict\";\r\n\r\nvar CONSTANTS = {};\r\nvar canvas = document.createElement(\"canvas\");\r\nvar gl = canvas.getContext(\"webgl2\");\r\n\r\nif (gl) {\r\n    for (var enumName in gl) {\r\n        if (enumName.match(/^[A-Z0-9_x]+$/) && typeof(gl[enumName]) === \"number\") {\r\n            CONSTANTS[enumName] = gl[enumName];\r\n        }\r\n    }\r\n}\r\n\r\nCONSTANTS.TYPE_SIZE = {};\r\nCONSTANTS.TYPE_SIZE[gl.BYTE]              = 1;\r\nCONSTANTS.TYPE_SIZE[gl.UNSIGNED_BYTE]     = 1;\r\nCONSTANTS.TYPE_SIZE[gl.SHORT]             = 2;\r\nCONSTANTS.TYPE_SIZE[gl.UNSIGNED_SHORT]    = 2;\r\nCONSTANTS.TYPE_SIZE[gl.INT]               = 4;\r\nCONSTANTS.TYPE_SIZE[gl.UNSIGNED_INT]      = 4;\r\nCONSTANTS.TYPE_SIZE[gl.FLOAT]             = 4;\r\n\r\nCONSTANTS.WEBGL_INFO = {};\r\nCONSTANTS.WEBGL_INFO.MAX_TEXTURE_UNITS = gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS);\r\nCONSTANTS.WEBGL_INFO.MAX_UNIFORM_BUFFERS = gl.getParameter(gl.MAX_UNIFORM_BUFFER_BINDINGS);\r\n\r\nCONSTANTS.DUMMY_OBJECT = {};\r\n\r\nmodule.exports = CONSTANTS;\r\n\r\n},{}],3:[function(require,module,exports){\r\n///////////////////////////////////////////////////////////////////////////////////\r\n// The MIT License (MIT)\r\n//\r\n// Copyright (c) 2017 Tarek Sherif\r\n//\r\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n// this software and associated documentation files (the \"Software\"), to deal in\r\n// the Software without restriction, including without limitation the rights to\r\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n// the Software, and to permit persons to whom the Software is furnished to do so,\r\n// subject to the following conditions:\r\n//\r\n// The above copyright notice and this permission notice shall be included in all\r\n// copies or substantial portions of the Software.\r\n//\r\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n///////////////////////////////////////////////////////////////////////////////////\r\n\r\n\"use strict\";\r\n\r\nvar CONSTANTS = require(\"./constants\");\r\nvar TEXTURE_FORMAT_DEFAULTS = require(\"./texture-format-defaults\");\r\n\r\n/**\r\n    Cubemap for environment mapping.\r\n\r\n    @class\r\n    @prop {WebGLRenderingContext} gl The WebGL context.\r\n    @prop {WebGLTexture} texture Handle to the texture.\r\n    @prop {GLEnum} type Type of data stored in the texture.\r\n    @prop {GLEnum} format Layout of texture data.\r\n    @prop {GLEnum} internalFormat Internal arrangement of the texture data.\r\n    @prop {Number} currentUnit The current texture unit this cubemap is bound to.\r\n    @prop {Object} appState Tracked GL state.\r\n*/\r\nfunction Cubemap(gl, appState, options) {\r\n    options = options || CONSTANTS.DUMMY_OBJECT;\r\n\r\n    this.gl = gl;\r\n    this.texture = gl.createTexture();\r\n    this.format = options.format !== undefined ? options.format : gl.RGBA;\r\n    this.type = options.type !== undefined ? options.type : gl.UNSIGNED_BYTE;\r\n    this.internalFormat = options.internalFormat !== undefined ? options.internalFormat : TEXTURE_FORMAT_DEFAULTS[this.type][this.format];\r\n    this.appState = appState;\r\n    \r\n    // -1 indicates unbound\r\n    this.currentUnit = -1;\r\n\r\n    var negX = options.negX;\r\n    var posX = options.posX;\r\n    var negY = options.negY;\r\n    var posY = options.posY;\r\n    var negZ = options.negZ;\r\n    var posZ = options.posZ;\r\n\r\n    var width = options.width || negX.width;\r\n    var height = options.height || negX.height;\r\n    var flipY = options.flipY !== undefined ? options.flipY : false;\r\n    var minFilter = options.minFilter !== undefined ? options.minFilter : gl.LINEAR_MIPMAP_NEAREST;\r\n    var magFilter = options.magFilter !== undefined ? options.magFilter : gl.LINEAR;\r\n    var compareMode = options.compareMode !== undefined ? options.compareMode : gl.NONE;\r\n    var compareFunc = options.compareFunc !== undefined ? options.compareFunc : gl.LEQUAL;\r\n    var generateMipmaps = options.generateMipmaps !== false &&\r\n                        (minFilter === gl.LINEAR_MIPMAP_NEAREST || minFilter === gl.LINEAR_MIPMAP_LINEAR);\r\n\r\n    this.bind(1);\r\n    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);\r\n    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, magFilter);\r\n    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, minFilter);\r\n    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_FUNC, compareFunc);\r\n    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_MODE, compareMode);\r\n    if (options.baseLevel !== undefined) {\r\n        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_BASE_LEVEL, options.baseLevel);\r\n    }\r\n    if (options.maxLevel !== undefined) {\r\n        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAX_LEVEL, options.maxLevel);\r\n    }\r\n    if (options.minLOD !== undefined) {\r\n        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_LOD, options.minLOD);\r\n    }\r\n    if (options.maxLOD !== undefined) {\r\n        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAX_LOD, options.maxLOD);\r\n    }\r\n\r\n    var levels = generateMipmaps ? Math.floor(Math.log2(Math.min(width, height))) + 1 : 1;\r\n    gl.texStorage2D(gl.TEXTURE_CUBE_MAP, levels, this.internalFormat, width, height);\r\n\r\n    gl.texSubImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, 0, 0, width, height, this.format, this.type, negX);\r\n    gl.texSubImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, 0, 0, width, height, this.format, this.type, posX);\r\n    gl.texSubImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, 0, 0, width, height, this.format, this.type, negY);\r\n    gl.texSubImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, 0, 0, width, height, this.format, this.type, posY);\r\n    gl.texSubImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, 0, 0, width, height, this.format, this.type, negZ);\r\n    gl.texSubImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, 0, 0, width, height, this.format, this.type, posZ);\r\n\r\n    if (generateMipmaps) {\r\n        gl.generateMipmap(gl.TEXTURE_CUBE_MAP);\r\n    }\r\n\r\n}\r\n\r\n/**\r\n    Delete this cubemap.\r\n\r\n    @method\r\n*/\r\nCubemap.prototype.delete = function() {\r\n    if (this.texture) {\r\n        this.gl.deleteTexture(this.texture);\r\n        this.texture = null;\r\n        this.appState.textures[this.currentUnit] = null;\r\n        this.currentUnit = -1;\r\n    }\r\n};\r\n\r\n// Bind this cubemap to a texture unit.\r\nCubemap.prototype.bind = function(unit) {\r\n    var currentTexture = this.appState.textures[unit];\r\n    \r\n    if (currentTexture !== this) {\r\n        if (currentTexture) {\r\n            currentTexture.currentUnit = -1;\r\n        }\r\n\r\n        if (this.currentUnit !== -1) {\r\n            this.appState.textures[this.currentUnit] = null;\r\n        }\r\n\r\n        this.gl.activeTexture(this.gl.TEXTURE0 + unit);\r\n        this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, this.texture);\r\n\r\n        this.appState.textures[unit] = this;\r\n        this.currentUnit = unit;\r\n    }\r\n\r\n    return this;\r\n};\r\n\r\nmodule.exports = Cubemap;\r\n\r\n},{\"./constants\":2,\"./texture-format-defaults\":10}],4:[function(require,module,exports){\r\n///////////////////////////////////////////////////////////////////////////////////\r\n// The MIT License (MIT)\r\n//\r\n// Copyright (c) 2017 Tarek Sherif\r\n//\r\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n// this software and associated documentation files (the \"Software\"), to deal in\r\n// the Software without restriction, including without limitation the rights to\r\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n// the Software, and to permit persons to whom the Software is furnished to do so,\r\n// subject to the following conditions:\r\n//\r\n// The above copyright notice and this permission notice shall be included in all\r\n// copies or substantial portions of the Software.\r\n//\r\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n///////////////////////////////////////////////////////////////////////////////////\r\n\r\n\"use strict\";\r\n\r\nvar CONSTANTS = require(\"./constants\");\r\n\r\n/**\r\n    A DrawCall represents the program and values of associated\r\n    attributes, uniforms and textures for a single draw call.\r\n\r\n    @class\r\n    @prop {WebGLRenderingContext} gl The WebGL context.\r\n    @prop {Program} currentProgram The program to use for this draw call.\r\n    @prop {VertexArray} currentVertexArray Vertex array to use for this draw call.\r\n    @prop {TransformFeedback} currentTransformFeedback Transform feedback to use for this draw call.\r\n    @prop {Array} uniformBuffers Ordered list of active uniform buffers.\r\n    @prop {Array} uniformBlockNames Ordered list of uniform block names.\r\n    @prop {Object} uniformBlockBases Map of uniform blocks to uniform buffer bases.\r\n    @prop {Number} uniformBlockCount Number of active uniform blocks for this draw call.\r\n    @prop {Object} uniformIndices Map of uniform names to indices in the uniform arrays.\r\n    @prop {Array} uniformNames Ordered list of uniform names.\r\n    @prop {Array} uniformValue Ordered list of uniform values.\r\n    @prop {number} uniformCount The number of active uniforms for this draw call.\r\n    @prop {Array} textures Array of active textures.\r\n    @prop {number} textureCount The number of active textures for this draw call.\r\n    @prop {GLEnum} primitive The primitive type being drawn.\r\n    @prop {Object} appState Tracked GL state.\r\n*/\r\nfunction DrawCall(gl, appState, program, vertexArray, primitive) {\r\n    this.gl = gl;\r\n    this.currentProgram = program;\r\n    this.currentVertexArray = vertexArray;\r\n    this.currentTransformFeedback = null;\r\n    this.appState = appState;\r\n\r\n    this.uniformIndices = {};\r\n    this.uniformNames = new Array(CONSTANTS.WEBGL_INFO.MAX_UNIFORMS);\r\n    this.uniformValues = new Array(CONSTANTS.WEBGL_INFO.MAX_UNIFORMS);\r\n    this.uniformCount = 0;\r\n    this.uniformBuffers = new Array(CONSTANTS.WEBGL_INFO.MAX_UNIFORM_BUFFERS);\r\n    this.uniformBlockNames = new Array(CONSTANTS.WEBGL_INFO.MAX_UNIFORM_BUFFERS);\r\n    this.uniformBlockBases = {};\r\n    this.uniformBlockCount = 0;\r\n    this.samplerIndices = {};\r\n    this.textures = new Array(CONSTANTS.WEBGL_INFO.MAX_TEXTURE_UNITS);\r\n    this.textureCount = 0;\r\n    this.primitive = primitive !== undefined ? primitive : CONSTANTS.TRIANGLES;\r\n}\r\n\r\nDrawCall.prototype.transformFeedback = function(transformFeedback) {\r\n    this.currentTransformFeedback = transformFeedback;\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Set the value for a uniform. Array uniforms are supported by\r\n    using appending \"[0]\" to the array name and passing a flat array\r\n    with all required values.\r\n\r\n    @method\r\n    @param {string} name Uniform name.\r\n    @param {any} value Uniform value.\r\n*/\r\nDrawCall.prototype.uniform = function(name, value) {\r\n    var index = this.uniformIndices[name];\r\n    if (index === undefined) {\r\n        index = this.uniformCount++;\r\n        this.uniformIndices[name] = index;\r\n        this.uniformNames[index] = name;\r\n    }\r\n    this.uniformValues[index] = value;\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Set texture to bind to a sampler uniform.\r\n\r\n    @method\r\n    @param {string} name Sampler uniform name.\r\n    @param {Texture} texture Texture to bind.\r\n*/\r\nDrawCall.prototype.texture = function(name, texture) {\r\n    var unit = this.currentProgram.samplers[name];\r\n    this.textures[unit] = texture;\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Set uniform buffer to bind to a uniform block.\r\n\r\n    @method\r\n    @param {string} name Uniform block name.\r\n    @param {UniformBuffer} buffer Uniform buffer to bind.\r\n*/\r\nDrawCall.prototype.uniformBlock = function(name, buffer) {\r\n    var base = this.uniformBlockBases[name];\r\n    if (base === undefined) {\r\n        base = this.uniformBlockCount++;\r\n        this.uniformBlockBases[name] = base;\r\n        this.uniformBlockNames[base] = name;\r\n    }\r\n\r\n    this.uniformBuffers[base] = buffer;\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Draw based on current state.\r\n\r\n    @method\r\n*/\r\nDrawCall.prototype.draw = function() {\r\n    var uniformNames = this.uniformNames;\r\n    var uniformValues = this.uniformValues;\r\n    var uniformBuffers = this.uniformBuffers;\r\n    var uniformBlockNames = this.uniformBlockNames;\r\n    var textures = this.textures;\r\n    var textureCount = this.currentProgram.samplerCount;\r\n\r\n    this.currentProgram.bind();\r\n    this.currentVertexArray.bind();\r\n\r\n    for (var uIndex = 0; uIndex < this.uniformCount; ++uIndex) {\r\n        this.currentProgram.uniform(uniformNames[uIndex], uniformValues[uIndex]);\r\n    }\r\n\r\n    for (var base = 0; base < this.uniformBlockCount; ++base) {\r\n        this.currentProgram.uniformBlock(uniformBlockNames[base], base);\r\n        uniformBuffers[base].bind(base);\r\n    }\r\n\r\n    /////////////////////////////////////////////////////////////////////////////////\r\n    // TODO(Tarek):\r\n    // Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=722288\r\n    // Start at 0 when that's fixed\r\n    /////////////////////////////////////////////////////////////////////////////////\r\n    for (var tIndex = 1; tIndex < textureCount; ++tIndex) {\r\n        textures[tIndex].bind(tIndex);\r\n    }\r\n\r\n    if (this.currentTransformFeedback) {\r\n        this.currentTransformFeedback.bind();\r\n        this.gl.beginTransformFeedback(this.primitive);\r\n    }\r\n\r\n    if (this.currentVertexArray.instanced) {\r\n        if (this.currentVertexArray.indexed) {\r\n            this.gl.drawElementsInstanced(this.primitive, this.currentVertexArray.numElements, this.currentVertexArray.indexType, 0, this.currentVertexArray.numInstances);\r\n        } else {\r\n            this.gl.drawArraysInstanced(this.primitive, 0, this.currentVertexArray.numElements, this.currentVertexArray.numInstances);\r\n        }\r\n    } else if (this.currentVertexArray.indexed) {\r\n        this.gl.drawElements(this.primitive, this.currentVertexArray.numElements, this.currentVertexArray.indexType, 0);\r\n    } else {\r\n        this.gl.drawArrays(this.primitive, 0, this.currentVertexArray.numElements);\r\n    }\r\n\r\n    if (this.currentTransformFeedback) {\r\n        this.gl.endTransformFeedback();\r\n        // TODO(Tarek): Need to rebind buffers due to bug in ANGLE.\r\n        // Remove this when that's fixed.\r\n        for (var i = 0, len = this.currentTransformFeedback.angleBugBuffers.length; i < len; ++i) {\r\n            this.gl.bindBufferBase(this.gl.TRANSFORM_FEEDBACK_BUFFER, i, null);\r\n        }\r\n    }\r\n};\r\n\r\nmodule.exports = DrawCall;\r\n\r\n},{\"./constants\":2}],5:[function(require,module,exports){\r\n///////////////////////////////////////////////////////////////////////////////////\r\n// The MIT License (MIT)\r\n//\r\n// Copyright (c) 2017 Tarek Sherif\r\n//\r\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n// this software and associated documentation files (the \"Software\"), to deal in\r\n// the Software without restriction, including without limitation the rights to\r\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n// the Software, and to permit persons to whom the Software is furnished to do so,\r\n// subject to the following conditions:\r\n//\r\n// The above copyright notice and this permission notice shall be included in all\r\n// copies or substantial portions of the Software.\r\n//\r\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n///////////////////////////////////////////////////////////////////////////////////\r\n\r\n\"use strict\";\r\n\r\nvar TEXTURE_FORMAT_DEFAULTS = require(\"./texture-format-defaults\");\r\nvar Texture = require(\"./texture\");\r\n\r\n/**\r\n    Storage for vertex data.\r\n\r\n    @class\r\n    @prop {WebGLRenderingContext} gl The WebGL context.\r\n    @prop {WebGLFramebuffer} framebuffer Handle to the framebuffer.\r\n    @prop {number} width The width of the framebuffer.\r\n    @prop {number} height The height of the framebuffer.\r\n    @prop {Array} colorTextures Array of color texture targets.\r\n    @prop {number} numColorTargets Number of color texture targets.\r\n    @prop {Texture} depthTexture Depth texture target.\r\n    @prop {Array} colorAttachments Array of color attachment enums.\r\n    @prop {Object} appState Tracked GL state.\r\n*/\r\nfunction Framebuffer(gl, appState, width, height) {\r\n    this.gl = gl;\r\n    this.framebuffer = gl.createFramebuffer();\r\n    this.appState = appState;\r\n\r\n    if (width && height) {\r\n        this.width = width;\r\n        this.height = height;\r\n    } else {\r\n        this.width = gl.drawingBufferWidth;\r\n        this.height = gl.drawingBufferHeight;\r\n    }\r\n\r\n    this.numColorTargets = 0;\r\n\r\n    this.colorTextures = [];\r\n    this.colorAttachments = [];\r\n    this.depthTexture = null;\r\n}\r\n\r\n/**\r\n    Add a color target to this framebuffer.\r\n\r\n    @method\r\n    @param {number} [index=0] Color attachment index.\r\n    @param {Object} [options] Texture options.\r\n    @param {GLEnum} [options.type=UNSIGNED_BYTE] Type of data stored in the texture.\r\n    @param {GLEnum} [options.format=RGBA] Texture data format.\r\n    @param {GLEnum} [options.internalFormat=RGBA] Texture data internal format.\r\n    @param {boolean} [options.flipY=true] Whether th y-axis be flipped when reading the texture.\r\n    @param {GLEnum} [options.minFilter=NEAREST] Minification filter.\r\n    @param {GLEnum} [options.magFilter=NEAREST] Magnification filter.\r\n    @param {GLEnum} [options.wrapS=CLAMP_TO_EDGE] Horizontal wrap mode.\r\n    @param {GLEnum} [options.wrapT=CLAMP_TO_EDGE] Vertical wrap mode.\r\n    @param {GLEnum} [options.compareMode=NONE] Comparison mode.\r\n    @param {GLEnum} [options.compareFunc=LEQUAL] Comparison function.\r\n    @param {GLEnum} [options.baseLevel] Base mipmap level.\r\n    @param {GLEnum} [options.maxLevel] Maximum mipmap level.\r\n    @param {GLEnum} [options.minLOD] Mimimum level of detail.\r\n    @param {GLEnum} [options.maxLOD] Maximum level of detail.\r\n    @param {boolean} [options.generateMipmaps=false] Should mipmaps be generated.\r\n*/\r\nFramebuffer.prototype.colorTarget = function(index, options) {\r\n    index = index || 0;\r\n    options = options || {};\r\n    options.type = options.type || this.gl.UNSIGNED_BYTE;\r\n    options.format = options.format || this.gl.RGBA;\r\n    options.internalFormat = options.internalFormat || TEXTURE_FORMAT_DEFAULTS[options.type][options.format];\r\n    options.minFilter = options.minFilter || this.gl.NEAREST;\r\n    options.magFilter = options.magFilter || this.gl.NEAREST;\r\n    options.wrapS = options.wrapS || this.gl.CLAMP_TO_EDGE;\r\n    options.wrapT = options.wrapT || this.gl.CLAMP_TO_EDGE;\r\n    options.generateMipmaps = options.generateMipmaps === undefined ? false : options.generateMipmaps;\r\n\r\n    this.colorAttachments[index] = this.gl.COLOR_ATTACHMENT0 + index;\r\n\r\n    var currentFramebuffer = this.bindAndCaptureState();\r\n\r\n    this.colorTextures[index] = new Texture(\r\n        this.gl,\r\n        this.appState,\r\n        this.gl.TEXTURE_2D,\r\n        null,\r\n        this.width,\r\n        this.height,\r\n        null,\r\n        false,\r\n        options\r\n    );\r\n\r\n    this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.colorAttachments[index], this.gl.TEXTURE_2D, this.colorTextures[index].texture, 0);\r\n    this.gl.drawBuffers(this.colorAttachments);\r\n    this.numColorTargets++;\r\n\r\n    this.restoreState(currentFramebuffer);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Add a depth target to this framebuffer.\r\n\r\n    @method\r\n    @param {Object} [options] Texture options.\r\n    @param {GLEnum} [options.type=UNSIGNED_BYTE] Type of data stored in the texture.\r\n    @param {GLEnum} [options.format=RGBA] Texture data format.\r\n    @param {GLEnum} [options.internalFormat=RGBA] Texture data internal format.\r\n    @param {boolean} [options.flipY=true] Whether th y-axis be flipped when reading the texture.\r\n    @param {GLEnum} [options.minFilter=NEAREST] Minification filter.\r\n    @param {GLEnum} [options.magFilter=NEAREST] Magnification filter.\r\n    @param {GLEnum} [options.wrapS=CLAMP_TO_EDGE] Horizontal wrap mode.\r\n    @param {GLEnum} [options.wrapT=CLAMP_TO_EDGE] Vertical wrap mode.\r\n    @param {GLEnum} [options.compareMode=NONE] Comparison mode.\r\n    @param {GLEnum} [options.compareFunc=LEQUAL] Comparison function.\r\n    @param {GLEnum} [options.baseLevel] Base mipmap level.\r\n    @param {GLEnum} [options.maxLevel] Maximum mipmap level.\r\n    @param {GLEnum} [options.minLOD] Mimimum level of detail.\r\n    @param {GLEnum} [options.maxLOD] Maximum level of detail.\r\n    @param {boolean} [options.generateMipmaps=false] Should mipmaps be generated.\r\n*/\r\nFramebuffer.prototype.depthTarget = function(options) {\r\n    options = options || {};\r\n    options.format = this.gl.DEPTH_COMPONENT;\r\n    options.type = options.type || this.gl.UNSIGNED_SHORT;\r\n    options.internalFormat = options.internalFormat || TEXTURE_FORMAT_DEFAULTS[options.type][options.format];\r\n    options.minFilter = options.minFilter || this.gl.NEAREST;\r\n    options.magFilter = options.magFilter || this.gl.NEAREST;\r\n    options.wrapS = options.wrapS || this.gl.CLAMP_TO_EDGE;\r\n    options.wrapT = options.wrapT || this.gl.CLAMP_TO_EDGE;\r\n    options.generateMipmaps = options.generateMipmaps === undefined ? false : options.generateMipmaps;\r\n\r\n    var currentFramebuffer = this.bindAndCaptureState();\r\n\r\n    this.depthTexture = new Texture(\r\n        this.gl,\r\n        this.appState,\r\n        this.gl.TEXTURE_2D,\r\n        null,\r\n        this.width,\r\n        this.height,\r\n        null,\r\n        false,\r\n        options\r\n    );\r\n\r\n    this.gl.framebufferTexture2D(this.gl.DRAW_FRAMEBUFFER, this.gl.DEPTH_ATTACHMENT, this.gl.TEXTURE_2D, this.depthTexture.texture, 0);\r\n\r\n    this.restoreState(currentFramebuffer);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Bind a new texture as a color target.\r\n\r\n    @method\r\n    @param {number} index Color attachment to bind the texture to.\r\n    @param {Texture} texture New texture to bind.\r\n*/\r\nFramebuffer.prototype.replaceTexture = function(index, texture) {\r\n    this.colorTextures[index] = texture;\r\n\r\n    var currentFramebuffer = this.bindAndCaptureState();\r\n    this.gl.framebufferTexture2D(this.gl.DRAW_FRAMEBUFFER, this.colorAttachments[index], this.gl.TEXTURE_2D, this.colorTextures[index].texture, 0);\r\n    this.restoreState(currentFramebuffer);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Resize framebuffer to current default drawing buffer\r\n    size. Should be called after calls to App.resize().\r\n\r\n    @method\r\n    @param {number} [width=app.width] New width of the framebuffer.\r\n    @param {number} [height=app.height] New height of the framebuffer.\r\n*/\r\nFramebuffer.prototype.resize = function(width, height) {\r\n\r\n    if (width && height) {\r\n        this.width = width;\r\n        this.height = height;\r\n    } else {\r\n        this.width = this.gl.drawingBufferWidth;\r\n        this.height = this.gl.drawingBufferHeight;\r\n    }\r\n\r\n    var currentFramebuffer = this.bindAndCaptureState();\r\n\r\n    for (var i = 0; i < this.numColorTargets; ++i) {\r\n        this.colorTextures[i].resize(this.width, this.height);\r\n        this.gl.framebufferTexture2D(this.gl.DRAW_FRAMEBUFFER, this.colorAttachments[i], this.gl.TEXTURE_2D, this.colorTextures[i].texture, 0);\r\n    }\r\n\r\n    if (this.depthTexture) {\r\n        this.depthTexture.resize(this.width, this.height);\r\n        this.gl.framebufferTexture2D(this.gl.DRAW_FRAMEBUFFER, this.gl.DEPTH_ATTACHMENT, this.gl.TEXTURE_2D, this.depthTexture.texture, 0);\r\n    }\r\n\r\n    this.restoreState(currentFramebuffer);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Delete this framebuffer. NOTE: will delete any currently\r\n    attached textures.\r\n\r\n    @method\r\n*/\r\nFramebuffer.prototype.delete = function() {\r\n    for (var i = 0; i < this.numColorTargets; ++i) {\r\n        this.colorTextures[i].delete();\r\n    }\r\n\r\n    if (this.depthTexture) {\r\n        this.depthTexture.delete();\r\n    }\r\n\r\n    if (this.framebuffer) {\r\n        this.gl.deleteFramebuffer(this.framebuffer);\r\n        this.framebuffer = null;\r\n    }\r\n};\r\n\r\n// Bind as the draw framebuffer\r\nFramebuffer.prototype.bindForDraw = function() {\r\n    if (this.appState.drawFramebuffer !== this) {\r\n        this.gl.bindFramebuffer(this.gl.DRAW_FRAMEBUFFER, this.framebuffer);\r\n        this.appState.drawFramebuffer = this;\r\n    }\r\n};\r\n\r\n// Bind as the read framebuffer\r\nFramebuffer.prototype.bindForRead = function() {\r\n    if (this.appState.readFramebuffer !== this) {\r\n        this.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER, this.framebuffer);\r\n        this.appState.readFramebuffer = this;\r\n    }\r\n};\r\n\r\n// Bind for a framebuffer state update.\r\n// Capture current binding so we can restore it later.\r\nFramebuffer.prototype.bindAndCaptureState = function() {\r\n    var currentFramebuffer = this.appState.drawFramebuffer;\r\n\r\n    if (currentFramebuffer !== this) {\r\n        this.gl.bindFramebuffer(this.gl.DRAW_FRAMEBUFFER, this.framebuffer);\r\n    }\r\n\r\n    return currentFramebuffer;\r\n};\r\n\r\n// Bind restore previous binding after state update\r\nFramebuffer.prototype.restoreState = function(framebuffer) {\r\n    if (framebuffer !== this) {\r\n        this.gl.bindFramebuffer(this.gl.DRAW_FRAMEBUFFER, framebuffer ? framebuffer.framebuffer : null);\r\n    }\r\n};\r\n\r\nmodule.exports = Framebuffer;\r\n\r\n},{\"./texture\":11,\"./texture-format-defaults\":10}],6:[function(require,module,exports){\r\n(function (global){\r\n///////////////////////////////////////////////////////////////////////////////////\r\n// The MIT License (MIT)\r\n//\r\n// Copyright (c) 2017 Tarek Sherif\r\n//\r\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n// this software and associated documentation files (the \"Software\"), to deal in\r\n// the Software without restriction, including without limitation the rights to\r\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n// the Software, and to permit persons to whom the Software is furnished to do so,\r\n// subject to the following conditions:\r\n//\r\n// The above copyright notice and this permission notice shall be included in all\r\n// copies or substantial portions of the Software.\r\n//\r\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n///////////////////////////////////////////////////////////////////////////////////\r\n\r\n\"use strict\";\r\n\r\nvar App = require(\"./app\");\r\n\r\n/**\r\n    Global PicoGL module. For convenience, all WebGL enums are stored\r\n    as properties of PicoGL (e.g. PicoGL.FLOAT, PicoGL.ONE_MINUS_SRC_ALPHA).\r\n\r\n    @namespace PicoGL\r\n*/\r\nvar PicoGL = global.PicoGL = require(\"./constants\");    \r\nPicoGL.version = \"0.6.10\";\r\n\r\n/**\r\n    Create a PicoGL app. The app is the primary entry point to PicoGL. It stores\r\n    the canvas, the WebGL context and all WebGL state.\r\n\r\n    @function PicoGL.createApp\r\n    @param {DOMElement} canvas The canvas on which to create the WebGL context.\r\n    @param {Object} [contextAttributes] Context attributes to pass when calling getContext().\r\n*/\r\nPicoGL.createApp = function(canvas, contextAttributes) {\r\n    return new App(canvas, contextAttributes);\r\n};\r\n\r\nmodule.exports = PicoGL;\r\n\r\n}).call(this,typeof global !== \"undefined\" ? global : typeof self !== \"undefined\" ? self : typeof window !== \"undefined\" ? window : {})\r\n},{\"./app\":1,\"./constants\":2}],7:[function(require,module,exports){\r\n///////////////////////////////////////////////////////////////////////////////////\r\n// The MIT License (MIT)\r\n//\r\n// Copyright (c) 2017 Tarek Sherif\r\n//\r\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n// this software and associated documentation files (the \"Software\"), to deal in\r\n// the Software without restriction, including without limitation the rights to\r\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n// the Software, and to permit persons to whom the Software is furnished to do so,\r\n// subject to the following conditions:\r\n//\r\n// The above copyright notice and this permission notice shall be included in all\r\n// copies or substantial portions of the Software.\r\n//\r\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n///////////////////////////////////////////////////////////////////////////////////\r\n\r\n\"use strict\";\r\n\r\nvar CONSTANTS = require(\"./constants\");\r\nvar Shader   = require(\"./shader\");\r\nvar Uniforms = require(\"./uniforms\");\r\n\r\n/**\r\n    WebGL program consisting of compiled and linked vertex and fragment\r\n    shaders.\r\n\r\n    @class\r\n    @prop {WebGLRenderingContext} gl The WebGL context.\r\n    @prop {WebGLProgram} program The WebGL program.\r\n    @prop {boolean} transformFeedback Whether this program is set up for transform feedback.\r\n    @prop {Object} uniforms Map of uniform names to handles.\r\n    @prop {Object} uniformBlocks Map of uniform block names to handles.\r\n    @prop {Object} appState Tracked GL state.\r\n*/\r\nfunction Program(gl, appState, vsSource, fsSource, xformFeebackVars) {\r\n    var i;\r\n\r\n    var vShader, fShader;\r\n\r\n    var ownVertexShader = false;\r\n    var ownFragmentShader = false;\r\n    if (typeof vsSource === \"string\") {\r\n        vShader = new Shader(gl, gl.VERTEX_SHADER, vsSource);\r\n        ownVertexShader = true;\r\n    } else {\r\n        vShader = vsSource;\r\n    }\r\n\r\n    if (typeof fsSource === \"string\") {\r\n        fShader = new Shader(gl, gl.FRAGMENT_SHADER, fsSource);\r\n        ownFragmentShader = true;\r\n    } else {\r\n        fShader = fsSource;\r\n    }\r\n\r\n    var program = gl.createProgram();\r\n    gl.attachShader(program, vShader.shader);\r\n    gl.attachShader(program, fShader.shader);\r\n    if (xformFeebackVars) {\r\n        gl.transformFeedbackVaryings(program, xformFeebackVars, gl.SEPARATE_ATTRIBS);\r\n    }\r\n    gl.linkProgram(program);\r\n\r\n    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\r\n        console.error(gl.getProgramInfoLog(program));\r\n    }\r\n\r\n    if (ownVertexShader) {\r\n        vShader.delete();\r\n    }\r\n\r\n    if (ownFragmentShader) {\r\n        fShader.delete();\r\n    }\r\n\r\n    this.gl = gl;\r\n    this.program = program;\r\n    this.appState = appState;\r\n    this.transformFeedback = !!xformFeebackVars;\r\n    this.uniforms = {};\r\n    this.uniformBlocks = {};\r\n    this.uniformBlockBindings = {};\r\n    this.samplers = {};\r\n    /////////////////////////////////////////////////////////////////////////////////\r\n    // TODO(Tarek):\r\n    // Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=722288\r\n    // Start at unit 0 when that's fixed\r\n    /////////////////////////////////////////////////////////////////////////////////\r\n    this.samplerCount = 1;\r\n\r\n    gl.useProgram(program);\r\n\r\n    var numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);\r\n\r\n    for (i = 0; i < numUniforms; ++i) {\r\n        var uniformInfo = gl.getActiveUniform(program, i);\r\n        var uniformHandle = gl.getUniformLocation(this.program, uniformInfo.name);\r\n        var UniformClass = null;\r\n        var type = uniformInfo.type;\r\n        var numElements = uniformInfo.size;\r\n\r\n        switch (type) {\r\n            case CONSTANTS.SAMPLER_2D:\r\n            case CONSTANTS.INT_SAMPLER_2D:\r\n            case CONSTANTS.UNSIGNED_INT_SAMPLER_2D:\r\n            case CONSTANTS.SAMPLER_2D_SHADOW:\r\n            case CONSTANTS.SAMPLER_2D_ARRAY:\r\n            case CONSTANTS.INT_SAMPLER_2D_ARRAY:\r\n            case CONSTANTS.UNSIGNED_INT_SAMPLER_2D_ARRAY:\r\n            case CONSTANTS.SAMPLER_2D_ARRAY_SHADOW:\r\n            case CONSTANTS.SAMPLER_CUBE:\r\n            case CONSTANTS.INT_SAMPLER_CUBE:\r\n            case CONSTANTS.UNSIGNED_INT_SAMPLER_CUBE:\r\n            case CONSTANTS.SAMPLER_CUBE_SHADOW:\r\n            case CONSTANTS.SAMPLER_3D:\r\n            case CONSTANTS.INT_SAMPLER_3D:\r\n            case CONSTANTS.UNSIGNED_INT_SAMPLER_3D:\r\n                var textureUnit = this.samplerCount++;\r\n                this.samplers[uniformInfo.name] = textureUnit;\r\n                this.gl.uniform1i(uniformHandle, textureUnit);\r\n                break;\r\n            case CONSTANTS.INT:\r\n            case CONSTANTS.UNSIGNED_INT:\r\n            case CONSTANTS.FLOAT:\r\n                UniformClass = numElements > 1 ? Uniforms.MultiNumericUniform : Uniforms.SingleComponentUniform;\r\n                break;\r\n            case CONSTANTS.BOOL:\r\n                UniformClass = numElements > 1 ? Uniforms.MultiBoolUniform : Uniforms.SingleComponentUniform;\r\n                break;\r\n            case CONSTANTS.FLOAT_VEC2:\r\n            case CONSTANTS.INT_VEC2:\r\n            case CONSTANTS.UNSIGNED_INT_VEC2:\r\n            case CONSTANTS.FLOAT_VEC3:\r\n            case CONSTANTS.INT_VEC3:\r\n            case CONSTANTS.UNSIGNED_INT_VEC3:\r\n            case CONSTANTS.FLOAT_VEC4:\r\n            case CONSTANTS.INT_VEC4:\r\n            case CONSTANTS.UNSIGNED_INT_VEC4:\r\n                UniformClass = Uniforms.MultiNumericUniform;\r\n                break;\r\n            case CONSTANTS.BOOL_VEC2:\r\n            case CONSTANTS.BOOL_VEC3:\r\n            case CONSTANTS.BOOL_VEC4:\r\n                UniformClass = Uniforms.MultiBoolUniform;\r\n                break;\r\n            case CONSTANTS.FLOAT_MAT2:\r\n            case CONSTANTS.FLOAT_MAT3:\r\n            case CONSTANTS.FLOAT_MAT4:\r\n            case CONSTANTS.FLOAT_MAT2x3:\r\n            case CONSTANTS.FLOAT_MAT2x4:\r\n            case CONSTANTS.FLOAT_MAT3x2:\r\n            case CONSTANTS.FLOAT_MAT3x4:\r\n            case CONSTANTS.FLOAT_MAT4x2:\r\n            case CONSTANTS.FLOAT_MAT4x3:\r\n                UniformClass = Uniforms.MatrixUniform;\r\n                break;\r\n            default:\r\n                console.error(\"Unrecognized type for uniform \", uniformInfo.name);\r\n                break;\r\n        }\r\n\r\n        if (UniformClass) {\r\n            this.uniforms[uniformInfo.name] = new UniformClass(gl, uniformHandle, type, numElements);\r\n        }\r\n    }\r\n\r\n    var numUniformBlocks = gl.getProgramParameter(program, gl.ACTIVE_UNIFORM_BLOCKS);\r\n\r\n    for (i = 0; i < numUniformBlocks; ++i) {\r\n        var blockName = gl.getActiveUniformBlockName(this.program, i);\r\n        var blockIndex = gl.getUniformBlockIndex(this.program, blockName);\r\n\r\n        this.uniformBlocks[blockName] = blockIndex;\r\n    }\r\n\r\n    gl.useProgram(null);\r\n}\r\n\r\n/**\r\n    Delete this program.\r\n\r\n    @method\r\n*/\r\nProgram.prototype.delete = function() {\r\n    if (this.program) {\r\n        this.gl.deleteProgram(this.program);\r\n        this.program = null;\r\n    }\r\n};\r\n\r\n// Set the value of a uniform.\r\nProgram.prototype.uniform = function(name, value) {\r\n    this.uniforms[name].set(value);\r\n};\r\n\r\n// Bind a uniform block to a uniform buffer base.\r\nProgram.prototype.uniformBlock = function(name, base) {\r\n    if (this.uniformBlockBindings[name] !== base) {\r\n        this.gl.uniformBlockBinding(this.program, this.uniformBlocks[name], base);\r\n        this.uniformBlockBindings[name] = base;\r\n    }\r\n};\r\n\r\n// Use this program.\r\nProgram.prototype.bind = function() {\r\n    if (this.appState.program !== this) {\r\n        this.gl.useProgram(this.program);\r\n        this.appState.program = this;\r\n    }\r\n};\r\n\r\nmodule.exports = Program;\r\n\r\n},{\"./constants\":2,\"./shader\":9,\"./uniforms\":15}],8:[function(require,module,exports){\r\n///////////////////////////////////////////////////////////////////////////////////\r\n// The MIT License (MIT)\r\n//\r\n// Copyright (c) 2017 Tarek Sherif\r\n//\r\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n// this software and associated documentation files (the \"Software\"), to deal in\r\n// the Software without restriction, including without limitation the rights to\r\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n// the Software, and to permit persons to whom the Software is furnished to do so,\r\n// subject to the following conditions:\r\n//\r\n// The above copyright notice and this permission notice shall be included in all\r\n// copies or substantial portions of the Software.\r\n//\r\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n///////////////////////////////////////////////////////////////////////////////////\r\n\r\n\"use strict\";\r\n\r\n/**\r\n    Generic query object.\r\n\r\n    @class\r\n    @prop {WebGLRenderingContext} gl The WebGL context.\r\n    @prop {WebGLQuery} query Query object.\r\n    @prop {GLEnum} target The type of information being queried.\r\n    @prop {boolean} active Whether or not a query is currently in progress.\r\n    @prop {Any} result The result of the query (only available after a call to ready() returns true). \r\n*/\r\nfunction Query(gl, target) {\r\n    this.gl = gl;\r\n    this.query = gl.createQuery();\r\n    this.target = target;\r\n    this.active = false;\r\n    this.result = null;\r\n}\r\n\r\n/**\r\n    Begin a query.\r\n\r\n    @method\r\n*/\r\nQuery.prototype.begin = function() {\r\n    if (!this.active) {\r\n        this.gl.beginQuery(this.target, this.query);\r\n        this.result = null;\r\n    }    \r\n};\r\n\r\n/**\r\n    End a query.\r\n\r\n    @method\r\n*/\r\nQuery.prototype.end = function() {\r\n    if (!this.active) {\r\n        this.gl.endQuery(this.target);\r\n        this.active = true;\r\n    }\r\n};\r\n\r\n/**\r\n    Check if query result is available.\r\n\r\n    @method\r\n*/\r\nQuery.prototype.ready = function() {\r\n    if (this.active && this.gl.getQueryParameter(this.query, this.gl.QUERY_RESULT_AVAILABLE)) {\r\n        this.active = false;\r\n        this.result = this.gl.getQueryParameter(this.query, this.gl.QUERY_RESULT);\r\n        return true;\r\n    }\r\n\r\n    return false;\r\n};\r\n\r\nmodule.exports = Query;\r\n\r\n},{}],9:[function(require,module,exports){\r\n///////////////////////////////////////////////////////////////////////////////////\r\n// The MIT License (MIT)\r\n//\r\n// Copyright (c) 2017 Tarek Sherif\r\n//\r\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n// this software and associated documentation files (the \"Software\"), to deal in\r\n// the Software without restriction, including without limitation the rights to\r\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n// the Software, and to permit persons to whom the Software is furnished to do so,\r\n// subject to the following conditions:\r\n//\r\n// The above copyright notice and this permission notice shall be included in all\r\n// copies or substantial portions of the Software.\r\n//\r\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n///////////////////////////////////////////////////////////////////////////////////\r\n\r\n\"use strict\";\r\n\r\n/**\r\n    WebGL shader.\r\n\r\n    @class\r\n    @prop {WebGLRenderingContext} gl The WebGL context.\r\n    @prop {WebGLShader} shader The shader.\r\n*/\r\nfunction Shader(gl, type, source) {\r\n    this.gl = gl;\r\n    this.shader = gl.createShader(type);\r\n    gl.shaderSource(this.shader, source);\r\n    gl.compileShader(this.shader);\r\n\r\n    if (!gl.getShaderParameter(this.shader, gl.COMPILE_STATUS)) {\r\n        var i, lines;\r\n\r\n        console.error(gl.getShaderInfoLog(this.shader));\r\n        lines = source.split(\"\\n\");\r\n        for (i = 0; i < lines.length; ++i) {\r\n            console.error((i + 1) + \":\", lines[i]);\r\n        }\r\n    }\r\n}\r\n\r\n/**\r\n    Delete this shader.\r\n\r\n    @method\r\n*/\r\nShader.prototype.delete = function() {\r\n    if (this.shader) {\r\n        this.gl.deleteShader(this.shader);\r\n        this.shader = null;\r\n    }\r\n};\r\n\r\nmodule.exports = Shader;\r\n\r\n},{}],10:[function(require,module,exports){\r\n// Copyright (c) 2017 Tarek Sherif\r\n//\r\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n// this software and associated documentation files (the \"Software\"), to deal in\r\n// the Software without restriction, including without limitation the rights to\r\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n// the Software, and to permit persons to whom the Software is furnished to do so,\r\n// subject to the following conditions:\r\n//\r\n// The above copyright notice and this permission notice shall be included in all\r\n// copies or substantial portions of the Software.\r\n//\r\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n///////////////////////////////////////////////////////////////////////////////////\r\n\r\n\"use strict\";\r\n\r\nvar CONSTANTS = require(\"./constants\");\r\n\r\nvar TEXTURE_FORMAT_DEFAULTS = {};\r\nvar UNSIGNED_BYTE = TEXTURE_FORMAT_DEFAULTS[CONSTANTS.UNSIGNED_BYTE] = {};\r\nUNSIGNED_BYTE[CONSTANTS.RED] = CONSTANTS.R8;\r\nUNSIGNED_BYTE[CONSTANTS.RG] = CONSTANTS.RG8;\r\nUNSIGNED_BYTE[CONSTANTS.RGB] = CONSTANTS.RGB8;\r\nUNSIGNED_BYTE[CONSTANTS.RGBA] = CONSTANTS.RGBA8;\r\n\r\nvar UNSIGNED_SHORT = TEXTURE_FORMAT_DEFAULTS[CONSTANTS.UNSIGNED_SHORT] = {};\r\nUNSIGNED_SHORT[CONSTANTS.DEPTH_COMPONENT] = CONSTANTS.DEPTH_COMPONENT16;\r\n\r\nvar FLOAT = TEXTURE_FORMAT_DEFAULTS[CONSTANTS.FLOAT] = {};\r\nFLOAT[CONSTANTS.RED] = CONSTANTS.R16F;\r\nFLOAT[CONSTANTS.RG] = CONSTANTS.RG16F;\r\nFLOAT[CONSTANTS.RGB] = CONSTANTS.RGB16F;\r\nFLOAT[CONSTANTS.RGBA] = CONSTANTS.RGBA16F;\r\nFLOAT[CONSTANTS.DEPTH_COMPONENT] = CONSTANTS.DEPTH_COMPONENT32F;\r\n\r\nTEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES = {};\r\n\r\n// TODO(Tarek): For https://bugs.chromium.org/p/chromium/issues/detail?id=757447\r\n// Remove this when that's fixed\r\nTEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE = {};\r\n\r\nmodule.exports = TEXTURE_FORMAT_DEFAULTS;\r\n\r\n},{\"./constants\":2}],11:[function(require,module,exports){\r\n///////////////////////////////////////////////////////////////////////////////////\r\n// The MIT License (MIT)\r\n//\r\n// Copyright (c) 2017 Tarek Sherif\r\n//\r\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n// this software and associated documentation files (the \"Software\"), to deal in\r\n// the Software without restriction, including without limitation the rights to\r\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n// the Software, and to permit persons to whom the Software is furnished to do so,\r\n// subject to the following conditions:\r\n//\r\n// The above copyright notice and this permission notice shall be included in all\r\n// copies or substantial portions of the Software.\r\n//\r\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n///////////////////////////////////////////////////////////////////////////////////\r\n\r\n\"use strict\";\r\n\r\nvar CONSTANTS = require(\"./constants\");\r\nvar TEXTURE_FORMAT_DEFAULTS = require(\"./texture-format-defaults\");\r\nvar DUMMY_ARRAY = new Array(1);\r\n\r\n/**\r\n    General-purpose texture.\r\n\r\n    @class\r\n    @prop {WebGLRenderingContext} gl The WebGL context.\r\n    @prop {WebGLTexture} texture Handle to the texture.\r\n    @prop {WebGLSamler} sampler Sampler object.\r\n    @prop {GLEnum} binding Binding point for the texture.\r\n    @prop {GLEnum} type Type of data stored in the texture.\r\n    @prop {GLEnum} format Layout of texture data.\r\n    @prop {GLEnum} internalFormat Internal arrangement of the texture data.\r\n    @prop {number} currentUnit The current texture unit this texture is bound to.\r\n    @prop {boolean} is3D Whether this texture contains 3D data.\r\n    @prop {boolean} flipY Whether the y-axis is being flipped for this texture.\r\n    @prop {boolean} mipmaps Whether this texture is using mipmap filtering \r\n        (and thus should have a complete mipmap chain).\r\n    @prop {Object} appState Tracked GL state.\r\n*/\r\nfunction Texture(gl, appState, binding, image, width, height, depth, is3D, options) {\r\n    width = width || image.width;\r\n    height = height || image.height;\r\n    options = options || CONSTANTS.DUMMY_OBJECT;\r\n\r\n    this.gl = gl;\r\n    this.binding = binding;\r\n    this.texture = null;\r\n    this.width = -1;\r\n    this.height = -1;\r\n    this.depth = -1;\r\n    this.type = options.type !== undefined ? options.type : gl.UNSIGNED_BYTE;\r\n    this.is3D = is3D;\r\n    this.appState = appState;\r\n\r\n    this.format = null;\r\n    this.internalFormat = null;\r\n    this.compressed = !!(TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[options.format] || TEXTURE_FORMAT_DEFAULTS.COMPRESSED_TYPES[options.internalFormat]);\r\n    \r\n    if (this.compressed) {\r\n        // For compressed textures, just need to provide one of format, internalFormat.\r\n        // The other will be the same.\r\n        this.format = options.format !== undefined ? options.format : options.internalFormat;\r\n        this.internalFormat = options.internalFormat !== undefined ? options.internalFormat : options.format;\r\n    } else {\r\n        this.format = options.format !== undefined ? options.format : gl.RGBA;\r\n        this.internalFormat = options.internalFormat !== undefined ? options.internalFormat : TEXTURE_FORMAT_DEFAULTS[this.type][this.format];\r\n    }\r\n\r\n    this.noTexStorage = !!TEXTURE_FORMAT_DEFAULTS.NO_TEX_STORAGE[this.internalFormat];\r\n\r\n    // -1 indicates unbound\r\n    this.currentUnit = -1;\r\n\r\n    // Sampler parameters\r\n    var minFilter = options.minFilter !== undefined ? options.minFilter : gl.LINEAR_MIPMAP_NEAREST;\r\n    var magFilter = options.magFilter !== undefined ? options.magFilter : gl.LINEAR;\r\n    var wrapS = options.wrapS !== undefined ? options.wrapS : gl.REPEAT;\r\n    var wrapT = options.wrapT !== undefined ? options.wrapT : gl.REPEAT;\r\n    var wrapR = options.wrapR !== undefined ? options.wrapR : gl.REPEAT;\r\n    var compareMode = options.compareMode !== undefined ? options.compareMode : gl.NONE;\r\n    var compareFunc = options.compareFunc !== undefined ? options.compareFunc : gl.LEQUAL;\r\n    var minLOD = options.minLOD !== undefined ? options.minLOD : null;\r\n    var maxLOD = options.maxLOD !== undefined ? options.maxLOD : null;\r\n\r\n    this.sampler = gl.createSampler();\r\n    gl.samplerParameteri(this.sampler, gl.TEXTURE_MIN_FILTER, minFilter);\r\n    gl.samplerParameteri(this.sampler, gl.TEXTURE_MAG_FILTER, magFilter);\r\n    gl.samplerParameteri(this.sampler, gl.TEXTURE_WRAP_S, wrapS);\r\n    gl.samplerParameteri(this.sampler, gl.TEXTURE_WRAP_T, wrapT);\r\n    gl.samplerParameteri(this.sampler, gl.TEXTURE_WRAP_R, wrapR);\r\n    gl.samplerParameteri(this.sampler, gl.TEXTURE_COMPARE_FUNC, compareFunc);\r\n    gl.samplerParameteri(this.sampler, gl.TEXTURE_COMPARE_MODE, compareMode);\r\n    if (minLOD !== null) {\r\n        gl.samplerParameterf(this.sampler, gl.TEXTURE_MIN_LOD, minLOD);\r\n    }\r\n    if (maxLOD !== null) {\r\n        gl.samplerParameterf(this.sampler, gl.TEXTURE_MAX_LOD, maxLOD);\r\n    }\r\n\r\n    // Texture parameters\r\n    this.flipY = options.flipY !== undefined ? options.flipY : false;\r\n    this.baseLevel = options.baseLevel !== undefined ? options.baseLevel : null;\r\n    this.maxLevel = options.maxLevel !== undefined ? options.maxLevel : null;\r\n    this.mipmaps = (minFilter === gl.LINEAR_MIPMAP_NEAREST || minFilter === gl.LINEAR_MIPMAP_LINEAR);\r\n\r\n    this.resize(width, height, depth);\r\n\r\n    if (image) {\r\n        this.data(image);\r\n    }\r\n}\r\n\r\n/**\r\n    Re-allocate texture storage.\r\n\r\n    @method\r\n    @param {number} width Image width.\r\n    @param {number} height Image height.\r\n    @param {number} [depth] Image depth or number of images. Required when passing 3D or texture array data.\r\n*/\r\nTexture.prototype.resize = function(width, height, depth) {\r\n    depth = depth || 0;\r\n\r\n    if (width === this.width && height === this.height && depth === this.depth) {\r\n        return; \r\n    }\r\n\r\n    this.gl.deleteTexture(this.texture);\r\n    if (this.currentUnit !== -1) {\r\n        this.appState.textures[this.currentUnit] = null;\r\n    }\r\n\r\n    this.texture = this.gl.createTexture();\r\n    this.bind(Math.max(this.currentUnit, 1));\r\n\r\n    this.width = width;\r\n    this.height = height;\r\n    this.depth = depth;\r\n\r\n    this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, this.flipY);\r\n\r\n    if (this.baseLevel !== null) {\r\n        this.gl.texParameteri(this.binding, this.gl.TEXTURE_BASE_LEVEL, this.baseLevel);\r\n    }\r\n\r\n    if (this.maxLevel !== null) {\r\n        this.gl.texParameteri(this.binding, this.gl.TEXTURE_MAX_LEVEL, this.maxLevel);\r\n    }\r\n\r\n    // TODO(Tarek): For https://bugs.chromium.org/p/chromium/issues/detail?id=757447\r\n    // Remove this when that's fixed\r\n    if (this.noTexStorage) {\r\n        return;\r\n    }\r\n\r\n    var levels;\r\n    if (this.is3D) {\r\n        if (this.mipmaps) {\r\n            levels = Math.floor(Math.log2(Math.max(Math.max(this.width, this.height), this.depth))) + 1;\r\n        } else {\r\n            levels = 1;\r\n        }\r\n        this.gl.texStorage3D(this.binding, levels, this.internalFormat, this.width, this.height, this.depth);\r\n    } else {\r\n        if (this.mipmaps) {\r\n            levels = Math.floor(Math.log2(Math.max(this.width, this.height))) + 1;\r\n        } else {\r\n            levels = 1;\r\n        }\r\n        this.gl.texStorage2D(this.binding, levels, this.internalFormat, this.width, this.height);\r\n    }\r\n};\r\n\r\n/**\r\n    Set the image data for the texture. An array can be passed to manually set all levels \r\n    of the mipmap chain. If a single level is passed and mipmap filtering is being used,\r\n    generateMipmap() will be called to produce the remaining levels.\r\n    NOTE: the data must fit the currently-allocated storage!\r\n\r\n    @method\r\n    @param {ImageElement|ArrayBufferView|Array} data Image data. If an array is passed, it will be \r\n        used to set mip map levels.\r\n*/\r\nTexture.prototype.data = function(data) {\r\n    if (!Array.isArray(data)) {\r\n        DUMMY_ARRAY[0] = data;\r\n        data = DUMMY_ARRAY;\r\n    }\r\n\r\n    var numLevels = this.mipmaps ? data.length : 1;\r\n    var width = this.width;\r\n    var height = this.height;\r\n    var depth = this.depth;\r\n    var generateMipmaps = this.mipmaps && data.length === 1;\r\n    var i;\r\n\r\n    this.bind(Math.max(this.currentUnit, 0));\r\n\r\n    if (this.compressed) {\r\n\r\n        // TODO(Tarek): For https://bugs.chromium.org/p/chromium/issues/detail?id=757447\r\n        // Remove this when that's fixed\r\n        if (this.noTexStorage) {\r\n            if (this.is3D) {\r\n                for (i = 0; i < numLevels; ++i) {\r\n                    this.gl.compressedTexImage3D(this.binding, i, this.internalFormat, width, height, depth, 0, data[i]);\r\n                    width = Math.max(width >> 1, 1);\r\n                    height = Math.max(height >> 1, 1);\r\n                    depth = Math.max(depth >> 1, 1);\r\n                }\r\n            } else {\r\n                for (i = 0; i < numLevels; ++i) {\r\n                    this.gl.compressedTexImage2D(this.binding, i, this.internalFormat, width, height, 0, data[i]);\r\n                    width = Math.max(width >> 1, 1);\r\n                    height = Math.max(height >> 1, 1);\r\n                }\r\n            }\r\n        } else if (this.is3D) {\r\n            for (i = 0; i < numLevels; ++i) {\r\n                this.gl.compressedTexSubImage3D(this.binding, i, 0, 0, 0, width, height, depth, this.format, data[i]);\r\n                width = Math.max(width >> 1, 1);\r\n                height = Math.max(height >> 1, 1);\r\n                depth = Math.max(depth >> 1, 1);\r\n            }\r\n        } else {\r\n            for (i = 0; i < numLevels; ++i) {\r\n                this.gl.compressedTexSubImage2D(this.binding, i, 0, 0, width, height, this.format, data[i]);\r\n                width = Math.max(width >> 1, 1);\r\n                height = Math.max(height >> 1, 1);\r\n            }\r\n        }\r\n    } else if (this.is3D) {\r\n        for (i = 0; i < numLevels; ++i) {\r\n            this.gl.texSubImage3D(this.binding, i, 0, 0, 0, width, height, depth, this.format, this.type, data[i]);\r\n            width = Math.max(width >> 1, 1);\r\n            height = Math.max(height >> 1, 1);\r\n            depth = Math.max(depth >> 1, 1);\r\n        }\r\n    } else {\r\n        for (i = 0; i < numLevels; ++i) {\r\n            this.gl.texSubImage2D(this.binding, i, 0, 0, width, height, this.format, this.type, data[i]);\r\n            width = Math.max(width >> 1, 1);\r\n            height = Math.max(height >> 1, 1);\r\n        }\r\n    }\r\n\r\n    if (generateMipmaps) {\r\n        this.gl.generateMipmap(this.binding);\r\n    }\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Delete this texture.\r\n\r\n    @method\r\n*/\r\nTexture.prototype.delete = function() {\r\n    if (this.texture) {\r\n        this.gl.deleteTexture(this.texture);\r\n        this.gl.deleteSampler(this.sampler);\r\n        this.texture = null;\r\n        this.sampler = null;\r\n        this.appState.textures[this.currentUnit] = null;\r\n        this.currentUnit = -1;\r\n    }\r\n};\r\n\r\n// Bind this texture to a texture unit.\r\nTexture.prototype.bind = function(unit) {\r\n    var currentTexture = this.appState.textures[unit];\r\n    \r\n    if (currentTexture !== this) {\r\n        if (currentTexture) {\r\n            currentTexture.currentUnit = -1;\r\n        }\r\n\r\n        if (this.currentUnit !== -1) {\r\n            this.appState.textures[this.currentUnit] = null;\r\n        }\r\n\r\n        this.gl.activeTexture(this.gl.TEXTURE0 + unit);\r\n        this.gl.bindTexture(this.binding, this.texture);\r\n        this.gl.bindSampler(unit, this.sampler);\r\n\r\n        this.appState.textures[unit] = this;\r\n        this.currentUnit = unit;\r\n    }\r\n\r\n    return this;\r\n};\r\n\r\nmodule.exports = Texture;\r\n\r\n},{\"./constants\":2,\"./texture-format-defaults\":10}],12:[function(require,module,exports){\r\n///////////////////////////////////////////////////////////////////////////////////\r\n// The MIT License (MIT)\r\n//\r\n// Copyright (c) 2017 Tarek Sherif\r\n//\r\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n// this software and associated documentation files (the \"Software\"), to deal in\r\n// the Software without restriction, including without limitation the rights to\r\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n// the Software, and to permit persons to whom the Software is furnished to do so,\r\n// subject to the following conditions:\r\n//\r\n// The above copyright notice and this permission notice shall be included in all\r\n// copies or substantial portions of the Software.\r\n//\r\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n///////////////////////////////////////////////////////////////////////////////////\r\n\r\n\"use strict\";\r\n\r\nvar Query = require(\"./query\");\r\n\r\n/**\r\n    Rendering timer.\r\n\r\n    @class\r\n    @prop {WebGLRenderingContext} gl The WebGL context.\r\n    @prop {Object} cpuTimer Timer for CPU. Will be window.performance, if available, or window.Date.\r\n    @prop {boolean} gpuTimer Whether the gpu timing is available (EXT_disjoint_timer_query_webgl2 or\r\n            EXT_disjoint_timer_query are supported).\r\n    @prop {WebGLQuery} gpuTimerQuery Timer query object for GPU (if gpu timing is supported).\r\n    @prop {boolean} gpuTimerQueryInProgress Whether a gpu timer query is currently in progress.\r\n    @prop {number} cpuStartTime When the last CPU timing started.\r\n    @prop {number} cpuTime Time spent on CPU during last timing. Only valid if ready() returns true.\r\n    @prop {number} gpuTime Time spent on GPU during last timing. Only valid if ready() returns true.\r\n            Will remain 0 if extension EXT_disjoint_timer_query_webgl2 is unavailable.\r\n*/\r\nfunction Timer(gl) {\r\n    this.gl = gl;\r\n    this.cpuTimer = window.performance || window.Date;\r\n\r\n    // Note(Tarek): Firefox for some reason only supports EXT_disjoint_timer_query, so have to try both\r\n    var gpuTimerExtension = this.gl.getExtension(\"EXT_disjoint_timer_query_webgl2\") || this.gl.getExtension(\"EXT_disjoint_timer_query\");\r\n    if (gpuTimerExtension) {\r\n        this.gpuTimer = true;\r\n        this.gpuTimerQuery = new Query(this.gl, gpuTimerExtension.TIME_ELAPSED_EXT);\r\n        this.GPU_DISJOINT_EXT = gpuTimerExtension.GPU_DISJOINT_EXT;\r\n    } else {\r\n        this.gpuTimer = false;\r\n        this.gpuTimerQuery = null;\r\n        this.GPU_DISJOINT_EXT = null;\r\n    }\r\n\r\n    this.cpuStartTime = 0;\r\n    this.cpuTime = 0;\r\n    this.gpuTime = 0;\r\n}\r\n\r\n\r\n/**\r\n    Start timing.\r\n\r\n    @method\r\n*/\r\nTimer.prototype.start = function() {\r\n    if (this.gpuTimer) {\r\n        if (!this.gpuTimerQuery.active) {\r\n            this.gpuTimerQuery.begin();\r\n            this.cpuStartTime = this.cpuTimer.now();\r\n        }\r\n    } else {\r\n        this.cpuStartTime = this.cpuTimer.now();\r\n    }\r\n};\r\n\r\n\r\n/**\r\n    Stop timing.\r\n\r\n    @method\r\n*/\r\nTimer.prototype.end = function() {\r\n    if (this.gpuTimer) {\r\n        if (!this.gpuTimerQuery.active) {\r\n            this.gpuTimerQuery.end();\r\n            this.cpuTime = this.cpuTimer.now() - this.cpuStartTime;\r\n        }\r\n    } else {\r\n        this.cpuTime = this.cpuTimer.now() - this.cpuStartTime;\r\n    }\r\n};\r\n\r\n/**\r\n    Check if timing results are available. If\r\n    this method returns true, the cpuTime and\r\n    gpuTime properties will be set to valid\r\n    values.\r\n\r\n    @method\r\n*/\r\nTimer.prototype.ready = function() {\r\n    if (this.gpuTimer) {\r\n        if (!this.gpuTimerQuery.active) {\r\n            return false;\r\n        }\r\n\r\n        var gpuTimerAvailable = this.gpuTimerQuery.ready();\r\n        var gpuTimerDisjoint = this.gl.getParameter(this.GPU_DISJOINT_EXT);\r\n\r\n        if (gpuTimerAvailable && !gpuTimerDisjoint) {\r\n            this.gpuTime = this.gpuTimerQuery.result  / 1000000;\r\n            return true;\r\n        } else {\r\n            return false;\r\n        }\r\n    } else {\r\n        return !!this.cpuStartTime;\r\n    }\r\n};\r\n\r\nmodule.exports = Timer;\r\n\r\n},{\"./query\":8}],13:[function(require,module,exports){\r\n///////////////////////////////////////////////////////////////////////////////////\r\n// The MIT License (MIT)\r\n//\r\n// Copyright (c) 2017 Tarek Sherif\r\n//\r\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n// this software and associated documentation files (the \"Software\"), to deal in\r\n// the Software without restriction, including without limitation the rights to\r\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n// the Software, and to permit persons to whom the Software is furnished to do so,\r\n// subject to the following conditions:\r\n//\r\n// The above copyright notice and this permission notice shall be included in all\r\n// copies or substantial portions of the Software.\r\n//\r\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n///////////////////////////////////////////////////////////////////////////////////\r\n\r\n\"use strict\";\r\n\r\n/**\r\n    Tranform feedback object.\r\n\r\n    @class\r\n    @prop {WebGLRenderingContext} gl The WebGL context.\r\n    @prop {WebGLTransformFeedback} transformFeedback Transform feedback object.\r\n    @prop {Object} appState Tracked GL state.\r\n*/\r\nfunction TransformFeedback(gl, appState) {\r\n    this.gl = gl;\r\n    this.transformFeedback = gl.createTransformFeedback();\r\n    this.appState = appState;\r\n    // TODO(Tarek): Need to rebind buffers due to bug in ANGLE.\r\n    // Remove this when that's fixed.\r\n    this.angleBugBuffers = [];\r\n}\r\n\r\n/**\r\n    Bind a feedback buffer to capture transform output.\r\n\r\n    @method\r\n    @param {number} index Index of transform feedback varying to capture.\r\n    @param {VertexBuffer} buffer Buffer to record output into.\r\n*/\r\nTransformFeedback.prototype.feedbackBuffer = function(index, buffer) {\r\n    this.gl.bindTransformFeedback(this.gl.TRANSFORM_FEEDBACK, this.transformFeedback);\r\n    this.gl.bindBufferBase(this.gl.TRANSFORM_FEEDBACK_BUFFER, index, buffer.buffer);\r\n    this.gl.bindTransformFeedback(this.gl.TRANSFORM_FEEDBACK, null);\r\n    this.gl.bindBufferBase(this.gl.TRANSFORM_FEEDBACK_BUFFER, index, null);\r\n\r\n    this.angleBugBuffers[index] = buffer;\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Delete this transform feedback.\r\n\r\n    @method\r\n*/\r\nTransformFeedback.prototype.delete = function() {\r\n    if (this.transformFeedback) {\r\n        this.gl.deleteTransformFeedback(this.transformFeedback);\r\n        this.transformFeedback = null;\r\n    }\r\n};\r\n\r\n// Bind this transform feedback.\r\nTransformFeedback.prototype.bind = function() {\r\n    if (this.appState.transformFeedback !== this) {\r\n        this.gl.bindTransformFeedback(this.gl.TRANSFORM_FEEDBACK, this.transformFeedback);\r\n\r\n        for (var i = 0, len = this.angleBugBuffers.length; i < len; ++i) {\r\n            this.gl.bindBufferBase(this.gl.TRANSFORM_FEEDBACK_BUFFER, i, this.angleBugBuffers[i].buffer);\r\n        }\r\n\r\n        this.appState.transformFeedback = this;\r\n    }\r\n\r\n    return this;\r\n};\r\n\r\nmodule.exports = TransformFeedback;\r\n\r\n},{}],14:[function(require,module,exports){\r\n///////////////////////////////////////////////////////////////////////////////////\r\n// The MIT License (MIT)\r\n//\r\n// Copyright (c) 2017 Tarek Sherif\r\n//\r\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n// this software and associated documentation files (the \"Software\"), to deal in\r\n// the Software without restriction, including without limitation the rights to\r\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n// the Software, and to permit persons to whom the Software is furnished to do so,\r\n// subject to the following conditions:\r\n//\r\n// The above copyright notice and this permission notice shall be included in all\r\n// copies or substantial portions of the Software.\r\n//\r\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n///////////////////////////////////////////////////////////////////////////////////\r\n\r\n\"use strict\";\r\n\r\nvar CONSTANTS = require(\"./constants\");\r\n\r\n/**\r\n    Storage for uniform data. Data is stored in std140 layout.\r\n\r\n    @class\r\n    @prop {WebGLRenderingContext} gl The WebGL context.\r\n    @prop {WebGLBuffer} buffer Allocated buffer storage.\r\n    @prop {Float32Array} data Buffer data.\r\n    @prop {Object} dataViews Map of base data types to matching ArrayBufferViews of the buffer data.\r\n    @prop {Array} offsets Offsets into the array for each item in the buffer.\r\n    @prop {Array} sizes Size of the item at the given offset.\r\n    @prop {Array} types The base type of the item at the given offset (FLOAT, INT or UNSIGNED_INT).\r\n    @prop {number} size The size of the buffer (in 4-byte items).\r\n    @prop {GLEnum} usage Usage pattern of the buffer.\r\n*/\r\nfunction UniformBuffer(gl, layout, usage) {\r\n    this.gl = gl;\r\n    this.buffer = gl.createBuffer();\r\n    this.dataViews = {};\r\n    this.offsets = new Array(layout.length);\r\n    this.sizes = new Array(layout.length);\r\n    this.types = new Array(layout.length);\r\n    this.size = 0;\r\n    this.usage = usage || gl.DYNAMIC_DRAW;\r\n\r\n    for (var i = 0, len = layout.length; i < len; ++i) {\r\n        var type = layout[i];\r\n        switch(type) {\r\n            case CONSTANTS.FLOAT:\r\n            case CONSTANTS.INT:\r\n            case CONSTANTS.UNSIGNED_INT:\r\n            case CONSTANTS.BOOL:\r\n                this.offsets[i] = this.size;\r\n                this.sizes[i] = 1;\r\n\r\n                if (type === CONSTANTS.INT) {\r\n                    this.types[i] = CONSTANTS.INT;\r\n                } else if (this.type === CONSTANTS.UNSIGNED_INT) {\r\n                    this.types[i] = CONSTANTS.UNSIGNED_INT;\r\n                } else {\r\n                    this.types[i] = CONSTANTS.FLOAT;\r\n                }\r\n\r\n                this.size++;\r\n                break;\r\n            case CONSTANTS.FLOAT_VEC2:\r\n            case CONSTANTS.INT_VEC2:\r\n            case CONSTANTS.UNSIGNED_INT_VEC2:\r\n            case CONSTANTS.BOOL_VEC2:\r\n                this.size += this.size % 2;\r\n                this.offsets[i] = this.size;\r\n                this.sizes[i] = 2;\r\n\r\n                if (type === CONSTANTS.INT_VEC2) {\r\n                    this.types[i] = CONSTANTS.INT;\r\n                } else if (this.type === CONSTANTS.UNSIGNED_INT_VEC2) {\r\n                    this.types[i] = CONSTANTS.UNSIGNED_INT;\r\n                } else {\r\n                    this.types[i] = CONSTANTS.FLOAT;\r\n                }\r\n\r\n                this.size += 2;\r\n                break;\r\n            case CONSTANTS.FLOAT_VEC3:\r\n            case CONSTANTS.INT_VEC3:\r\n            case CONSTANTS.UNSIGNED_INT_VEC3:\r\n            case CONSTANTS.BOOL_VEC3:\r\n            case CONSTANTS.FLOAT_VEC4:\r\n            case CONSTANTS.INT_VEC4:\r\n            case CONSTANTS.UNSIGNED_INT_VEC4:\r\n            case CONSTANTS.BOOL_VEC4:\r\n                this.size += (4 - this.size % 4) % 4;\r\n                this.offsets[i] = this.size;\r\n                this.sizes[i] = 4;\r\n\r\n                if (type === CONSTANTS.INT_VEC4 || type === CONSTANTS.INT_VEC3) {\r\n                    this.types[i] = CONSTANTS.INT;\r\n                } else if (this.type === CONSTANTS.UNSIGNED_INT_VEC4 || this.type === CONSTANTS.UNSIGNED_INT_VEC3) {\r\n                    this.types[i] = CONSTANTS.UNSIGNED_INT;\r\n                } else {\r\n                    this.types[i] = CONSTANTS.FLOAT;\r\n                }\r\n\r\n                this.size += 4;\r\n                break;\r\n            case CONSTANTS.FLOAT_MAT2:\r\n            case CONSTANTS.FLOAT_MAT2x3:\r\n            case CONSTANTS.FLOAT_MAT2x4:\r\n                this.size += (4 - this.size % 4) % 4;\r\n                this.offsets[i] = this.size;\r\n                this.sizes[i] = 8;\r\n                this.types[i] = CONSTANTS.FLOAT;\r\n\r\n                this.size += 8;\r\n                break;\r\n            case CONSTANTS.FLOAT_MAT3:\r\n            case CONSTANTS.FLOAT_MAT3x2:\r\n            case CONSTANTS.FLOAT_MAT3x4:\r\n                this.size += (4 - this.size % 4) % 4;\r\n                this.offsets[i] = this.size;\r\n                this.sizes[i] = 12;\r\n                this.types[i] = CONSTANTS.FLOAT;\r\n\r\n                this.size += 12;\r\n                break;\r\n            case CONSTANTS.FLOAT_MAT4:\r\n            case CONSTANTS.FLOAT_MAT4x2:\r\n            case CONSTANTS.FLOAT_MAT4x3:\r\n                this.size += (4 - this.size % 4) % 4;\r\n                this.offsets[i] = this.size;\r\n                this.sizes[i] = 16;\r\n                this.types[i] = CONSTANTS.FLOAT;\r\n\r\n                this.size += 16;\r\n                break;\r\n            default:\r\n                console.error(\"Unsupported type for uniform buffer.\");\r\n        }\r\n    }\r\n\r\n    this.size += (4 - this.size % 4) % 4;\r\n\r\n    this.data = new Float32Array(this.size);\r\n    this.dataViews[CONSTANTS.FLOAT] = this.data;\r\n    this.dataViews[CONSTANTS.INT] = new Int32Array(this.data.buffer);\r\n    this.dataViews[CONSTANTS.UNSIGNED_INT] = new Uint32Array(this.data.buffer);\r\n\r\n    this.gl.bindBufferBase(this.gl.UNIFORM_BUFFER, 0, this.buffer);\r\n    this.gl.bufferData(this.gl.UNIFORM_BUFFER, this.size * 4, this.usage);\r\n    this.gl.bindBufferBase(this.gl.UNIFORM_BUFFER, 0, null);\r\n}\r\n\r\n/**\r\n    Update data for a given item in the buffer. NOTE: Data is not\r\n    sent the the GPU until the update() method is called!\r\n\r\n    @method\r\n    @param {number} index Index in the layout of item to set.\r\n    @param {ArrayBufferView} value Value to store at the layout location.\r\n*/\r\nUniformBuffer.prototype.set = function(index, value) {\r\n    var view = this.dataViews[this.types[index]];\r\n\r\n    if (this.sizes[index] === 1)  {\r\n        view[this.offsets[index]] = value;\r\n    } else {\r\n        view.set(value, this.offsets[index]);\r\n    }\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Send stored buffer data to the GPU.\r\n\r\n    @param {number} [index] Index in the layout of item to send to the GPU. If ommited, entire buffer is sent.\r\n    @method\r\n*/\r\nUniformBuffer.prototype.update = function(index) {\r\n    var data;\r\n    var offset;\r\n    if (index === undefined) {\r\n        data = this.data;\r\n        offset = 0;\r\n    } else {\r\n        var begin = this.offsets[index];\r\n        var end = begin + this.sizes[index];\r\n        data = this.data.subarray(begin, end);\r\n        offset = begin * 4;\r\n    }\r\n\r\n    this.gl.bindBufferBase(this.gl.UNIFORM_BUFFER, 0, this.buffer);\r\n    this.gl.bufferSubData(this.gl.UNIFORM_BUFFER, offset, data);\r\n    this.gl.bindBufferBase(this.gl.UNIFORM_BUFFER, 0, null);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Delete this uniform buffer.\r\n\r\n    @method\r\n*/\r\nUniformBuffer.prototype.delete = function() {\r\n    if (this.buffer) {\r\n        this.gl.deleteBuffer(this.buffer);\r\n        this.buffer = null;\r\n    }\r\n};\r\n\r\n// Bind this uniform buffer to the given base.\r\nUniformBuffer.prototype.bind = function(base) {\r\n    this.gl.bindBufferBase(this.gl.UNIFORM_BUFFER, base, this.buffer);\r\n\r\n    return this;\r\n};\r\n\r\nmodule.exports = UniformBuffer;\r\n\r\n},{\"./constants\":2}],15:[function(require,module,exports){\r\n///////////////////////////////////////////////////////////////////////////////////\r\n// The MIT License (MIT)\r\n//\r\n// Copyright (c) 2017 Tarek Sherif\r\n//\r\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n// this software and associated documentation files (the \"Software\"), to deal in\r\n// the Software without restriction, including without limitation the rights to\r\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n// the Software, and to permit persons to whom the Software is furnished to do so,\r\n// subject to the following conditions:\r\n//\r\n// The above copyright notice and this permission notice shall be included in all\r\n// copies or substantial portions of the Software.\r\n//\r\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n///////////////////////////////////////////////////////////////////////////////////\r\n\r\n\"use strict\";\r\n\r\nvar CONSTANTS = require(\"./constants\");\r\n\r\n// Classes to manage uniform value updates, including\r\n// caching current values.\r\n\r\nvar UNIFORM_FUNC_NAME = {};\r\nUNIFORM_FUNC_NAME[CONSTANTS.BOOL] = \"uniform1i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.INT] = \"uniform1i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.SAMPLER_2D] = \"uniform1i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.INT_SAMPLER_2D] = \"uniform1i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.UNSIGNED_INT_SAMPLER_2D] = \"uniform1i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.SAMPLER_2D_SHADOW] = \"uniform1i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.SAMPLER_2D_ARRAY] = \"uniform1i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.INT_SAMPLER_2D_ARRAY] = \"uniform1i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.UNSIGNED_INT_SAMPLER_2D_ARRAY] = \"uniform1i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.SAMPLER_2D_ARRAY_SHADOW] = \"uniform1i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.SAMPLER_CUBE] = \"uniform1i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.INT_SAMPLER_CUBE] = \"uniform1i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.UNSIGNED_INT_SAMPLER_CUBE] = \"uniform1i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.SAMPLER_CUBE_SHADOW] = \"uniform1i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.SAMPLER_3D] = \"uniform1i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.INT_SAMPLER_3D] = \"uniform1i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.UNSIGNED_INT_SAMPLER_3D] = \"uniform1i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.UNSIGNED_INT] = \"uniform1ui\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.FLOAT] = \"uniform1f\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.FLOAT_VEC2] = \"uniform2f\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.FLOAT_VEC3] = \"uniform3f\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.FLOAT_VEC4] = \"uniform4f\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.INT_VEC2] = \"uniform2i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.INT_VEC3] = \"uniform3i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.INT_VEC4] = \"uniform4i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.UNSIGNED_INT_VEC2] = \"uniform2ui\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.UNSIGNED_INT_VEC3] = \"uniform3ui\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.UNSIGNED_INT_VEC4] = \"uniform4ui\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.BOOL_VEC2] = \"uniform2i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.BOOL_VEC3] = \"uniform3i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.BOOL_VEC4] = \"uniform4i\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.FLOAT_MAT2] = \"uniformMatrix2fv\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.FLOAT_MAT3] = \"uniformMatrix3fv\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.FLOAT_MAT4] = \"uniformMatrix4fv\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.FLOAT_MAT2x3] = \"uniformMatrix2x3fv\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.FLOAT_MAT2x4] = \"uniformMatrix2x4fv\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.FLOAT_MAT3x2] = \"uniformMatrix3x2fv\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.FLOAT_MAT3x4] = \"uniformMatrix3x4fv\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.FLOAT_MAT4x2] = \"uniformMatrix4x2fv\";\r\nUNIFORM_FUNC_NAME[CONSTANTS.FLOAT_MAT4x3] = \"uniformMatrix4x3fv\";\r\n\r\nvar UNIFORM_COMPONENT_COUNT = {};\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.BOOL] = 1;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.INT] = 1;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.SAMPLER_2D] = 1;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.INT_SAMPLER_2D] = 1;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.UNSIGNED_INT_SAMPLER_2D] = 1;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.SAMPLER_2D_SHADOW] = 1;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.SAMPLER_2D_ARRAY] = 1;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.INT_SAMPLER_2D_ARRAY] = 1;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.UNSIGNED_INT_SAMPLER_2D_ARRAY] = 1;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.SAMPLER_2D_ARRAY_SHADOW] = 1;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.SAMPLER_CUBE] = 1;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.INT_SAMPLER_CUBE] = 1;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.UNSIGNED_INT_SAMPLER_CUBE] = 1;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.SAMPLER_CUBE_SHADOW] = 1;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.SAMPLER_3D] = 1;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.INT_SAMPLER_3D] = 1;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.UNSIGNED_INT_SAMPLER_3D] = 1;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.UNSIGNED_INT] = 1;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.FLOAT] = 1;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.FLOAT_VEC2] = 2;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.FLOAT_VEC3] = 3;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.FLOAT_VEC4] = 4;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.INT_VEC2] = 2;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.INT_VEC3] = 3;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.INT_VEC4] = 4;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.UNSIGNED_INT_VEC2] = 2;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.UNSIGNED_INT_VEC3] = 3;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.UNSIGNED_INT_VEC4] = 4;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.BOOL_VEC2] = 2;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.BOOL_VEC3] = 3;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.BOOL_VEC4] = 4;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.FLOAT_MAT2] = 4;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.FLOAT_MAT3] = 9;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.FLOAT_MAT4] = 16;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.FLOAT_MAT2x3] = 6;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.FLOAT_MAT2x4] = 8;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.FLOAT_MAT3x2] = 6;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.FLOAT_MAT3x4] = 12;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.FLOAT_MAT4x2] = 8;\r\nUNIFORM_COMPONENT_COUNT[CONSTANTS.FLOAT_MAT4x3] = 12;\r\n\r\nvar UNIFORM_CACHE_CLASS = {};\r\nUNIFORM_CACHE_CLASS[CONSTANTS.INT] = Int32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.SAMPLER_2D] = Int32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.INT_SAMPLER_2D] = Int32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.UNSIGNED_INT_SAMPLER_2D] = Int32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.SAMPLER_2D_SHADOW] = Int32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.SAMPLER_2D_ARRAY] = Int32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.INT_SAMPLER_2D_ARRAY] = Int32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.UNSIGNED_INT_SAMPLER_2D_ARRAY] = Int32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.SAMPLER_2D_ARRAY_SHADOW] = Int32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.SAMPLER_CUBE] = Int32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.INT_SAMPLER_CUBE] = Int32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.UNSIGNED_INT_SAMPLER_CUBE] = Int32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.SAMPLER_CUBE_SHADOW] = Int32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.SAMPLER_3D] = Int32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.INT_SAMPLER_3D] = Int32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.UNSIGNED_INT_SAMPLER_3D] = Int32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.UNSIGNED_INT] = Uint32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.FLOAT] = Float32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.FLOAT_VEC2] = Float32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.FLOAT_VEC3] = Float32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.FLOAT_VEC4] = Float32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.INT_VEC2] = Int32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.INT_VEC3] = Int32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.INT_VEC4] = Int32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.UNSIGNED_INT_VEC2] = Uint32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.UNSIGNED_INT_VEC3] = Uint32Array;\r\nUNIFORM_CACHE_CLASS[CONSTANTS.UNSIGNED_INT_VEC4] = Uint32Array;\r\n\r\nfunction SingleComponentUniform(gl, handle, type) {\r\n    this.gl = gl;\r\n    this.handle = handle;\r\n    this.glFuncName = UNIFORM_FUNC_NAME[type];\r\n    this.cache = type === CONSTANTS.BOOL ? false : 0;\r\n}\r\n\r\nSingleComponentUniform.prototype.set = function(value) {\r\n    if (this.cache !== value) {\r\n        this.gl[this.glFuncName](this.handle, value);\r\n        this.cache = value;\r\n    }\r\n};\r\n\r\nfunction MultiNumericUniform(gl, handle, type, count) {\r\n    this.gl = gl;\r\n    this.handle = handle;\r\n    this.glFuncName = UNIFORM_FUNC_NAME[type] + \"v\";\r\n    this.count = count;\r\n    this.cache = new UNIFORM_CACHE_CLASS[type](UNIFORM_COMPONENT_COUNT[type] * count);\r\n}\r\n\r\nMultiNumericUniform.prototype.set = function(value) {\r\n    for (var i = 0, len = value.length; i < len; ++i) {\r\n        if (this.cache[i] !== value[i]) {\r\n            this.gl[this.glFuncName](this.handle, value);\r\n            this.cache.set(value);\r\n            return;\r\n        }\r\n    }\r\n};\r\n\r\nfunction MultiBoolUniform(gl, handle, type, count) {\r\n    this.gl = gl;\r\n    this.handle = handle;\r\n    this.glFuncName = UNIFORM_FUNC_NAME[type] + \"v\";\r\n    this.count = count;\r\n    this.cache = new Array(UNIFORM_COMPONENT_COUNT[type] * count).fill(false);\r\n}\r\n\r\nMultiBoolUniform.prototype.set = function(value) {\r\n    for (var i = 0, len = value.length; i < len; ++i) {\r\n        if (this.cache[i] !== value[i]) {\r\n            this.gl[this.glFuncName](this.handle, value);\r\n            for (var j = i; j < len; j++) {\r\n                this.cache[j] = value[j];\r\n            }\r\n            return;\r\n        }\r\n    }\r\n};\r\n\r\nfunction MatrixUniform(gl, handle, type, count) {\r\n    this.gl = gl;\r\n    this.handle = handle;\r\n    this.glFuncName = UNIFORM_FUNC_NAME[type];\r\n    this.count = count;\r\n    this.cache = new Float32Array(UNIFORM_COMPONENT_COUNT[type] * count);\r\n}\r\n\r\nMatrixUniform.prototype.set = function(value) {\r\n    for (var i = 0, len = value.length; i < len; ++i) {\r\n        if (this.cache[i] !== value[i]) {\r\n            this.gl[this.glFuncName](this.handle, false, value);\r\n            this.cache.set(value);\r\n            return;\r\n        }\r\n    }\r\n};\r\n\r\nmodule.exports.MatrixUniform = MatrixUniform;\r\nmodule.exports.MultiBoolUniform = MultiBoolUniform;\r\nmodule.exports.MultiNumericUniform = MultiNumericUniform;\r\nmodule.exports.SingleComponentUniform = SingleComponentUniform;\r\n\r\n},{\"./constants\":2}],16:[function(require,module,exports){\r\n// Copyright (c) 2017 Tarek Sherif\r\n//\r\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n// this software and associated documentation files (the \"Software\"), to deal in\r\n// the Software without restriction, including without limitation the rights to\r\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n// the Software, and to permit persons to whom the Software is furnished to do so,\r\n// subject to the following conditions:\r\n//\r\n// The above copyright notice and this permission notice shall be included in all\r\n// copies or substantial portions of the Software.\r\n//\r\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n///////////////////////////////////////////////////////////////////////////////////\r\n\r\n\"use strict\";\r\n\r\nvar CONSTANTS = require(\"./constants\");\r\n\r\n/**\r\n    Organizes vertex buffer and attribute state.\r\n\r\n    @class\r\n    @prop {WebGLRenderingContext} gl The WebGL context.\r\n    @prop {WebGLVertexArrayObject} vertexArray Vertex array object.\r\n    @prop {number} numElements Number of elements in the vertex array.\r\n    @prop {boolean} indexed Whether this vertex array is set up for indexed drawing.\r\n    @prop {GLenum} indexType Data type of the indices.\r\n    @prop {boolean} instanced Whether this vertex array is set up for instanced drawing.\r\n    @prop {number} numInstances Number of instances to draw with this vertex array.\r\n    @prop {Object} appState Tracked GL state.\r\n*/\r\nfunction VertexArray(gl, appState) {\r\n    this.gl = gl;\r\n    this.vertexArray = gl.createVertexArray();\r\n    this.appState = appState;\r\n    this.numElements = 0;\r\n    this.indexType = null;\r\n    this.instancedBuffers = 0;\r\n    this.indexed = false;\r\n    this.numInstances = 0;\r\n}\r\n\r\n/**\r\n    Bind an per-vertex attribute buffer to this vertex array.\r\n\r\n    @method\r\n    @param {number} attributeIndex The attribute location to bind to.\r\n    @param {VertexBuffer} vertexBuffer The VertexBuffer to bind.\r\n*/\r\nVertexArray.prototype.vertexAttributeBuffer = function(attributeIndex, vertexBuffer) {\r\n    this.attributeBuffer(attributeIndex, vertexBuffer, false, false, false);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Bind an per-instance attribute buffer to this vertex array.\r\n\r\n    @method\r\n    @param {number} attributeIndex The attribute location to bind to.\r\n    @param {VertexBuffer} vertexBuffer The VertexBuffer to bind.\r\n*/\r\nVertexArray.prototype.instanceAttributeBuffer = function(attributeIndex, vertexBuffer) {\r\n    this.attributeBuffer(attributeIndex, vertexBuffer, true, false, false);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Bind an per-vertex integer attribute buffer to this vertex array.\r\n    Note that this refers to the attribute in the shader being an integer,\r\n    not the data stored in the vertex buffer.\r\n\r\n    @method\r\n    @param {number} attributeIndex The attribute location to bind to.\r\n    @param {VertexBuffer} vertexBuffer The VertexBuffer to bind.\r\n*/\r\nVertexArray.prototype.vertexIntegerAttributeBuffer = function(attributeIndex, vertexBuffer) {\r\n    this.attributeBuffer(attributeIndex, vertexBuffer, false, true, false);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Bind an per-instance integer attribute buffer to this vertex array.\r\n    Note that this refers to the attribute in the shader being an integer,\r\n    not the data stored in the vertex buffer.\r\n\r\n    @method\r\n    @param {number} attributeIndex The attribute location to bind to.\r\n    @param {VertexBuffer} vertexBuffer The VertexBuffer to bind.\r\n*/\r\nVertexArray.prototype.instanceIntegerAttributeBuffer = function(attributeIndex, vertexBuffer) {\r\n    this.attributeBuffer(attributeIndex, vertexBuffer, true, true, false);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Bind an per-vertex normalized attribute buffer to this vertex array.\r\n    Integer data in the vertex buffer will be normalized to [-1.0, 1.0] if\r\n    signed, [0.0, 1.0] if unsigned.\r\n\r\n    @method\r\n    @param {number} attributeIndex The attribute location to bind to.\r\n    @param {VertexBuffer} vertexBuffer The VertexBuffer to bind.\r\n*/\r\nVertexArray.prototype.vertexNormalizedAttributeBuffer = function(attributeIndex, vertexBuffer) {\r\n    this.attributeBuffer(attributeIndex, vertexBuffer, false, false, true);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Bind an per-instance normalized attribute buffer to this vertex array.\r\n    Integer data in the vertex buffer will be normalized to [-1.0, 1.0] if\r\n    signed, [0.0, 1.0] if unsigned.\r\n    \r\n    @method\r\n    @param {number} attributeIndex The attribute location to bind to.\r\n    @param {VertexBuffer} vertexBuffer The VertexBuffer to bind.\r\n*/\r\nVertexArray.prototype.instanceNormalizedAttributeBuffer = function(attributeIndex, vertexBuffer) {\r\n    this.attributeBuffer(attributeIndex, vertexBuffer, true, false, true);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Bind an index buffer to this vertex array.\r\n\r\n    @method\r\n    @param {VertexBuffer} vertexBuffer The VertexBuffer to bind.\r\n*/\r\nVertexArray.prototype.indexBuffer = function(vertexBuffer) {\r\n    this.gl.bindVertexArray(this.vertexArray);\r\n    this.gl.bindBuffer(vertexBuffer.binding, vertexBuffer.buffer);\r\n\r\n    this.numElements = vertexBuffer.numItems * 3;\r\n    this.indexType = vertexBuffer.type;\r\n    this.indexed = true;\r\n\r\n    this.gl.bindVertexArray(null);\r\n    this.gl.bindBuffer(vertexBuffer.binding, null);\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Delete this vertex array.\r\n\r\n    @method\r\n*/\r\nVertexArray.prototype.delete = function() {\r\n    if (this.vertexArray) {\r\n        this.gl.deleteVertexArray(this.vertexArray);\r\n        this.vertexArray = null;\r\n    }\r\n    this.gl.bindVertexArray(null);\r\n\r\n    return this;\r\n};\r\n\r\n// Bind this vertex array.\r\nVertexArray.prototype.bind = function() {\r\n    if (this.appState.vertexArray !== this) {\r\n        this.gl.bindVertexArray(this.vertexArray);\r\n        this.appState.vertexArray = this;\r\n    }\r\n\r\n    return this;\r\n};\r\n\r\n// Attach an attribute buffer\r\nVertexArray.prototype.attributeBuffer = function(attributeIndex, vertexBuffer, instanced, integer, normalized) {\r\n    this.gl.bindVertexArray(this.vertexArray);\r\n    this.gl.bindBuffer(vertexBuffer.binding, vertexBuffer.buffer);\r\n\r\n    var numColumns = vertexBuffer.numColumns;\r\n\r\n    for (var i = 0; i < numColumns; ++i) {\r\n        if (integer) {\r\n            this.gl.vertexAttribIPointer(\r\n                attributeIndex + i,\r\n                vertexBuffer.itemSize,\r\n                vertexBuffer.type,\r\n                numColumns * vertexBuffer.itemSize * CONSTANTS.TYPE_SIZE[vertexBuffer.type],\r\n                i * vertexBuffer.itemSize * CONSTANTS.TYPE_SIZE[vertexBuffer.type]);\r\n        } else {\r\n            this.gl.vertexAttribPointer(\r\n                attributeIndex + i,\r\n                vertexBuffer.itemSize,\r\n                vertexBuffer.type,\r\n                normalized,\r\n                numColumns * vertexBuffer.itemSize * CONSTANTS.TYPE_SIZE[vertexBuffer.type],\r\n                i * vertexBuffer.itemSize * CONSTANTS.TYPE_SIZE[vertexBuffer.type]);\r\n        }\r\n\r\n        if (instanced) {\r\n            this.gl.vertexAttribDivisor(attributeIndex + i, 1);\r\n        }\r\n\r\n        this.gl.enableVertexAttribArray(attributeIndex + i);\r\n    }\r\n\r\n    this.instanced = this.instanced || instanced;\r\n\r\n    if (instanced) {\r\n        this.numInstances = vertexBuffer.numItems;\r\n    } else {\r\n        this.numElements = this.numElements || vertexBuffer.numItems;\r\n    }\r\n\r\n    this.gl.bindVertexArray(null);\r\n    this.gl.bindBuffer(vertexBuffer.binding, null);\r\n\r\n    return this;\r\n};\r\n\r\nmodule.exports = VertexArray;\r\n\r\n},{\"./constants\":2}],17:[function(require,module,exports){\r\n///////////////////////////////////////////////////////////////////////////////////\r\n// The MIT License (MIT)\r\n//\r\n// Copyright (c) 2017 Tarek Sherif\r\n//\r\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n// this software and associated documentation files (the \"Software\"), to deal in\r\n// the Software without restriction, including without limitation the rights to\r\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n// the Software, and to permit persons to whom the Software is furnished to do so,\r\n// subject to the following conditions:\r\n//\r\n// The above copyright notice and this permission notice shall be included in all\r\n// copies or substantial portions of the Software.\r\n//\r\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n///////////////////////////////////////////////////////////////////////////////////\r\n\r\n\"use strict\";\r\n\r\nvar CONSTANTS = require(\"./constants\");\r\n\r\n/**\r\n    Storage for vertex data.\r\n\r\n    @class\r\n    @prop {WebGLRenderingContext} gl The WebGL context.\r\n    @prop {WebGLBuffer} buffer Allocated buffer storage.\r\n    @prop {GLEnum} type The type of data stored in the buffer.\r\n    @prop {number} itemSize Number of array elements per vertex.\r\n    @prop {number} numItems Number of vertices represented.\r\n    @prop {GLEnum} usage The usage pattern of the buffer.\r\n    @prop {boolean} indexArray Whether this is an index array.\r\n    @prop {GLEnum} binding GL binding point (ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER).\r\n    @prop {Object} appState Tracked GL state.\r\n*/\r\nfunction VertexBuffer(gl, appState, type, itemSize, data, usage, indexArray) {\r\n    var numColumns;\r\n    switch(type) {\r\n        case CONSTANTS.FLOAT_MAT4:\r\n        case CONSTANTS.FLOAT_MAT4x2:\r\n        case CONSTANTS.FLOAT_MAT4x3:\r\n            numColumns = 4;\r\n            break;\r\n        case CONSTANTS.FLOAT_MAT3:\r\n        case CONSTANTS.FLOAT_MAT3x2:\r\n        case CONSTANTS.FLOAT_MAT3x4:\r\n            numColumns = 3;\r\n            break;\r\n        case CONSTANTS.FLOAT_MAT2:\r\n        case CONSTANTS.FLOAT_MAT2x3:\r\n        case CONSTANTS.FLOAT_MAT2x4:\r\n            numColumns = 2;\r\n            break;\r\n        default:\r\n            numColumns = 1;\r\n    }\r\n\r\n    switch(type) {\r\n        case CONSTANTS.FLOAT_MAT4:\r\n        case CONSTANTS.FLOAT_MAT3x4:\r\n        case CONSTANTS.FLOAT_MAT2x4:\r\n            itemSize = 4;\r\n            type = CONSTANTS.FLOAT;\r\n            break;\r\n        case CONSTANTS.FLOAT_MAT3:\r\n        case CONSTANTS.FLOAT_MAT4x3:\r\n        case CONSTANTS.FLOAT_MAT2x3:\r\n            itemSize = 3;\r\n            type = CONSTANTS.FLOAT;\r\n            break;\r\n        case CONSTANTS.FLOAT_MAT2:\r\n        case CONSTANTS.FLOAT_MAT3x2:\r\n        case CONSTANTS.FLOAT_MAT4x2:\r\n            itemSize = 2;\r\n            type = CONSTANTS.FLOAT;\r\n            break;\r\n    }\r\n\r\n    var dataLength;\r\n    if (typeof data === \"number\") {\r\n        dataLength = data;\r\n        data *= CONSTANTS.TYPE_SIZE[type];\r\n    } else {\r\n        dataLength = data.length;\r\n    }\r\n\r\n    this.gl = gl;\r\n    this.buffer = gl.createBuffer();\r\n    this.appState = appState;\r\n    this.type = type;\r\n    this.itemSize = itemSize;\r\n    this.numItems = dataLength / (itemSize * numColumns);\r\n    this.numColumns = numColumns;\r\n    this.usage = usage || gl.STATIC_DRAW;\r\n    this.indexArray = !!indexArray;\r\n    this.binding = this.indexArray ? gl.ELEMENT_ARRAY_BUFFER : gl.ARRAY_BUFFER;\r\n\r\n    gl.bindBuffer(this.binding, this.buffer);\r\n    gl.bufferData(this.binding, data, this.usage);\r\n    gl.bindBuffer(this.binding, null);\r\n}\r\n\r\n/**\r\n    Update data in this buffer. NOTE: the data must fit\r\n    the originally-allocated buffer!\r\n\r\n    @method\r\n    @param {VertexBufferView} data Data to store in the buffer.\r\n*/\r\nVertexBuffer.prototype.data = function(data) {\r\n    // Don't want to update vertex array bindings\r\n    var currentVertexArray = this.appState.vertexArray;\r\n    if (currentVertexArray) {\r\n        this.gl.bindVertexArray(null);\r\n    }\r\n\r\n    this.gl.bindBuffer(this.binding, this.buffer);\r\n    this.gl.bufferSubData(this.binding, 0, data);\r\n    this.gl.bindBuffer(this.binding, null);\r\n\r\n    if (currentVertexArray) {\r\n        this.gl.bindVertexArray(currentVertexArray.vertexArray);\r\n    }\r\n\r\n    return this;\r\n};\r\n\r\n/**\r\n    Delete this array buffer.\r\n\r\n    @method\r\n*/\r\nVertexBuffer.prototype.delete = function() {\r\n    if (this.buffer) {\r\n        this.gl.deleteBuffer(this.buffer);\r\n        this.buffer = null;\r\n    }\r\n};\r\n\r\nmodule.exports = VertexBuffer;\r\n\r\n},{\"./constants\":2}]},{},[6])(6)\r\n});"
  },
  {
    "path": "libs/picogl.js/utils.js",
    "content": "///////////////////////////////////////////////////////////////////////////////////\r\n// The MIT License (MIT)\r\n//\r\n// Copyright (c) 2017 Tarek Sherif\r\n//\r\n// Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n// this software and associated documentation files (the \"Software\"), to deal in\r\n// the Software without restriction, including without limitation the rights to\r\n// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n// the Software, and to permit persons to whom the Software is furnished to do so,\r\n// subject to the following conditions:\r\n//\r\n// The above copyright notice and this permission notice shall be included in all\r\n// copies or substantial portions of the Software.\r\n//\r\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n///////////////////////////////////////////////////////////////////////////////////\r\n\r\n(function() {\r\n    var dummyGL = document.createElement(\"canvas\").getContext(\"webgl2\");\r\n\r\n    if (window.mat4) {\r\n        var translateMat = mat4.create();\r\n        var rotateXMat = mat4.create();\r\n        var rotateYMat = mat4.create();\r\n        var rotateZMat = mat4.create();\r\n        var scaleMat = mat4.create();\r\n    }\r\n\r\n    var zeros = [0, 0, 0];\r\n    var ones = [1, 1, 1];\r\n\r\n    var NUM_TIMING_SAMPLES = 10;\r\n\r\n    var cpuTimeSum = 0;\r\n    var gpuTimeSum = 0;\r\n    var timeSampleCount = NUM_TIMING_SAMPLES - 1;\r\n\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_pvrtc/\r\n    function pvrtc2bppSize(width, height) {\r\n        var width = Math.max(width, 16);\r\n        var height = Math.max(height, 8);\r\n\r\n        return width * height / 4;\r\n    }\r\n\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_pvrtc/\r\n    function pvrtc4bppSize(width, height) {\r\n        var width = Math.max(width, 8);\r\n        var height = Math.max(height, 8);\r\n\r\n        return width * height / 2;\r\n    }\r\n\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc/\r\n    // Size for: \r\n    // COMPRESSED_RGB_S3TC_DXT1_EXT\r\n    // COMPRESSED_R11_EAC\r\n    // COMPRESSED_SIGNED_R11_EAC\r\n    // COMPRESSED_RGB8_ETC2\r\n    // COMPRESSED_SRGB8_ETC2\r\n    // COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2\r\n    // COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2\r\n    function dxtEtcSmallSize(width, height) {\r\n        return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 8;\r\n    }\r\n\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc/\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/\r\n    // Size for: \r\n    // COMPRESSED_RGBA_S3TC_DXT3_EXT\r\n    // COMPRESSED_RGBA_S3TC_DXT5_EXT\r\n    // COMPRESSED_RG11_EAC\r\n    // COMPRESSED_SIGNED_RG11_EAC\r\n    // COMPRESSED_RGBA8_ETC2_EAC\r\n    // COMPRESSED_SRGB8_ALPHA8_ETC2_EAC\r\n    // COMPRESSED_RGBA_ASTC_4x4_KHR\r\n    function dxtEtcAstcBigSize(width, height) {\r\n        return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 16;\r\n    }\r\n\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/\r\n    function atc5x4Size(width, height) {\r\n        return Math.floor((width + 4) / 5) * Math.floor((height + 3) / 4) * 16;\r\n    }\r\n\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/\r\n    function atc5x5Size(width, height) {\r\n        return Math.floor((width + 4) / 5) * Math.floor((height + 4) / 5) * 16;\r\n    }\r\n\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/\r\n    function atc6x5Size(width, height) {\r\n        return Math.floor((width + 5) / 6) * Math.floor((height + 4) / 5) * 16;\r\n    }\r\n\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/\r\n    function atc6x6Size(width, height) {\r\n        return Math.floor((width + 5) / 6) * Math.floor((height + 5) / 6) * 16;\r\n    }\r\n\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/\r\n    function atc8x5Size(width, height) {\r\n        return Math.floor((width + 7) / 8) * Math.floor((height + 4) / 5) * 16;\r\n    }\r\n\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/\r\n    function atc8x6Size(width, height) {\r\n        return Math.floor((width + 7) / 8) * Math.floor((height + 5) / 6) * 16;\r\n    }\r\n\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/\r\n    function atc8x8Size(width, height) {\r\n        return Math.floor((width + 7) / 8) * Math.floor((height + 7) / 8) * 16;\r\n    }\r\n\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/\r\n    function atc10x5Size(width, height) {\r\n        return Math.floor((width + 9) / 10) * Math.floor((height + 4) / 5) * 16;\r\n    }\r\n\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/\r\n    function atc10x6Size(width, height) {\r\n        return Math.floor((width + 9) / 10) * Math.floor((height + 5) / 6) * 16;\r\n    }\r\n\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/\r\n    function atc10x8Size(width, height) {\r\n        return Math.floor((width + 9) / 10) * Math.floor((height + 7) / 8) * 16;\r\n    }\r\n\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/\r\n    function atc10x10Size(width, height) {\r\n        return Math.floor((width + 9) / 10) * Math.floor((height + 9) / 10) * 16;\r\n    }\r\n\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/\r\n    function atc12x10Size(width, height) {\r\n        return Math.floor((width + 11) / 12) * Math.floor((height + 9) / 10) * 16;\r\n    }\r\n\r\n    // https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/\r\n    function atc12x12Size(width, height) {\r\n        return Math.floor((width + 11) / 12) * Math.floor((height + 11) / 12) * 16;\r\n    }\r\n\r\n    var PVR_CONSTANTS = {\r\n        MAGIC_NUMBER: 0x03525650,\r\n        HEADER_LENGTH: 13,\r\n        HEADER_SIZE: 52,\r\n        MAGIC_NUMBER_INDEX: 0,\r\n        PIXEL_FORMAT_INDEX: 2,\r\n        HEIGHT_INDEX: 6,\r\n        WIDTH_INDEX: 7,\r\n        MIPMAPCOUNT_INDEX: 11,\r\n        METADATA_SIZE_INDEX: 12,\r\n        FORMATS: {\r\n            0: \"COMPRESSED_RGB_PVRTC_2BPPV1_IMG\",\r\n            1: \"COMPRESSED_RGBA_PVRTC_2BPPV1_IMG\",\r\n            2: \"COMPRESSED_RGB_PVRTC_4BPPV1_IMG\",\r\n            3: \"COMPRESSED_RGBA_PVRTC_4BPPV1_IMG\",\r\n            6: \"COMPRESSED_RGB8_ETC2\",\r\n            7: \"COMPRESSED_RGB_S3TC_DXT1_EXT\",\r\n            9: \"COMPRESSED_RGBA_S3TC_DXT3_EXT\",\r\n            11: \"COMPRESSED_RGBA_S3TC_DXT5_EXT\",\r\n            22: \"COMPRESSED_RGB8_ETC2\",\r\n            23: \"COMPRESSED_RGBA8_ETC2_EAC\",\r\n            24: \"COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2\",\r\n            25: \"COMPRESSED_R11_EAC\",\r\n            26: \"COMPRESSED_RG11_EAC\",\r\n            27: \"COMPRESSED_RGBA_ASTC_4x4_KHR\",\r\n            28: \"COMPRESSED_RGBA_ASTC_5x4_KHR\",\r\n            29: \"COMPRESSED_RGBA_ASTC_5x5_KHR\",\r\n            30: \"COMPRESSED_RGBA_ASTC_6x5_KHR\",\r\n            31: \"COMPRESSED_RGBA_ASTC_6x6_KHR\",\r\n            32: \"COMPRESSED_RGBA_ASTC_8x5_KHR\",\r\n            33: \"COMPRESSED_RGBA_ASTC_8x6_KHR\",\r\n            34: \"COMPRESSED_RGBA_ASTC_8x8_KHR\",\r\n            35: \"COMPRESSED_RGBA_ASTC_10x5_KHR\",\r\n            36: \"COMPRESSED_RGBA_ASTC_10x6_KHR\",\r\n            37: \"COMPRESSED_RGBA_ASTC_10x8_KHR\",\r\n            38: \"COMPRESSED_RGBA_ASTC_10x10_KHR\",\r\n            39: \"COMPRESSED_RGBA_ASTC_12x10_KHR\",\r\n            40: \"COMPRESSED_RGBA_ASTC_12x12_KHR\"\r\n        },\r\n        SIZE_FUNCTIONS: {\r\n            0: pvrtc2bppSize,\r\n            1: pvrtc2bppSize,\r\n            2: pvrtc4bppSize,\r\n            3: pvrtc4bppSize,\r\n            6: dxtEtcSmallSize,\r\n            7: dxtEtcSmallSize,\r\n            9: dxtEtcAstcBigSize,\r\n            11: dxtEtcAstcBigSize,\r\n            22: dxtEtcSmallSize,\r\n            23: dxtEtcAstcBigSize,\r\n            24: dxtEtcSmallSize,\r\n            25: dxtEtcSmallSize,\r\n            26: dxtEtcAstcBigSize,\r\n            27: dxtEtcAstcBigSize,\r\n            28: atc5x4Size,\r\n            29: atc5x5Size,\r\n            30: atc6x5Size,\r\n            31: atc6x6Size,\r\n            32: atc8x5Size,\r\n            33: atc8x6Size,\r\n            34: atc8x8Size,\r\n            35: atc10x5Size,\r\n            36: atc10x6Size,\r\n            37: atc10x8Size,\r\n            38: atc10x10Size,\r\n            39: atc12x10Size,\r\n            40: atc12x12Size\r\n        }\r\n    };\r\n\r\n    window.utils = {\r\n        testWebGL2: function() {\r\n            return !!dummyGL;\r\n        },\r\n        testExtension: function(ext) {\r\n            return !!dummyGL.getExtension(ext);\r\n        },\r\n        xformMatrix: function xformMatrix(xform, translate, rotate, scale) {\r\n            translate = translate || zeros;\r\n            rotate = rotate || zeros;\r\n            scale = scale || ones;\r\n\r\n            mat4.fromTranslation(translateMat, translate);\r\n            mat4.fromXRotation(rotateXMat, rotate[0]);\r\n            mat4.fromYRotation(rotateYMat, rotate[1]);\r\n            mat4.fromZRotation(rotateZMat, rotate[2]);\r\n            mat4.fromScaling(scaleMat, scale);\r\n\r\n            mat4.multiply(xform, rotateXMat, scaleMat);\r\n            mat4.multiply(xform, rotateYMat, xform);\r\n            mat4.multiply(xform, rotateZMat, xform);\r\n            mat4.multiply(xform, translateMat, xform);\r\n        },\r\n\r\n        loadCubemapImages: function loadCubeMapImages(urls, ok) {\r\n            var numImages = 6;\r\n          \r\n            var negX = new Image();\r\n            var posX = new Image();\r\n            var negY = new Image();\r\n            var posY = new Image();\r\n            var negZ = new Image();\r\n            var posZ = new Image();\r\n\r\n            function onload() {\r\n                if (--numImages === 0) {\r\n                    ok(negX, posX, negY, posY, negZ, posZ);\r\n                }\r\n            }\r\n\r\n            negX.onload = onload;\r\n            posX.onload = onload;\r\n            negY.onload = onload;\r\n            posY.onload = onload;\r\n            negZ.onload = onload;\r\n            posZ.onload = onload;\r\n\r\n            negX.src = urls.negX;\r\n            posX.src = urls.posX;\r\n            negY.src = urls.negY;\r\n            posY.src = urls.posY;\r\n            negZ.src = urls.negZ;\r\n            posZ.src = urls.posZ;\r\n        },\r\n\r\n        createBox: function createBox(options) {\r\n            options = options || {};\r\n\r\n            var dimensions = options.dimensions || [1, 1, 1];\r\n            var position = options.position || [-dimensions[0] / 2, -dimensions[1] / 2, -dimensions[2] / 2];\r\n            var x = position[0];\r\n            var y = position[1];\r\n            var z = position[2];\r\n            var width = dimensions[0];\r\n            var height = dimensions[1];\r\n            var depth = dimensions[2];\r\n\r\n            var fbl = {x: x,         y: y,          z: z + depth};\r\n            var fbr = {x: x + width, y: y,          z: z + depth};\r\n            var ftl = {x: x,         y: y + height, z: z + depth};\r\n            var ftr = {x: x + width, y: y + height, z: z + depth};\r\n            var bbl = {x: x,         y: y,          z: z };\r\n            var bbr = {x: x + width, y: y,          z: z };\r\n            var btl = {x: x,         y: y + height, z: z };\r\n            var btr = {x: x + width, y: y + height, z: z };\r\n\r\n            var positions = new Float32Array([\r\n                //front\r\n                fbl.x, fbl.y, fbl.z,\r\n                fbr.x, fbr.y, fbr.z,\r\n                ftl.x, ftl.y, ftl.z,\r\n                ftl.x, ftl.y, ftl.z,\r\n                fbr.x, fbr.y, fbr.z,\r\n                ftr.x, ftr.y, ftr.z,\r\n\r\n                //right\r\n                fbr.x, fbr.y, fbr.z,\r\n                bbr.x, bbr.y, bbr.z,\r\n                ftr.x, ftr.y, ftr.z,\r\n                ftr.x, ftr.y, ftr.z,\r\n                bbr.x, bbr.y, bbr.z,\r\n                btr.x, btr.y, btr.z,\r\n\r\n                //back\r\n                fbr.x, bbr.y, bbr.z,\r\n                bbl.x, bbl.y, bbl.z,\r\n                btr.x, btr.y, btr.z,\r\n                btr.x, btr.y, btr.z,\r\n                bbl.x, bbl.y, bbl.z,\r\n                btl.x, btl.y, btl.z,\r\n\r\n                //left\r\n                bbl.x, bbl.y, bbl.z,\r\n                fbl.x, fbl.y, fbl.z,\r\n                btl.x, btl.y, btl.z,\r\n                btl.x, btl.y, btl.z,\r\n                fbl.x, fbl.y, fbl.z,\r\n                ftl.x, ftl.y, ftl.z,\r\n\r\n                //top\r\n                ftl.x, ftl.y, ftl.z,\r\n                ftr.x, ftr.y, ftr.z,\r\n                btl.x, btl.y, btl.z,\r\n                btl.x, btl.y, btl.z,\r\n                ftr.x, ftr.y, ftr.z,\r\n                btr.x, btr.y, btr.z,\r\n\r\n                //bottom\r\n                bbl.x, bbl.y, bbl.z,\r\n                bbr.x, bbr.y, bbr.z,\r\n                fbl.x, fbl.y, fbl.z,\r\n                fbl.x, fbl.y, fbl.z,\r\n                bbr.x, bbr.y, bbr.z,\r\n                fbr.x, fbr.y, fbr.z\r\n            ]);\r\n\r\n            var uvs = new Float32Array([\r\n                //front\r\n                0, 0,\r\n                1, 0,\r\n                0, 1,\r\n                0, 1,\r\n                1, 0,\r\n                1, 1,\r\n\r\n                //right\r\n                0, 0,\r\n                1, 0,\r\n                0, 1,\r\n                0, 1,\r\n                1, 0,\r\n                1, 1,\r\n\r\n                //back\r\n                0, 0,\r\n                1, 0,\r\n                0, 1,\r\n                0, 1,\r\n                1, 0,\r\n                1, 1,\r\n\r\n                //left\r\n                0, 0,\r\n                1, 0,\r\n                0, 1,\r\n                0, 1,\r\n                1, 0,\r\n                1, 1,\r\n\r\n                //top\r\n                0, 0,\r\n                1, 0,\r\n                0, 1,\r\n                0, 1,\r\n                1, 0,\r\n                1, 1,\r\n\r\n                //bottom\r\n                0, 0,\r\n                1, 0,\r\n                0, 1,\r\n                0, 1,\r\n                1, 0,\r\n                1, 1\r\n            ]);\r\n\r\n            var normals = new Float32Array([\r\n                // front\r\n                0, 0, 1, \r\n                0, 0, 1, \r\n                0, 0, 1, \r\n                0, 0, 1, \r\n                0, 0, 1, \r\n                0, 0, 1,\r\n\r\n                // right\r\n                1, 0, 0, \r\n                1, 0, 0, \r\n                1, 0, 0, \r\n                1, 0, 0, \r\n                1, 0, 0, \r\n                1, 0, 0,\r\n\r\n                // back \r\n                0, 0, -1, \r\n                0, 0, -1, \r\n                0, 0, -1, \r\n                0, 0, -1, \r\n                0, 0, -1, \r\n                0, 0, -1, \r\n\r\n                // left\r\n                -1, 0, 0, \r\n                -1, 0, 0, \r\n                -1, 0, 0, \r\n                -1, 0, 0, \r\n                -1, 0, 0, \r\n                -1, 0, 0,\r\n\r\n                // top \r\n                0, 1, 0, \r\n                0, 1, 0, \r\n                0, 1, 0, \r\n                0, 1, 0, \r\n                0, 1, 0, \r\n                0, 1, 0,\r\n\r\n                // bottom\r\n                0, -1, 0, \r\n                0, -1, 0, \r\n                0, -1, 0, \r\n                0, -1, 0, \r\n                0, -1, 0, \r\n                0, -1, 0\r\n            ]);\r\n\r\n            return {\r\n                positions: positions,\r\n                normals: normals,\r\n                uvs: uvs\r\n            };\r\n\r\n        },\r\n\r\n        createSphere: function createSphere(options) {\r\n            options = options || {};\r\n\r\n            var longBands = options.longBands || 32;\r\n            var latBands = options.latBands || 32;\r\n            var radius = options.radius || 1;\r\n            var lat_step = Math.PI / latBands;\r\n            var long_step = 2 * Math.PI / longBands;\r\n            var num_positions = longBands * latBands * 4;\r\n            var num_indices = longBands * latBands * 6;\r\n            var lat_angle, long_angle;\r\n            var positions = new Float32Array(num_positions * 3);\r\n            var normals = new Float32Array(num_positions * 3);\r\n            var uvs = new Float32Array(num_positions * 2);\r\n            var indices = new Uint16Array(num_indices);\r\n            var x1, x2, x3, x4,\r\n                y1, y2,\r\n                z1, z2, z3, z4,\r\n                u1, u2,\r\n                v1, v2;\r\n            var i, j;\r\n            var k = 0, l = 0;\r\n            var vi, ti;\r\n\r\n            for (i = 0; i < latBands; i++) {\r\n                lat_angle = i * lat_step;\r\n                y1 = Math.cos(lat_angle);\r\n                y2 = Math.cos(lat_angle + lat_step);\r\n                for (j = 0; j < longBands; j++) {\r\n                    long_angle = j * long_step;\r\n                    x1 = Math.sin(lat_angle) * Math.cos(long_angle);\r\n                    x2 = Math.sin(lat_angle) * Math.cos(long_angle + long_step);\r\n                    x3 = Math.sin(lat_angle + lat_step) * Math.cos(long_angle);\r\n                    x4 = Math.sin(lat_angle + lat_step) * Math.cos(long_angle + long_step);\r\n                    z1 = Math.sin(lat_angle) * Math.sin(long_angle);\r\n                    z2 = Math.sin(lat_angle) * Math.sin(long_angle + long_step);\r\n                    z3 = Math.sin(lat_angle + lat_step) * Math.sin(long_angle);\r\n                    z4 = Math.sin(lat_angle + lat_step) * Math.sin(long_angle + long_step);\r\n                    u1 = 1 - j / longBands;\r\n                    u2 = 1 - (j + 1) / longBands;\r\n                    v1 = 1 - i / latBands;\r\n                    v2 = 1 - (i + 1) / latBands;\r\n                    vi = k * 3;\r\n                    ti = k * 2;\r\n\r\n                    positions[vi] = x1 * radius; \r\n                    positions[vi+1] = y1 * radius; \r\n                    positions[vi+2] = z1 * radius; //v0\r\n\r\n                    positions[vi+3] = x2 * radius; \r\n                    positions[vi+4] = y1 * radius; \r\n                    positions[vi+5] = z2 * radius; //v1\r\n\r\n                    positions[vi+6] = x3 * radius; \r\n                    positions[vi+7] = y2 * radius; \r\n                    positions[vi+8] = z3 * radius; // v2\r\n\r\n\r\n                    positions[vi+9] = x4 * radius; \r\n                    positions[vi+10] = y2 * radius; \r\n                    positions[vi+11] = z4 * radius; // v3\r\n\r\n                    normals[vi] = x1;\r\n                    normals[vi+1] = y1; \r\n                    normals[vi+2] = z1;\r\n\r\n                    normals[vi+3] = x2;\r\n                    normals[vi+4] = y1; \r\n                    normals[vi+5] = z2;\r\n\r\n                    normals[vi+6] = x3;\r\n                    normals[vi+7] = y2; \r\n                    normals[vi+8] = z3;\r\n\r\n                    normals[vi+9] = x4;\r\n                    normals[vi+10] = y2; \r\n                    normals[vi+11] = z4;\r\n\r\n                    uvs[ti] = u1; \r\n                    uvs[ti+1] = v1; \r\n\r\n                    uvs[ti+2] = u2; \r\n                    uvs[ti+3] = v1;\r\n\r\n                    uvs[ti+4] = u1;\r\n                    uvs[ti+5] = v2; \r\n\r\n                    uvs[ti+6] = u2;\r\n                    uvs[ti+7] = v2;\r\n\r\n                    indices[l    ] = k;\r\n                    indices[l + 1] = k + 1;\r\n                    indices[l + 2] = k + 2;\r\n                    indices[l + 3] = k + 2;\r\n                    indices[l + 4] = k + 1;\r\n                    indices[l + 5] = k + 3;\r\n\r\n                    k += 4;\r\n                    l += 6;\r\n                }\r\n            }\r\n\r\n            return {\r\n                positions: positions,\r\n                normals: normals,\r\n                uvs: uvs,\r\n                indices: indices\r\n            };\r\n        },\r\n\r\n        computeBoundingBox: function (position, options) {\r\n            options = options || {};\r\n            var buildGeometry = options.buildGeometry || false;\r\n\r\n            var boundary = {\r\n                min: vec3.create(),\r\n                max: vec3.create()\r\n            };\r\n            vec3.set(boundary.min, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY);\r\n            vec3.set(boundary.max, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY);\r\n            for (var i = 0, len = position.length; i < len; i += 3) {\r\n                boundary.min[0] = Math.min(position[i], boundary.min[0]);\r\n                boundary.max[0] = Math.max(position[i], boundary.max[0]);\r\n                boundary.min[1] = Math.min(position[i + 1], boundary.min[1]);\r\n                boundary.max[1] = Math.max(position[i + 1], boundary.max[1]);\r\n                boundary.min[2] = Math.min(position[i + 2], boundary.min[2]);\r\n                boundary.max[2] = Math.max(position[i + 2], boundary.max[2]);\r\n            }\r\n\r\n            if (buildGeometry) {\r\n                var size = vec3.create();\r\n                vec3.subtract(size, boundary.max, boundary.min);\r\n                boundary.geometry = utils.createBox({\r\n                    position: boundary.min,\r\n                    dimensions: size\r\n                });\r\n            }\r\n\r\n            return boundary;\r\n        },\r\n\r\n        addTimerElement: function() {\r\n            this.timerDiv = document.createElement(\"div\")\r\n            this.timerDiv.id = \"timer\";\r\n            this.cpuTimeElement = document.createElement(\"div\");\r\n            this.gpuTimeElement = document.createElement(\"div\");\r\n            this.timerDiv.appendChild(this.cpuTimeElement);\r\n            this.timerDiv.appendChild(this.gpuTimeElement);\r\n            document.body.appendChild(this.timerDiv);\r\n        },\r\n\r\n        updateTimerElement: function(cpuTime, gpuTime) {\r\n            cpuTimeSum += cpuTime;\r\n            gpuTimeSum += gpuTime;\r\n            ++timeSampleCount;\r\n\r\n            if (timeSampleCount === NUM_TIMING_SAMPLES) {\r\n                var cpuTimeAve = cpuTimeSum / NUM_TIMING_SAMPLES;\r\n                var gpuTimeAve = gpuTimeSum / NUM_TIMING_SAMPLES;\r\n                this.cpuTimeElement.innerText = \"CPU time: \" + cpuTimeAve.toFixed(3) + \"ms\";\r\n                if (gpuTimeAve > 0) {\r\n                    this.gpuTimeElement.innerText = \"GPU time: \" + gpuTimeAve.toFixed(3) + \"ms\";\r\n                } else {\r\n                    this.gpuTimeElement.innerText = \"GPU time: (Unavailable)\";\r\n                }\r\n\r\n                cpuTimeSum = 0;\r\n                gpuTimeSum = 0;\r\n                timeSampleCount = 0;\r\n            }\r\n        },\r\n\r\n        getBinary: function(url, ok) {\r\n            var xhr = new XMLHttpRequest();\r\n            xhr.open(\"GET\", url);\r\n            xhr.responseType = \"arraybuffer\";\r\n\r\n            xhr.onload = function() {\r\n                ok(xhr.response);\r\n            };\r\n\r\n            xhr.send(null);\r\n        },\r\n\r\n        // http://cdn.imgtec.com/sdk-documentation/PVR+File+Format.Specification.pdf\r\n        parsePVR: function(data) {\r\n            var header = new Uint32Array(data, 0, PVR_CONSTANTS.HEADER_LENGTH);\r\n\r\n            var pvrFormat = header[PVR_CONSTANTS.PIXEL_FORMAT_INDEX]\r\n\r\n            var formatEnum = PVR_CONSTANTS.FORMATS[pvrFormat];\r\n            var sizeFunction = PVR_CONSTANTS.SIZE_FUNCTIONS[pvrFormat];\r\n\r\n            var mipMapLevels = header[PVR_CONSTANTS.MIPMAPCOUNT_INDEX];\r\n\r\n            var width = header[PVR_CONSTANTS.WIDTH_INDEX];\r\n            var height = header[PVR_CONSTANTS.HEIGHT_INDEX];\r\n\r\n            var dataOffset = PVR_CONSTANTS.HEADER_SIZE + header[PVR_CONSTANTS.METADATA_SIZE_INDEX];\r\n\r\n            var data = new Uint8Array(data, dataOffset);\r\n\r\n            var levels = new Array(mipMapLevels);\r\n            var levelWidth = width;\r\n            var levelHeight = height;\r\n            var offset = 0;\r\n\r\n            for (var i = 0; i < mipMapLevels; ++i) {\r\n                var levelSize = sizeFunction(levelWidth, levelHeight);\r\n                levels[i] = new Uint8Array(data.buffer, data.byteOffset + offset, levelSize);\r\n\r\n                levelWidth = Math.max(1, levelWidth >> 1);\r\n                levelHeight = Math.max(1, levelHeight >> 1);\r\n\r\n                offset += levelSize;\r\n            }\r\n\r\n            return {\r\n                data: levels,\r\n                width: width,\r\n                height: height,\r\n                format: formatEnum\r\n            }\r\n        }\r\n    }\r\n\r\n})();\r\n"
  },
  {
    "path": "nn/using-deeplab/README.md",
    "content": "## DeepLabV3+ segmentation in TensorFlow.js\n\nIn the [previous work](https://01.org/blogs/astojilj/2018/background-removal-intel-realsense-depth-camera-webrtc-and-webgl), I used a Intel® RealSense™ Depth Camera with the Chrome* Web browser to implement [a working prototype](https://01.org/sites/default/files/users/u58404/bg-removal-1.gif).<br /> Here, instead of using a depth camera, I use a standard web camera, TensorFlow.js and DeepLab3+ MobileNetV2 model downloaded from exported to lower resolution and converted to TensorFlow.js web friendly format. For beginners, [the article here is a good introduction](https://01.org/blogs/astojilj/2018/background-removal-tensorflow.js) to tools and the model.\n\nThis is not a background removal demo, yet - it doesn't handle border area processing, like it is done in [depth camera demo](https://01.org/sites/default/files/users/u58404/bg-removal-1.gif), nor it includes [all the planned optimizations](https://01.org/blogs/astojilj/2018/background-removal-tensorflow.js). In addition to use previous mask as input to speedup the inference the plan is to utilize also depth camera input, when available.\n\nThis code is used for benchmarking TensorFlow.js implementation. TensorFlow.js tfjs-core code included here is built from pull requests [#1448 Packed batch<->space ND](https://github.com/tensorflow/tfjs-core/pull/1448) and [#1423 Packed arithmetics](https://github.com/tensorflow/tfjs-core/pull/1423) applied to master at [a71700b](https://github.com/tensorflow/tfjs-core/commit/a71700bedf5a65b79203a88523e4c27d3e9b9ae8).\n\nRun **live** benchmark on your device [by following the link](https://01org.github.io/depth-camera-web-demo/nn/using-deeplab/index.html).\n\n## Benchmark results\n\nBenchmark runs inference and dataSync() to read back data from GPU on every frame and displays last 20 frames average for both as *total(inference + dataSync)ms* per frame.<br />\n\nThe measurements show that packing operations, when using GL_FLOAT output (*packing* here means 2x2 pixel block from GL_R32F texture gets encoded as 1 pixel in GL_RGBA32F texture) don't show significant improvement.<br />\n\nOn the other hand, when forcing GL_HALF_FLOAT (`WEBGL_RENDER_FLOAT32_ENABLED:false,WEBGL_VERSION:1`) use, not only that unpacked operations are faster, but there is a significant improvement of half float packed operations compared to half float unpacked operations mode.\n\n**Devices:**<br />\n**1.** [MacBook Pro (Retina, 15-inch, Mid 2014) with integrated card](https://support.apple.com/kb/sp704?locale=en_US) using model and input of resolution 257 x 257.<br />\n**2.** [Lenovo Phab 2 Pro, Android](https://www.lenovo.com/gb/en/smart-devices/smartphones-and-watches/lenovo/phab-series/Lenovo-PB2-690M/p/ZZITZTPPB4M) using model and input of resolution 225 x 225.\n\n<table cellspacing=\"0\" cellpadding=\"0\" style=\"border-collapse: collapse; border: none;\">\n<tr>\n<td align=\"center\" width=\"150\" valign=\"center\">\n  Device:\n</td>\n<td align=\"center\" width=\"200\" valign=\"center\">\n   Half float, WebGL 1.0 + Packed ops\n</td>\n<td align=\"center\" width=\"200\" valign=\"center\">\n   Half float, WebGL 1.0\n</td>\n<td align=\"center\" width=\"200\" valign=\"center\">\n   GL_FLOAT + Packed ops\n</td>\n<td align=\"center\" width=\"200\" valign=\"center\">\n   GL_FLOAT (default master)\n</td>\n</tr>\n<tr>\n<td align=\"center\" width=\"150\" valign=\"center\">\n  1. MPB\n  <br /> Input: 257 x 257\n</td>\n<td align=\"center\" width=\"200\" valign=\"center\">\n   125ms\n</td>\n<td align=\"center\" width=\"200\" valign=\"center\">\n   170ms\n</td>\n<td align=\"center\" width=\"200\" valign=\"center\">\n   190ms\n</td>\n<td align=\"center\" width=\"200\" valign=\"center\">\n   195ms\n</td>\n</tr>\n<tr>\n<td align=\"center\" width=\"150\" valign=\"center\">\n  2. Lenovo Phab 2 Pro<br />Input: 225 x 225\n</td>\n<td align=\"center\" width=\"200\" valign=\"center\">\n   560ms\n</td>\n<td align=\"center\" width=\"200\" valign=\"center\">\n   640ms\n</td>\n<td align=\"center\" width=\"200\" valign=\"center\">\n   680ms\n</td>\n<td align=\"center\" width=\"200\" valign=\"center\">\n   660ms\n</td>\n</tr>\n</table>\n\n\n## Converting DeepLab model to TensorFlow.js friendly format with lower resolution\n\nOriginal DeepLabV3+ MobileNetV2 [checkpoints at TensorFlow models repo](https://github.com/tensorflow/models/blob/master/research/deeplab/g3doc/model_zoo.md) are supporting 513x513 input. The example shows that we can use this, higher precision (and higher memory bandwidth) implementation, on [high end laptop GPU](https://01.org/blogs/astojilj/2018/background-removal-tensorflow.js). Lower resolution input model, e.g. 257x257, is used here for benchmarking because it performs significantly better, but still quite slow, on mid range laptop GPUs and mobile.\n\nThe simplest way to export the low res variant of original frozen model is to clone [TensorFlow/models](https://github.com/tensorflow/models) repository. Then, modify DeepLab test script like below and run ```sh local_test_mobilenetv2.sh```.\n\n```\n--- a/research/deeplab/local_test_mobilenetv2.sh\n+++ b/research/deeplab/local_test_mobilenetv2.sh\n@@ -124,8 +124,8 @@ python \"${WORK_DIR}\"/export_model.py \\\n   --export_path=\"${EXPORT_PATH}\" \\\n   --model_variant=\"mobilenet_v2\" \\\n   --num_classes=21 \\\n-  --crop_size=513 \\\n-  --crop_size=513 \\\n+  --crop_size=257 \\\n+  --crop_size=257 \\\n   --inference_scales=1.0\n```\n\nThis generates frozen_inference_graph.pb. After this, I used transform_graph tool to replace batch normalizations with add operations (biasAdd) followed by tensorflowjs_converter, to export to TensorFlow.js web friendly model.\n\n```\nbazel-bin/tensorflow/tools/graph_transforms/transform_graph --in_graph=frozen_inference_graph.pb --out_graph=frozen_inference_graph_257_1.pb --inputs='ImageTensor' --outputs='ArgMax' --transforms='strip_unused_nodes(type=float, shape=\"1,257,257,3\") fold_constants(ignore_errors=true) fold_batch_norms fold_old_batch_norms'\n\nbazel-bin/tensorflow/tools/graph_transforms/transform_graph --in_graph=frozen_inference_graph_257_1.pb --out_graph=frozen_inference_graph_257_2.pb --inputs='ImageTensor' --outputs='ArgMax' --transforms='strip_unused_nodes(type=float, shape=\"1,257,257,3\") fold_constants(ignore_errors=true) fold_batch_norms fold_old_batch_norms'\n\ntensorflowjs_converter --input_format=tf_frozen_model --output_node_names=\"ArgMax\" --saved_model_tags=serve ./frozen_inference_graph_257_2.pb  argmax257_2\n```\n\n\n## References\n\n**DeepLab: Semantic Image Segmentation with Deep Convolutional Nets,**\n    **Atrous Convolution, and Fully Connected CRFs** <br />\n    Liang-Chieh Chen+, George Papandreou+, Iasonas Kokkinos, Kevin Murphy, and Alan L Yuille (+ equal\n    contribution). <br />\n    [[link]](http://arxiv.org/abs/1606.00915). TPAMI 2017.\n \n **MobileNetV2: Inverted Residuals and Linear Bottlenecks**<br />\n    Mark Sandler, Andrew Howard, Menglong Zhu, Andrey Zhmoginov, Liang-Chieh Chen<br />\n    [[link]](https://arxiv.org/abs/1801.04381). In CVPR, 2018.\n"
  },
  {
    "path": "nn/using-deeplab/argmax257_2/LICENSE",
    "content": "Copyright 2016 The TensorFlow Authors.  All rights reserved.\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2016, The Authors.\n\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"
  },
  {
    "path": "nn/using-deeplab/argmax257_2/weights_manifest.json",
    "content": "[{\"paths\": [\"group1-shard1of2\", \"group1-shard2of2\"], \"weights\": [{\"name\": \"image_pooling/weights/read/_271__cf__271\", \"shape\": [1, 1, 320, 256], \"dtype\": \"float32\"}, {\"name\": \"image_pooling/Conv2D_bn_offset\", \"shape\": [256], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_15/expand/weights/read/_115__cf__115\", \"shape\": [1, 1, 160, 960], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_15/expand/Conv2D_bn_offset\", \"shape\": [960], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_15/depthwise/depthwise_weights/read/_110__cf__110\", \"shape\": [3, 3, 960, 1], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_15/depthwise/depthwise_bn_offset\", \"shape\": [960], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_15/project/weights/read/_120__cf__120\", \"shape\": [1, 1, 960, 160], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_15/project/Conv2D_bn_offset\", \"shape\": [160], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_14/expand/weights/read/_100__cf__100\", \"shape\": [1, 1, 160, 960], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_14/expand/Conv2D_bn_offset\", \"shape\": [960], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_14/depthwise/depthwise_weights/read/_95__cf__95\", \"shape\": [3, 3, 960, 1], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_14/depthwise/depthwise_bn_offset\", \"shape\": [960], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_14/project/weights/read/_105__cf__105\", \"shape\": [1, 1, 960, 160], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_14/project/Conv2D_bn_offset\", \"shape\": [160], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_12/expand/weights/read/_70__cf__70\", \"shape\": [1, 1, 96, 576], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_12/expand/Conv2D_bn_offset\", \"shape\": [576], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_12/depthwise/depthwise_weights/read/_65__cf__65\", \"shape\": [3, 3, 576, 1], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_12/depthwise/depthwise_bn_offset\", \"shape\": [576], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_12/project/weights/read/_75__cf__75\", \"shape\": [1, 1, 576, 96], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_12/project/Conv2D_bn_offset\", \"shape\": [96], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_11/expand/weights/read/_55__cf__55\", \"shape\": [1, 1, 96, 576], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_11/expand/Conv2D_bn_offset\", \"shape\": [576], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_11/depthwise/depthwise_weights/read/_50__cf__50\", \"shape\": [3, 3, 576, 1], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_11/depthwise/depthwise_bn_offset\", \"shape\": [576], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_11/project/weights/read/_60__cf__60\", \"shape\": [1, 1, 576, 96], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_11/project/Conv2D_bn_offset\", \"shape\": [96], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_9/expand/weights/read/_250__cf__250\", \"shape\": [1, 1, 64, 384], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_9/expand/Conv2D_bn_offset\", \"shape\": [384], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_9/depthwise/depthwise_weights/read/_245__cf__245\", \"shape\": [3, 3, 384, 1], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_9/depthwise/depthwise_bn_offset\", \"shape\": [384], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_9/project/weights/read/_255__cf__255\", \"shape\": [1, 1, 384, 64], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_9/project/Conv2D_bn_offset\", \"shape\": [64], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_8/expand/weights/read/_235__cf__235\", \"shape\": [1, 1, 64, 384], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_8/expand/Conv2D_bn_offset\", \"shape\": [384], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_8/depthwise/depthwise_weights/read/_230__cf__230\", \"shape\": [3, 3, 384, 1], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_8/depthwise/depthwise_bn_offset\", \"shape\": [384], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_8/project/weights/read/_240__cf__240\", \"shape\": [1, 1, 384, 64], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_8/project/Conv2D_bn_offset\", \"shape\": [64], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_7/expand/weights/read/_220__cf__220\", \"shape\": [1, 1, 64, 384], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_7/expand/Conv2D_bn_offset\", \"shape\": [384], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_7/depthwise/depthwise_weights/read/_215__cf__215\", \"shape\": [3, 3, 384, 1], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_7/depthwise/depthwise_bn_offset\", \"shape\": [384], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_7/project/weights/read/_225__cf__225\", \"shape\": [1, 1, 384, 64], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_7/project/Conv2D_bn_offset\", \"shape\": [64], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_5/expand/weights/read/_190__cf__190\", \"shape\": [1, 1, 32, 192], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_5/expand/Conv2D_bn_offset\", \"shape\": [192], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_5/depthwise/depthwise_weights/read/_185__cf__185\", \"shape\": [3, 3, 192, 1], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_5/depthwise/depthwise_bn_offset\", \"shape\": [192], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_5/project/weights/read/_195__cf__195\", \"shape\": [1, 1, 192, 32], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_5/project/Conv2D_bn_offset\", \"shape\": [32], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_4/expand/weights/read/_175__cf__175\", \"shape\": [1, 1, 32, 192], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_4/expand/Conv2D_bn_offset\", \"shape\": [192], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_4/depthwise/depthwise_weights/read/_170__cf__170\", \"shape\": [3, 3, 192, 1], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_4/depthwise/depthwise_bn_offset\", \"shape\": [192], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_4/project/weights/read/_180__cf__180\", \"shape\": [1, 1, 192, 32], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_4/project/Conv2D_bn_offset\", \"shape\": [32], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_2/expand/weights/read/_145__cf__145\", \"shape\": [1, 1, 24, 144], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_2/expand/Conv2D_bn_offset\", \"shape\": [144], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_2/depthwise/depthwise_weights/read/_140__cf__140\", \"shape\": [3, 3, 144, 1], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_2/depthwise/depthwise_bn_offset\", \"shape\": [144], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_2/project/weights/read/_150__cf__150\", \"shape\": [1, 1, 144, 24], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_2/project/Conv2D_bn_offset\", \"shape\": [24], \"dtype\": \"float32\"}, {\"name\": \"mul/x\", \"shape\": [], \"dtype\": \"float32\"}, {\"name\": \"strided_slice_1/stack\", \"shape\": [1], \"dtype\": \"int32\"}, {\"name\": \"sub_1/x\", \"shape\": [], \"dtype\": \"int32\"}, {\"name\": \"strided_slice_2/stack_1\", \"shape\": [1], \"dtype\": \"int32\"}, {\"name\": \"strided_slice_2/stack\", \"shape\": [1], \"dtype\": \"int32\"}, {\"name\": \"stack_2\", \"shape\": [2], \"dtype\": \"int32\"}, {\"name\": \"Reshape/_256__cf__256\", \"shape\": [1, 1, 3], \"dtype\": \"float32\"}, {\"name\": \"stack/0\", \"shape\": [], \"dtype\": \"int32\"}, {\"name\": \"sub_7/y\", \"shape\": [], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/Conv/weights/read/_5__cf__5\", \"shape\": [3, 3, 3, 32], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/Conv/Conv2D_bn_offset\", \"shape\": [32], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv/depthwise/depthwise_weights/read/_10__cf__10\", \"shape\": [3, 3, 32, 1], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv/depthwise/depthwise_bn_offset\", \"shape\": [32], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv/project/weights/read/_15__cf__15\", \"shape\": [1, 1, 32, 16], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv/project/Conv2D_bn_offset\", \"shape\": [16], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_1/expand/weights/read/_25__cf__25\", \"shape\": [1, 1, 16, 96], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_1/expand/Conv2D_bn_offset\", \"shape\": [96], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_1/depthwise/depthwise_weights/read/_20__cf__20\", \"shape\": [3, 3, 96, 1], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_1/depthwise/depthwise_bn_offset\", \"shape\": [96], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_1/project/weights/read/_30__cf__30\", \"shape\": [1, 1, 96, 24], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_1/project/Conv2D_bn_offset\", \"shape\": [24], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_3/expand/weights/read/_160__cf__160\", \"shape\": [1, 1, 24, 144], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_3/expand/Conv2D_bn_offset\", \"shape\": [144], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_3/depthwise/depthwise_weights/read/_155__cf__155\", \"shape\": [3, 3, 144, 1], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_3/depthwise/depthwise_bn_offset\", \"shape\": [144], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_3/project/weights/read/_165__cf__165\", \"shape\": [1, 1, 144, 32], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_3/project/Conv2D_bn_offset\", \"shape\": [32], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_6/expand/weights/read/_205__cf__205\", \"shape\": [1, 1, 32, 192], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_6/expand/Conv2D_bn_offset\", \"shape\": [192], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_6/depthwise/depthwise_weights/read/_200__cf__200\", \"shape\": [3, 3, 192, 1], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_6/depthwise/depthwise_bn_offset\", \"shape\": [192], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_6/project/weights/read/_210__cf__210\", \"shape\": [1, 1, 192, 64], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_6/project/Conv2D_bn_offset\", \"shape\": [64], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_10/expand/weights/read/_40__cf__40\", \"shape\": [1, 1, 64, 384], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_10/expand/Conv2D_bn_offset\", \"shape\": [384], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_10/depthwise/depthwise_weights/read/_35__cf__35\", \"shape\": [3, 3, 384, 1], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_10/depthwise/depthwise_bn_offset\", \"shape\": [384], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_10/project/weights/read/_45__cf__45\", \"shape\": [1, 1, 384, 96], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_10/project/Conv2D_bn_offset\", \"shape\": [96], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_13/expand/weights/read/_85__cf__85\", \"shape\": [1, 1, 96, 576], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_13/expand/Conv2D_bn_offset\", \"shape\": [576], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_12/depthwise/depthwise/SpaceToBatchND/paddings\", \"shape\": [2, 2], \"dtype\": \"int32\"}, {\"name\": \"MobilenetV2/expanded_conv_13/depthwise/depthwise_weights/read/_80__cf__80\", \"shape\": [3, 3, 576, 1], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_13/depthwise/depthwise_bn_offset\", \"shape\": [576], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_12/depthwise/depthwise/SpaceToBatchND/block_shape\", \"shape\": [2], \"dtype\": \"int32\"}, {\"name\": \"MobilenetV2/expanded_conv_12/depthwise/depthwise/BatchToSpaceND/crops\", \"shape\": [2, 2], \"dtype\": \"int32\"}, {\"name\": \"MobilenetV2/expanded_conv_13/project/weights/read/_90__cf__90\", \"shape\": [1, 1, 576, 160], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_13/project/Conv2D_bn_offset\", \"shape\": [160], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_16/expand/weights/read/_130__cf__130\", \"shape\": [1, 1, 160, 960], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_16/expand/Conv2D_bn_offset\", \"shape\": [960], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_15/depthwise/depthwise/SpaceToBatchND/paddings\", \"shape\": [2, 2], \"dtype\": \"int32\"}, {\"name\": \"MobilenetV2/expanded_conv_16/depthwise/depthwise_weights/read/_125__cf__125\", \"shape\": [3, 3, 960, 1], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_16/depthwise/depthwise_bn_offset\", \"shape\": [960], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_15/depthwise/depthwise/SpaceToBatchND/block_shape\", \"shape\": [2], \"dtype\": \"int32\"}, {\"name\": \"MobilenetV2/expanded_conv_15/depthwise/depthwise/BatchToSpaceND/crops\", \"shape\": [2, 2], \"dtype\": \"int32\"}, {\"name\": \"MobilenetV2/expanded_conv_16/project/weights/read/_135__cf__135\", \"shape\": [1, 1, 960, 320], \"dtype\": \"float32\"}, {\"name\": \"MobilenetV2/expanded_conv_16/project/Conv2D_bn_offset\", \"shape\": [320], \"dtype\": \"float32\"}, {\"name\": \"aspp0/weights/read/_261__cf__261\", \"shape\": [1, 1, 320, 256], \"dtype\": \"float32\"}, {\"name\": \"aspp0/Conv2D_bn_offset\", \"shape\": [256], \"dtype\": \"float32\"}, {\"name\": \"concat_projection/weights/read/_266__cf__266\", \"shape\": [1, 1, 512, 256], \"dtype\": \"float32\"}, {\"name\": \"concat_projection/Conv2D_bn_offset\", \"shape\": [256], \"dtype\": \"float32\"}, {\"name\": \"logits/semantic/weights/read/_273__cf__273\", \"shape\": [1, 1, 256, 21], \"dtype\": \"float32\"}, {\"name\": \"logits/semantic/biases/read/_272__cf__272\", \"shape\": [21], \"dtype\": \"float32\"}, {\"name\": \"ResizeBilinear/size\", \"shape\": [2], \"dtype\": \"int32\"}, {\"name\": \"strided_slice_6/_274__cf__274\", \"shape\": [2], \"dtype\": \"int32\"}, {\"name\": \"Assert/Assert/data_1\", \"shape\": [], \"dtype\": \"int32\"}]}]"
  },
  {
    "path": "nn/using-deeplab/index.html",
    "content": "<html>\n  <head>\n    <body onload=\"onLoad()\">\n      <div id=\"container\">\n        <div class=\"ctrl\" id=\"use-packed\">Use packed operations<input id=\"use-packed-toggle\" type=\"checkbox\" onclick=\"toggleEnv()\" checked></div>\n        <div class=\"ctrl\" id=\"use-packed-array\">Use packed array ops<input id=\"use-packed-array-toggle\" type=\"checkbox\" onclick=\"toggleEnv()\" checked></div>\n        <div class=\"ctrl\" id=\"force-r16\">Use half float and WebGL 1.0<input id=\"force-r16-toggle\" type=\"checkbox\" onclick=\"toggleEnv()\" checked></div>\n        <div class=\"ctrl\" id=\"show-background\">Show background as cyan<input id=\"show-background-toggle\" type=\"checkbox\" checked></div>\n        <div class=\"ctrl\" id=\"show-average\">20 average: ...</div>\n        <canvas id=\"canvas\" width=640px height=480px></canvas>\n      </div>\n    </body>\n  </head>\n  <script>\n    // Forcing half float and WebGL 1.0 envirmental flags needs to be done\n    // before loading tfjs-core. Flags are specified through search string.\n    function calculateLocationSearchForFlags() {\n      const pack = sessionStorage.pack != 'false';\n      sessionStorage.pack = pack;\n      const packarray = sessionStorage.packarray != 'false';\n      sessionStorage.packarray = packarray;\n\n      let flags = pack ? 'WEBGL_PACK:true,' : '';\n      flags += ('WEBGL_PACK_ARRAY_OPERATIONS:' + (packarray ? 'true,' : 'false,')); \n      const r16 = sessionStorage.r16 != 'false';\n      sessionStorage.r16 = r16;\n      if (r16)\n        flags += 'WEBGL_RENDER_FLOAT32_ENABLED:false,WEBGL_VERSION:1';\n      return '?tfjsflags=' + flags;\n    }\n    const calculated = calculateLocationSearchForFlags();\n    if (location.search != calculated)\n      location.search = calculated; // For initial opening, to force R16 and packed.\n  </script>\n  <script src=\"tfjs/tf-core.js\"> </script>\n  <script src=\"tfjs/tf-converter.min.js\"> </script>\n  <script src=\"tfjs/tf-layers.min.js\"> </script>\n\n  <script>\n    function toggleEnv() {\n      sessionStorage.pack = document.getElementById(\"use-packed-toggle\").checked;\n      sessionStorage.packarray = document.getElementById(\"use-packed-array-toggle\").checked;\n      sessionStorage.r16 = document.getElementById(\"force-r16-toggle\").checked;\n      const calculated = calculateLocationSearchForFlags();\n      location.search = calculated; // reloads...\n    }\n\n    async function onLoad() {\n      const TENSOR_EDGE = 257;\n      const MODEL_URL = `argmax${TENSOR_EDGE}_2/tensorflowjs_model.pb`;\n      const WEIGHTS_URL = `argmax${TENSOR_EDGE}_2/weights_manifest.json`;\n\n      const pack = sessionStorage.pack == 'true';\n      document.getElementById(\"use-packed-toggle\").checked = pack;\n      const packarray = sessionStorage.packarray == 'true';\n      document.getElementById(\"use-packed-array-toggle\").checked = packarray;\n      const r16 = sessionStorage.r16 != 'false';\n      document.getElementById(\"force-r16-toggle\").checked = r16;\n\n      const [model, stream] = await Promise.all([\n          tf.loadFrozenModel(MODEL_URL, WEIGHTS_URL),\n          navigator.mediaDevices.getUserMedia({video: {facingMode: 'user',\n              frameRate: 15, width : 640, height:480}})]);\n      const video = document.createElement('video');\n      video.autoplay = true;\n      video.width = video.height = TENSOR_EDGE;\n      const ctx = document.getElementById(\"canvas\").getContext(\"2d\");        \n      const videoCopy = ctx.canvas.cloneNode(false).getContext(\"2d\");\n      const maskContext = document.createElement('canvas').getContext(\"2d\");\n      const average = document.getElementById(\"show-average\");\n      maskContext.canvas.width = maskContext.canvas.height = TENSOR_EDGE;\n      const img = maskContext.createImageData(TENSOR_EDGE, TENSOR_EDGE);\n      let imgd = img.data;\n      new Uint32Array(imgd.buffer).fill(0x00FFFF00);\n\n      let compiled = model.executor.compiledMap.get(\"ImageTensor\");\n      \n      // Note: For production code, do this using graph_transform. Node removal\n      // is implemented here to speedup debugging and trial and error approach.\n      function findNodeIndex(name) {\n        for (let i = 0; i < compiled.length; i++) {\n          if (compiled[i].name == name)\n            return i;\n        }\n        return -1;\n      }\n      function removeNode(name, replaceByChild = -1, replaceByInput = -1) {\n        const index = findNodeIndex(name);\n        if (index < 0) {\n          console.error(\"No such node:\" + name);\n          return;\n        }\n        let n = compiled.splice(index, 1)[0];\n        if (replaceByChild + replaceByInput == -2)\n          return; // we remove the node and don't update connections.\n        for (let i = 0; i < n.inputs.length; i++) {\n          const input = n.inputs[i];\n          const inchild = input.children[0].name == name ? 0 :\n                          input.children[1].name == name ? 1 :\n                          input.children[2].name == name ? 2 :\n                          input.children[3].name == name ? 3 : -1;\n          input.children[inchild] = n.children[replaceByChild];  \n        }\n        const replacement = n.inputs[replaceByInput];\n        for (let i = 0; i < n.children.length; i++) {\n          const cinput = n.children[i].inputNames[0] == name ? 0 :\n                         n.children[i].inputNames[1] == name ? 1 :\n                         n.children[i].inputNames[2] == name ? 2 :\n                         n.children[i].inputNames[3] == name ? 3 : -1;\n          n.children[i].inputs[cinput] = replacement;\n          n.children[i].inputNames[cinput] = replacement.name;\n        }\n      }\n      \n      if (TENSOR_EDGE == 513) {\n        let cast = compiled[findNodeIndex(\"Cast\")];\n        let expand_dims_1 = compiled[findNodeIndex(\"ExpandDims_1\")];\n        cast.children.splice(1, 1);\n        cast.children[0] = expand_dims_1;\n        expand_dims_1.inputs[0] = cast;\n        expand_dims_1.inputNames[0] = cast.name;\n\n        removeNode(\"ResizeBilinear_2\", 0, 0);\n        // Note: For production code, do this using graph_transform. Node removal\n        // is implemented here to speedup debugging and trial and error research approach.\n        const removeNodes = [\"stack\", \"stack/0\", \"stack_1\", \"stack_3\", \"stack_2\", \"ImageTensor\",\n                           \"Shape_1\", \"strided_slice_1\", \"strided_slice_2\",\n                           \"ToFloat_1/x\", \"ToFloat_1\", \"ToInt32\", \"Squeeze_1\", \"Shape_3\", \"strided_slice_5\",\n                           \"Shape_2\", \"strided_slice_3\", \"strided_slice_4\",\n                           \"strided_slice_6\", \"sub_1\", \"sub_2\", \"Pad\", \"add_2\", \"ResizeBilinear\", \n                           \"sub\", \"Maximum_1\", \"Maximum\", \"add_1\", \"add\", \"Assert/Assert/data_1\",\n                           \"sub_1/x\", \"sub_6\", \"sub_4\", \"ExpandDims\"];\n        for (let i = 0; i < removeNodes.length; i++)\n          removeNode(removeNodes[i], -1, -1);\n      } else {\n        let cast = compiled[findNodeIndex(\"Cast\")];\n        let expand_dims_1 = compiled[findNodeIndex(\"ExpandDims\")];\n        cast.children.splice(1, 1);\n        cast.children[0] = expand_dims_1;\n        expand_dims_1.inputs[0] = cast;\n        expand_dims_1.inputNames[0] = cast.name;\n\n        removeNode(\"ResizeBilinear_1\", 0, 0);\n        const removeNodes = [\"stack\", \"stack/0\", \"stack_1\", \"stack_3\", \"stack_2\", \"ImageTensor\",\n                           \"Shape_1\", \"strided_slice_1\", \"strided_slice_2\",\n                           \"Shape_2\", \"strided_slice_3\", \"strided_slice_4\",\n                           \"strided_slice_6\", \"sub_1\",  \"sub_2\", \"Pad\", \"add_2\", \"Reshape\",\n                           \"sub\", \"Maximum_1\", \"Maximum\", \"add_1\", \"add\", \"Assert/Assert/data_1\",\n                           \"sub_1/x\", \"sub_6\", \"sub_4\"];\n        for (let i = 0; i < removeNodes.length; i++)\n          removeNode(removeNodes[i], -1, -1);\n      }\n      compiled.splice(0, 120);\n      let averageCount = 0;\n      let timeExecute = 0;\n      let timeRead = 0;\n      const render = () => {\n        videoCopy.drawImage(video, 0, 0, ctx.canvas.width, ctx.canvas.height);\n        const t1 = performance.now();\n        const out = tf.tidy(() => {\n          return model.execute({'ImageTensor': tf.fromPixels(video).expandDims(0)});\n        });\n        const t2 = performance.now();\n        const data = document.getElementById(\"show-background-toggle\").checked ?\n                     out.dataSync() : new Uint8Array(TENSOR_EDGE * TENSOR_EDGE).fill(15);\n        const t3 = performance.now();\n        for (let i = 0; i < data.length; i++) {\n          imgd[i * 4 + 3] = data[i] == 15 ? 0 : 255;\n        }\n        maskContext.putImageData(img, 0, 0);\n        ctx.drawImage(videoCopy.canvas, 0, 0);\n        ctx.drawImage(maskContext.canvas, 0, 0, ctx.canvas.width, ctx.canvas.height);\n        timeExecute += (t2 - t1);\n        timeRead += (t3 - t2);\n        if (++averageCount == 20) {\n          timeExecute /= averageCount;\n          timeRead /= averageCount;\n          average.innerText = '20 average: ' + (timeExecute + timeRead).toFixed(2) \n              + '(' + timeExecute.toFixed(2) + ' + ' + timeRead.toFixed(2) + ')ms';\n          timeExecute = 0;\n          timeRead = 0;\n          averageCount = 0;\n        }\n        window.requestAnimationFrame(render);\n      }\n      video.oncanplay = render;\n      video.srcObject = stream;\n    }\n  </script>\n  <style type=\"text/css\">\n    #container {\n      position: relative;\n      display: inline-block;\n    }\n    .ctrl {\n      position: absolute;\n      color: lightgrey;\n      z-index: 5;\n      height: 20px;\n      display:block;\n      -webkit-touch-callout: none;\n      -moz-user-select: none;\n      user-select: none; \n    }\n    #show-average {\n      bottom: 20px;\n      left: 10px;\n      text-align: left;\n    }\n    #force-r16 {\n      bottom: 95px;\n      right: 20px;\n      text-align: right;\n    }\n    #use-packed-array {\n      bottom: 70px;\n      right: 20px;\n      text-align: right;\n    }\n    #use-packed {\n      bottom: 45px;\n      right: 20px;\n      text-align: right;\n    }\n    #show-background {\n      bottom: 20px;\n      right: 20px;\n      text-align: right;\n    }\n    #show-background-toggle, #use-packed-toggle, #force-r16-toggle, #use-packed-array-toggle {\n      height: 15px !important;\n      vertical-align:middle;\n    }\n  </style>    \n</html>\n\n        \n\n"
  },
  {
    "path": "nn/using-deeplab/tfjs/LICENSE",
    "content": "Copyright 2016 The TensorFlow Authors.  All rights reserved.\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2016, The Authors.\n\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"
  },
  {
    "path": "nn/using-deeplab/tfjs/tf-core.js",
    "content": "/**\n * @license\n * Copyright 2019 Google LLC. All Rights Reserved.\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(function (global, factory) {\n    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :\n    typeof define === 'function' && define.amd ? define(['exports'], factory) :\n    (factory((global.tf = global.tf || {})));\n}(this, (function (exports) { 'use strict';\n\n    /*! *****************************************************************************\r\n    Copyright (c) Microsoft Corporation. All rights reserved.\r\n    Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use\r\n    this file except in compliance with the License. You may obtain a copy of the\r\n    License at http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n    THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r\n    KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED\r\n    WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,\r\n    MERCHANTABLITY OR NON-INFRINGEMENT.\r\n\r\n    See the Apache Version 2.0 License for specific language governing permissions\r\n    and limitations under the License.\r\n    ***************************************************************************** */\r\n    /* global Reflect, Promise */\r\n\r\n    var extendStatics = function(d, b) {\r\n        extendStatics = Object.setPrototypeOf ||\r\n            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\r\n        return extendStatics(d, b);\r\n    };\r\n\r\n    function __extends(d, b) {\r\n        extendStatics(d, b);\r\n        function __() { this.constructor = d; }\r\n        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n    }\r\n\r\n    var __assign = function() {\r\n        __assign = Object.assign || function __assign(t) {\r\n            for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n                s = arguments[i];\r\n                for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n            }\r\n            return t;\r\n        };\r\n        return __assign.apply(this, arguments);\r\n    };\r\n\r\n    function __awaiter(thisArg, _arguments, P, generator) {\r\n        return new (P || (P = Promise))(function (resolve, reject) {\r\n            function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n            function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n            function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }\r\n            step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n        });\r\n    }\r\n\r\n    function __generator(thisArg, body) {\r\n        var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n        return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n        function verb(n) { return function (v) { return step([n, v]); }; }\r\n        function step(op) {\r\n            if (f) throw new TypeError(\"Generator is already executing.\");\r\n            while (_) try {\r\n                if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n                if (y = 0, t) op = [op[0] & 2, t.value];\r\n                switch (op[0]) {\r\n                    case 0: case 1: t = op; break;\r\n                    case 4: _.label++; return { value: op[1], done: false };\r\n                    case 5: _.label++; y = op[1]; op = [0]; continue;\r\n                    case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n                    default:\r\n                        if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n                        if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n                        if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n                        if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n                        if (t[2]) _.ops.pop();\r\n                        _.trys.pop(); continue;\r\n                }\r\n                op = body.call(thisArg, _);\r\n            } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n            if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n        }\r\n    }\n\n    var contexts = {};\r\n    var WEBGL_ATTRIBUTES = {\r\n        alpha: false,\r\n        antialias: false,\r\n        premultipliedAlpha: false,\r\n        preserveDrawingBuffer: false,\r\n        depth: false,\r\n        stencil: false,\r\n        failIfMajorPerformanceCaveat: true\r\n    };\r\n    function getWebGLContext(webGLVersion) {\r\n        if (!(webGLVersion in contexts)) {\r\n            var canvas = document.createElement('canvas');\r\n            canvas.addEventListener('webglcontextlost', function (ev) {\r\n                ev.preventDefault();\r\n                delete contexts[webGLVersion];\r\n            }, false);\r\n            contexts[webGLVersion] = getWebGLRenderingContext(webGLVersion);\r\n        }\r\n        var gl = contexts[webGLVersion];\r\n        if (gl.isContextLost()) {\r\n            delete contexts[webGLVersion];\r\n            return getWebGLContext(webGLVersion);\r\n        }\r\n        gl.disable(gl.DEPTH_TEST);\r\n        gl.disable(gl.STENCIL_TEST);\r\n        gl.disable(gl.BLEND);\r\n        gl.disable(gl.DITHER);\r\n        gl.disable(gl.POLYGON_OFFSET_FILL);\r\n        gl.disable(gl.SAMPLE_COVERAGE);\r\n        gl.enable(gl.SCISSOR_TEST);\r\n        gl.enable(gl.CULL_FACE);\r\n        gl.cullFace(gl.BACK);\r\n        return contexts[webGLVersion];\r\n    }\r\n    function getWebGLRenderingContext(webGLVersion) {\r\n        if (webGLVersion !== 1 && webGLVersion !== 2) {\r\n            throw new Error('Cannot get WebGL rendering context, WebGL is disabled.');\r\n        }\r\n        var canvas = document.createElement('canvas');\r\n        if (webGLVersion === 1) {\r\n            return (canvas.getContext('webgl', WEBGL_ATTRIBUTES) ||\r\n                canvas.getContext('experimental-webgl', WEBGL_ATTRIBUTES));\r\n        }\r\n        return canvas.getContext('webgl2', WEBGL_ATTRIBUTES);\r\n    }\n\n    function isMobile() {\r\n        var a = navigator.userAgent || navigator.vendor || window.opera;\r\n        return /(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\r\n            .test(a) ||\r\n            /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\r\n                .test(a.substr(0, 4));\r\n    }\n\n    function shuffle(array) {\r\n        var counter = array.length;\r\n        var temp = 0;\r\n        var index = 0;\r\n        while (counter > 0) {\r\n            index = (Math.random() * counter) | 0;\r\n            counter--;\r\n            temp = array[counter];\r\n            array[counter] = array[index];\r\n            array[index] = temp;\r\n        }\r\n    }\r\n    function clamp(min, x, max) {\r\n        return Math.max(min, Math.min(x, max));\r\n    }\r\n    function nearestLargerEven(val) {\r\n        return val % 2 === 0 ? val : val + 1;\r\n    }\r\n    function sum(arr) {\r\n        var sum = 0;\r\n        for (var i = 0; i < arr.length; i++) {\r\n            sum += arr[i];\r\n        }\r\n        return sum;\r\n    }\r\n    function randUniform(a, b) {\r\n        var r = Math.random();\r\n        return (b * r) + (1 - r) * a;\r\n    }\r\n    function distSquared(a, b) {\r\n        var result = 0;\r\n        for (var i = 0; i < a.length; i++) {\r\n            var diff = Number(a[i]) - Number(b[i]);\r\n            result += diff * diff;\r\n        }\r\n        return result;\r\n    }\r\n    function assert(expr, msg) {\r\n        if (!expr) {\r\n            throw new Error(typeof msg === 'string' ? msg : msg());\r\n        }\r\n    }\r\n    function assertShapesMatch(shapeA, shapeB, errorMessagePrefix) {\r\n        if (errorMessagePrefix === void 0) { errorMessagePrefix = ''; }\r\n        assert(arraysEqual(shapeA, shapeB), errorMessagePrefix + (\" Shapes \" + shapeA + \" and \" + shapeB + \" must match\"));\r\n    }\r\n    function assertNonNull(a) {\r\n        assert(a != null, \"The input to the tensor constructor must be a non-null value.\");\r\n    }\r\n    function flatten(arr, ret) {\r\n        if (ret === void 0) { ret = []; }\r\n        if (Array.isArray(arr) || isTypedArray(arr)) {\r\n            for (var i = 0; i < arr.length; ++i) {\r\n                flatten(arr[i], ret);\r\n            }\r\n        }\r\n        else {\r\n            ret.push(arr);\r\n        }\r\n        return ret;\r\n    }\r\n    function sizeFromShape(shape) {\r\n        if (shape.length === 0) {\r\n            return 1;\r\n        }\r\n        var size = shape[0];\r\n        for (var i = 1; i < shape.length; i++) {\r\n            size *= shape[i];\r\n        }\r\n        return size;\r\n    }\r\n    function isScalarShape(shape) {\r\n        return shape.length === 0;\r\n    }\r\n    function arraysEqual(n1, n2) {\r\n        if (n1 === n2) {\r\n            return true;\r\n        }\r\n        if (n1 == null || n2 == null) {\r\n            return false;\r\n        }\r\n        if (n1.length !== n2.length) {\r\n            return false;\r\n        }\r\n        for (var i = 0; i < n1.length; i++) {\r\n            if (n1[i] !== n2[i]) {\r\n                return false;\r\n            }\r\n        }\r\n        return true;\r\n    }\r\n    function isInt(a) {\r\n        return a % 1 === 0;\r\n    }\r\n    function tanh(x) {\r\n        if (Math.tanh != null) {\r\n            return Math.tanh(x);\r\n        }\r\n        if (x === Infinity) {\r\n            return 1;\r\n        }\r\n        else if (x === -Infinity) {\r\n            return -1;\r\n        }\r\n        else {\r\n            var e2x = Math.exp(2 * x);\r\n            return (e2x - 1) / (e2x + 1);\r\n        }\r\n    }\r\n    function sizeToSquarishShape(size) {\r\n        var width = Math.ceil(Math.sqrt(size));\r\n        return [width, Math.ceil(size / width)];\r\n    }\r\n    function createShuffledIndices(n) {\r\n        var shuffledIndices = new Uint32Array(n);\r\n        for (var i = 0; i < n; ++i) {\r\n            shuffledIndices[i] = i;\r\n        }\r\n        shuffle(shuffledIndices);\r\n        return shuffledIndices;\r\n    }\r\n    function rightPad(a, size) {\r\n        if (size <= a.length) {\r\n            return a;\r\n        }\r\n        return a + ' '.repeat(size - a.length);\r\n    }\r\n    function repeatedTry(checkFn, delayFn, maxCounter) {\r\n        if (delayFn === void 0) { delayFn = function (counter) { return 0; }; }\r\n        return new Promise(function (resolve, reject) {\r\n            var tryCount = 0;\r\n            var tryFn = function () {\r\n                if (checkFn()) {\r\n                    resolve();\r\n                    return;\r\n                }\r\n                tryCount++;\r\n                var nextBackoff = delayFn(tryCount);\r\n                if (maxCounter != null && tryCount >= maxCounter) {\r\n                    reject();\r\n                    return;\r\n                }\r\n                setTimeout(tryFn, nextBackoff);\r\n            };\r\n            tryFn();\r\n        });\r\n    }\r\n    function inferFromImplicitShape(shape, size) {\r\n        var shapeProd = 1;\r\n        var implicitIdx = -1;\r\n        for (var i = 0; i < shape.length; ++i) {\r\n            if (shape[i] >= 0) {\r\n                shapeProd *= shape[i];\r\n            }\r\n            else if (shape[i] === -1) {\r\n                if (implicitIdx !== -1) {\r\n                    throw Error(\"Shapes can only have 1 implicit size. \" +\r\n                        (\"Found -1 at dim \" + implicitIdx + \" and dim \" + i));\r\n                }\r\n                implicitIdx = i;\r\n            }\r\n            else if (shape[i] < 0) {\r\n                throw Error(\"Shapes can not be < 0. Found \" + shape[i] + \" at dim \" + i);\r\n            }\r\n        }\r\n        if (implicitIdx === -1) {\r\n            if (size > 0 && size !== shapeProd) {\r\n                throw Error(\"Size(\" + size + \") must match the product of shape \" + shape);\r\n            }\r\n            return shape;\r\n        }\r\n        if (shapeProd === 0) {\r\n            throw Error(\"Cannot infer the missing size in [\" + shape + \"] when \" +\r\n                \"there are 0 elements\");\r\n        }\r\n        if (size % shapeProd !== 0) {\r\n            throw Error(\"The implicit shape can't be a fractional number. \" +\r\n                (\"Got \" + size + \" / \" + shapeProd));\r\n        }\r\n        var newShape = shape.slice();\r\n        newShape[implicitIdx] = size / shapeProd;\r\n        return newShape;\r\n    }\r\n    function parseAxisParam(axis, shape) {\r\n        var rank = shape.length;\r\n        axis = axis == null ? shape.map(function (s, i) { return i; }) : [].concat(axis);\r\n        assert(axis.every(function (ax) { return ax >= -rank && ax < rank; }), \"All values in axis param must be in range [-\" + rank + \", \" + rank + \") but \" +\r\n            (\"got axis \" + axis));\r\n        assert(axis.every(function (ax) { return isInt(ax); }), \"All values in axis param must be integers but \" +\r\n            (\"got axis \" + axis));\r\n        return axis.map(function (a) { return a < 0 ? rank + a : a; });\r\n    }\r\n    function squeezeShape(shape, axis) {\r\n        var newShape = [];\r\n        var keptDims = [];\r\n        var axes = axis == null ? null : parseAxisParam(axis, shape).sort();\r\n        var j = 0;\r\n        for (var i = 0; i < shape.length; ++i) {\r\n            if (axes != null) {\r\n                if (axes[j] === i && shape[i] !== 1) {\r\n                    throw new Error(\"Can't squeeze axis \" + i + \" since its dim '\" + shape[i] + \"' is not 1\");\r\n                }\r\n                if ((axes[j] == null || axes[j] > i) && shape[i] === 1) {\r\n                    newShape.push(shape[i]);\r\n                    keptDims.push(i);\r\n                }\r\n                if (axes[j] <= i) {\r\n                    j++;\r\n                }\r\n            }\r\n            if (shape[i] !== 1) {\r\n                newShape.push(shape[i]);\r\n                keptDims.push(i);\r\n            }\r\n        }\r\n        return { newShape: newShape, keptDims: keptDims };\r\n    }\r\n    function getTypedArrayFromDType(dtype, size) {\r\n        var values = null;\r\n        if (dtype == null || dtype === 'float32') {\r\n            values = new Float32Array(size);\r\n        }\r\n        else if (dtype === 'int32') {\r\n            values = new Int32Array(size);\r\n        }\r\n        else if (dtype === 'bool') {\r\n            values = new Uint8Array(size);\r\n        }\r\n        else {\r\n            throw new Error(\"Unknown data type \" + dtype);\r\n        }\r\n        return values;\r\n    }\r\n    function getArrayFromDType(dtype, size) {\r\n        var values = null;\r\n        if (dtype == null || dtype === 'float32') {\r\n            values = new Float32Array(size);\r\n        }\r\n        else if (dtype === 'int32') {\r\n            values = new Int32Array(size);\r\n        }\r\n        else if (dtype === 'bool') {\r\n            values = new Uint8Array(size);\r\n        }\r\n        else if (dtype === 'string') {\r\n            values = new Array(size);\r\n        }\r\n        else {\r\n            throw new Error(\"Unknown data type \" + dtype);\r\n        }\r\n        return values;\r\n    }\r\n    function checkComputationForErrors(vals, dtype, name) {\r\n        if (dtype !== 'float32') {\r\n            return;\r\n        }\r\n        for (var i = 0; i < vals.length; i++) {\r\n            var num = vals[i];\r\n            if (isNaN(num) || !isFinite(num)) {\r\n                throw Error(\"The result of the '\" + name + \"' is \" + num + \".\");\r\n            }\r\n        }\r\n    }\r\n    function checkConversionForErrors(vals, dtype) {\r\n        for (var i = 0; i < vals.length; i++) {\r\n            var num = vals[i];\r\n            if (isNaN(num) || !isFinite(num)) {\r\n                throw Error(\"A tensor of type \" + dtype + \" being uploaded contains \" + num + \".\");\r\n            }\r\n        }\r\n    }\r\n    function hasEncodingLoss(oldType, newType) {\r\n        if (newType === 'complex64') {\r\n            return false;\r\n        }\r\n        if (newType === 'float32' && oldType !== 'complex64') {\r\n            return false;\r\n        }\r\n        if (newType === 'int32' && oldType !== 'float32' && oldType !== 'complex64') {\r\n            return false;\r\n        }\r\n        if (newType === 'bool' && oldType === 'bool') {\r\n            return false;\r\n        }\r\n        return true;\r\n    }\r\n    function isTypedArray(a) {\r\n        return a instanceof Float32Array || a instanceof Int32Array ||\r\n            a instanceof Uint8Array;\r\n    }\r\n    function bytesPerElement(dtype) {\r\n        if (dtype === 'float32' || dtype === 'int32') {\r\n            return 4;\r\n        }\r\n        else if (dtype === 'complex64') {\r\n            return 8;\r\n        }\r\n        else if (dtype === 'bool') {\r\n            return 1;\r\n        }\r\n        else {\r\n            throw new Error(\"Unknown dtype \" + dtype);\r\n        }\r\n    }\r\n    function bytesFromStringArray(arr) {\r\n        if (arr == null) {\r\n            return 0;\r\n        }\r\n        var bytes = 0;\r\n        arr.forEach(function (x) { return bytes += x.length * 2; });\r\n        return bytes;\r\n    }\r\n    function isString(value) {\r\n        return typeof value === 'string' || value instanceof String;\r\n    }\r\n    function isBoolean(value) {\r\n        return typeof value === 'boolean';\r\n    }\r\n    function isNumber(value) {\r\n        return typeof value === 'number';\r\n    }\r\n    function inferDtype(values) {\r\n        if (Array.isArray(values)) {\r\n            return inferDtype(values[0]);\r\n        }\r\n        if (values instanceof Float32Array) {\r\n            return 'float32';\r\n        }\r\n        else if (values instanceof Int32Array || values instanceof Uint8Array) {\r\n            return 'int32';\r\n        }\r\n        else if (isNumber(values)) {\r\n            return 'float32';\r\n        }\r\n        else if (isString(values)) {\r\n            return 'string';\r\n        }\r\n        else if (isBoolean(values)) {\r\n            return 'bool';\r\n        }\r\n        return 'float32';\r\n    }\r\n    function isFunction(f) {\r\n        return !!(f && f.constructor && f.call && f.apply);\r\n    }\r\n    function nearestDivisor(size, start) {\r\n        for (var i = start; i < size; ++i) {\r\n            if (size % i === 0) {\r\n                return i;\r\n            }\r\n        }\r\n        return size;\r\n    }\r\n    function computeStrides(shape) {\r\n        var rank = shape.length;\r\n        if (rank < 2) {\r\n            return [];\r\n        }\r\n        var strides = new Array(rank - 1);\r\n        strides[rank - 2] = shape[rank - 1];\r\n        for (var i = rank - 3; i >= 0; --i) {\r\n            strides[i] = strides[i + 1] * shape[i + 1];\r\n        }\r\n        return strides;\r\n    }\r\n    function toTypedArray(a, dtype, debugMode) {\r\n        if (dtype === 'string') {\r\n            throw new Error('Cannot convert a string[] to a TypedArray');\r\n        }\r\n        if (Array.isArray(a)) {\r\n            a = flatten(a);\r\n        }\r\n        if (debugMode) {\r\n            checkConversionForErrors(a, dtype);\r\n        }\r\n        if (noConversionNeeded(a, dtype)) {\r\n            return a;\r\n        }\r\n        if (dtype == null || dtype === 'float32' || dtype === 'complex64') {\r\n            return new Float32Array(a);\r\n        }\r\n        else if (dtype === 'int32') {\r\n            return new Int32Array(a);\r\n        }\r\n        else if (dtype === 'bool') {\r\n            var bool = new Uint8Array(a.length);\r\n            for (var i = 0; i < bool.length; ++i) {\r\n                if (Math.round(a[i]) !== 0) {\r\n                    bool[i] = 1;\r\n                }\r\n            }\r\n            return bool;\r\n        }\r\n        else {\r\n            throw new Error(\"Unknown data type \" + dtype);\r\n        }\r\n    }\r\n    function createNestedArray(offset, shape, a) {\r\n        var ret = new Array();\r\n        if (shape.length === 1) {\r\n            var d = shape[0];\r\n            for (var i = 0; i < d; i++) {\r\n                ret[i] = a[offset + i];\r\n            }\r\n        }\r\n        else {\r\n            var d = shape[0];\r\n            var rest = shape.slice(1);\r\n            var len = rest.reduce(function (acc, c) { return acc * c; });\r\n            for (var i = 0; i < d; i++) {\r\n                ret[i] = createNestedArray(offset + i * len, rest, a);\r\n            }\r\n        }\r\n        return ret;\r\n    }\r\n    function toNestedArray(shape, a) {\r\n        if (shape.length === 0) {\r\n            return [];\r\n        }\r\n        var size = shape.reduce(function (acc, c) { return acc * c; });\r\n        if (size === 0) {\r\n            return [];\r\n        }\r\n        if (size !== a.length) {\r\n            throw new Error(\"[\" + shape + \"] does not match the input size.\");\r\n        }\r\n        return createNestedArray(0, shape, a);\r\n    }\r\n    function noConversionNeeded(a, dtype) {\r\n        return (a instanceof Float32Array && dtype === 'float32') ||\r\n            (a instanceof Int32Array && dtype === 'int32') ||\r\n            (a instanceof Uint8Array && dtype === 'bool');\r\n    }\r\n    function makeOnesTypedArray(size, dtype) {\r\n        var array = makeZerosTypedArray(size, dtype);\r\n        for (var i = 0; i < array.length; i++) {\r\n            array[i] = 1;\r\n        }\r\n        return array;\r\n    }\r\n    function makeZerosTypedArray(size, dtype) {\r\n        if (dtype == null || dtype === 'float32' || dtype === 'complex64') {\r\n            return new Float32Array(size);\r\n        }\r\n        else if (dtype === 'int32') {\r\n            return new Int32Array(size);\r\n        }\r\n        else if (dtype === 'bool') {\r\n            return new Uint8Array(size);\r\n        }\r\n        else {\r\n            throw new Error(\"Unknown data type \" + dtype);\r\n        }\r\n    }\r\n    function now() {\r\n        if (typeof performance !== 'undefined') {\r\n            return performance.now();\r\n        }\r\n        else if (typeof process !== 'undefined') {\r\n            var time = process.hrtime();\r\n            return time[0] * 1000 + time[1] / 1000000;\r\n        }\r\n        else {\r\n            throw new Error('Cannot measure time in this environment. You should run tf.js ' +\r\n                'in the browser or in Node.js');\r\n        }\r\n    }\r\n    function monitorPromisesProgress(promises, onProgress, startFraction, endFraction) {\r\n        checkPromises(promises);\r\n        startFraction = startFraction == null ? 0 : startFraction;\r\n        endFraction = endFraction == null ? 1 : endFraction;\r\n        checkFraction(startFraction, endFraction);\r\n        var resolvedPromise = 0;\r\n        function registerMonitor(promise) {\r\n            promise.then(function (value) {\r\n                var fraction = startFraction + ++resolvedPromise / promises.length *\r\n                    (endFraction - startFraction);\r\n                onProgress(fraction);\r\n                return value;\r\n            });\r\n            return promise;\r\n        }\r\n        function checkPromises(promises) {\r\n            assert(promises != null && Array.isArray(promises) && promises.length > 0, 'promises must be a none empty array');\r\n        }\r\n        function checkFraction(startFraction, endFraction) {\r\n            assert(startFraction >= 0 && startFraction <= 1, \"Progress fraction must be in range [0, 1], but \" +\r\n                (\"got startFraction \" + startFraction));\r\n            assert(endFraction >= 0 && endFraction <= 1, \"Progress fraction must be in range [0, 1], but \" +\r\n                (\"got endFraction \" + endFraction));\r\n            assert(endFraction >= startFraction, \"startFraction must be no more than endFraction, but \" +\r\n                (\"got startFraction \" + startFraction + \" and endFraction \" + endFraction));\r\n        }\r\n        return Promise.all(promises.map(registerMonitor));\r\n    }\n\n    var util = /*#__PURE__*/Object.freeze({\n        shuffle: shuffle,\n        clamp: clamp,\n        nearestLargerEven: nearestLargerEven,\n        sum: sum,\n        randUniform: randUniform,\n        distSquared: distSquared,\n        assert: assert,\n        assertShapesMatch: assertShapesMatch,\n        assertNonNull: assertNonNull,\n        flatten: flatten,\n        sizeFromShape: sizeFromShape,\n        isScalarShape: isScalarShape,\n        arraysEqual: arraysEqual,\n        isInt: isInt,\n        tanh: tanh,\n        sizeToSquarishShape: sizeToSquarishShape,\n        createShuffledIndices: createShuffledIndices,\n        rightPad: rightPad,\n        repeatedTry: repeatedTry,\n        inferFromImplicitShape: inferFromImplicitShape,\n        parseAxisParam: parseAxisParam,\n        squeezeShape: squeezeShape,\n        getTypedArrayFromDType: getTypedArrayFromDType,\n        getArrayFromDType: getArrayFromDType,\n        checkComputationForErrors: checkComputationForErrors,\n        checkConversionForErrors: checkConversionForErrors,\n        hasEncodingLoss: hasEncodingLoss,\n        isTypedArray: isTypedArray,\n        bytesPerElement: bytesPerElement,\n        bytesFromStringArray: bytesFromStringArray,\n        isString: isString,\n        isBoolean: isBoolean,\n        isNumber: isNumber,\n        inferDtype: inferDtype,\n        isFunction: isFunction,\n        nearestDivisor: nearestDivisor,\n        computeStrides: computeStrides,\n        toTypedArray: toTypedArray,\n        toNestedArray: toNestedArray,\n        makeOnesTypedArray: makeOnesTypedArray,\n        makeZerosTypedArray: makeZerosTypedArray,\n        now: now,\n        monitorPromisesProgress: monitorPromisesProgress\n    });\n\n    var Profiler = (function () {\r\n        function Profiler(backendTimer, logger) {\r\n            this.backendTimer = backendTimer;\r\n            this.logger = logger;\r\n            if (logger == null) {\r\n                this.logger = new Logger();\r\n            }\r\n        }\r\n        Profiler.prototype.profileKernel = function (name, f) {\r\n            var _this = this;\r\n            var result;\r\n            var holdResultWrapperFn = function () {\r\n                result = f();\r\n            };\r\n            var timer = this.backendTimer.time(holdResultWrapperFn);\r\n            var results = Array.isArray(result) ? result : [result];\r\n            results.forEach(function (r) {\r\n                var vals = r.dataSync();\r\n                checkComputationForErrors(vals, r.dtype, name);\r\n                timer.then(function (timing) {\r\n                    var extraInfo = '';\r\n                    if (timing.getExtraProfileInfo != null) {\r\n                        extraInfo = timing.getExtraProfileInfo();\r\n                    }\r\n                    _this.logger.logKernelProfile(name, r, vals, timing.kernelMs, extraInfo);\r\n                });\r\n            });\r\n            return result;\r\n        };\r\n        return Profiler;\r\n    }());\r\n    var Logger = (function () {\r\n        function Logger() {\r\n        }\r\n        Logger.prototype.logKernelProfile = function (name, result, vals, timeMs, extraInfo) {\r\n            var time = rightPad(timeMs + \"ms\", 9);\r\n            var paddedName = rightPad(name, 25);\r\n            var rank = result.rank;\r\n            var size = result.size;\r\n            var shape = rightPad(result.shape.toString(), 14);\r\n            console.log(\"%c\" + paddedName + \"\\t%c\" + time + \"\\t%c\" + rank + \"D \" + shape + \"\\t%c\" + size + \"\\t%c\" + extraInfo, 'font-weight:bold', 'color:red', 'color:blue', 'color: orange', 'color: green');\r\n        };\r\n        return Logger;\r\n    }());\n\n    var FORMAT_LIMIT_NUM_VALS = 20;\r\n    var FORMAT_NUM_FIRST_LAST_VALS = 3;\r\n    var FORMAT_NUM_SIG_DIGITS = 7;\r\n    function tensorToString(vals, shape, dtype, verbose) {\r\n        var strides = computeStrides(shape);\r\n        var padPerCol = computeMaxSizePerColumn(vals, shape, dtype, strides);\r\n        var rank = shape.length;\r\n        var valsLines = subTensorToString(vals, shape, dtype, strides, padPerCol);\r\n        var lines = ['Tensor'];\r\n        if (verbose) {\r\n            lines.push(\"  dtype: \" + dtype);\r\n            lines.push(\"  rank: \" + rank);\r\n            lines.push(\"  shape: [\" + shape + \"]\");\r\n            lines.push(\"  values:\");\r\n        }\r\n        lines.push(valsLines.map(function (l) { return '    ' + l; }).join('\\n'));\r\n        return lines.join('\\n');\r\n    }\r\n    function computeMaxSizePerColumn(vals, shape, dtype, strides) {\r\n        var n = sizeFromShape(shape);\r\n        var numCols = strides[strides.length - 1];\r\n        var padPerCol = new Array(numCols).fill(0);\r\n        var rank = shape.length;\r\n        var valuesOrTuples = dtype === 'complex64' ? createComplexTuples(vals) : vals;\r\n        if (rank > 1) {\r\n            for (var row = 0; row < n / numCols; row++) {\r\n                var offset = row * numCols;\r\n                for (var j = 0; j < numCols; j++) {\r\n                    padPerCol[j] = Math.max(padPerCol[j], valToString(valuesOrTuples[offset + j], 0).length);\r\n                }\r\n            }\r\n        }\r\n        return padPerCol;\r\n    }\r\n    function valToString(val, pad) {\r\n        var valStr;\r\n        if (Array.isArray(val)) {\r\n            valStr = parseFloat(val[0].toFixed(FORMAT_NUM_SIG_DIGITS)) + \" + \" +\r\n                (parseFloat(val[1].toFixed(FORMAT_NUM_SIG_DIGITS)) + \"j\");\r\n        }\r\n        else if (isString(val)) {\r\n            valStr = \"'\" + val + \"'\";\r\n        }\r\n        else {\r\n            valStr = parseFloat(val.toFixed(FORMAT_NUM_SIG_DIGITS)).toString();\r\n        }\r\n        return rightPad(valStr, pad);\r\n    }\r\n    function subTensorToString(vals, shape, dtype, strides, padPerCol, isLast) {\r\n        if (isLast === void 0) { isLast = true; }\r\n        var storagePerElement = dtype === 'complex64' ? 2 : 1;\r\n        var size = shape[0];\r\n        var rank = shape.length;\r\n        if (rank === 0) {\r\n            if (dtype === 'complex64') {\r\n                var complexTuple = createComplexTuples(vals);\r\n                return [valToString(complexTuple[0], 0)];\r\n            }\r\n            return [vals[0].toString()];\r\n        }\r\n        if (rank === 1) {\r\n            if (size > FORMAT_LIMIT_NUM_VALS) {\r\n                var firstValsSize = FORMAT_NUM_FIRST_LAST_VALS * storagePerElement;\r\n                var firstVals = Array.from(vals.slice(0, firstValsSize));\r\n                var lastVals = Array.from(vals.slice(size - FORMAT_NUM_FIRST_LAST_VALS * storagePerElement, size));\r\n                if (dtype === 'complex64') {\r\n                    firstVals = createComplexTuples(firstVals);\r\n                    lastVals = createComplexTuples(lastVals);\r\n                }\r\n                return [\r\n                    '[' + firstVals.map(function (x, i) { return valToString(x, padPerCol[i]); }).join(', ') +\r\n                        ', ..., ' +\r\n                        lastVals\r\n                            .map(function (x, i) { return valToString(x, padPerCol[size - FORMAT_NUM_FIRST_LAST_VALS + i]); })\r\n                            .join(', ') +\r\n                        ']'\r\n                ];\r\n            }\r\n            var displayVals = dtype === 'complex64' ? createComplexTuples(vals) :\r\n                Array.from(vals);\r\n            return [\r\n                '[' + displayVals.map(function (x, i) { return valToString(x, padPerCol[i]); }).join(', ') +\r\n                    ']'\r\n            ];\r\n        }\r\n        var subshape = shape.slice(1);\r\n        var substrides = strides.slice(1);\r\n        var stride = strides[0] * storagePerElement;\r\n        var lines = [];\r\n        if (size > FORMAT_LIMIT_NUM_VALS) {\r\n            for (var i = 0; i < FORMAT_NUM_FIRST_LAST_VALS; i++) {\r\n                var start = i * stride;\r\n                var end = start + stride;\r\n                lines.push.apply(lines, subTensorToString(vals.slice(start, end), subshape, dtype, substrides, padPerCol, false));\r\n            }\r\n            lines.push('...');\r\n            for (var i = size - FORMAT_NUM_FIRST_LAST_VALS; i < size; i++) {\r\n                var start = i * stride;\r\n                var end = start + stride;\r\n                lines.push.apply(lines, subTensorToString(vals.slice(start, end), subshape, dtype, substrides, padPerCol, i === size - 1));\r\n            }\r\n        }\r\n        else {\r\n            for (var i = 0; i < size; i++) {\r\n                var start = i * stride;\r\n                var end = start + stride;\r\n                lines.push.apply(lines, subTensorToString(vals.slice(start, end), subshape, dtype, substrides, padPerCol, i === size - 1));\r\n            }\r\n        }\r\n        var sep = rank === 2 ? ',' : '';\r\n        lines[0] = '[' + lines[0] + sep;\r\n        for (var i = 1; i < lines.length - 1; i++) {\r\n            lines[i] = ' ' + lines[i] + sep;\r\n        }\r\n        var newLineSep = ',\\n';\r\n        for (var i = 2; i < rank; i++) {\r\n            newLineSep += '\\n';\r\n        }\r\n        lines[lines.length - 1] =\r\n            ' ' + lines[lines.length - 1] + ']' + (isLast ? '' : newLineSep);\r\n        return lines;\r\n    }\r\n    function createComplexTuples(vals) {\r\n        var complexTuples = [];\r\n        for (var i = 0; i < vals.length; i += 2) {\r\n            complexTuples.push([vals[i], vals[i + 1]]);\r\n        }\r\n        return complexTuples;\r\n    }\n\n    var TensorBuffer = (function () {\r\n        function TensorBuffer(shape, dtype, values) {\r\n            this.dtype = dtype;\r\n            this.shape = shape.slice();\r\n            this.size = sizeFromShape(shape);\r\n            if (values != null) {\r\n                var n = values.length;\r\n                assert(n === this.size, \"Length of values '\" + n + \"' does not match the size \" +\r\n                    (\"inferred by the shape '\" + this.size + \"'.\"));\r\n            }\r\n            if (dtype === 'complex64') {\r\n                throw new Error(\"complex64 dtype TensorBuffers are not supported. Please create \" +\r\n                    \"a TensorBuffer for the real and imaginary parts separately and \" +\r\n                    \"call tf.complex(real, imag).\");\r\n            }\r\n            this.values =\r\n                values || getArrayFromDType(dtype, sizeFromShape(this.shape));\r\n            this.strides = computeStrides(shape);\r\n        }\r\n        TensorBuffer.prototype.set = function (value) {\r\n            var locs = [];\r\n            for (var _i = 1; _i < arguments.length; _i++) {\r\n                locs[_i - 1] = arguments[_i];\r\n            }\r\n            if (locs.length === 0) {\r\n                locs = [0];\r\n            }\r\n            assert(locs.length === this.rank, \"The number of provided coordinates (\" + locs.length + \") must \" +\r\n                (\"match the rank (\" + this.rank + \")\"));\r\n            var index = this.locToIndex(locs);\r\n            this.values[index] = value;\r\n        };\r\n        TensorBuffer.prototype.get = function () {\r\n            var locs = [];\r\n            for (var _i = 0; _i < arguments.length; _i++) {\r\n                locs[_i] = arguments[_i];\r\n            }\r\n            if (locs.length === 0) {\r\n                locs = [0];\r\n            }\r\n            var index = locs[locs.length - 1];\r\n            for (var i = 0; i < locs.length - 1; ++i) {\r\n                index += this.strides[i] * locs[i];\r\n            }\r\n            return this.values[index];\r\n        };\r\n        TensorBuffer.prototype.locToIndex = function (locs) {\r\n            if (this.rank === 0) {\r\n                return 0;\r\n            }\r\n            else if (this.rank === 1) {\r\n                return locs[0];\r\n            }\r\n            var index = locs[locs.length - 1];\r\n            for (var i = 0; i < locs.length - 1; ++i) {\r\n                index += this.strides[i] * locs[i];\r\n            }\r\n            return index;\r\n        };\r\n        TensorBuffer.prototype.indexToLoc = function (index) {\r\n            if (this.rank === 0) {\r\n                return [];\r\n            }\r\n            else if (this.rank === 1) {\r\n                return [index];\r\n            }\r\n            var locs = new Array(this.shape.length);\r\n            for (var i = 0; i < locs.length - 1; ++i) {\r\n                locs[i] = Math.floor(index / this.strides[i]);\r\n                index -= locs[i] * this.strides[i];\r\n            }\r\n            locs[locs.length - 1] = index;\r\n            return locs;\r\n        };\r\n        Object.defineProperty(TensorBuffer.prototype, \"rank\", {\r\n            get: function () {\r\n                return this.shape.length;\r\n            },\r\n            enumerable: true,\r\n            configurable: true\r\n        });\r\n        TensorBuffer.prototype.toTensor = function () {\r\n            return Tensor.make(this.shape, { values: this.values }, this.dtype);\r\n        };\r\n        return TensorBuffer;\r\n    }());\r\n    var trackerFn = null;\r\n    var opHandler = null;\r\n    function setTensorTracker(fn) {\r\n        trackerFn = fn;\r\n    }\r\n    function setOpHandler(handler) {\r\n        opHandler = handler;\r\n    }\r\n    var Tensor = (function () {\r\n        function Tensor(shape, dtype, values, dataId) {\r\n            this.isDisposedInternal = false;\r\n            this.shape = shape.slice();\r\n            this.dtype = dtype || 'float32';\r\n            this.size = sizeFromShape(shape);\r\n            this.strides = computeStrides(shape);\r\n            this.dataId = dataId != null ? dataId : {};\r\n            this.id = trackerFn().nextTensorId();\r\n            this.rankType = (this.rank < 5 ? this.rank.toString() : 'higher');\r\n            trackerFn().registerTensor(this);\r\n            if (values != null) {\r\n                trackerFn().write(this.dataId, values);\r\n            }\r\n        }\r\n        Tensor.make = function (shape, data, dtype) {\r\n            return new Tensor(shape, dtype, data.values, data.dataId);\r\n        };\r\n        Tensor.prototype.flatten = function () {\r\n            this.throwIfDisposed();\r\n            return this.as1D();\r\n        };\r\n        Tensor.prototype.asScalar = function () {\r\n            this.throwIfDisposed();\r\n            assert(this.size === 1, 'The array must have only 1 element.');\r\n            return this.reshape([]);\r\n        };\r\n        Tensor.prototype.as1D = function () {\r\n            this.throwIfDisposed();\r\n            return this.reshape([this.size]);\r\n        };\r\n        Tensor.prototype.as2D = function (rows, columns) {\r\n            this.throwIfDisposed();\r\n            return this.reshape([rows, columns]);\r\n        };\r\n        Tensor.prototype.as3D = function (rows, columns, depth) {\r\n            this.throwIfDisposed();\r\n            return this.reshape([rows, columns, depth]);\r\n        };\r\n        Tensor.prototype.as4D = function (rows, columns, depth, depth2) {\r\n            this.throwIfDisposed();\r\n            return this.reshape([rows, columns, depth, depth2]);\r\n        };\r\n        Tensor.prototype.as5D = function (rows, columns, depth, depth2, depth3) {\r\n            this.throwIfDisposed();\r\n            return this.reshape([rows, columns, depth, depth2, depth3]);\r\n        };\r\n        Tensor.prototype.asType = function (dtype) {\r\n            this.throwIfDisposed();\r\n            return opHandler.cast(this, dtype);\r\n        };\r\n        Object.defineProperty(Tensor.prototype, \"rank\", {\r\n            get: function () {\r\n                return this.shape.length;\r\n            },\r\n            enumerable: true,\r\n            configurable: true\r\n        });\r\n        Tensor.prototype.get = function () {\r\n            var locs = [];\r\n            for (var _i = 0; _i < arguments.length; _i++) {\r\n                locs[_i] = arguments[_i];\r\n            }\r\n            assert(locs.length === this.rank, 'Number of coordinates in get() must match the rank of the tensor');\r\n            assert(this.dtype !== 'complex64', 'Tensor.get() is not supported for complex64 tensors yet.');\r\n            this.throwIfDisposed();\r\n            if (locs.length === 0) {\r\n                locs = [0];\r\n            }\r\n            var index = locs[locs.length - 1];\r\n            for (var i = 0; i < locs.length - 1; ++i) {\r\n                index += this.strides[i] * locs[i];\r\n            }\r\n            return this.dataSync()[index];\r\n        };\r\n        Tensor.prototype.buffer = function () {\r\n            return opHandler.buffer(this.shape, this.dtype, this.dataSync());\r\n        };\r\n        Tensor.prototype.data = function () {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                return __generator(this, function (_a) {\r\n                    this.throwIfDisposed();\r\n                    return [2, trackerFn().read(this.dataId)];\r\n                });\r\n            });\r\n        };\r\n        Tensor.prototype.dataSync = function () {\r\n            this.throwIfDisposed();\r\n            return trackerFn().readSync(this.dataId);\r\n        };\r\n        Tensor.prototype.dispose = function () {\r\n            if (this.isDisposed) {\r\n                return;\r\n            }\r\n            trackerFn().disposeTensor(this);\r\n            this.isDisposedInternal = true;\r\n        };\r\n        Object.defineProperty(Tensor.prototype, \"isDisposed\", {\r\n            get: function () {\r\n                return this.isDisposedInternal;\r\n            },\r\n            enumerable: true,\r\n            configurable: true\r\n        });\r\n        Tensor.prototype.throwIfDisposed = function () {\r\n            if (this.isDisposed) {\r\n                throw new Error(\"Tensor is disposed.\");\r\n            }\r\n        };\r\n        Tensor.prototype.toFloat = function () {\r\n            return this.asType('float32');\r\n        };\r\n        Tensor.prototype.toInt = function () {\r\n            return this.asType('int32');\r\n        };\r\n        Tensor.prototype.toBool = function () {\r\n            return this.asType('bool');\r\n        };\r\n        Tensor.prototype.print = function (verbose) {\r\n            if (verbose === void 0) { verbose = false; }\r\n            return opHandler.print(this, verbose);\r\n        };\r\n        Tensor.prototype.reshape = function (newShape) {\r\n            this.throwIfDisposed();\r\n            return opHandler.reshape(this, newShape);\r\n        };\r\n        Tensor.prototype.reshapeAs = function (x) {\r\n            this.throwIfDisposed();\r\n            return this.reshape(x.shape);\r\n        };\r\n        Tensor.prototype.expandDims = function (axis) {\r\n            if (axis === void 0) { axis = 0; }\r\n            return opHandler.expandDims(this, axis);\r\n        };\r\n        Tensor.prototype.cumsum = function (axis, exclusive, reverse) {\r\n            if (axis === void 0) { axis = 0; }\r\n            if (exclusive === void 0) { exclusive = false; }\r\n            if (reverse === void 0) { reverse = false; }\r\n            return opHandler.cumsum(this, axis, exclusive, reverse);\r\n        };\r\n        Tensor.prototype.squeeze = function (axis) {\r\n            this.throwIfDisposed();\r\n            return opHandler.squeeze(this, axis);\r\n        };\r\n        Tensor.prototype.clone = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.clone(this);\r\n        };\r\n        Tensor.prototype.oneHot = function (depth, onValue, offValue) {\r\n            this.throwIfDisposed();\r\n            return opHandler.oneHot(this, depth, onValue, offValue);\r\n        };\r\n        Tensor.prototype.toString = function (verbose) {\r\n            if (verbose === void 0) { verbose = false; }\r\n            var vals = this.dataSync();\r\n            return tensorToString(vals, this.shape, this.dtype, verbose);\r\n        };\r\n        Tensor.prototype.tile = function (reps) {\r\n            this.throwIfDisposed();\r\n            return opHandler.tile(this, reps);\r\n        };\r\n        Tensor.prototype.gather = function (indices, axis) {\r\n            if (axis === void 0) { axis = 0; }\r\n            this.throwIfDisposed();\r\n            return opHandler.gather(this, indices, axis);\r\n        };\r\n        Tensor.prototype.matMul = function (b, transposeA, transposeB) {\r\n            if (transposeA === void 0) { transposeA = false; }\r\n            if (transposeB === void 0) { transposeB = false; }\r\n            this.throwIfDisposed();\r\n            return opHandler.matMul(this, b, transposeA, transposeB);\r\n        };\r\n        Tensor.prototype.dot = function (b) {\r\n            this.throwIfDisposed();\r\n            return opHandler.dot(this, b);\r\n        };\r\n        Tensor.prototype.norm = function (ord, axis, keepDims) {\r\n            if (ord === void 0) { ord = 'euclidean'; }\r\n            if (axis === void 0) { axis = null; }\r\n            if (keepDims === void 0) { keepDims = false; }\r\n            this.throwIfDisposed();\r\n            return opHandler.norm(this, ord, axis, keepDims);\r\n        };\r\n        Tensor.prototype.slice = function (begin, size) {\r\n            this.throwIfDisposed();\r\n            return opHandler.slice(this, begin, size);\r\n        };\r\n        Tensor.prototype.reverse = function (axis) {\r\n            this.throwIfDisposed();\r\n            return opHandler.reverse(this, axis);\r\n        };\r\n        Tensor.prototype.concat = function (x, axis) {\r\n            if (axis === void 0) { axis = 0; }\r\n            this.throwIfDisposed();\r\n            if (x instanceof Tensor) {\r\n                x = [x];\r\n            }\r\n            return opHandler.concat([this].concat(x), axis);\r\n        };\r\n        Tensor.prototype.split = function (numOrSizeSplits, axis) {\r\n            if (axis === void 0) { axis = 0; }\r\n            this.throwIfDisposed();\r\n            return opHandler.split(this, numOrSizeSplits, axis);\r\n        };\r\n        Tensor.prototype.stack = function (x, axis) {\r\n            if (axis === void 0) { axis = 0; }\r\n            return opHandler.stack([this, x], axis);\r\n        };\r\n        Tensor.prototype.unstack = function (x, axis) {\r\n            if (axis === void 0) { axis = 0; }\r\n            return opHandler.unstack(this, axis);\r\n        };\r\n        Tensor.prototype.pad = function (paddings, constantValue) {\r\n            if (constantValue === void 0) { constantValue = 0; }\r\n            return opHandler.pad(this, paddings, constantValue);\r\n        };\r\n        Tensor.prototype.batchNormalization = function (mean, variance, varianceEpsilon, scale, offset) {\r\n            if (varianceEpsilon === void 0) { varianceEpsilon = .001; }\r\n            this.throwIfDisposed();\r\n            return opHandler.batchNormalization(this, mean, variance, varianceEpsilon, scale, offset);\r\n        };\r\n        Tensor.prototype.all = function (axis, keepDims) {\r\n            if (axis === void 0) { axis = null; }\r\n            if (keepDims === void 0) { keepDims = false; }\r\n            this.throwIfDisposed();\r\n            return opHandler.all(this, axis, keepDims);\r\n        };\r\n        Tensor.prototype.any = function (axis, keepDims) {\r\n            if (axis === void 0) { axis = null; }\r\n            if (keepDims === void 0) { keepDims = false; }\r\n            this.throwIfDisposed();\r\n            return opHandler.any(this, axis, keepDims);\r\n        };\r\n        Tensor.prototype.logSumExp = function (axis, keepDims) {\r\n            if (axis === void 0) { axis = null; }\r\n            if (keepDims === void 0) { keepDims = false; }\r\n            this.throwIfDisposed();\r\n            return opHandler.logSumExp(this, axis, keepDims);\r\n        };\r\n        Tensor.prototype.sum = function (axis, keepDims) {\r\n            if (axis === void 0) { axis = null; }\r\n            if (keepDims === void 0) { keepDims = false; }\r\n            this.throwIfDisposed();\r\n            return opHandler.sum(this, axis, keepDims);\r\n        };\r\n        Tensor.prototype.prod = function (axis, keepDims) {\r\n            if (axis === void 0) { axis = null; }\r\n            if (keepDims === void 0) { keepDims = false; }\r\n            this.throwIfDisposed();\r\n            return opHandler.prod(this, axis, keepDims);\r\n        };\r\n        Tensor.prototype.mean = function (axis, keepDims) {\r\n            if (axis === void 0) { axis = null; }\r\n            if (keepDims === void 0) { keepDims = false; }\r\n            this.throwIfDisposed();\r\n            return opHandler.mean(this, axis, keepDims);\r\n        };\r\n        Tensor.prototype.min = function (axis, keepDims) {\r\n            if (axis === void 0) { axis = null; }\r\n            if (keepDims === void 0) { keepDims = false; }\r\n            this.throwIfDisposed();\r\n            return opHandler.min(this, axis, keepDims);\r\n        };\r\n        Tensor.prototype.max = function (axis, keepDims) {\r\n            if (axis === void 0) { axis = null; }\r\n            if (keepDims === void 0) { keepDims = false; }\r\n            this.throwIfDisposed();\r\n            return opHandler.max(this, axis, keepDims);\r\n        };\r\n        Tensor.prototype.argMin = function (axis) {\r\n            if (axis === void 0) { axis = null; }\r\n            this.throwIfDisposed();\r\n            return opHandler.argMin(this, axis);\r\n        };\r\n        Tensor.prototype.argMax = function (axis) {\r\n            if (axis === void 0) { axis = null; }\r\n            this.throwIfDisposed();\r\n            return opHandler.argMax(this, axis);\r\n        };\r\n        Tensor.prototype.cast = function (dtype) {\r\n            this.throwIfDisposed();\r\n            return opHandler.cast(this, dtype);\r\n        };\r\n        Tensor.prototype.add = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.add(this, x);\r\n        };\r\n        Tensor.prototype.addStrict = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.addStrict(this, x);\r\n        };\r\n        Tensor.prototype.atan2 = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.atan2(this, x);\r\n        };\r\n        Tensor.prototype.sub = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.sub(this, x);\r\n        };\r\n        Tensor.prototype.subStrict = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.subStrict(this, x);\r\n        };\r\n        Tensor.prototype.pow = function (exp) {\r\n            this.throwIfDisposed();\r\n            return opHandler.pow(this, exp);\r\n        };\r\n        Tensor.prototype.powStrict = function (exp) {\r\n            this.throwIfDisposed();\r\n            return opHandler.powStrict(this, exp);\r\n        };\r\n        Tensor.prototype.mul = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.mul(this, x);\r\n        };\r\n        Tensor.prototype.mulStrict = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.mulStrict(this, x);\r\n        };\r\n        Tensor.prototype.div = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.div(this, x);\r\n        };\r\n        Tensor.prototype.floorDiv = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.floorDiv(this, x);\r\n        };\r\n        Tensor.prototype.divStrict = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.divStrict(this, x);\r\n        };\r\n        Tensor.prototype.minimum = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.minimum(this, x);\r\n        };\r\n        Tensor.prototype.minimumStrict = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.minimumStrict(this, x);\r\n        };\r\n        Tensor.prototype.maximum = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.maximum(this, x);\r\n        };\r\n        Tensor.prototype.maximumStrict = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.maximumStrict(this, x);\r\n        };\r\n        Tensor.prototype.mod = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.mod(this, x);\r\n        };\r\n        Tensor.prototype.modStrict = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.modStrict(this, x);\r\n        };\r\n        Tensor.prototype.squaredDifference = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.squaredDifference(this, x);\r\n        };\r\n        Tensor.prototype.squaredDifferenceStrict = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.squaredDifferenceStrict(this, x);\r\n        };\r\n        Tensor.prototype.transpose = function (perm) {\r\n            this.throwIfDisposed();\r\n            return opHandler.transpose(this, perm);\r\n        };\r\n        Tensor.prototype.notEqual = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.notEqual(this, x);\r\n        };\r\n        Tensor.prototype.notEqualStrict = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.notEqualStrict(this, x);\r\n        };\r\n        Tensor.prototype.less = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.less(this, x);\r\n        };\r\n        Tensor.prototype.lessStrict = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.lessStrict(this, x);\r\n        };\r\n        Tensor.prototype.equal = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.equal(this, x);\r\n        };\r\n        Tensor.prototype.equalStrict = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.equalStrict(this, x);\r\n        };\r\n        Tensor.prototype.lessEqual = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.lessEqual(this, x);\r\n        };\r\n        Tensor.prototype.lessEqualStrict = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.lessEqualStrict(this, x);\r\n        };\r\n        Tensor.prototype.greater = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.greater(this, x);\r\n        };\r\n        Tensor.prototype.greaterStrict = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.greaterStrict(this, x);\r\n        };\r\n        Tensor.prototype.greaterEqual = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.greaterEqual(this, x);\r\n        };\r\n        Tensor.prototype.greaterEqualStrict = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.greaterEqualStrict(this, x);\r\n        };\r\n        Tensor.prototype.logicalAnd = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.logicalAnd(this, x);\r\n        };\r\n        Tensor.prototype.logicalOr = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.logicalOr(this, x);\r\n        };\r\n        Tensor.prototype.logicalNot = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.logicalNot(this);\r\n        };\r\n        Tensor.prototype.logicalXor = function (x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.logicalXor(this, x);\r\n        };\r\n        Tensor.prototype.where = function (condition, x) {\r\n            this.throwIfDisposed();\r\n            return opHandler.where(condition, this, x);\r\n        };\r\n        Tensor.prototype.neg = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.neg(this);\r\n        };\r\n        Tensor.prototype.ceil = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.ceil(this);\r\n        };\r\n        Tensor.prototype.floor = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.floor(this);\r\n        };\r\n        Tensor.prototype.sign = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.sign(this);\r\n        };\r\n        Tensor.prototype.exp = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.exp(this);\r\n        };\r\n        Tensor.prototype.expm1 = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.expm1(this);\r\n        };\r\n        Tensor.prototype.log = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.log(this);\r\n        };\r\n        Tensor.prototype.log1p = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.log1p(this);\r\n        };\r\n        Tensor.prototype.sqrt = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.sqrt(this);\r\n        };\r\n        Tensor.prototype.rsqrt = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.rsqrt(this);\r\n        };\r\n        Tensor.prototype.square = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.square(this);\r\n        };\r\n        Tensor.prototype.reciprocal = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.reciprocal(this);\r\n        };\r\n        Tensor.prototype.abs = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.abs(this);\r\n        };\r\n        Tensor.prototype.clipByValue = function (min, max) {\r\n            this.throwIfDisposed();\r\n            return opHandler.clipByValue(this, min, max);\r\n        };\r\n        Tensor.prototype.relu = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.relu(this);\r\n        };\r\n        Tensor.prototype.elu = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.elu(this);\r\n        };\r\n        Tensor.prototype.selu = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.selu(this);\r\n        };\r\n        Tensor.prototype.leakyRelu = function (alpha) {\r\n            if (alpha === void 0) { alpha = 0.2; }\r\n            this.throwIfDisposed();\r\n            return opHandler.leakyRelu(this, alpha);\r\n        };\r\n        Tensor.prototype.prelu = function (alpha) {\r\n            this.throwIfDisposed();\r\n            return opHandler.prelu(this, alpha);\r\n        };\r\n        Tensor.prototype.sigmoid = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.sigmoid(this);\r\n        };\r\n        Tensor.prototype.logSigmoid = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.logSigmoid(this);\r\n        };\r\n        Tensor.prototype.softplus = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.softplus(this);\r\n        };\r\n        Tensor.prototype.zerosLike = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.zerosLike(this);\r\n        };\r\n        Tensor.prototype.onesLike = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.onesLike(this);\r\n        };\r\n        Tensor.prototype.sin = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.sin(this);\r\n        };\r\n        Tensor.prototype.cos = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.cos(this);\r\n        };\r\n        Tensor.prototype.tan = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.tan(this);\r\n        };\r\n        Tensor.prototype.asin = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.asin(this);\r\n        };\r\n        Tensor.prototype.acos = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.acos(this);\r\n        };\r\n        Tensor.prototype.atan = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.atan(this);\r\n        };\r\n        Tensor.prototype.sinh = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.sinh(this);\r\n        };\r\n        Tensor.prototype.cosh = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.cosh(this);\r\n        };\r\n        Tensor.prototype.tanh = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.tanh(this);\r\n        };\r\n        Tensor.prototype.asinh = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.asinh(this);\r\n        };\r\n        Tensor.prototype.acosh = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.acosh(this);\r\n        };\r\n        Tensor.prototype.atanh = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.atanh(this);\r\n        };\r\n        Tensor.prototype.erf = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.erf(this);\r\n        };\r\n        Tensor.prototype.round = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.round(this);\r\n        };\r\n        Tensor.prototype.step = function (alpha) {\r\n            if (alpha === void 0) { alpha = 0.0; }\r\n            this.throwIfDisposed();\r\n            return opHandler.step(this, alpha);\r\n        };\r\n        Tensor.prototype.softmax = function (dim) {\r\n            if (dim === void 0) { dim = -1; }\r\n            this.throwIfDisposed();\r\n            return opHandler.softmax(this, dim);\r\n        };\r\n        Tensor.prototype.logSoftmax = function (axis) {\r\n            if (axis === void 0) { axis = -1; }\r\n            this.throwIfDisposed();\r\n            return opHandler.logSoftmax(this, axis);\r\n        };\r\n        Tensor.prototype.resizeBilinear = function (newShape2D, alignCorners) {\r\n            if (alignCorners === void 0) { alignCorners = false; }\r\n            this.throwIfDisposed();\r\n            return opHandler.image.resizeBilinear(this, newShape2D, alignCorners);\r\n        };\r\n        Tensor.prototype.resizeNearestNeighbor = function (newShape2D, alignCorners) {\r\n            if (alignCorners === void 0) { alignCorners = false; }\r\n            this.throwIfDisposed();\r\n            return opHandler.image.resizeNearestNeighbor(this, newShape2D, alignCorners);\r\n        };\r\n        Tensor.prototype.conv1d = function (filter, stride, pad, dataFormat, dilation, dimRoundingMode) {\r\n            if (dataFormat === void 0) { dataFormat = 'NWC'; }\r\n            if (dilation === void 0) { dilation = 1; }\r\n            this.throwIfDisposed();\r\n            return opHandler.conv1d(this, filter, stride, pad, dataFormat, dilation, dimRoundingMode);\r\n        };\r\n        Tensor.prototype.conv2d = function (filter, strides, pad, dataFormat, dilations, dimRoundingMode) {\r\n            if (dataFormat === void 0) { dataFormat = 'NHWC'; }\r\n            if (dilations === void 0) { dilations = [1, 1]; }\r\n            this.throwIfDisposed();\r\n            return opHandler.conv2d(this, filter, strides, pad, dataFormat, dilations, dimRoundingMode);\r\n        };\r\n        Tensor.prototype.conv2dTranspose = function (filter, outputShape, strides, pad, dimRoundingMode) {\r\n            this.throwIfDisposed();\r\n            return opHandler.conv2dTranspose(this, filter, outputShape, strides, pad, dimRoundingMode);\r\n        };\r\n        Tensor.prototype.depthwiseConv2D = function (filter, strides, pad, dataFormat, dilations, dimRoundingMode) {\r\n            if (dataFormat === void 0) { dataFormat = 'NHWC'; }\r\n            if (dilations === void 0) { dilations = [1, 1]; }\r\n            this.throwIfDisposed();\r\n            return opHandler.depthwiseConv2d(this, filter, strides, pad, dataFormat, dilations, dimRoundingMode);\r\n        };\r\n        Tensor.prototype.separableConv2d = function (depthwiseFilter, pointwiseFilter, strides, pad, dilation, dataFormat) {\r\n            if (dilation === void 0) { dilation = [1, 1]; }\r\n            if (dataFormat === void 0) { dataFormat = 'NHWC'; }\r\n            this.throwIfDisposed();\r\n            return opHandler.separableConv2d(this, depthwiseFilter, pointwiseFilter, strides, pad, dilation, dataFormat);\r\n        };\r\n        Tensor.prototype.avgPool = function (filterSize, strides, pad, dimRoundingMode) {\r\n            this.throwIfDisposed();\r\n            return opHandler.avgPool(this, filterSize, strides, pad, dimRoundingMode);\r\n        };\r\n        Tensor.prototype.maxPool = function (filterSize, strides, pad, dimRoundingMode) {\r\n            this.throwIfDisposed();\r\n            return opHandler.maxPool(this, filterSize, strides, pad, dimRoundingMode);\r\n        };\r\n        Tensor.prototype.localResponseNormalization = function (radius, bias, alpha, beta) {\r\n            if (radius === void 0) { radius = 5; }\r\n            if (bias === void 0) { bias = 1; }\r\n            if (alpha === void 0) { alpha = 1; }\r\n            if (beta === void 0) { beta = 0.5; }\r\n            return opHandler.localResponseNormalization(this, radius, bias, alpha, beta);\r\n        };\r\n        Tensor.prototype.pool = function (windowShape, poolingType, padding, dilationRate, strides) {\r\n            this.throwIfDisposed();\r\n            return opHandler.pool(this, windowShape, poolingType, padding, dilationRate, strides);\r\n        };\r\n        Tensor.prototype.variable = function (trainable, name, dtype) {\r\n            if (trainable === void 0) { trainable = true; }\r\n            this.throwIfDisposed();\r\n            return Variable.variable(this, trainable, name, dtype);\r\n        };\r\n        Tensor.prototype.unsortedSegmentSum = function (segmentIds, numSegments) {\r\n            this.throwIfDisposed();\r\n            return opHandler.unsortedSegmentSum(this, segmentIds, numSegments);\r\n        };\r\n        Tensor.prototype.batchToSpaceND = function (blockShape, crops) {\r\n            this.throwIfDisposed();\r\n            return opHandler.batchToSpaceND(this, blockShape, crops);\r\n        };\r\n        Tensor.prototype.spaceToBatchND = function (blockShape, paddings) {\r\n            this.throwIfDisposed();\r\n            return opHandler.spaceToBatchND(this, blockShape, paddings);\r\n        };\r\n        Tensor.prototype.topk = function (k, sorted) {\r\n            if (k === void 0) { k = 1; }\r\n            if (sorted === void 0) { sorted = true; }\r\n            this.throwIfDisposed();\r\n            return opHandler.topk(this, k, sorted);\r\n        };\r\n        Tensor.prototype.stridedSlice = function (begin, end, strides, beginMask, endMask, ellipsisMask, newAxisMask, shrinkAxisMask) {\r\n            if (beginMask === void 0) { beginMask = 0; }\r\n            if (endMask === void 0) { endMask = 0; }\r\n            if (ellipsisMask === void 0) { ellipsisMask = 0; }\r\n            if (newAxisMask === void 0) { newAxisMask = 0; }\r\n            if (shrinkAxisMask === void 0) { shrinkAxisMask = 0; }\r\n            this.throwIfDisposed();\r\n            return opHandler.stridedSlice(this, begin, end, strides, beginMask, endMask, ellipsisMask, newAxisMask, shrinkAxisMask);\r\n        };\r\n        Tensor.prototype.depthToSpace = function (blockSize, dataFormat) {\r\n            this.throwIfDisposed();\r\n            return opHandler.depthToSpace(this, blockSize, dataFormat);\r\n        };\r\n        Tensor.prototype.fft = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.spectral.fft(this);\r\n        };\r\n        Tensor.prototype.ifft = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.spectral.ifft(this);\r\n        };\r\n        Tensor.prototype.rfft = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.spectral.rfft(this);\r\n        };\r\n        Tensor.prototype.irfft = function () {\r\n            this.throwIfDisposed();\r\n            return opHandler.spectral.irfft(this);\r\n        };\r\n        return Tensor;\r\n    }());\r\n    Object.defineProperty(Tensor, Symbol.hasInstance, {\r\n        value: function (instance) {\r\n            return !!instance && instance.dataId != null && instance.shape != null &&\r\n                instance.dtype != null;\r\n        }\r\n    });\r\n    var Variable = (function (_super) {\r\n        __extends(Variable, _super);\r\n        function Variable(initialValue, trainable, name) {\r\n            if (trainable === void 0) { trainable = true; }\r\n            var _this = _super.call(this, initialValue.shape, initialValue.dtype, null, initialValue.dataId) || this;\r\n            _this.trainable = trainable;\r\n            _this.name = name;\r\n            if (_this.name == null) {\r\n                _this.name = trackerFn().nextVariableId().toString();\r\n            }\r\n            try {\r\n                trackerFn().registerVariable(_this);\r\n            }\r\n            catch (ex) {\r\n                trackerFn().disposeTensor(_this);\r\n                throw ex;\r\n            }\r\n            return _this;\r\n        }\r\n        Variable.variable = function (initialValue, trainable, name, dtype) {\r\n            if (trainable === void 0) { trainable = true; }\r\n            if (dtype != null && dtype !== initialValue.dtype) {\r\n                initialValue = initialValue.asType(dtype);\r\n            }\r\n            return new Variable(initialValue, trainable, name);\r\n        };\r\n        Variable.prototype.assign = function (newValue) {\r\n            if (newValue.dtype !== this.dtype) {\r\n                throw new Error(\"dtype of the new value (\" + newValue.dtype + \") and \" +\r\n                    (\"previous value (\" + this.dtype + \") must match\"));\r\n            }\r\n            if (!arraysEqual(newValue.shape, this.shape)) {\r\n                throw new Error(\"shape of the new value (\" + newValue.shape + \") and \" +\r\n                    (\"previous value (\" + this.shape + \") must match\"));\r\n            }\r\n            trackerFn().disposeTensor(this);\r\n            this.dataId = newValue.dataId;\r\n            trackerFn().registerTensor(this);\r\n        };\r\n        return Variable;\r\n    }(Tensor));\r\n    Object.defineProperty(Variable, Symbol.hasInstance, {\r\n        value: function (instance) {\r\n            return instance instanceof Tensor && instance.assign != null &&\r\n                instance.assign instanceof Function;\r\n        }\r\n    });\r\n    var variable = Variable.variable;\n\n    function getFilteredNodesXToY(tape, xs, y) {\r\n        var tensorsFromX = {};\r\n        var nodesFromX = {};\r\n        for (var i = 0; i < xs.length; i++) {\r\n            tensorsFromX[xs[i].id] = true;\r\n        }\r\n        for (var i = 0; i < tape.length; i++) {\r\n            var node = tape[i];\r\n            var nodeInputs = node.inputs;\r\n            for (var inputName in nodeInputs) {\r\n                var input = nodeInputs[inputName];\r\n                var anyInputFromX = false;\r\n                for (var j = 0; j < xs.length; j++) {\r\n                    if (tensorsFromX[input.id]) {\r\n                        node.outputs.forEach(function (output) { return tensorsFromX[output.id] = true; });\r\n                        anyInputFromX = true;\r\n                        nodesFromX[node.id] = true;\r\n                        break;\r\n                    }\r\n                }\r\n                if (anyInputFromX) {\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n        var tensorsLeadToY = {};\r\n        tensorsLeadToY[y.id] = true;\r\n        var nodesToY = {};\r\n        for (var i = tape.length - 1; i >= 0; i--) {\r\n            var node = tape[i];\r\n            var nodeInputs = node.inputs;\r\n            for (var j = 0; j < node.outputs.length; j++) {\r\n                if (tensorsLeadToY[node.outputs[j].id]) {\r\n                    for (var inputName in nodeInputs) {\r\n                        tensorsLeadToY[nodeInputs[inputName].id] = true;\r\n                        nodesToY[node.id] = true;\r\n                    }\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n        var filteredTape = [];\r\n        for (var i = 0; i < tape.length; i++) {\r\n            var node = tape[i];\r\n            if (nodesFromX[node.id] && nodesToY[node.id]) {\r\n                var prunedInputs = {};\r\n                for (var inputName in node.inputs) {\r\n                    var nodeInput = node.inputs[inputName];\r\n                    if (tensorsFromX[nodeInput.id]) {\r\n                        prunedInputs[inputName] = nodeInput;\r\n                    }\r\n                }\r\n                var prunedNode = Object.assign({}, node);\r\n                prunedNode.inputs = prunedInputs;\r\n                prunedNode.outputs = node.outputs;\r\n                filteredTape.push(prunedNode);\r\n            }\r\n        }\r\n        return filteredTape;\r\n    }\r\n    function backpropagateGradients(tensorAccumulatedGradientMap, filteredTape) {\r\n        var _loop_1 = function (i) {\r\n            var node = filteredTape[i];\r\n            var dys = [];\r\n            node.outputs.forEach(function (o) {\r\n                var gradTensor = tensorAccumulatedGradientMap[o.id];\r\n                if (gradTensor != null) {\r\n                    dys.push(gradTensor);\r\n                }\r\n                else {\r\n                    var dy = Tensor.make(o.shape, { values: makeZerosTypedArray(o.size, o.dtype) }, o.dtype);\r\n                    dys.push(dy);\r\n                }\r\n            });\r\n            if (node.gradient == null) {\r\n                throw new Error(\"Cannot compute gradient: gradient function not found \" +\r\n                    (\"for \" + node.name + \".\"));\r\n            }\r\n            var inputGradients = node.gradient(node.outputs.length === 1 ? dys[0] : dys);\r\n            for (var inputName in node.inputs) {\r\n                if (!(inputName in inputGradients)) {\r\n                    throw new Error(\"Cannot backprop through input \" + inputName + \". \" +\r\n                        (\"Available gradients found: \" + Object.keys(inputGradients) + \".\"));\r\n                }\r\n                var dx = inputGradients[inputName]();\r\n                if (dx.dtype !== 'float32') {\r\n                    throw new Error(\"Error in gradient for op \" + node.name + \". The gradient of input \" +\r\n                        (inputName + \" must have 'float32' dtype, but has '\" + dx.dtype + \"'\"));\r\n                }\r\n                var x = node.inputs[inputName];\r\n                if (!arraysEqual(dx.shape, x.shape)) {\r\n                    throw new Error(\"Error in gradient for op \" + node.name + \". The gradient of input \" +\r\n                        (\"'\" + inputName + \"' has shape '\" + dx.shape + \"', which does not match \") +\r\n                        (\"the shape of the input '\" + x.shape + \"'\"));\r\n                }\r\n                if (tensorAccumulatedGradientMap[x.id] == null) {\r\n                    tensorAccumulatedGradientMap[x.id] = dx;\r\n                }\r\n                else {\r\n                    var curGradient = tensorAccumulatedGradientMap[x.id];\r\n                    tensorAccumulatedGradientMap[x.id] = curGradient.add(dx);\r\n                    curGradient.dispose();\r\n                }\r\n            }\r\n        };\r\n        for (var i = filteredTape.length - 1; i >= 0; i--) {\r\n            _loop_1(i);\r\n        }\r\n    }\n\n    (function (Rank) {\r\n        Rank[\"R0\"] = \"R0\";\r\n        Rank[\"R1\"] = \"R1\";\r\n        Rank[\"R2\"] = \"R2\";\r\n        Rank[\"R3\"] = \"R3\";\r\n        Rank[\"R4\"] = \"R4\";\r\n        Rank[\"R5\"] = \"R5\";\r\n        Rank[\"R6\"] = \"R6\";\r\n    })(exports.Rank || (exports.Rank = {}));\r\n    var UpcastInt32AndMap;\r\n    (function (UpcastInt32AndMap) {\r\n        UpcastInt32AndMap[\"float32\"] = \"float32\";\r\n        UpcastInt32AndMap[\"int32\"] = \"int32\";\r\n        UpcastInt32AndMap[\"bool\"] = \"int32\";\r\n        UpcastInt32AndMap[\"complex64\"] = \"complex64\";\r\n    })(UpcastInt32AndMap || (UpcastInt32AndMap = {}));\r\n    var UpcastBoolAndMap;\r\n    (function (UpcastBoolAndMap) {\r\n        UpcastBoolAndMap[\"float32\"] = \"float32\";\r\n        UpcastBoolAndMap[\"int32\"] = \"int32\";\r\n        UpcastBoolAndMap[\"bool\"] = \"bool\";\r\n        UpcastBoolAndMap[\"complex64\"] = \"complex64\";\r\n    })(UpcastBoolAndMap || (UpcastBoolAndMap = {}));\r\n    var UpcastFloat32AndMap;\r\n    (function (UpcastFloat32AndMap) {\r\n        UpcastFloat32AndMap[\"float32\"] = \"float32\";\r\n        UpcastFloat32AndMap[\"int32\"] = \"float32\";\r\n        UpcastFloat32AndMap[\"bool\"] = \"float32\";\r\n        UpcastFloat32AndMap[\"complex64\"] = \"complex64\";\r\n    })(UpcastFloat32AndMap || (UpcastFloat32AndMap = {}));\r\n    var UpcastComplex64AndMap;\r\n    (function (UpcastComplex64AndMap) {\r\n        UpcastComplex64AndMap[\"float32\"] = \"complex64\";\r\n        UpcastComplex64AndMap[\"int32\"] = \"complex64\";\r\n        UpcastComplex64AndMap[\"bool\"] = \"complex64\";\r\n        UpcastComplex64AndMap[\"complex64\"] = \"complex64\";\r\n    })(UpcastComplex64AndMap || (UpcastComplex64AndMap = {}));\r\n    var upcastTypeMap = {\r\n        'float32': UpcastFloat32AndMap,\r\n        'int32': UpcastInt32AndMap,\r\n        'bool': UpcastBoolAndMap,\r\n        'complex64': UpcastComplex64AndMap\r\n    };\r\n    function upcastType(typeA, typeB) {\r\n        if (typeA === 'string' || typeB === 'string') {\r\n            if (typeA === 'string' && typeB === 'string') {\r\n                return 'string';\r\n            }\r\n            throw new Error(\"Can not upcast \" + typeA + \" with \" + typeB);\r\n        }\r\n        return upcastTypeMap[typeA][typeB];\r\n    }\r\n    function sumOutType(type) {\r\n        return upcastType(type, 'int32');\r\n    }\n\n    function makeTypesMatch(a, b) {\r\n        if (a.dtype === b.dtype) {\r\n            return [a, b];\r\n        }\r\n        var dtype = upcastType(a.dtype, b.dtype);\r\n        return [a.cast(dtype), b.cast(dtype)];\r\n    }\r\n    function assertTypesMatch(a, b) {\r\n        assert(a.dtype === b.dtype, \"The dtypes of the first(\" + a.dtype + \") and\" +\r\n            (\" second(\" + b.dtype + \") input must match\"));\r\n    }\r\n    function isTensorInList(tensor, tensorList) {\r\n        for (var i = 0; i < tensorList.length; i++) {\r\n            if (tensorList[i].id === tensor.id) {\r\n                return true;\r\n            }\r\n        }\r\n        return false;\r\n    }\r\n    function getTensorsInContainer(result) {\r\n        var list = [];\r\n        var seen = new Set();\r\n        walkTensorContainer(result, list, seen);\r\n        return list;\r\n    }\r\n    function walkTensorContainer(container, list, seen) {\r\n        if (container == null) {\r\n            return;\r\n        }\r\n        if (container instanceof Tensor) {\r\n            list.push(container);\r\n            return;\r\n        }\r\n        if (!isIterable(container)) {\r\n            return;\r\n        }\r\n        var iterable = container;\r\n        for (var k in iterable) {\r\n            var val = iterable[k];\r\n            if (!seen.has(val)) {\r\n                seen.add(val);\r\n                walkTensorContainer(val, list, seen);\r\n            }\r\n        }\r\n    }\r\n    function isIterable(obj) {\r\n        return Array.isArray(obj) || typeof obj === 'object';\r\n    }\n\n    var Engine = (function () {\r\n        function Engine(backend, safeMode, debugMode) {\r\n            this.backend = backend;\r\n            this.safeMode = safeMode;\r\n            this.debugMode = debugMode;\r\n            this.registeredVariables = {};\r\n            this.nextTapeNodeId = 0;\r\n            this.numBytes = 0;\r\n            this.numTensors = 0;\r\n            this.numStringTensors = 0;\r\n            this.numDataBuffers = 0;\r\n            this.profiling = false;\r\n            this.gradientScopeCount = 0;\r\n            this.customGradientDepth = 0;\r\n            this.scopeStack = [];\r\n            this.keepTensors = new Set();\r\n            this.tensorInfo = new WeakMap();\r\n            this.profiler = new Profiler(backend);\r\n            this.activeProfile =\r\n                { newBytes: 0, newTensors: 0, peakBytes: 0, kernels: [], result: null };\r\n        }\r\n        Engine.prototype.moveData = function (dataId) {\r\n            this.write(dataId, this.readSync(dataId));\r\n        };\r\n        Engine.prototype.tidy = function (nameOrFn, fn, gradMode) {\r\n            var _this = this;\r\n            if (gradMode === void 0) { gradMode = false; }\r\n            var name = null;\r\n            if (fn == null) {\r\n                if (typeof nameOrFn !== 'function') {\r\n                    throw new Error('Please provide a function to tidy()');\r\n                }\r\n                fn = nameOrFn;\r\n            }\r\n            else {\r\n                if (typeof nameOrFn !== 'string' && !(nameOrFn instanceof String)) {\r\n                    throw new Error('When calling with two arguments, the first argument ' +\r\n                        'to tidy() must be a string');\r\n                }\r\n                if (typeof fn !== 'function') {\r\n                    throw new Error('When calling with two arguments, the 2nd argument ' +\r\n                        'to tidy() must be a function');\r\n                }\r\n                name = nameOrFn;\r\n            }\r\n            var result;\r\n            return this.scopedRun(function () { return _this.startScope(name, gradMode); }, function () { return _this.endScope(result, gradMode); }, function () {\r\n                result = fn();\r\n                if (result instanceof Promise) {\r\n                    console.error('Cannot return a Promise inside of tidy.');\r\n                }\r\n                return result;\r\n            });\r\n        };\r\n        Engine.prototype.scopedRun = function (start, end, f) {\r\n            start();\r\n            try {\r\n                var res = f();\r\n                end();\r\n                return res;\r\n            }\r\n            catch (ex) {\r\n                end();\r\n                throw ex;\r\n            }\r\n        };\r\n        Engine.prototype.nextTensorId = function () {\r\n            return Engine.nextTensorId++;\r\n        };\r\n        Engine.prototype.nextVariableId = function () {\r\n            return Engine.nextVariableId++;\r\n        };\r\n        Engine.prototype.runKernel = function (forwardFunc, inputs, backwardsFunc) {\r\n            var _this = this;\r\n            var result;\r\n            var saved = [];\r\n            var saveFunc = function (x) {\r\n                saved.push(x);\r\n                return x;\r\n            };\r\n            var scopeName = this.activeScope != null ? this.activeScope.name : '';\r\n            var startingBytecount = this.numBytes;\r\n            var startingNumTensors = this.numTensors;\r\n            this.scopedRun(function () { return _this.customGradientDepth++; }, function () { return _this.customGradientDepth--; }, function () {\r\n                if (!_this.debugMode()) {\r\n                    result = forwardFunc(_this.backend, saveFunc);\r\n                }\r\n                else {\r\n                    result = _this.profiler.profileKernel(scopeName, function () { return forwardFunc(_this.backend, saveFunc); });\r\n                }\r\n            });\r\n            if (this.shouldRecord()) {\r\n                var tapeNode = {\r\n                    id: this.nextTapeNodeId++,\r\n                    name: scopeName,\r\n                    inputs: inputs,\r\n                    outputs: Array.isArray(result) ? result : [result]\r\n                };\r\n                if (backwardsFunc != null) {\r\n                    tapeNode.gradient =\r\n                        (function (dy) { return backwardsFunc(dy, saved); });\r\n                }\r\n                this.activeTape.push(tapeNode);\r\n            }\r\n            if (this.profiling) {\r\n                this.activeProfile.kernels.push({\r\n                    name: scopeName,\r\n                    bytesAdded: this.numBytes - startingBytecount,\r\n                    totalBytesSnapshot: this.numBytes,\r\n                    tensorsAdded: this.numTensors - startingNumTensors,\r\n                    totalTensorsSnapshot: this.numTensors,\r\n                    inputShapes: Object.keys(inputs).map(function (key) { return inputs[key].shape; }),\r\n                    outputShape: Array.isArray(result) ?\r\n                        result.map(function (item) { return item.shape; }) :\r\n                        result.shape\r\n                });\r\n            }\r\n            return result;\r\n        };\r\n        Engine.prototype.registerTensor = function (a) {\r\n            var refCount = this.tensorInfo.has(a.dataId) ?\r\n                this.tensorInfo.get(a.dataId).refCount :\r\n                0;\r\n            this.numTensors++;\r\n            if (a.dtype === 'string') {\r\n                this.numStringTensors++;\r\n            }\r\n            if (refCount === 0) {\r\n                this.numDataBuffers++;\r\n                var bytes = 0;\r\n                if (a.dtype !== 'complex64' && a.dtype !== 'string') {\r\n                    bytes = sizeFromShape(a.shape) * bytesPerElement(a.dtype);\r\n                }\r\n                this.tensorInfo.set(a.dataId, {\r\n                    backend: this.backend,\r\n                    dtype: a.dtype,\r\n                    shape: a.shape,\r\n                    bytes: bytes,\r\n                    refCount: 0\r\n                });\r\n                this.numBytes += bytes;\r\n                this.backend.register(a.dataId, a.shape, a.dtype);\r\n            }\r\n            this.tensorInfo.get(a.dataId).refCount++;\r\n            if (!(a instanceof Variable)) {\r\n                this.track(a);\r\n            }\r\n        };\r\n        Engine.prototype.registerVariable = function (v) {\r\n            if (this.registeredVariables[v.name] != null) {\r\n                throw new Error(\"Variable with name \" + v.name + \" was already registered\");\r\n            }\r\n            this.registeredVariables[v.name] = v;\r\n        };\r\n        Engine.prototype.disposeTensor = function (a) {\r\n            if (!this.tensorInfo.has(a.dataId)) {\r\n                return;\r\n            }\r\n            if (this.keepTensors.has(a.id)) {\r\n                this.keepTensors.delete(a.id);\r\n            }\r\n            this.numTensors--;\r\n            if (a.dtype === 'string') {\r\n                this.numStringTensors--;\r\n            }\r\n            var info = this.tensorInfo.get(a.dataId);\r\n            var refCount = info.refCount;\r\n            if (refCount <= 1) {\r\n                if (a.dtype !== 'complex64') {\r\n                    this.numBytes -= info.bytes;\r\n                }\r\n                this.numDataBuffers--;\r\n                info.backend.disposeData(a.dataId);\r\n                this.tensorInfo.delete(a.dataId);\r\n            }\r\n            else {\r\n                this.tensorInfo.get(a.dataId).refCount--;\r\n            }\r\n        };\r\n        Engine.prototype.disposeVariables = function () {\r\n            for (var varName in this.registeredVariables) {\r\n                var v = this.registeredVariables[varName];\r\n                this.disposeTensor(v);\r\n                delete this.registeredVariables[varName];\r\n            }\r\n        };\r\n        Engine.prototype.memory = function () {\r\n            var info = this.backend.memory();\r\n            info.numTensors = this.numTensors;\r\n            info.numDataBuffers = this.numDataBuffers;\r\n            info.numBytes = this.numBytes;\r\n            if (this.numStringTensors > 0) {\r\n                info.unreliable = true;\r\n                if (info.reasons == null) {\r\n                    info.reasons = [];\r\n                }\r\n                info.reasons.push('Memory usage by string tensors is approximate ' +\r\n                    '(2 bytes per character)');\r\n            }\r\n            return info;\r\n        };\r\n        Engine.prototype.profile = function (query) {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var startBytes, startNumTensors;\r\n                return __generator(this, function (_a) {\r\n                    this.profiling = true;\r\n                    startBytes = this.numBytes;\r\n                    startNumTensors = this.numTensors;\r\n                    this.activeProfile.kernels = [];\r\n                    this.activeProfile.result = query();\r\n                    this.profiling = false;\r\n                    this.activeProfile.peakBytes = Math.max.apply(Math, this.activeProfile.kernels.map(function (d) { return d.totalBytesSnapshot; }));\r\n                    this.activeProfile.newBytes = this.numBytes - startBytes;\r\n                    this.activeProfile.newTensors = this.numTensors - startNumTensors;\r\n                    return [2, this.activeProfile];\r\n                });\r\n            });\r\n        };\r\n        Engine.prototype.shouldRecord = function () {\r\n            return this.activeTape != null && this.customGradientDepth === 0;\r\n        };\r\n        Engine.prototype.addTapeNode = function (inputs, result, gradientsFunc) {\r\n            var inputsMap = {};\r\n            inputs.forEach(function (input, idx) {\r\n                inputsMap[idx] = input;\r\n            });\r\n            var gradient = function (dy) {\r\n                var res = gradientsFunc(dy);\r\n                var resMap = {};\r\n                res.forEach(function (r, idx) {\r\n                    resMap[idx] = function () { return r; };\r\n                });\r\n                return resMap;\r\n            };\r\n            var tapeNode = {\r\n                id: this.nextTapeNodeId++,\r\n                name: this.activeScope.name,\r\n                inputs: inputsMap,\r\n                outputs: [result],\r\n                gradient: gradient\r\n            };\r\n            this.activeTape.push(tapeNode);\r\n        };\r\n        Engine.prototype.keep = function (result) {\r\n            if (this.scopeStack.length === 1 && this.safeMode) {\r\n                throw new Error('Safe mode is ON. Enclose all tensor operations inside tf.tidy(): ' +\r\n                    'tf.tidy(() => {...}) to avoid memory leaks.');\r\n            }\r\n            this.keepTensors.add(result.id);\r\n            return result;\r\n        };\r\n        Engine.prototype.startScope = function (name, gradientsMode) {\r\n            if (gradientsMode === void 0) { gradientsMode = false; }\r\n            if (gradientsMode && this.gradientScopeCount === 0) {\r\n                this.activeTape = [];\r\n            }\r\n            if (gradientsMode) {\r\n                this.gradientScopeCount++;\r\n            }\r\n            var scopeInfo = { track: [], name: 'unnamed scope' };\r\n            if (name) {\r\n                scopeInfo.name = name;\r\n            }\r\n            this.scopeStack.push(scopeInfo);\r\n            this.activeScope = scopeInfo;\r\n        };\r\n        Engine.prototype.endScope = function (result, gradientsMode) {\r\n            var _this = this;\r\n            if (gradientsMode === void 0) { gradientsMode = false; }\r\n            if (gradientsMode) {\r\n                this.gradientScopeCount--;\r\n                if (this.gradientScopeCount === 0) {\r\n                    this.activeTape = null;\r\n                }\r\n            }\r\n            var tensorsToKeep = new Set(this.keepTensors);\r\n            var tensorsToTrackInParent = getTensorsInContainer(result);\r\n            tensorsToTrackInParent.forEach(function (tensor) { return tensorsToKeep.add(tensor.id); });\r\n            for (var i = 0; i < this.activeScope.track.length; i++) {\r\n                var tensor = this.activeScope.track[i];\r\n                if (tensorsToKeep.has(tensor.id)) {\r\n                    continue;\r\n                }\r\n                if (this.activeTape != null) {\r\n                    tensorsToTrackInParent.push(tensor);\r\n                }\r\n                else {\r\n                    tensor.dispose();\r\n                }\r\n            }\r\n            var oldScope = this.scopeStack.pop();\r\n            this.activeScope = this.scopeStack.length === 0 ?\r\n                null :\r\n                this.scopeStack[this.scopeStack.length - 1];\r\n            tensorsToTrackInParent.forEach(function (tensor) {\r\n                if (!_this.keepTensors.has(tensor.id) &&\r\n                    isTensorInList(tensor, oldScope.track)) {\r\n                    _this.track(tensor);\r\n                }\r\n            });\r\n        };\r\n        Engine.prototype.gradients = function (f, xs, dy, allowNoGradients) {\r\n            var _this = this;\r\n            if (allowNoGradients === void 0) { allowNoGradients = false; }\r\n            assert(xs.length > 0, 'gradients() received an empty list of xs.');\r\n            if (dy != null && dy.dtype !== 'float32') {\r\n                throw new Error(\"dy must have 'float32' dtype, but has '\" + dy.dtype + \"'\");\r\n            }\r\n            return this.tidy('gradients', function () {\r\n                var y = f();\r\n                assert(y instanceof Tensor, 'The result y returned by f() must be a tensor.');\r\n                var filteredTape = getFilteredNodesXToY(_this.activeTape, xs, y);\r\n                if (!allowNoGradients && filteredTape.length === 0 && xs.length > 0) {\r\n                    throw new Error('Cannot compute gradient of y=f(x) with respect to x. Make sure ' +\r\n                        'that the f you passed encloses all operations that lead from x ' +\r\n                        'to y.');\r\n                }\r\n                var accumulatedGradientMap = {};\r\n                accumulatedGradientMap[y.id] = (dy == null) ? ones(y.shape) : dy;\r\n                backpropagateGradients(accumulatedGradientMap, filteredTape);\r\n                var grads = xs.map(function (x) { return accumulatedGradientMap[x.id]; });\r\n                return { value: y, grads: grads };\r\n            }, true);\r\n        };\r\n        Engine.prototype.customGrad = function (f) {\r\n            var _this = this;\r\n            assert(isFunction(f), 'The f passed in customGrad(f) must be a function.');\r\n            return function () {\r\n                var inputs = [];\r\n                for (var _i = 0; _i < arguments.length; _i++) {\r\n                    inputs[_i] = arguments[_i];\r\n                }\r\n                assert(inputs.every(function (t) { return t instanceof Tensor; }), 'The args passed in customGrad(f)(x1, x2,...) must all be tensors');\r\n                var gradientsFunc;\r\n                var result;\r\n                _this.scopedRun(function () { return _this.customGradientDepth++; }, function () { return _this.customGradientDepth--; }, function () {\r\n                    var gradientsMode = true;\r\n                    result = _this.tidy(f.name, function () {\r\n                        var _a = f.apply(void 0, inputs), value = _a.value, gradFunc = _a.gradFunc;\r\n                        assert(value instanceof Tensor, 'The function f passed in customGrad(f) must return an ' +\r\n                            'object where `obj.value` is a tensor');\r\n                        assert(isFunction(gradFunc), 'The function f passed in customGrad(f) must return an ' +\r\n                            'object where `obj.gradFunc` is a function.');\r\n                        gradientsFunc = gradFunc;\r\n                        return value;\r\n                    }, gradientsMode);\r\n                });\r\n                if (_this.shouldRecord()) {\r\n                    var gradFunc = function (dy) {\r\n                        var res = gradientsFunc(dy);\r\n                        var grads = Array.isArray(res) ? res : [res];\r\n                        assert(grads.length === inputs.length, 'The function f passed in customGrad(f) must return an object ' +\r\n                            'where `obj.gradFunc` is a function that returns the same ' +\r\n                            'number of tensors as inputs passed to f(...).');\r\n                        assert(grads.every(function (t) { return t instanceof Tensor; }), 'The function f passed in customGrad(f) must return an object ' +\r\n                            'where `obj.gradFunc` is a function that returns a list of ' +\r\n                            'only tensors.');\r\n                        return grads;\r\n                    };\r\n                    _this.addTapeNode(inputs, result, gradFunc);\r\n                }\r\n                return result;\r\n            };\r\n        };\r\n        Engine.prototype.write = function (dataId, values) {\r\n            var info = this.tensorInfo.get(dataId);\r\n            if (info.dtype === 'string') {\r\n                var newBytes = bytesFromStringArray(values);\r\n                this.numBytes += newBytes - info.bytes;\r\n                info.bytes = newBytes;\r\n            }\r\n            if (this.backend !== info.backend) {\r\n                info.backend.disposeData(dataId);\r\n                info.backend = this.backend;\r\n                this.backend.register(dataId, info.shape, info.dtype);\r\n            }\r\n            this.backend.write(dataId, values);\r\n        };\r\n        Engine.prototype.readSync = function (dataId) {\r\n            var info = this.tensorInfo.get(dataId);\r\n            return info.backend.readSync(dataId);\r\n        };\r\n        Engine.prototype.read = function (dataId) {\r\n            var info = this.tensorInfo.get(dataId);\r\n            return info.backend.read(dataId);\r\n        };\r\n        Engine.prototype.fromPixels = function (pixels, numChannels) {\r\n            return this.backend.fromPixels(pixels, numChannels);\r\n        };\r\n        Engine.prototype.time = function (query) {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var start, timingInfo;\r\n                return __generator(this, function (_a) {\r\n                    switch (_a.label) {\r\n                        case 0:\r\n                            start = now();\r\n                            return [4, this.backend.time(query)];\r\n                        case 1:\r\n                            timingInfo = _a.sent();\r\n                            timingInfo.wallMs = now() - start;\r\n                            return [2, timingInfo];\r\n                    }\r\n                });\r\n            });\r\n        };\r\n        Engine.prototype.track = function (result) {\r\n            if (this.scopeStack.length === 1 && this.safeMode) {\r\n                throw new Error('Safe mode is ON. Enclose all tensor operations inside tf.tidy(): ' +\r\n                    'tf.tidy(() => {op();...}); to avoid memory leaks.');\r\n            }\r\n            if (this.activeScope != null) {\r\n                this.activeScope.track.push(result);\r\n            }\r\n            return result;\r\n        };\r\n        Engine.nextTensorId = 0;\r\n        Engine.nextVariableId = 0;\r\n        return Engine;\r\n    }());\r\n    function ones(shape) {\r\n        var values = makeOnesTypedArray(sizeFromShape(shape), 'float32');\r\n        return Tensor.make(shape, { values: values });\r\n    }\n\n    var Type;\r\n    (function (Type) {\r\n        Type[Type[\"NUMBER\"] = 0] = \"NUMBER\";\r\n        Type[Type[\"BOOLEAN\"] = 1] = \"BOOLEAN\";\r\n        Type[Type[\"STRING\"] = 2] = \"STRING\";\r\n    })(Type || (Type = {}));\r\n    var URL_PROPERTIES = [\r\n        { name: 'DEBUG', type: Type.BOOLEAN },\r\n        { name: 'IS_BROWSER', type: Type.BOOLEAN },\r\n        { name: 'WEBGL_LAZILY_UNPACK', type: Type.BOOLEAN },\r\n        { name: 'WEBGL_CPU_FORWARD', type: Type.BOOLEAN },\r\n        { name: 'WEBGL_PACK', type: Type.BOOLEAN },\r\n        { name: 'WEBGL_PACK_BATCHNORMALIZATION', type: Type.BOOLEAN },\r\n        { name: 'WEBGL_PACK_CLIP', type: Type.BOOLEAN },\r\n        { name: 'WEBGL_PACK_DEPTHWISECONV', type: Type.BOOLEAN },\r\n        { name: 'WEBGL_PACK_BINARY_OPERATIONS', type: Type.BOOLEAN },\r\n        { name: 'WEBGL_PACK_ARRAY_OPERATIONS', type: Type.BOOLEAN },\r\n        { name: 'WEBGL_CONV_IM2COL', type: Type.BOOLEAN },\r\n        { name: 'WEBGL_MAX_TEXTURE_SIZE', type: Type.NUMBER },\r\n        { name: 'WEBGL_NUM_MB_BEFORE_PAGING', type: Type.NUMBER },\r\n        { name: 'WEBGL_MAX_TEXTURES_IN_SHADER', type: Type.NUMBER },\r\n        { name: 'WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION', type: Type.NUMBER },\r\n        { name: 'WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_RELIABLE', type: Type.BOOLEAN },\r\n        { name: 'WEBGL_VERSION', type: Type.NUMBER },\r\n        { name: 'WEBGL_RENDER_FLOAT32_ENABLED', type: Type.BOOLEAN },\r\n        { name: 'WEBGL_DOWNLOAD_FLOAT_ENABLED', type: Type.BOOLEAN },\r\n        { name: 'WEBGL_FENCE_API_ENABLED', type: Type.BOOLEAN },\r\n        { name: 'WEBGL_SIZE_UPLOAD_UNIFORM', type: Type.NUMBER },\r\n        { name: 'BACKEND', type: Type.STRING },\r\n        { name: 'EPSILON', type: Type.NUMBER },\r\n        { name: 'PROD', type: Type.BOOLEAN },\r\n        { name: 'TENSORLIKE_CHECK_SHAPE_CONSISTENCY', type: Type.BOOLEAN },\r\n    ];\r\n    function isWebGLVersionEnabled(webGLVersion) {\r\n        try {\r\n            var gl = getWebGLContext(webGLVersion);\r\n            if (gl != null) {\r\n                return true;\r\n            }\r\n        }\r\n        catch (e) {\r\n            return false;\r\n        }\r\n        return false;\r\n    }\r\n    var MAX_TEXTURE_SIZE;\r\n    var MAX_TEXTURES_IN_SHADER;\r\n    function getWebGLMaxTextureSize(webGLVersion) {\r\n        if (MAX_TEXTURE_SIZE == null) {\r\n            var gl = getWebGLContext(webGLVersion);\r\n            MAX_TEXTURE_SIZE = gl.getParameter(gl.MAX_TEXTURE_SIZE);\r\n        }\r\n        return MAX_TEXTURE_SIZE;\r\n    }\r\n    function getMaxTexturesInShader(webGLVersion) {\r\n        if (MAX_TEXTURES_IN_SHADER == null) {\r\n            var gl = getWebGLContext(webGLVersion);\r\n            MAX_TEXTURES_IN_SHADER = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);\r\n        }\r\n        return Math.min(16, MAX_TEXTURES_IN_SHADER);\r\n    }\r\n    function getWebGLDisjointQueryTimerVersion(webGLVersion) {\r\n        if (webGLVersion === 0) {\r\n            return 0;\r\n        }\r\n        var queryTimerVersion;\r\n        var gl = getWebGLContext(webGLVersion);\r\n        if (hasExtension(gl, 'EXT_disjoint_timer_query_webgl2') &&\r\n            webGLVersion === 2) {\r\n            queryTimerVersion = 2;\r\n        }\r\n        else if (hasExtension(gl, 'EXT_disjoint_timer_query')) {\r\n            queryTimerVersion = 1;\r\n        }\r\n        else {\r\n            queryTimerVersion = 0;\r\n        }\r\n        return queryTimerVersion;\r\n    }\r\n    function isRenderToFloatTextureEnabled(webGLVersion) {\r\n        if (webGLVersion === 0) {\r\n            return false;\r\n        }\r\n        var gl = getWebGLContext(webGLVersion);\r\n        if (webGLVersion === 1) {\r\n            if (!hasExtension(gl, 'OES_texture_float')) {\r\n                return false;\r\n            }\r\n        }\r\n        else {\r\n            if (!hasExtension(gl, 'EXT_color_buffer_float')) {\r\n                return false;\r\n            }\r\n        }\r\n        var isFrameBufferComplete = createFloatTextureAndBindToFramebuffer(gl, webGLVersion);\r\n        return isFrameBufferComplete;\r\n    }\r\n    function isDownloadFloatTextureEnabled(webGLVersion) {\r\n        if (webGLVersion === 0) {\r\n            return false;\r\n        }\r\n        var gl = getWebGLContext(webGLVersion);\r\n        if (webGLVersion === 1) {\r\n            if (!hasExtension(gl, 'OES_texture_float')) {\r\n                return false;\r\n            }\r\n            if (!hasExtension(gl, 'WEBGL_color_buffer_float')) {\r\n                return false;\r\n            }\r\n        }\r\n        else {\r\n            if (!hasExtension(gl, 'EXT_color_buffer_float')) {\r\n                return false;\r\n            }\r\n        }\r\n        var isFrameBufferComplete = createFloatTextureAndBindToFramebuffer(gl, webGLVersion);\r\n        return isFrameBufferComplete;\r\n    }\r\n    function isWebGLFenceEnabled(webGLVersion) {\r\n        if (webGLVersion !== 2) {\r\n            return false;\r\n        }\r\n        var gl = getWebGLContext(webGLVersion);\r\n        var isEnabled = gl.fenceSync != null;\r\n        return isEnabled;\r\n    }\r\n    function isChrome() {\r\n        return typeof navigator !== 'undefined' && navigator != null &&\r\n            navigator.userAgent != null && /Chrome/.test(navigator.userAgent) &&\r\n            /Google Inc/.test(navigator.vendor);\r\n    }\r\n    var TENSORFLOWJS_FLAGS_PREFIX = 'tfjsflags';\r\n    function getFeaturesFromURL() {\r\n        var features = {};\r\n        if (typeof window === 'undefined' || typeof window.location === 'undefined' ||\r\n            typeof window.location.search === 'undefined') {\r\n            return features;\r\n        }\r\n        var urlParams = getQueryParams(window.location.search);\r\n        if (TENSORFLOWJS_FLAGS_PREFIX in urlParams) {\r\n            var urlFlags_1 = {};\r\n            var keyValues = urlParams[TENSORFLOWJS_FLAGS_PREFIX].split(',');\r\n            keyValues.forEach(function (keyValue) {\r\n                var _a = keyValue.split(':'), key = _a[0], value = _a[1];\r\n                urlFlags_1[key] = value;\r\n            });\r\n            URL_PROPERTIES.forEach(function (urlProperty) {\r\n                if (urlProperty.name in urlFlags_1) {\r\n                    console.log(\"Setting feature override from URL \" + urlProperty.name + \": \" +\r\n                        (\"\" + urlFlags_1[urlProperty.name]));\r\n                    if (urlProperty.type === Type.NUMBER) {\r\n                        features[urlProperty.name] = +urlFlags_1[urlProperty.name];\r\n                    }\r\n                    else if (urlProperty.type === Type.BOOLEAN) {\r\n                        features[urlProperty.name] = urlFlags_1[urlProperty.name] === 'true';\r\n                    }\r\n                    else if (urlProperty.type === Type.STRING) {\r\n                        features[urlProperty.name] = urlFlags_1[urlProperty.name];\r\n                    }\r\n                    else {\r\n                        console.warn(\"Unknown URL param: \" + urlProperty.name + \".\");\r\n                    }\r\n                }\r\n            });\r\n        }\r\n        return features;\r\n    }\r\n    function hasExtension(gl, extensionName) {\r\n        var ext = gl.getExtension(extensionName);\r\n        return ext != null;\r\n    }\r\n    function createFloatTextureAndBindToFramebuffer(gl, webGLVersion) {\r\n        var frameBuffer = gl.createFramebuffer();\r\n        var texture = gl.createTexture();\r\n        gl.bindTexture(gl.TEXTURE_2D, texture);\r\n        var internalFormat = webGLVersion === 2 ? gl.RGBA32F : gl.RGBA;\r\n        gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, 1, 1, 0, gl.RGBA, gl.FLOAT, null);\r\n        gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);\r\n        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);\r\n        var isFrameBufferComplete = gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE;\r\n        gl.bindTexture(gl.TEXTURE_2D, null);\r\n        gl.bindFramebuffer(gl.FRAMEBUFFER, null);\r\n        gl.deleteTexture(texture);\r\n        gl.deleteFramebuffer(frameBuffer);\r\n        return isFrameBufferComplete;\r\n    }\r\n    function getQueryParams(queryString) {\r\n        var params = {};\r\n        queryString.replace(/[?&]([^=?&]+)(?:=([^&]*))?/g, function (s) {\r\n            var t = [];\r\n            for (var _i = 1; _i < arguments.length; _i++) {\r\n                t[_i - 1] = arguments[_i];\r\n            }\r\n            decodeParam(params, t[0], t[1]);\r\n            return t.join('=');\r\n        });\r\n        return params;\r\n    }\r\n    function decodeParam(params, name, value) {\r\n        params[decodeURIComponent(name)] = decodeURIComponent(value || '');\r\n    }\r\n    var BEFORE_PAGING_CONSTANT = 600;\r\n    function getNumMBBeforePaging() {\r\n        return (window.screen.height * window.screen.width *\r\n            window.devicePixelRatio) *\r\n            BEFORE_PAGING_CONSTANT / 1024;\r\n    }\n\n    var EPSILON_FLOAT16 = 1e-4;\r\n    var TEST_EPSILON_FLOAT16 = 1e-1;\r\n    var EPSILON_FLOAT32 = 1e-7;\r\n    var TEST_EPSILON_FLOAT32 = 1e-3;\r\n    var Environment = (function () {\r\n        function Environment(features) {\r\n            this.features = {};\r\n            this.registry = {};\r\n            if (features != null) {\r\n                this.features = features;\r\n            }\r\n            if (this.get('DEBUG')) {\r\n                console.warn('Debugging mode is ON. The output of every math call will ' +\r\n                    'be downloaded to CPU and checked for NaNs. ' +\r\n                    'This significantly impacts performance.');\r\n            }\r\n        }\r\n        Environment.setBackend = function (backendName, safeMode) {\r\n            if (safeMode === void 0) { safeMode = false; }\r\n            if (!(backendName in ENV.registry)) {\r\n                throw new Error(\"Backend name '\" + backendName + \"' not found in registry\");\r\n            }\r\n            ENV.engine.backend = ENV.findBackend(backendName);\r\n            ENV.backendName = backendName;\r\n        };\r\n        Environment.getBackend = function () {\r\n            ENV.initEngine();\r\n            return ENV.backendName;\r\n        };\r\n        Environment.disposeVariables = function () {\r\n            ENV.engine.disposeVariables();\r\n        };\r\n        Environment.memory = function () {\r\n            return ENV.engine.memory();\r\n        };\r\n        Environment.profile = function (f) {\r\n            return ENV.engine.profile(f);\r\n        };\r\n        Environment.tidy = function (nameOrFn, fn) {\r\n            return ENV.engine.tidy(nameOrFn, fn);\r\n        };\r\n        Environment.dispose = function (container) {\r\n            var tensors = getTensorsInContainer(container);\r\n            tensors.forEach(function (tensor) { return tensor.dispose(); });\r\n        };\r\n        Environment.keep = function (result) {\r\n            return ENV.engine.keep(result);\r\n        };\r\n        Environment.time = function (f) {\r\n            return ENV.engine.time(f);\r\n        };\r\n        Environment.prototype.get = function (feature) {\r\n            if (feature in this.features) {\r\n                return this.features[feature];\r\n            }\r\n            this.features[feature] = this.evaluateFeature(feature);\r\n            return this.features[feature];\r\n        };\r\n        Environment.prototype.getFeatures = function () {\r\n            return this.features;\r\n        };\r\n        Environment.prototype.set = function (feature, value) {\r\n            this.features[feature] = value;\r\n        };\r\n        Environment.prototype.getBestBackendName = function () {\r\n            var _this = this;\r\n            if (Object.keys(this.registry).length === 0) {\r\n                throw new Error('No backend found in registry.');\r\n            }\r\n            var sortedBackends = Object.keys(this.registry)\r\n                .map(function (name) {\r\n                return { name: name, entry: _this.registry[name] };\r\n            })\r\n                .sort(function (a, b) {\r\n                return b.entry.priority - a.entry.priority;\r\n            });\r\n            return sortedBackends[0].name;\r\n        };\r\n        Environment.prototype.evaluateFeature = function (feature) {\r\n            if (feature === 'DEBUG') {\r\n                return false;\r\n            }\r\n            else if (feature === 'IS_BROWSER') {\r\n                return typeof window !== 'undefined';\r\n            }\r\n            else if (feature === 'IS_NODE') {\r\n                return (typeof process !== 'undefined') &&\r\n                    (typeof process.versions !== 'undefined') &&\r\n                    (typeof process.versions.node !== 'undefined');\r\n            }\r\n            else if (feature === 'IS_CHROME') {\r\n                return isChrome();\r\n            }\r\n            else if (feature === 'WEBGL_CPU_FORWARD') {\r\n                return true;\r\n            }\r\n            else if (feature === 'WEBGL_PACK') {\r\n                return false;\r\n            }\r\n            else if (feature === 'WEBGL_PACK_BATCHNORMALIZATION') {\r\n                return this.get('WEBGL_PACK');\r\n            }\r\n            else if (feature === 'WEBGL_PACK_CLIP') {\r\n                return this.get('WEBGL_PACK');\r\n            }\r\n            else if (feature === 'WEBGL_PACK_DEPTHWISECONV') {\r\n                return this.get('WEBGL_PACK');\r\n            }\r\n            else if (feature === 'WEBGL_PACK_BINARY_OPERATIONS') {\r\n                return this.get('WEBGL_PACK');\r\n            }\r\n            else if (feature === 'WEBGL_PACK_ARRAY_OPERATIONS') {\r\n                return this.get('WEBGL_PACK');\r\n            }\r\n            else if (feature === 'WEBGL_LAZILY_UNPACK') {\r\n                return this.get('WEBGL_PACK');\r\n            }\r\n            else if (feature === 'WEBGL_CONV_IM2COL') {\r\n                return this.get('WEBGL_PACK');\r\n            }\r\n            else if (feature === 'WEBGL_NUM_MB_BEFORE_PAGING') {\r\n                if (this.get('PROD') || !this.get('IS_BROWSER')) {\r\n                    return Number.POSITIVE_INFINITY;\r\n                }\r\n                return getNumMBBeforePaging();\r\n            }\r\n            else if (feature === 'WEBGL_MAX_TEXTURE_SIZE') {\r\n                return getWebGLMaxTextureSize(this.get('WEBGL_VERSION'));\r\n            }\r\n            else if (feature === 'WEBGL_MAX_TEXTURES_IN_SHADER') {\r\n                return getMaxTexturesInShader(this.get('WEBGL_VERSION'));\r\n            }\r\n            else if (feature === 'IS_TEST') {\r\n                return false;\r\n            }\r\n            else if (feature === 'BACKEND') {\r\n                return this.getBestBackendName();\r\n            }\r\n            else if (feature === 'WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') {\r\n                var webGLVersion = this.get('WEBGL_VERSION');\r\n                if (webGLVersion === 0) {\r\n                    return 0;\r\n                }\r\n                return getWebGLDisjointQueryTimerVersion(webGLVersion);\r\n            }\r\n            else if (feature === 'WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_RELIABLE') {\r\n                return this.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') > 0 &&\r\n                    !isMobile();\r\n            }\r\n            else if (feature === 'HAS_WEBGL') {\r\n                return this.get('WEBGL_VERSION') > 0;\r\n            }\r\n            else if (feature === 'WEBGL_VERSION') {\r\n                if (isWebGLVersionEnabled(2)) {\r\n                    return 2;\r\n                }\r\n                else if (isWebGLVersionEnabled(1)) {\r\n                    return 1;\r\n                }\r\n                return 0;\r\n            }\r\n            else if (feature === 'WEBGL_RENDER_FLOAT32_ENABLED') {\r\n                return isRenderToFloatTextureEnabled(this.get('WEBGL_VERSION'));\r\n            }\r\n            else if (feature === 'WEBGL_DOWNLOAD_FLOAT_ENABLED') {\r\n                return isDownloadFloatTextureEnabled(this.get('WEBGL_VERSION'));\r\n            }\r\n            else if (feature === 'WEBGL_FENCE_API_ENABLED') {\r\n                return isWebGLFenceEnabled(this.get('WEBGL_VERSION'));\r\n            }\r\n            else if (feature === 'WEBGL_SIZE_UPLOAD_UNIFORM') {\r\n                var useUniforms = this.get('WEBGL_RENDER_FLOAT32_ENABLED');\r\n                return useUniforms ? 4 : 0;\r\n            }\r\n            else if (feature === 'TEST_EPSILON') {\r\n                return this.backend.floatPrecision() === 32 ? TEST_EPSILON_FLOAT32 :\r\n                    TEST_EPSILON_FLOAT16;\r\n            }\r\n            else if (feature === 'EPSILON') {\r\n                return this.backend.floatPrecision() === 32 ? EPSILON_FLOAT32 :\r\n                    EPSILON_FLOAT16;\r\n            }\r\n            else if (feature === 'PROD') {\r\n                return false;\r\n            }\r\n            else if (feature === 'TENSORLIKE_CHECK_SHAPE_CONSISTENCY') {\r\n                return !this.get('PROD');\r\n            }\r\n            throw new Error(\"Unknown feature \" + feature + \".\");\r\n        };\r\n        Environment.prototype.setFeatures = function (features) {\r\n            this.features = Object.assign({}, features);\r\n        };\r\n        Environment.prototype.reset = function () {\r\n            this.features = getFeaturesFromURL();\r\n            if (this.globalEngine != null) {\r\n                this.globalEngine = null;\r\n            }\r\n        };\r\n        Object.defineProperty(Environment.prototype, \"backend\", {\r\n            get: function () {\r\n                return this.engine.backend;\r\n            },\r\n            enumerable: true,\r\n            configurable: true\r\n        });\r\n        Environment.prototype.findBackend = function (name) {\r\n            if (!(name in this.registry)) {\r\n                return null;\r\n            }\r\n            return this.registry[name].backend;\r\n        };\r\n        Environment.prototype.registerBackend = function (name, factory, priority, setTensorTrackerFn) {\r\n            var _this = this;\r\n            if (priority === void 0) { priority = 1; }\r\n            if (name in this.registry) {\r\n                console.warn(name + \" backend was already registered. Reusing existing backend\");\r\n                if (setTensorTrackerFn != null) {\r\n                    setTensorTrackerFn(function () { return _this.engine; });\r\n                }\r\n                return false;\r\n            }\r\n            try {\r\n                var backend = factory();\r\n                backend.setDataMover({ moveData: function (dataId) { return _this.engine.moveData(dataId); } });\r\n                this.registry[name] = { backend: backend, priority: priority };\r\n                return true;\r\n            }\r\n            catch (err) {\r\n                console.warn(\"Registration of backend \" + name + \" failed\");\r\n                console.warn(err.stack || err.message);\r\n                return false;\r\n            }\r\n        };\r\n        Environment.prototype.removeBackend = function (name) {\r\n            if (!(name in this.registry)) {\r\n                throw new Error(name + \" backend not found in registry\");\r\n            }\r\n            this.registry[name].backend.dispose();\r\n            delete this.registry[name];\r\n        };\r\n        Object.defineProperty(Environment.prototype, \"engine\", {\r\n            get: function () {\r\n                this.initEngine();\r\n                return this.globalEngine;\r\n            },\r\n            enumerable: true,\r\n            configurable: true\r\n        });\r\n        Environment.prototype.initEngine = function () {\r\n            var _this = this;\r\n            if (this.globalEngine == null) {\r\n                this.backendName = this.get('BACKEND');\r\n                var backend = this.findBackend(this.backendName);\r\n                this.globalEngine =\r\n                    new Engine(backend, false, function () { return _this.get('DEBUG'); });\r\n            }\r\n        };\r\n        return Environment;\r\n    }());\r\n    function getGlobalNamespace() {\r\n        var ns;\r\n        if (typeof (window) !== 'undefined') {\r\n            ns = window;\r\n        }\r\n        else if (typeof (process) !== 'undefined') {\r\n            ns = process;\r\n        }\r\n        else {\r\n            throw new Error('Could not find a global object');\r\n        }\r\n        return ns;\r\n    }\r\n    function getOrMakeEnvironment() {\r\n        var ns = getGlobalNamespace();\r\n        if (ns.ENV == null) {\r\n            ns.ENV = new Environment(getFeaturesFromURL());\r\n            setTensorTracker(function () { return ns.ENV.engine; });\r\n        }\r\n        return ns.ENV;\r\n    }\r\n    function enableProdMode() {\r\n        ENV.set('PROD', true);\r\n    }\r\n    var ENV = getOrMakeEnvironment();\n\n    var environment = /*#__PURE__*/Object.freeze({\n        EPSILON_FLOAT16: EPSILON_FLOAT16,\n        EPSILON_FLOAT32: EPSILON_FLOAT32,\n        Environment: Environment,\n        enableProdMode: enableProdMode,\n        ENV: ENV\n    });\n\n    function grad(f) {\r\n        assert(isFunction(f), 'The f passed in grad(f) must be a function');\r\n        return function (x, dy) {\r\n            assert(x instanceof Tensor, 'The x passed in grad(f)(x) must be a tensor');\r\n            assert(dy == null || dy instanceof Tensor, 'The dy passed in grad(f)(x, dy) must be a tensor');\r\n            return ENV.engine.tidy(function () {\r\n                var _a = ENV.engine.gradients(function () { return f(x); }, [x], dy), value = _a.value, grads = _a.grads;\r\n                if (dy != null) {\r\n                    assertShapesMatch(value.shape, dy.shape, 'The shape of dy passed in grad(f)(x, dy) must match the shape ' +\r\n                        'returned by f(x)');\r\n                }\r\n                checkGrads(grads);\r\n                return grads[0];\r\n            });\r\n        };\r\n    }\r\n    function grads(f) {\r\n        assert(isFunction(f), 'The f passed in grads(f) must be a function');\r\n        return function (args, dy) {\r\n            assert(Array.isArray(args) && args.every(function (arg) { return arg instanceof Tensor; }), 'The args passed in grads(f)(args) must be an array of tensors');\r\n            assert(dy == null || dy instanceof Tensor, 'The dy passed in grads(f)(args, dy) must be a tensor');\r\n            return ENV.engine.tidy(function () {\r\n                var _a = ENV.engine.gradients(function () { return f.apply(void 0, args); }, args, dy), value = _a.value, grads = _a.grads;\r\n                if (dy != null) {\r\n                    assertShapesMatch(value.shape, dy.shape, 'The shape of dy passed in grads(f)([x1,...], dy) must ' +\r\n                        'match the shape returned by f([x1,...])');\r\n                }\r\n                checkGrads(grads);\r\n                return grads;\r\n            });\r\n        };\r\n    }\r\n    function valueAndGrad(f) {\r\n        assert(isFunction(f), 'The f passed in valueAndGrad(f) must be a function');\r\n        return function (x, dy) {\r\n            assert(x instanceof Tensor, 'The x passed in valueAndGrad(f)(x) must be a tensor');\r\n            assert(dy == null || dy instanceof Tensor, 'The dy passed in valueAndGrad(f)(x, dy) must be a tensor');\r\n            var _a = ENV.engine.gradients(function () { return f(x); }, [x], dy), grads = _a.grads, value = _a.value;\r\n            checkGrads(grads);\r\n            return { grad: grads[0], value: value };\r\n        };\r\n    }\r\n    function valueAndGrads(f) {\r\n        assert(isFunction(f), 'The f passed in valueAndGrads(f) must be a function');\r\n        return function (args, dy) {\r\n            assert(Array.isArray(args) && args.every(function (arg) { return arg instanceof Tensor; }), 'The args passed in valueAndGrads(f)(args) must be array of tensors');\r\n            assert(dy == null || dy instanceof Tensor, 'The dy passed in valueAndGrads(f)(args, dy) must be a tensor');\r\n            var res = ENV.engine.gradients(function () { return f.apply(void 0, args); }, args, dy);\r\n            if (dy != null) {\r\n                assertShapesMatch(res.value.shape, dy.shape, 'The shape of dy passed in valueAndGrads(f)([x1,...], dy) must ' +\r\n                    'match the shape returned by f([x1,...])');\r\n            }\r\n            checkGrads(res.grads);\r\n            return res;\r\n        };\r\n    }\r\n    function variableGrads(f, varList) {\r\n        assert(isFunction(f), 'The f passed in variableGrads(f) must be a function');\r\n        assert(varList == null ||\r\n            Array.isArray(varList) && varList.every(function (v) { return v instanceof Variable; }), 'The varList passed in variableGrads(f, varList) must be an array ' +\r\n            'of variables');\r\n        if (varList == null) {\r\n            varList = [];\r\n            for (var varName in ENV.engine.registeredVariables) {\r\n                varList.push(ENV.engine.registeredVariables[varName]);\r\n            }\r\n        }\r\n        var originalVarCount = varList.length;\r\n        varList = varList.filter(function (variable$$1) { return variable$$1.trainable; });\r\n        assert(varList.length > 0, \"variableGrads() expects at least one of the input variables to be \" +\r\n            (\"trainable, but none of the \" + originalVarCount + \" variables is \") +\r\n            \"trainable.\");\r\n        var allowNoGradients = true;\r\n        var _a = ENV.engine.gradients(f, varList, null, allowNoGradients), value = _a.value, grads = _a.grads;\r\n        assert(grads.some(function (g) { return g != null; }), 'Cannot find a connection between any variable and the result of the ' +\r\n            'loss function y=f(x). Please make sure the operations that use ' +\r\n            'variables are inside the function f passed to minimize().');\r\n        assert(value.rank === 0, \"The f passed in variableGrads(f) must return a scalar, but it \" +\r\n            (\"returned a rank-\" + value.rank + \" tensor\"));\r\n        var namedGrads = {};\r\n        varList.forEach(function (v, i) {\r\n            if (grads[i] != null) {\r\n                namedGrads[v.name] = grads[i];\r\n            }\r\n        });\r\n        return { value: value, grads: namedGrads };\r\n    }\r\n    function customGrad(f) {\r\n        return ENV.engine.customGrad(f);\r\n    }\r\n    function checkGrads(grads) {\r\n        var numNullGradients = grads.filter(function (g) { return g == null; }).length;\r\n        if (numNullGradients > 0) {\r\n            throw new Error(\"Cannot compute gradient of y=f(x) with respect to x. Make sure that\\n    the f you passed encloses all operations that lead from x to y.\");\r\n        }\r\n    }\n\n    var tidy = Environment.tidy;\r\n    var keep = Environment.keep;\r\n    var dispose = Environment.dispose;\r\n    var time = Environment.time;\r\n    var profile = Environment.profile;\n\n    function warn() {\r\n        var msg = [];\r\n        for (var _i = 0; _i < arguments.length; _i++) {\r\n            msg[_i] = arguments[_i];\r\n        }\r\n        if (!ENV.get('IS_TEST')) {\r\n            console.warn.apply(console, msg);\r\n        }\r\n    }\n\n    function getReshaped(inputShape, blockShape, prod, batchToSpace) {\r\n        if (batchToSpace === void 0) { batchToSpace = true; }\r\n        var reshaped = [];\r\n        if (batchToSpace) {\r\n            reshaped = reshaped.concat(blockShape.slice(0));\r\n            reshaped.push(inputShape[0] / prod);\r\n            reshaped = reshaped.concat(inputShape.slice(1));\r\n        }\r\n        else {\r\n            reshaped = reshaped.concat(inputShape[0]);\r\n            var spatialLength = blockShape.length;\r\n            for (var i = 0; i < spatialLength; ++i) {\r\n                reshaped =\r\n                    reshaped.concat([inputShape[i + 1] / blockShape[i], blockShape[i]]);\r\n            }\r\n            reshaped = reshaped.concat(inputShape.slice(spatialLength + 1));\r\n        }\r\n        return reshaped;\r\n    }\r\n    function getPermuted(reshapedRank, blockShapeRank, batchToSpace) {\r\n        if (batchToSpace === void 0) { batchToSpace = true; }\r\n        var permuted = [];\r\n        if (batchToSpace) {\r\n            permuted.push(blockShapeRank);\r\n            for (var i = blockShapeRank + 1; i < reshapedRank; ++i) {\r\n                if (i <= 2 * blockShapeRank) {\r\n                    permuted.push(i);\r\n                    permuted.push(i - (blockShapeRank + 1));\r\n                }\r\n                else {\r\n                    permuted.push(i);\r\n                }\r\n            }\r\n        }\r\n        else {\r\n            var permutedBeforeBatch = [];\r\n            var permutedAfterBatch = [];\r\n            for (var i = 1; i < reshapedRank; ++i) {\r\n                if (i >= blockShapeRank * 2 + 1 || i % 2 === 1) {\r\n                    permutedAfterBatch.push(i);\r\n                }\r\n                else {\r\n                    permutedBeforeBatch.push(i);\r\n                }\r\n            }\r\n            permuted.push.apply(permuted, permutedBeforeBatch);\r\n            permuted.push(0);\r\n            permuted.push.apply(permuted, permutedAfterBatch);\r\n        }\r\n        return permuted;\r\n    }\r\n    function getReshapedPermuted(inputShape, blockShape, prod, batchToSpace) {\r\n        if (batchToSpace === void 0) { batchToSpace = true; }\r\n        var reshapedPermuted = [];\r\n        if (batchToSpace) {\r\n            reshapedPermuted.push(inputShape[0] / prod);\r\n        }\r\n        else {\r\n            reshapedPermuted.push(inputShape[0] * prod);\r\n        }\r\n        for (var i = 1; i < inputShape.length; ++i) {\r\n            if (i <= blockShape.length) {\r\n                if (batchToSpace) {\r\n                    reshapedPermuted.push(blockShape[i - 1] * inputShape[i]);\r\n                }\r\n                else {\r\n                    reshapedPermuted.push(inputShape[i] / blockShape[i - 1]);\r\n                }\r\n            }\r\n            else {\r\n                reshapedPermuted.push(inputShape[i]);\r\n            }\r\n        }\r\n        return reshapedPermuted;\r\n    }\r\n    function getSliceBeginCoords(crops, blockShape) {\r\n        var sliceBeginCoords = [0];\r\n        for (var i = 0; i < blockShape; ++i) {\r\n            sliceBeginCoords.push(crops[i][0]);\r\n        }\r\n        return sliceBeginCoords;\r\n    }\r\n    function getSliceSize(uncroppedShape, crops, blockShape) {\r\n        var sliceSize = uncroppedShape.slice(0, 1);\r\n        for (var i = 0; i < blockShape; ++i) {\r\n            sliceSize.push(uncroppedShape[i + 1] - crops[i][0] - crops[i][1]);\r\n        }\r\n        return sliceSize;\r\n    }\n\n    function axesAreInnerMostDims(axes, rank) {\r\n        for (var i = 0; i < axes.length; ++i) {\r\n            if (axes[axes.length - i - 1] !== rank - 1 - i) {\r\n                return false;\r\n            }\r\n        }\r\n        return true;\r\n    }\r\n    function combineLocations(outputLoc, reduceLoc, axes) {\r\n        var rank = outputLoc.length + reduceLoc.length;\r\n        var loc = [];\r\n        var outIdx = 0;\r\n        var reduceIdx = 0;\r\n        for (var dim = 0; dim < rank; dim++) {\r\n            if (axes.indexOf(dim) === -1) {\r\n                loc.push(outputLoc[outIdx++]);\r\n            }\r\n            else {\r\n                loc.push(reduceLoc[reduceIdx++]);\r\n            }\r\n        }\r\n        return loc;\r\n    }\r\n    function computeOutAndReduceShapes(aShape, axes) {\r\n        var outShape = [];\r\n        var rank = aShape.length;\r\n        for (var dim = 0; dim < rank; dim++) {\r\n            if (axes.indexOf(dim) === -1) {\r\n                outShape.push(aShape[dim]);\r\n            }\r\n        }\r\n        var reduceShape = axes.map(function (dim) { return aShape[dim]; });\r\n        return [outShape, reduceShape];\r\n    }\r\n    function expandShapeToKeepDim(shape, axes) {\r\n        var reduceSubShape = axes.map(function (x) { return 1; });\r\n        return combineLocations(shape, reduceSubShape, axes);\r\n    }\r\n    function assertAxesAreInnerMostDims(msg, axes, rank) {\r\n        assert(axesAreInnerMostDims(axes, rank), msg + \" supports only inner-most axes for now. \" +\r\n            (\"Got axes \" + axes + \" and rank-\" + rank + \" input.\"));\r\n    }\r\n    function getAxesPermutation(axes, rank) {\r\n        if (axesAreInnerMostDims(axes, rank)) {\r\n            return null;\r\n        }\r\n        var result = [];\r\n        for (var i = 0; i < rank; ++i) {\r\n            if (axes.indexOf(i) === -1) {\r\n                result.push(i);\r\n            }\r\n        }\r\n        axes.forEach(function (axis) { return result.push(axis); });\r\n        return result;\r\n    }\r\n    function getUndoAxesPermutation(axes) {\r\n        return axes.map(function (axis, i) { return [i, axis]; })\r\n            .sort(function (a, b) { return a[1] - b[1]; })\r\n            .map(function (x) { return x[0]; });\r\n    }\r\n    function getInnerMostAxes(numAxes, rank) {\r\n        var res = [];\r\n        for (var i = rank - numAxes; i < rank; ++i) {\r\n            res.push(i);\r\n        }\r\n        return res;\r\n    }\n\n    function getBroadcastDims(inShape, outShape) {\r\n        var inRank = inShape.length;\r\n        var dims = [];\r\n        for (var i = 0; i < inRank; i++) {\r\n            var dim = inRank - 1 - i;\r\n            var a = inShape[dim] || 1;\r\n            var b = outShape[outShape.length - 1 - i] || 1;\r\n            if (b > 1 && a === 1) {\r\n                dims.unshift(dim);\r\n            }\r\n        }\r\n        return dims;\r\n    }\r\n    function getReductionAxes(inShape, outShape) {\r\n        var result = [];\r\n        for (var i = 0; i < outShape.length; i++) {\r\n            var inDim = inShape[inShape.length - i - 1];\r\n            var outAxis = outShape.length - i - 1;\r\n            var outDim = outShape[outAxis];\r\n            if (inDim == null || (inDim === 1 && outDim > 1)) {\r\n                result.unshift(outAxis);\r\n            }\r\n        }\r\n        return result;\r\n    }\r\n    function assertAndGetBroadcastShape(shapeA, shapeB) {\r\n        var result = [];\r\n        var l = Math.max(shapeA.length, shapeB.length);\r\n        for (var i = 0; i < l; i++) {\r\n            var a = shapeA[shapeA.length - i - 1];\r\n            if (a == null) {\r\n                a = 1;\r\n            }\r\n            var b = shapeB[shapeB.length - i - 1];\r\n            if (b == null) {\r\n                b = 1;\r\n            }\r\n            if (a === 1) {\r\n                result.unshift(b);\r\n            }\r\n            else if (b === 1) {\r\n                result.unshift(a);\r\n            }\r\n            else if (a !== b) {\r\n                var errMsg = \"Operands could not be broadcast together with shapes \" +\r\n                    (shapeA + \" and \" + shapeB + \".\");\r\n                throw Error(errMsg);\r\n            }\r\n            else {\r\n                result.unshift(a);\r\n            }\r\n        }\r\n        return result;\r\n    }\n\n    function assertParamsConsistent(shapes, axis) {\r\n        var rank = shapes[0].length;\r\n        shapes.forEach(function (shape, i) {\r\n            assert(shape.length === rank, \"Error in concat\" + rank + \"D: rank of tensors[\" + i + \"] must be the same \" +\r\n                (\"as the rank of the rest (\" + rank + \")\"));\r\n        });\r\n        assert(axis >= 0 && axis < rank, \"Error in concat\" + rank + \"D: axis must be between 0 and \" + (rank - 1) + \".\");\r\n        var firstShape = shapes[0];\r\n        shapes.forEach(function (shape, i) {\r\n            for (var r = 0; r < rank; r++) {\r\n                assert((r === axis) || (shape[r] === firstShape[r]), \"Error in concat\" + rank + \"D: Shape of tensors[\" + i + \"] (\" + shape + \") \" +\r\n                    (\"does not match the shape of the rest (\" + firstShape + \") \") +\r\n                    (\"along the non-concatenated axis \" + i + \".\"));\r\n            }\r\n        });\r\n    }\r\n    function computeOutShape(shapes, axis) {\r\n        var outputShape = shapes[0].slice();\r\n        for (var i = 1; i < shapes.length; i++) {\r\n            outputShape[axis] += shapes[i][axis];\r\n        }\r\n        return outputShape;\r\n    }\n\n    function prepareAndValidate(tensor, indices) {\r\n        if (tensor.rank < 1) {\r\n            throw new Error('tf.gatherND() expects the input to be rank 1 or higher,' +\r\n                (\" but the rank was \" + tensor.rank + \".\"));\r\n        }\r\n        if (indices.rank < 1) {\r\n            throw new Error('tf.gatherND() expects the indices to be rank 1 or higher,' +\r\n                (\" but the rank was \" + indices.rank + \".\"));\r\n        }\r\n        if (indices.dtype !== 'int32') {\r\n            throw new Error('tf.gatherND() expects the indices to be int32 type,' +\r\n                (\" but the dtype was \" + indices.dtype + \".\"));\r\n        }\r\n        if (indices.shape[indices.rank - 1] > tensor.rank) {\r\n            throw new Error('index innermost dimension length must be <= tensor rank; saw: ' +\r\n                (indices.shape[indices.rank - 1] + \" vs. \" + tensor.rank));\r\n        }\r\n        if (tensor.size === 0) {\r\n            throw new Error('Requested more than 0 entries, but input is empty.' +\r\n                (\" Input shape: \" + tensor.shape + \".\"));\r\n        }\r\n        var indicesShape = indices.shape;\r\n        var sliceRank = indicesShape[indicesShape.length - 1];\r\n        var nResult = 1;\r\n        for (var i = 0; i < indicesShape.length - 1; ++i) {\r\n            nResult *= indicesShape[i];\r\n        }\r\n        var inputShape = tensor.shape;\r\n        var resultShape = indicesShape.slice();\r\n        resultShape.pop();\r\n        var sliceSize = 1;\r\n        for (var i = sliceRank; i < tensor.rank; ++i) {\r\n            sliceSize *= inputShape[i];\r\n            resultShape.push(inputShape[i]);\r\n        }\r\n        var strides = computeStrides(tensor.shape).map(function (stride) { return stride / sliceSize; }).concat([1]).slice(0, sliceRank);\r\n        return [resultShape, nResult, sliceSize, strides];\r\n    }\n\n    var PARALLELIZE_THRESHOLD = 30;\r\n    function computeOptimalWindowSize(inSize) {\r\n        if (inSize <= PARALLELIZE_THRESHOLD) {\r\n            return inSize;\r\n        }\r\n        return nearestDivisor(inSize, Math.floor(Math.sqrt(inSize)));\r\n    }\n\n    function validateUpdateShape(shape, indices, updates) {\r\n        var sliceDim = (indices.rank > 1) ? indices.shape[indices.rank - 1] : 1;\r\n        var batchDim = (indices.rank > 1) ? indices.rank - 1 : 1;\r\n        var shapeError = 'Must have updates.shape = indices.shape[:batchDim] + ' +\r\n            (\"shape[sliceDim:], got updates.shape: \" + updates.shape) +\r\n            (\", indices.shape: \" + indices.shape + \", shape: \" + shape) +\r\n            (\", sliceDim: \" + sliceDim + \", and batchDim: \" + batchDim + \".\");\r\n        if (updates.rank < batchDim) {\r\n            throw new Error(shapeError + (\" update.rank < \" + batchDim + \". \"));\r\n        }\r\n        if (shape.length < sliceDim + (updates.rank - batchDim)) {\r\n            throw new Error(shapeError +\r\n                (\" Output shape length < \" + (sliceDim + (updates.rank - batchDim))));\r\n        }\r\n        if (updates.rank !== batchDim + shape.length - sliceDim) {\r\n            throw new Error(shapeError + (\" update.rank != \" + (batchDim + shape.length - sliceDim)));\r\n        }\r\n        for (var d = 0; d < batchDim; ++d) {\r\n            if (updates.shape[d] !== indices.shape[d]) {\r\n                throw new Error(shapeError +\r\n                    (\" updates.shape[\" + d + \"] (\" + updates.shape[d] + \") != indices.shape[\" + d + \"] (\" + indices.shape[d] + \").\"));\r\n            }\r\n        }\r\n        for (var d = 0; d < updates.rank - batchDim; ++d) {\r\n            if (updates.shape[d + batchDim] !== shape[d + sliceDim]) {\r\n                throw new Error(shapeError +\r\n                    (\" updates.shape[\" + (d + batchDim) + \"] (\" + updates.shape[d + batchDim] + \") != shape[\" + (d + batchDim) + \"] (\" + shape[d + batchDim] + \")\"));\r\n            }\r\n        }\r\n    }\r\n    function validateInput(updates, indices, shape) {\r\n        if (indices.rank < 1) {\r\n            throw new Error('tf.scatterND() expects the indices to be rank 1 or higher,' +\r\n                (\" but the rank was \" + indices.rank + \".\"));\r\n        }\r\n        if (updates.rank < 1) {\r\n            throw new Error('tf.scatterND() expects the updates to be rank 1 or higher,' +\r\n                (\" but the rank was \" + updates.rank + \".\"));\r\n        }\r\n        if (indices.dtype !== 'int32') {\r\n            throw new Error(\"The dtype of 'indices' should be int32, but got dtype: \" + indices.dtype);\r\n        }\r\n        if (shape.length < 1) {\r\n            throw new Error(\"Output rank must be greater or equal to 1, but got shape: \" + shape);\r\n        }\r\n        if (shape.length === 0) {\r\n            if (indices.size === 0) {\r\n                throw new Error(\"Indices specified for empty output. indices shape: \" + indices.shape);\r\n            }\r\n            if (updates.size === 0) {\r\n                throw new Error(\"Updates specified for empty output. updates shape: \" + updates.shape);\r\n            }\r\n        }\r\n        validateUpdateShape(shape, indices, updates);\r\n    }\r\n    function calculateShapes(updates, indices, shape) {\r\n        var sliceRank = (indices.rank > 1) ? indices.shape[indices.rank - 1] : 1;\r\n        var totalNd = shape.length;\r\n        var sliceSize = 1;\r\n        for (var i = sliceRank; i < totalNd; ++i) {\r\n            sliceSize *= shape[i];\r\n        }\r\n        var safeSliceDim = (sliceRank < 1) ? 1 : sliceRank;\r\n        var numUpdates = indices.size / safeSliceDim;\r\n        var strides = computeStrides(shape.slice(0, sliceRank)).concat([1]);\r\n        var outputSize = sizeFromShape(shape);\r\n        return { sliceRank: sliceRank, numUpdates: numUpdates, sliceSize: sliceSize, strides: strides, outputSize: outputSize };\r\n    }\n\n    function segOpComputeOptimalWindowSize(inSize, numSegments) {\r\n        var done = false;\r\n        var res;\r\n        if (inSize <= PARALLELIZE_THRESHOLD) {\r\n            res = inSize;\r\n            done = true;\r\n        }\r\n        else {\r\n            res = nearestDivisor(inSize, Math.floor(Math.sqrt(inSize)));\r\n        }\r\n        while (!done) {\r\n            if (res > numSegments || res === inSize) {\r\n                done = true;\r\n                break;\r\n            }\r\n            else {\r\n                res = nearestDivisor(inSize, res + 1);\r\n            }\r\n        }\r\n        return res;\r\n    }\r\n    function computeOutShape$1(aShape, axis, numSegments) {\r\n        var outShape = [];\r\n        var rank = aShape.length;\r\n        for (var dim = 0; dim < rank; dim++) {\r\n            if (dim !== axis) {\r\n                outShape.push(aShape[dim]);\r\n            }\r\n            else {\r\n                outShape.push(numSegments);\r\n            }\r\n        }\r\n        return outShape;\r\n    }\r\n    function collectGatherOpShapeInfo(x, indices, axis) {\r\n        var dimSize = x.shape[axis];\r\n        var outputShape = [];\r\n        var batchSize = 1;\r\n        var sliceSize = 1;\r\n        for (var i = 0; i < axis; i++) {\r\n            outputShape.push(x.shape[i]);\r\n            batchSize *= x.shape[i];\r\n        }\r\n        for (var i = 0; i < indices.rank; i++) {\r\n            outputShape.push(indices.shape[i]);\r\n        }\r\n        for (var i = axis + 1; i < x.rank; i++) {\r\n            outputShape.push(x.shape[i]);\r\n            sliceSize *= x.shape[i];\r\n        }\r\n        return { batchSize: batchSize, sliceSize: sliceSize, dimSize: dimSize, outputShape: outputShape };\r\n    }\n\n    function assertParamsValid(input, begin, size) {\r\n        assert(input.rank === begin.length, \"Error in slice\" + input.rank + \"D: Length of begin \" + begin + \" must \" +\r\n            (\"match the rank of the array (\" + input.rank + \").\"));\r\n        assert(input.rank === size.length, \"Error in slice\" + input.rank + \"D: Length of size \" + size + \" must \" +\r\n            (\"match the rank of the array (\" + input.rank + \").\"));\r\n        for (var i = 0; i < input.rank; ++i) {\r\n            assert(begin[i] + size[i] <= input.shape[i], \"Error in slice\" + input.rank + \"D: begin[\" + i + \"] + size[\" + i + \"] \" +\r\n                (\"(\" + (begin[i] + size[i]) + \") would overflow input.shape[\" + i + \"] (\" + input.shape[i] + \")\"));\r\n        }\r\n    }\r\n    function getStridedSlicedInfo(shape, begin, end, strides, beginMask, endMask, ellipsisMask, newAxisMask, shrinkAxisMask) {\r\n        if (beginMask === void 0) { beginMask = 0; }\r\n        if (endMask === void 0) { endMask = 0; }\r\n        if (ellipsisMask === void 0) { ellipsisMask = 0; }\r\n        if (newAxisMask === void 0) { newAxisMask = 0; }\r\n        if (shrinkAxisMask === void 0) { shrinkAxisMask = 0; }\r\n        if (ellipsisMask !== 0) {\r\n            throw new Error('ellipsis mask is not yet supported');\r\n        }\r\n        if (newAxisMask !== 0) {\r\n            throw new Error('new axis mask is not yet supported');\r\n        }\r\n        var startIndex = [];\r\n        var endIndex = [];\r\n        var shrinkAxis = [];\r\n        for (var i = 0; i < shape.length; i++) {\r\n            startIndex[i] = startForAxis(beginMask, begin, strides, shape, i);\r\n            endIndex[i] = stopForAxis(endMask, end, strides, shape, i);\r\n            if (shrinkAxisMask & 1 << i) {\r\n                endIndex[i] = startIndex[i] + 1;\r\n                shrinkAxis.push(i);\r\n            }\r\n        }\r\n        var size = new Array(shape.length).fill(0);\r\n        size = size.map(function (d, i) {\r\n            var count = 0;\r\n            for (var start = startIndex[i]; !(strides[i] > 0 ? start >= endIndex[i] : start <= endIndex[i]); start += strides[i]) {\r\n                count += 1;\r\n            }\r\n            return count;\r\n        });\r\n        return [startIndex, size, shrinkAxis];\r\n    }\r\n    function startForAxis(beginMask, startIndices, strides, inputShape, axis) {\r\n        var start = startIndices[axis];\r\n        if (beginMask & 1 << axis) {\r\n            if (strides[axis] > 0) {\r\n                start = Number.MIN_SAFE_INTEGER;\r\n            }\r\n            else {\r\n                start = Number.MAX_SAFE_INTEGER;\r\n            }\r\n        }\r\n        var axisSize = inputShape[axis];\r\n        if (start < 0) {\r\n            start += axisSize;\r\n        }\r\n        start = clamp(0, start, axisSize - 1);\r\n        return start;\r\n    }\r\n    function stopForAxis(endMask, stopIndices, strides, inputShape, axis) {\r\n        var stop = stopIndices[axis];\r\n        if (endMask & (1 << axis)) {\r\n            if (strides[axis] > 0) {\r\n                stop = Number.MAX_SAFE_INTEGER;\r\n            }\r\n            else {\r\n                stop = Number.MIN_SAFE_INTEGER;\r\n            }\r\n        }\r\n        var axisSize = inputShape[axis];\r\n        if (stop < 0) {\r\n            stop += axisSize;\r\n        }\r\n        if (strides[axis] > 0) {\r\n            stop = clamp(0, stop, axisSize);\r\n        }\r\n        else {\r\n            stop = clamp(-1, stop, axisSize - 1);\r\n        }\r\n        return stop;\r\n    }\r\n    function isSliceContinous(shape, begin, size) {\r\n        var firstNonOneAxis = size.length;\r\n        for (var i = 0; i < size.length; i++) {\r\n            if (size[i] > 1) {\r\n                firstNonOneAxis = i;\r\n                break;\r\n            }\r\n        }\r\n        for (var i = firstNonOneAxis + 1; i < size.length; i++) {\r\n            if (begin[i] > 0 || size[i] !== shape[i]) {\r\n                return false;\r\n            }\r\n        }\r\n        return true;\r\n    }\r\n    function computeFlatOffset(begin, strides) {\r\n        var flatOffset = begin.length > 0 ? begin[begin.length - 1] : 1;\r\n        for (var i = 0; i < begin.length - 1; i++) {\r\n            flatOffset += begin[i] * strides[i];\r\n        }\r\n        return flatOffset;\r\n    }\n\n    function inferShape(val) {\r\n        var firstElem = val;\r\n        if (isTypedArray(val)) {\r\n            return [val.length];\r\n        }\r\n        if (!Array.isArray(val)) {\r\n            return [];\r\n        }\r\n        var shape = [];\r\n        while (Array.isArray(firstElem) || isTypedArray(firstElem)) {\r\n            shape.push(firstElem.length);\r\n            firstElem = firstElem[0];\r\n        }\r\n        if (Array.isArray(val) && ENV.get('TENSORLIKE_CHECK_SHAPE_CONSISTENCY')) {\r\n            deepAssertShapeConsistency(val, shape, []);\r\n        }\r\n        return shape;\r\n    }\r\n    function deepAssertShapeConsistency(val, shape, indices) {\r\n        indices = indices || [];\r\n        if (!(Array.isArray(val)) && !isTypedArray(val)) {\r\n            assert(shape.length === 0, function () { return \"Element arr[\" + indices.join('][') + \"] is a primitive, \" +\r\n                (\"but should be an array/TypedArray of \" + shape[0] + \" elements\"); });\r\n            return;\r\n        }\r\n        assert(shape.length > 0, function () { return \"Element arr[\" + indices.join('][') + \"] should be a primitive, \" +\r\n            (\"but is an array of \" + val.length + \" elements\"); });\r\n        assert(val.length === shape[0], function () { return \"Element arr[\" + indices.join('][') + \"] should have \" + shape[0] + \" \" +\r\n            (\"elements, but has \" + val.length + \" elements\"); });\r\n        var subShape = shape.slice(1);\r\n        for (var i = 0; i < val.length; ++i) {\r\n            deepAssertShapeConsistency(val[i], subShape, indices.concat(i));\r\n        }\r\n    }\r\n    function assertDtype(expectedDtype, actualDType, argName, functionName) {\r\n        if (expectedDtype == null) {\r\n            return;\r\n        }\r\n        if (expectedDtype !== 'numeric' && expectedDtype !== actualDType ||\r\n            expectedDtype === 'numeric' && actualDType === 'string') {\r\n            throw new Error(\"Argument '\" + argName + \"' passed to '\" + functionName + \"' must \" +\r\n                (\"be \" + expectedDtype + \" tensor, but got \" + actualDType + \" tensor\"));\r\n        }\r\n    }\r\n    function convertToTensor(x, argName, functionName, parseAsDtype) {\r\n        if (parseAsDtype === void 0) { parseAsDtype = 'numeric'; }\r\n        if (x instanceof Tensor) {\r\n            assertDtype(parseAsDtype, x.dtype, argName, functionName);\r\n            return x;\r\n        }\r\n        var inferredDtype = inferDtype(x);\r\n        if (inferredDtype !== 'string' &&\r\n            ['bool', 'int32', 'float32'].indexOf(parseAsDtype) >= 0) {\r\n            inferredDtype = parseAsDtype;\r\n        }\r\n        assertDtype(parseAsDtype, inferredDtype, argName, functionName);\r\n        if (!isTypedArray(x) && !Array.isArray(x) && typeof x !== 'number' &&\r\n            typeof x !== 'boolean' && typeof x !== 'string') {\r\n            throw new Error(\"Argument '\" + argName + \"' passed to '\" + functionName + \"' must be a \" +\r\n                (\"Tensor or TensorLike, but got '\" + x.constructor.name + \"'\"));\r\n        }\r\n        var inferredShape = inferShape(x);\r\n        if (!isTypedArray(x) && !Array.isArray(x)) {\r\n            x = [x];\r\n        }\r\n        var values = inferredDtype !== 'string' ?\r\n            toTypedArray(x, inferredDtype, ENV.get('DEBUG')) :\r\n            flatten(x);\r\n        return Tensor.make(inferredShape, { values: values }, inferredDtype);\r\n    }\r\n    function convertToTensorArray(arg, argName, functionName) {\r\n        if (!Array.isArray(arg)) {\r\n            throw new Error(\"Argument \" + argName + \" passed to \" + functionName + \" must be a \" +\r\n                '`Tensor[]` or `TensorLike[]`');\r\n        }\r\n        var tensors = arg;\r\n        return tensors.map(function (t, i) { return convertToTensor(t, argName + \"[\" + i + \"]\", functionName); });\r\n    }\n\n    function op(f) {\r\n        var keys = Object.keys(f);\r\n        if (keys.length !== 1) {\r\n            throw new Error(\"Please provide an object with a single key \" +\r\n                \"(operation name) mapping to a function. Got an object with \" +\r\n                (keys.length + \" keys.\"));\r\n        }\r\n        var opName = keys[0];\r\n        var fn = f[opName];\r\n        if (opName.endsWith('_')) {\r\n            opName = opName.substring(0, opName.length - 1);\r\n        }\r\n        var f2 = function () {\r\n            var args = [];\r\n            for (var _i = 0; _i < arguments.length; _i++) {\r\n                args[_i] = arguments[_i];\r\n            }\r\n            ENV.engine.startScope(opName);\r\n            try {\r\n                var result = fn.apply(void 0, args);\r\n                if (result instanceof Promise) {\r\n                    console.error('Cannot return a Promise inside of tidy.');\r\n                }\r\n                ENV.engine.endScope(result);\r\n                return result;\r\n            }\r\n            catch (ex) {\r\n                ENV.engine.endScope(null);\r\n                throw ex;\r\n            }\r\n        };\r\n        Object.defineProperty(f2, 'name', { value: opName, configurable: true });\r\n        return f2;\r\n    }\n\n    function softmax_(logits, dim) {\r\n        if (dim === void 0) { dim = -1; }\r\n        var $logits = convertToTensor(logits, 'logits', 'softmax');\r\n        if (dim === -1) {\r\n            dim = $logits.rank - 1;\r\n        }\r\n        if (dim !== $logits.rank - 1) {\r\n            throw Error('Softmax along a non-last dimension is not yet supported. ' +\r\n                (\"Logits was rank \" + $logits.rank + \" and dim was \" + dim));\r\n        }\r\n        var customOp = customGrad(function (logits) {\r\n            var keepDims = true;\r\n            var lse = logits.logSumExp([dim], keepDims);\r\n            var logResult = logits.toFloat().sub(lse);\r\n            var y = logResult.exp();\r\n            var gradFunc = function (dy) {\r\n                var dyTimesY = dy.mul(y);\r\n                var keepDims = true;\r\n                return dyTimesY.sub(dyTimesY.sum([dim], keepDims).mul(y));\r\n            };\r\n            return { value: y, gradFunc: gradFunc };\r\n        });\r\n        return customOp($logits);\r\n    }\r\n    function logSoftmax_(logits, axis) {\r\n        if (axis === void 0) { axis = -1; }\r\n        var $logits = convertToTensor(logits, 'logits', 'logSoftmax');\r\n        if (axis === -1) {\r\n            axis = $logits.rank - 1;\r\n        }\r\n        if (axis !== $logits.rank - 1) {\r\n            throw Error('Log Softmax along a non-last dimension is not yet supported. ' +\r\n                (\"Logits was rank \" + $logits.rank + \" and axis was \" + axis));\r\n        }\r\n        var customOp = customGrad(function (logits) {\r\n            var keepDims = true;\r\n            var xMax = logits.max(axis, true);\r\n            var shifted = logits.sub(xMax);\r\n            var value = shifted.toFloat().sub(shifted.exp().sum(axis, keepDims).log());\r\n            var gradFunc = function (dy) {\r\n                var softmax = value.exp();\r\n                return dy.sub(dy.sum(axis, keepDims).mul(softmax));\r\n            };\r\n            return { value: value, gradFunc: gradFunc };\r\n        });\r\n        return customOp($logits);\r\n    }\r\n    var softmax = op({ softmax_: softmax_ });\r\n    var logSoftmax = op({ logSoftmax_: logSoftmax_ });\n\n    function complex_(real, imag) {\r\n        var $real = convertToTensor(real, 'real', 'complex');\r\n        var $imag = convertToTensor(imag, 'imag', 'complex');\r\n        assertShapesMatch($real.shape, $imag.shape, \"real and imag shapes, \" + $real.shape + \" and \" + $imag.shape + \", \" +\r\n            \"must match in call to tf.complex().\");\r\n        return ENV.engine.runKernel(function (backend) { return backend.complex($real, $imag); }, { $real: $real, $imag: $imag });\r\n    }\r\n    function real_(input) {\r\n        var $input = convertToTensor(input, 'input', 'real');\r\n        return ENV.engine.runKernel(function (backend) { return backend.real($input); }, { $input: $input });\r\n    }\r\n    function imag_(input) {\r\n        var $input = convertToTensor(input, 'input', 'imag');\r\n        return ENV.engine.runKernel(function (backend) { return backend.imag($input); }, { $input: $input });\r\n    }\r\n    var complex = op({ complex_: complex_ });\r\n    var real = op({ real_: real_ });\r\n    var imag = op({ imag_: imag_ });\n\n    function tensor(values, shape, dtype) {\r\n        if (dtype == null) {\r\n            dtype = inferDtype(values);\r\n        }\r\n        if (dtype === 'complex64') {\r\n            throw new Error(\"Cannot construct a complex64 tensor directly. \" +\r\n                \"Please use tf.complex(real, imag).\");\r\n        }\r\n        if (!isTypedArray(values) && !Array.isArray(values) &&\r\n            typeof values !== 'number' && typeof values !== 'boolean' &&\r\n            typeof values !== 'string') {\r\n            throw new Error('values passed to tensor(values) must be a number/boolean/string or ' +\r\n                'an array of numbers/booleans/strings, or a TypedArray');\r\n        }\r\n        var inferredShape = inferShape(values);\r\n        if (shape != null) {\r\n            var providedSize_1 = sizeFromShape(shape);\r\n            var inferredSize_1 = sizeFromShape(inferredShape);\r\n            assert(providedSize_1 === inferredSize_1, function () {\r\n                return \"Based on the provided shape, [\" + shape + \"], the tensor should have \" +\r\n                    (providedSize_1 + \" values but has \" + inferredSize_1);\r\n            });\r\n            for (var i = 0; i < inferredShape.length; ++i) {\r\n                var inferred = inferredShape[i];\r\n                var flatDimsDontMatch = i === inferredShape.length - 1 ?\r\n                    inferred !== sizeFromShape(shape.slice(i)) :\r\n                    true;\r\n                assert(inferredShape[i] === shape[i] || !flatDimsDontMatch, function () { return \"Error creating a new Tensor. Inferred shape \" +\r\n                    (\"(\" + inferredShape + \") does not match the provided \") +\r\n                    (\"shape (\" + shape + \"). \"); });\r\n            }\r\n        }\r\n        if (!isTypedArray(values) && !Array.isArray(values)) {\r\n            values = [values];\r\n        }\r\n        shape = shape || inferredShape;\r\n        values = dtype !== 'string' ? toTypedArray(values, dtype, ENV.get('DEBUG')) :\r\n            flatten(values);\r\n        return Tensor.make(shape, { values: values }, dtype);\r\n    }\r\n    function scalar(value, dtype) {\r\n        if ((isTypedArray(value) || Array.isArray(value)) && dtype !== 'complex64') {\r\n            throw new Error('Error creating a new Scalar: value must be a primitive ' +\r\n                '(number|boolean|string)');\r\n        }\r\n        return tensor(value, [], dtype);\r\n    }\r\n    function tensor1d(values, dtype) {\r\n        assertNonNull(values);\r\n        var inferredShape = inferShape(values);\r\n        if (inferredShape.length !== 1) {\r\n            throw new Error('tensor1d() requires values to be a flat/TypedArray');\r\n        }\r\n        return tensor(values, inferredShape, dtype);\r\n    }\r\n    function tensor2d(values, shape, dtype) {\r\n        assertNonNull(values);\r\n        if (shape != null && shape.length !== 2) {\r\n            throw new Error('tensor2d() requires shape to have two numbers');\r\n        }\r\n        var inferredShape = inferShape(values);\r\n        if (inferredShape.length !== 2 && inferredShape.length !== 1) {\r\n            throw new Error('tensor2d() requires values to be number[][] or flat/TypedArray');\r\n        }\r\n        if (inferredShape.length === 1 && shape == null) {\r\n            throw new Error('tensor2d() requires shape to be provided when `values` ' +\r\n                'are a flat/TypedArray');\r\n        }\r\n        shape = shape || inferredShape;\r\n        return tensor(values, shape, dtype);\r\n    }\r\n    function tensor3d(values, shape, dtype) {\r\n        assertNonNull(values);\r\n        if (shape != null && shape.length !== 3) {\r\n            throw new Error('tensor3d() requires shape to have three numbers');\r\n        }\r\n        var inferredShape = inferShape(values);\r\n        if (inferredShape.length !== 3 && inferredShape.length !== 1) {\r\n            throw new Error('tensor3d() requires values to be number[][][] or flat/TypedArray');\r\n        }\r\n        if (inferredShape.length === 1 && shape == null) {\r\n            throw new Error('tensor3d() requires shape to be provided when `values` ' +\r\n                'are a flat array');\r\n        }\r\n        shape = shape || inferredShape;\r\n        return tensor(values, shape, dtype);\r\n    }\r\n    function tensor4d(values, shape, dtype) {\r\n        assertNonNull(values);\r\n        if (shape != null && shape.length !== 4) {\r\n            throw new Error('tensor4d() requires shape to have four numbers');\r\n        }\r\n        var inferredShape = inferShape(values);\r\n        if (inferredShape.length !== 4 && inferredShape.length !== 1) {\r\n            throw new Error('tensor4d() requires values to be number[][][][] or flat/TypedArray');\r\n        }\r\n        if (inferredShape.length === 1 && shape == null) {\r\n            throw new Error('tensor4d() requires shape to be provided when `values` ' +\r\n                'are a flat array');\r\n        }\r\n        shape = shape || inferredShape;\r\n        return tensor(values, shape, dtype);\r\n    }\r\n    function tensor5d(values, shape, dtype) {\r\n        assertNonNull(values);\r\n        if (shape != null && shape.length !== 5) {\r\n            throw new Error('tensor5d() requires shape to have five numbers');\r\n        }\r\n        var inferredShape = inferShape(values);\r\n        if (inferredShape.length !== 5 && inferredShape.length !== 1) {\r\n            throw new Error('tensor5d() requires values to be ' +\r\n                'number[][][][][] or flat/TypedArray');\r\n        }\r\n        if (inferredShape.length === 1 && shape == null) {\r\n            throw new Error('tensor5d() requires shape to be provided when `values` ' +\r\n                'are a flat array');\r\n        }\r\n        shape = shape || inferredShape;\r\n        return tensor(values, shape, dtype);\r\n    }\r\n    function tensor6d(values, shape, dtype) {\r\n        assertNonNull(values);\r\n        if (shape != null && shape.length !== 6) {\r\n            throw new Error('tensor6d() requires shape to have six numbers');\r\n        }\r\n        var inferredShape = inferShape(values);\r\n        if (inferredShape.length !== 6 && inferredShape.length !== 1) {\r\n            throw new Error('tensor6d() requires values to be number[][][][][][] or ' +\r\n                'flat/TypedArray');\r\n        }\r\n        if (inferredShape.length === 1 && shape == null) {\r\n            throw new Error('tensor6d() requires shape to be provided when `values` ' +\r\n                'are a flat array');\r\n        }\r\n        shape = shape ||\r\n            inferredShape;\r\n        return tensor(values, shape, dtype);\r\n    }\r\n    function ones$1(shape, dtype) {\r\n        if (dtype === void 0) { dtype = 'float32'; }\r\n        if (dtype === 'complex64') {\r\n            var real$$1 = ones$1(shape, 'float32');\r\n            var imag$$1 = ones$1(shape, 'float32');\r\n            return complex(real$$1, imag$$1);\r\n        }\r\n        var values = makeOnesTypedArray(sizeFromShape(shape), dtype);\r\n        return Tensor.make(shape, { values: values }, dtype);\r\n    }\r\n    function zeros(shape, dtype) {\r\n        if (dtype === void 0) { dtype = 'float32'; }\r\n        if (dtype === 'complex64') {\r\n            var real$$1 = zeros(shape, 'float32');\r\n            var imag$$1 = zeros(shape, 'float32');\r\n            return complex(real$$1, imag$$1);\r\n        }\r\n        var values = makeZerosTypedArray(sizeFromShape(shape), dtype);\r\n        return Tensor.make(shape, { values: values }, dtype);\r\n    }\r\n    function fill(shape, value, dtype) {\r\n        dtype = dtype || inferDtype(value);\r\n        var values = getArrayFromDType(dtype, sizeFromShape(shape));\r\n        values.fill(value);\r\n        return Tensor.make(shape, { values: values }, dtype);\r\n    }\r\n    function onesLike_(x) {\r\n        var $x = convertToTensor(x, 'x', 'onesLike');\r\n        return ones$1($x.shape, $x.dtype);\r\n    }\r\n    function zerosLike_(x) {\r\n        var $x = convertToTensor(x, 'x', 'zerosLike');\r\n        return zeros($x.shape, $x.dtype);\r\n    }\r\n    function linspace(start, stop, num) {\r\n        if (num === 0) {\r\n            throw new Error('Cannot request zero samples');\r\n        }\r\n        var step = (stop - start) / (num - 1);\r\n        var values = makeZerosTypedArray(num, 'float32');\r\n        values[0] = start;\r\n        for (var i = 1; i < values.length; i++) {\r\n            values[i] = values[i - 1] + step;\r\n        }\r\n        return tensor1d(values, 'float32');\r\n    }\r\n    function range(start, stop, step, dtype) {\r\n        if (step === void 0) { step = 1; }\r\n        if (dtype === void 0) { dtype = 'float32'; }\r\n        if (step === 0) {\r\n            throw new Error('Cannot have a step of zero');\r\n        }\r\n        var sameStartStop = start === stop;\r\n        var increasingRangeNegativeStep = start < stop && step < 0;\r\n        var decreasingRangePositiveStep = stop < start && step > 1;\r\n        if (sameStartStop || increasingRangeNegativeStep ||\r\n            decreasingRangePositiveStep) {\r\n            return zeros([0], dtype);\r\n        }\r\n        var numElements = Math.abs(Math.ceil((stop - start) / step));\r\n        var values = makeZerosTypedArray(numElements, dtype);\r\n        if (stop < start && step === 1) {\r\n            step = -1;\r\n        }\r\n        values[0] = start;\r\n        for (var i = 1; i < values.length; i++) {\r\n            values[i] = values[i - 1] + step;\r\n        }\r\n        return tensor1d(values, dtype);\r\n    }\r\n    var onesLike = op({ onesLike_: onesLike_ });\r\n    var zerosLike = op({ zerosLike_: zerosLike_ });\n\n    var DataStorage = (function () {\r\n        function DataStorage(dataMover) {\r\n            this.dataMover = dataMover;\r\n            this.data = new WeakMap();\r\n        }\r\n        DataStorage.prototype.get = function (dataId) {\r\n            if (!this.data.has(dataId)) {\r\n                this.dataMover.moveData(dataId);\r\n            }\r\n            return this.data.get(dataId);\r\n        };\r\n        DataStorage.prototype.set = function (dataId, value) {\r\n            this.data.set(dataId, value);\r\n        };\r\n        DataStorage.prototype.has = function (dataId) {\r\n            return this.data.has(dataId);\r\n        };\r\n        DataStorage.prototype.delete = function (dataId) {\r\n            return this.data.delete(dataId);\r\n        };\r\n        return DataStorage;\r\n    }());\r\n    var KernelBackend = (function () {\r\n        function KernelBackend() {\r\n        }\r\n        KernelBackend.prototype.time = function (f) {\r\n            throw new Error('Not yet implemented.');\r\n        };\r\n        KernelBackend.prototype.read = function (dataId) {\r\n            throw new Error('Not yet implemented.');\r\n        };\r\n        KernelBackend.prototype.readSync = function (dataId) {\r\n            throw new Error('Not yet implemented.');\r\n        };\r\n        KernelBackend.prototype.disposeData = function (dataId) {\r\n            throw new Error('Not yet implemented.');\r\n        };\r\n        KernelBackend.prototype.write = function (dataId, values) {\r\n            throw new Error('Not yet implemented.');\r\n        };\r\n        KernelBackend.prototype.fromPixels = function (pixels, numChannels) {\r\n            throw new Error('Not yet implemented.');\r\n        };\r\n        KernelBackend.prototype.register = function (dataId, shape, dtype) {\r\n            throw new Error('Not yet implemented.');\r\n        };\r\n        KernelBackend.prototype.memory = function () {\r\n            throw new Error('Not yet implemented.');\r\n        };\r\n        KernelBackend.prototype.floatPrecision = function () {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.batchMatMul = function (a, b, transposeA, transposeB) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.fusedBatchMatMul = function (a, b, transposeA, transposeB, bias, activation) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.slice = function (x, begin, size) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.stridedSlice = function (x, begin, end, strides, beginMask, endMask, ellipsisMask, newAxisMask, shrinkAxisMask) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.unstack = function (x, axis) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.reverse = function (a, axis) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.concat = function (tensors, axis) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.neg = function (a) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.add = function (a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.addN = function (tensors) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.subtract = function (a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.multiply = function (a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.realDivide = function (a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.floorDiv = function (a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.sum = function (x, axes) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.prod = function (x, axes) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.unsortedSegmentSum = function (x, segmentIds, numSegments) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.argMin = function (x, axis) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.argMax = function (x, axis) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.equal = function (a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.notEqual = function (a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.less = function (a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.lessEqual = function (a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.greater = function (a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.greaterEqual = function (a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.logicalNot = function (a) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.logicalAnd = function (a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.logicalOr = function (a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.where = function (condition) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.select = function (condition, a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.topk = function (x, k, sorted) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.min = function (x, axes) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.minimum = function (a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.mod = function (a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.max = function (x, axes) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.maximum = function (a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.all = function (x, axes) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.any = function (x, axes) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.squaredDifference = function (a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.ceil = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.floor = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.round = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.sign = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.pow = function (a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.exp = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.expm1 = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.log = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.log1p = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.sqrt = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.rsqrt = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.square = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.reciprocal = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.relu = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.prelu = function (x, a) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.elu = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.eluDer = function (dy, y) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.selu = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.int = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.clip = function (x, min, max) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.abs = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.complexAbs = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.sigmoid = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.softplus = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.sin = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.cos = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.tan = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.asin = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.acos = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.atan = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.atan2 = function (a, b) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.sinh = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.cosh = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.tanh = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.asinh = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.acosh = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.atanh = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.erf = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.step = function (x, alpha) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.conv2d = function (x, filter, convInfo) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.conv2dDerInput = function (dy, filter, convInfo) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.conv2dDerFilter = function (x, dY, convInfo) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.depthwiseConv2D = function (input, filter, convInfo) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.depthwiseConv2DDerInput = function (dy, filter, convInfo) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.depthwiseConv2DDerFilter = function (x, dY, convInfo) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.conv3d = function (x, filter, convInfo) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.conv3dDerInput = function (dy, filter, convInfo) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.conv3dDerFilter = function (x, dY, convInfo) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.maxPool = function (x, convInfo) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.maxPoolBackprop = function (dy, x, y, convInfo) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.avgPool = function (x, convInfo) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.avgPoolBackprop = function (dy, x, convInfo) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.reshape = function (x, shape) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.cast = function (x, dtype) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.tile = function (x, reps) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.pad = function (x, paddings, constantValue) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.transpose = function (x, perm) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.gather = function (x, indices, axis) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.gatherND = function (x, indices) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.scatterND = function (indices, updates, shape) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.batchToSpaceND = function (x, blockShape, crops) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.spaceToBatchND = function (x, blockShape, paddings) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.resizeBilinear = function (x, newHeight, newWidth, alignCorners) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.resizeBilinearBackprop = function (dy, x, alignCorners) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.resizeNearestNeighbor = function (x, newHEight, newWidth, alignCorners) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.resizeNearestNeighborBackprop = function (dy, x, alignCorners) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.batchNormalization = function (x, mean, variance, varianceEpsilon, scale, offset) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.localResponseNormalization4D = function (x, radius, bias, alpha, beta) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.LRNGrad = function (dy, inputImage, outputImage, radius, bias, alpha, beta) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.multinomial = function (logits, normalized, numSamples, seed) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.oneHot = function (indices, depth, onValue, offValue) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.cumsum = function (x, axis, exclusive, reverse) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.nonMaxSuppression = function (boxes, scores, maxOutputSize, iouThreshold, scoreThreshold) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.fft = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.ifft = function (x) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.complex = function (real, imag) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.real = function (input) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.imag = function (input) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.cropAndResize = function (image, boxes, boxIndex, cropSize, method, extrapolationValue) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.depthToSpace = function (x, blockSize, dataFormat) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.split = function (value, sizeSplits, axis) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.sparseToDense = function (sparseIndices, sparseValues, outputShape, defaultValue) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.setDataMover = function (dataMover) {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        KernelBackend.prototype.dispose = function () {\r\n            throw new Error('Not yet implemented');\r\n        };\r\n        return KernelBackend;\r\n    }());\n\n    function castTensor(x, dtype, backend) {\r\n        if (dtype === 'complex64') {\r\n            if (x.dtype === 'complex64') {\r\n                return x.clone();\r\n            }\r\n            var zerosTensor = zeros(x.shape);\r\n            var floatX = x.toFloat();\r\n            var result = backend.complex(floatX, zerosTensor);\r\n            zerosTensor.dispose();\r\n            floatX.dispose();\r\n            return result;\r\n        }\r\n        if (!hasEncodingLoss(x.dtype, dtype)) {\r\n            return Tensor.make(x.shape, { dataId: x.dataId }, dtype);\r\n        }\r\n        if (x.dtype === 'complex64') {\r\n            var real = backend.real(x);\r\n            var result = real.cast(dtype);\r\n            real.dispose();\r\n            return result;\r\n        }\r\n        if (dtype === 'int32') {\r\n            return backend.int(x);\r\n        }\r\n        else if (dtype === 'bool') {\r\n            var zero = scalar(0, x.dtype);\r\n            var result = backend.notEqual(x, zero);\r\n            zero.dispose();\r\n            return result;\r\n        }\r\n        else {\r\n            throw new Error(\"Error in Cast: unknown dtype argument (\" + dtype + \")\");\r\n        }\r\n    }\r\n    function reshapeTensor(x, shape) {\r\n        return Tensor.make(shape, { dataId: x.dataId }, x.dtype);\r\n    }\n\n    function mergeRealAndImagArrays(real, imag) {\r\n        if (real.length !== imag.length) {\r\n            throw new Error(\"Cannot merge real and imag arrays of different lengths. real:\" +\r\n                (real.length + \", imag: \" + imag.length + \".\"));\r\n        }\r\n        var result = new Float32Array(real.length * 2);\r\n        for (var i = 0; i < result.length; i += 2) {\r\n            result[i] = real[i / 2];\r\n            result[i + 1] = imag[i / 2];\r\n        }\r\n        return result;\r\n    }\r\n    function splitRealAndImagArrays(complex) {\r\n        var real = new Float32Array(complex.length / 2);\r\n        var imag = new Float32Array(complex.length / 2);\r\n        for (var i = 0; i < complex.length; i += 2) {\r\n            real[i / 2] = complex[i];\r\n            imag[i / 2] = complex[i + 1];\r\n        }\r\n        return { real: real, imag: imag };\r\n    }\r\n    function complexWithEvenIndex(complex) {\r\n        var len = Math.ceil(complex.length / 4);\r\n        var real = new Float32Array(len);\r\n        var imag = new Float32Array(len);\r\n        for (var i = 0; i < complex.length; i += 4) {\r\n            real[Math.floor(i / 4)] = complex[i];\r\n            imag[Math.floor(i / 4)] = complex[i + 1];\r\n        }\r\n        return { real: real, imag: imag };\r\n    }\r\n    function complexWithOddIndex(complex) {\r\n        var len = Math.floor(complex.length / 4);\r\n        var real = new Float32Array(len);\r\n        var imag = new Float32Array(len);\r\n        for (var i = 2; i < complex.length; i += 4) {\r\n            real[Math.floor(i / 4)] = complex[i];\r\n            imag[Math.floor(i / 4)] = complex[i + 1];\r\n        }\r\n        return { real: real, imag: imag };\r\n    }\r\n    function getComplexWithIndex(complex, index) {\r\n        var real = complex[index * 2];\r\n        var imag = complex[index * 2 + 1];\r\n        return { real: real, imag: imag };\r\n    }\r\n    function assignToTypedArray(data, real, imag, index) {\r\n        data[index * 2] = real;\r\n        data[index * 2 + 1] = imag;\r\n    }\r\n    function exponents(n, inverse) {\r\n        var real = new Float32Array(n / 2);\r\n        var imag = new Float32Array(n / 2);\r\n        for (var i = 0; i < Math.ceil(n / 2); i++) {\r\n            var x = (inverse ? 2 : -2) * Math.PI * (i / n);\r\n            real[i] = Math.cos(x);\r\n            imag[i] = Math.sin(x);\r\n        }\r\n        return { real: real, imag: imag };\r\n    }\r\n    function exponent(k, n, inverse) {\r\n        var x = (inverse ? 2 : -2) * Math.PI * (k / n);\r\n        var real = Math.cos(x);\r\n        var imag = Math.sin(x);\r\n        return { real: real, imag: imag };\r\n    }\n\n    function nonMaxSuppressionImpl(boxes, scores, maxOutputSize, iouThreshold, scoreThreshold) {\r\n        var candidates = Array.from(scores)\r\n            .map(function (score, boxIndex) { return ({ score: score, boxIndex: boxIndex }); })\r\n            .filter(function (c) { return c.score > scoreThreshold; })\r\n            .sort(function (c1, c2) { return c2.score - c1.score; });\r\n        var selected = [];\r\n        for (var i = 0; i < candidates.length; i++) {\r\n            var _a = candidates[i], score = _a.score, boxIndex = _a.boxIndex;\r\n            if (score < scoreThreshold) {\r\n                break;\r\n            }\r\n            var ignoreCandidate = false;\r\n            for (var j = selected.length - 1; j >= 0; --j) {\r\n                var iou = intersectionOverUnion(boxes, boxIndex, selected[j]);\r\n                if (iou >= iouThreshold) {\r\n                    ignoreCandidate = true;\r\n                    break;\r\n                }\r\n            }\r\n            if (!ignoreCandidate) {\r\n                selected.push(boxIndex);\r\n                if (selected.length >= maxOutputSize) {\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n        return tensor1d(selected, 'int32');\r\n    }\r\n    function intersectionOverUnion(boxes, i, j) {\r\n        var iCoord = boxes.subarray(i * 4, i * 4 + 4);\r\n        var jCoord = boxes.subarray(j * 4, j * 4 + 4);\r\n        var yminI = Math.min(iCoord[0], iCoord[2]);\r\n        var xminI = Math.min(iCoord[1], iCoord[3]);\r\n        var ymaxI = Math.max(iCoord[0], iCoord[2]);\r\n        var xmaxI = Math.max(iCoord[1], iCoord[3]);\r\n        var yminJ = Math.min(jCoord[0], jCoord[2]);\r\n        var xminJ = Math.min(jCoord[1], jCoord[3]);\r\n        var ymaxJ = Math.max(jCoord[0], jCoord[2]);\r\n        var xmaxJ = Math.max(jCoord[1], jCoord[3]);\r\n        var areaI = (ymaxI - yminI) * (xmaxI - xminI);\r\n        var areaJ = (ymaxJ - yminJ) * (xmaxJ - xminJ);\r\n        if (areaI <= 0 || areaJ <= 0) {\r\n            return 0.0;\r\n        }\r\n        var intersectionYmin = Math.max(yminI, yminJ);\r\n        var intersectionXmin = Math.max(xminI, xminJ);\r\n        var intersectionYmax = Math.min(ymaxI, ymaxJ);\r\n        var intersectionXmax = Math.min(xmaxI, xmaxJ);\r\n        var intersectionArea = Math.max(intersectionYmax - intersectionYmin, 0.0) *\r\n            Math.max(intersectionXmax - intersectionXmin, 0.0);\r\n        return intersectionArea / (areaI + areaJ - intersectionArea);\r\n    }\n\n    function split(x, sizeSplits, axis) {\r\n        var begin = new Array(x.rank).fill(0);\r\n        var size = x.shape.slice();\r\n        return sizeSplits.map(function (s) {\r\n            size[axis] = s;\r\n            var slice = x.slice(begin, size);\r\n            begin[axis] += s;\r\n            return slice;\r\n        });\r\n    }\n\n    function topkImpl(x, xShape, xDtype, k, sorted) {\r\n        var lastDim = xShape[xShape.length - 1];\r\n        var _a = [x.length / lastDim, lastDim], batch = _a[0], size = _a[1];\r\n        var allTopKVals = getTypedArrayFromDType(xDtype, batch * k);\r\n        var allTopKIndices = getTypedArrayFromDType('int32', batch * k);\r\n        for (var b = 0; b < batch; b++) {\r\n            var offset = b * size;\r\n            var vals = x.subarray(offset, offset + size);\r\n            var valAndInd = [];\r\n            for (var i = 0; i < vals.length; i++) {\r\n                valAndInd.push({ value: vals[i], index: i });\r\n            }\r\n            valAndInd.sort(function (a, b) { return b.value - a.value; });\r\n            var outOffset = b * k;\r\n            var topKVals = allTopKVals.subarray(outOffset, outOffset + k);\r\n            var topKIndices = allTopKIndices.subarray(outOffset, outOffset + k);\r\n            for (var i = 0; i < k; i++) {\r\n                topKVals[i] = valAndInd[i].value;\r\n                topKIndices[i] = valAndInd[i].index;\r\n            }\r\n        }\r\n        var outputShape = xShape.slice();\r\n        outputShape[outputShape.length - 1] = k;\r\n        return [\r\n            tensor(allTopKVals, outputShape, xDtype),\r\n            tensor(allTopKIndices, outputShape, 'int32')\r\n        ];\r\n    }\n\n    var ArgMinMaxProgram = (function () {\r\n        function ArgMinMaxProgram(reduceInfo, op, firstPass) {\r\n            this.variableNames = ['A'];\r\n            var windowSize = reduceInfo.windowSize;\r\n            var batchSize = reduceInfo.batchSize;\r\n            var inSize = reduceInfo.inSize;\r\n            var outSize = Math.ceil(inSize / windowSize);\r\n            if (!firstPass) {\r\n                this.variableNames.push('bestIndicesA');\r\n            }\r\n            this.outputShape = [batchSize, outSize];\r\n            var compOp = (op === 'max') ? '>' : '<';\r\n            var indexSnippet = firstPass ?\r\n                'inOffset + i;' :\r\n                'round(getBestIndicesA(batch, inOffset + i));';\r\n            this.userCode = \"\\n      void main() {\\n        ivec2 coords = getOutputCoords();\\n        int batch = coords[0];\\n        int outIdx = coords[1];\\n        int inOffset = outIdx * \" + windowSize + \";\\n\\n        int bestIndex = inOffset;\\n        float bestValue = getA(batch, bestIndex);\\n\\n        for (int i = 0; i < \" + windowSize + \"; i++) {\\n          int inIdx = \" + indexSnippet + \";\\n          float candidate = getA(batch, inIdx);\\n          if (candidate \" + compOp + \" bestValue) {\\n            bestValue = candidate;\\n            bestIndex = inIdx;\\n          }\\n        }\\n        setOutput(float(bestIndex));\\n      }\\n    \";\r\n        }\r\n        return ArgMinMaxProgram;\r\n    }());\n\n    var AvgPool2DBackpropProgram = (function () {\r\n        function AvgPool2DBackpropProgram(convInfo) {\r\n            this.variableNames = ['dy'];\r\n            this.outputShape = convInfo.inShape;\r\n            var filterHeight = convInfo.filterHeight;\r\n            var filterWidth = convInfo.filterWidth;\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var dilationHeight = convInfo.dilationHeight;\r\n            var dilationWidth = convInfo.dilationWidth;\r\n            var effectiveFilterHeight = convInfo.effectiveFilterHeight;\r\n            var effectiveFilterWidth = convInfo.effectiveFilterWidth;\r\n            var padTop = effectiveFilterHeight - 1 - convInfo.padInfo.top;\r\n            var padLeft = effectiveFilterWidth - 1 - convInfo.padInfo.left;\r\n            var avgMultiplier = 1 / (filterHeight * filterWidth);\r\n            this.userCode = \"\\n      const ivec2 pads = ivec2(\" + padTop + \", \" + padLeft + \");\\n      const float avgMultiplier = float(\" + avgMultiplier + \");\\n\\n      void main() {\\n        ivec4 coords = getOutputCoords();\\n        int b = coords[0];\\n        int d = coords[3];\\n\\n        ivec2 dyRCCorner = coords.yz - pads;\\n        int dyRCorner = dyRCCorner.x;\\n        int dyCCorner = dyRCCorner.y;\\n\\n        // Convolve dy(?, ?, d) with pos mask(:, :, d) to get dx(xR, xC, d).\\n        // ? = to be determined. : = across all values in that axis.\\n        float dotProd = 0.0;\\n        for (int wR = 0; wR < \" + effectiveFilterHeight + \";\\n            wR += \" + dilationHeight + \") {\\n          float dyR = float(dyRCorner + wR) / \" + strideHeight + \".0;\\n\\n          if (dyR < 0.0 || dyR >= \" + convInfo.outHeight + \".0 || fract(dyR) > 0.0) {\\n            continue;\\n          }\\n          int idyR = int(dyR);\\n\\n          for (int wC = 0; wC < \" + effectiveFilterWidth + \";\\n            wC+= \" + dilationWidth + \") {\\n            float dyC = float(dyCCorner + wC) / \" + strideWidth + \".0;\\n\\n            if (dyC < 0.0 || dyC >= \" + convInfo.outWidth + \".0 ||\\n                fract(dyC) > 0.0) {\\n              continue;\\n            }\\n            int idyC = int(dyC);\\n\\n            float dyValue = getDy(b, idyR, idyC, d);\\n\\n            dotProd += dyValue * avgMultiplier;\\n          }\\n        }\\n        setOutput(dotProd);\\n      }\\n    \";\r\n        }\r\n        return AvgPool2DBackpropProgram;\r\n    }());\n\n    var BatchNormProgram = (function () {\r\n        function BatchNormProgram(xShape, meanShape, varianceShape, offsetShape, scaleShape, varianceEpsilon) {\r\n            this.outputShape = [];\r\n            this.variableNames = ['x', 'mean', 'variance'];\r\n            assertAndGetBroadcastShape(xShape, meanShape);\r\n            assertAndGetBroadcastShape(xShape, varianceShape);\r\n            var offsetSnippet = '0.0';\r\n            if (offsetShape != null) {\r\n                assertAndGetBroadcastShape(xShape, offsetShape);\r\n                this.variableNames.push('offset');\r\n                offsetSnippet = 'getOffsetAtOutCoords()';\r\n            }\r\n            var scaleSnippet = '1.0';\r\n            if (scaleShape != null) {\r\n                assertAndGetBroadcastShape(xShape, scaleShape);\r\n                this.variableNames.push('scale');\r\n                scaleSnippet = 'getScaleAtOutCoords()';\r\n            }\r\n            this.outputShape = xShape;\r\n            this.userCode = \"\\n      void main() {\\n        float x = getXAtOutCoords();\\n        float mean = getMeanAtOutCoords();\\n        float variance = getVarianceAtOutCoords();\\n        float offset = \" + offsetSnippet + \";\\n        float scale = \" + scaleSnippet + \";\\n        float inv = scale * inversesqrt(variance + float(\" + varianceEpsilon + \"));\\n        setOutput(dot(vec3(x, -mean, offset), vec3(inv, inv, 1)));\\n      }\\n    \";\r\n        }\r\n        return BatchNormProgram;\r\n    }());\n\n    var BatchNormPackedProgram = (function () {\r\n        function BatchNormPackedProgram(xShape, meanShape, varianceShape, offsetShape, scaleShape, varianceEpsilon) {\r\n            this.usesPackedTextures = true;\r\n            this.variableNames = ['x', 'mean', 'variance'];\r\n            assertAndGetBroadcastShape(xShape, meanShape);\r\n            assertAndGetBroadcastShape(xShape, varianceShape);\r\n            var offsetSnippet = 'vec4(0.0)';\r\n            if (offsetShape != null) {\r\n                assertAndGetBroadcastShape(xShape, offsetShape);\r\n                this.variableNames.push('offset');\r\n                offsetSnippet = 'getOffsetAtOutCoords()';\r\n            }\r\n            var scaleSnippet = 'vec4(1.0)';\r\n            if (scaleShape != null) {\r\n                assertAndGetBroadcastShape(xShape, scaleShape);\r\n                this.variableNames.push('scale');\r\n                scaleSnippet = 'getScaleAtOutCoords()';\r\n            }\r\n            this.outputShape = xShape;\r\n            this.userCode = \"\\n      void main() {\\n        vec4 offset = \" + offsetSnippet + \";\\n        vec4 scale = \" + scaleSnippet + \";\\n\\n        vec4 x = getXAtOutCoords();\\n        vec4 mean = getMeanAtOutCoords();\\n        vec4 variance = getVarianceAtOutCoords();\\n\\n        vec4 inv = scale * inversesqrt(variance + vec4(\" + varianceEpsilon + \"));\\n\\n        setOutput((x - mean) * inv + offset);\\n      }\\n    \";\r\n        }\r\n        return BatchNormPackedProgram;\r\n    }());\n\n    var COMPLEX_MULTIPLY = {\r\n        REAL: 'return areal * breal - aimag * bimag;',\r\n        IMAG: 'return areal * bimag + aimag * breal;'\r\n    };\r\n    var BinaryOpComplexProgram = (function () {\r\n        function BinaryOpComplexProgram(op, aShape, bShape) {\r\n            this.variableNames = ['AReal', 'AImag', 'BReal', 'BImag'];\r\n            this.outputShape =\r\n                assertAndGetBroadcastShape(aShape, bShape);\r\n            this.userCode = \"\\n      float binaryOpComplex(\\n          float areal, float aimag, float breal, float bimag) {\\n        \" + op + \"\\n      }\\n\\n      void main() {\\n        float areal = getARealAtOutCoords();\\n        float aimag = getAImagAtOutCoords();\\n        float breal = getBRealAtOutCoords();\\n        float bimag = getBImagAtOutCoords();\\n        setOutput(binaryOpComplex(areal, aimag, breal, bimag));\\n      }\\n    \";\r\n        }\r\n        return BinaryOpComplexProgram;\r\n    }());\n\n    var CHECK_NAN_SNIPPET = \"\\n  if (isNaN(a)) return a;\\n  if (isNaN(b)) return b;\\n\";\r\n    var ADD = 'return a + b;';\r\n    var SUB = 'return a - b;';\r\n    var MUL = 'return a * b;';\r\n    var DIV = \"if (a == b) return 1.0;\\n  return a / b;\";\r\n    var INT_DIV = \"\\n  float resultSign = sign(a) * sign(b);\\n  int ia = round(a);\\n  int ib = round(b);\\n  int result = ia / ib;\\n  int amodb = ia - ib * result;\\n\\n  if (resultSign < 0.0 && amodb != 0) {\\n    result -= 1;\\n  }\\n  return float(result);\\n\";\r\n    var POW = \"\\nif(a < 0.0 && floor(b) < b){\\n  return NAN;\\n}\\nreturn (round(mod(b, 2.0)) != 1) ?\\n    pow(abs(a), b) : sign(a) * pow(abs(a), b);\\n\";\r\n    var SQUARED_DIFFERENCE = 'return (a - b) * (a - b);';\r\n    var EQUAL = \"return float(a == b);\";\r\n    var NOT_EQUAL = \"return float(a != b);\";\r\n    var LESS = \"return float(a < b);\";\r\n    var LESS_EQUAL = \"return float(a <= b);\";\r\n    var GREATER = \"return float(a > b);\";\r\n    var GREATER_EQUAL = \"return float(a >= b);\";\r\n    var LOGICAL_AND = \"return float(a >= 1.0 && b >= 1.0);\";\r\n    var LOGICAL_OR = \"return float(a >= 1.0 || b >= 1.0);\";\r\n    var MAX = CHECK_NAN_SNIPPET + \"\\n  return max(a, b);\\n\";\r\n    var MIN = CHECK_NAN_SNIPPET + \"\\n  return min(a, b);\\n\";\r\n    var MOD = \"if (b == 0.0) return NAN;\\n  return mod(a, b);\";\r\n    var ATAN2 = CHECK_NAN_SNIPPET + \"\\n  return atan(a, b);\\n\";\r\n    var ELU_DER = \"return (b >= 1.0) ? a : a * (b + 1.0);\";\r\n    var PRELU = \"return (a < 0.) ? b * a : a;\";\r\n    var BinaryOpProgram = (function () {\r\n        function BinaryOpProgram(op, aShape, bShape) {\r\n            this.variableNames = ['A', 'B'];\r\n            this.outputShape =\r\n                assertAndGetBroadcastShape(aShape, bShape);\r\n            this.userCode = \"\\n      uniform float NAN;\\n      float binaryOperation(float a, float b) {\\n        \" + op + \"\\n      }\\n\\n      void main() {\\n        float a = getAAtOutCoords();\\n        float b = getBAtOutCoords();\\n        setOutput(binaryOperation(a, b));\\n      }\\n    \";\r\n        }\r\n        BinaryOpProgram.prototype.getCustomSetupFunc = function () {\r\n            var _this = this;\r\n            return function (gpgpu, webGLProgram) {\r\n                if (_this.startLoc == null) {\r\n                    _this.startLoc = gpgpu.getUniformLocationNoThrow(webGLProgram, 'NAN');\r\n                    if (_this.startLoc == null) {\r\n                        return;\r\n                    }\r\n                }\r\n                gpgpu.gl.uniform1f(_this.startLoc, NaN);\r\n            };\r\n        };\r\n        return BinaryOpProgram;\r\n    }());\n\n    var PACKED_DIV = \"\\n  vec4 one = vec4(equal(a, b));\\n  return one + (vec4(1.0) - one) * a / b;\\n\";\r\n    var PACKED_INT_DIV = \"\\n  vec4 resultSign = sign(a) * sign(b);\\n  ivec4 ia = round(a);\\n  ivec4 ib = round(b);\\n  ivec4 result = ia / ib;\\n  ivec4 amodb = ia - ib * result;\\n  \\n  // Vectorize INT_DIV\\n  // if (resultSign < 0.0 && amodb != 0) result -= 1;\\n  // return float(result);\\n  return vec4(result -\\n     ivec4(lessThan(resultSign, vec4(0.0))) * ivec4(notEqual(amodb, ivec4(0))));\\n\";\r\n    var PACKED_POW = \"\\n  // isModRound1 has 1 for components with round(mod(b, 2.0)) == 1, 0 otherwise.\\n  vec4 isModRound1 = vec4(equal(round(mod(b, 2.0)), ivec4(1)));\\n  vec4 multiplier = sign(a) * isModRound1 + (vec4(1.0) - isModRound1);\\n  vec4 result = multiplier * pow(abs(a), b);\\n\\n  vec4 isNaN = vec4(lessThan(a, vec4(0.0))) * vec4(lessThan(floor(b), b));\\n  result.r = isNaN.r == 1.0 ? NAN : result.r;\\n  result.g = isNaN.g == 1.0 ? NAN : result.g;\\n  result.b = isNaN.b == 1.0 ? NAN : result.b;\\n  result.a = isNaN.a == 1.0 ? NAN : result.a;\\n  \\n  return result;\\n\";\r\n    var BinaryOpPackedProgram = (function () {\r\n        function BinaryOpPackedProgram(op, aShape, bShape) {\r\n            this.variableNames = ['A', 'B'];\r\n            this.supportsBroadcasting = true;\r\n            this.usesPackedTextures = true;\r\n            this.outputShape =\r\n                assertAndGetBroadcastShape(aShape, bShape);\r\n            this.userCode = \"\\n      uniform float NAN;\\n      vec4 binaryOperation(vec4 a, vec4 b) {\\n        \" + op + \"\\n      }\\n\\n      void main() {\\n        vec4 a = getAAtOutCoords();\\n        vec4 b = getBAtOutCoords();\\n        setOutput(binaryOperation(a, b));\\n      }\\n    \";\r\n        }\r\n        BinaryOpPackedProgram.prototype.getCustomSetupFunc = function () {\r\n            var _this = this;\r\n            return function (gpgpu, webGLProgram) {\r\n                if (_this.startLoc == null) {\r\n                    _this.startLoc = gpgpu.getUniformLocationNoThrow(webGLProgram, 'NAN');\r\n                    if (_this.startLoc == null) {\r\n                        return;\r\n                    }\r\n                }\r\n                gpgpu.gl.uniform1f(_this.startLoc, NaN);\r\n            };\r\n        };\r\n        return BinaryOpPackedProgram;\r\n    }());\n\n    var ClipProgram = (function () {\r\n        function ClipProgram(aShape) {\r\n            this.variableNames = ['A'];\r\n            this.outputShape = aShape;\r\n            this.userCode = \"\\n      uniform float min;\\n      uniform float max;\\n\\n      void main() {\\n        float value = getAAtOutCoords();\\n        if (isNaN(value)) {\\n          setOutput(value);\\n          return;\\n        }\\n\\n        setOutput(clamp(value, min, max));\\n      }\\n    \";\r\n        }\r\n        ClipProgram.prototype.getCustomSetupFunc = function (min, max) {\r\n            var _this = this;\r\n            return function (gpgpu, webGLProgram) {\r\n                if (_this.minLoc == null) {\r\n                    _this.minLoc = gpgpu.getUniformLocationNoThrow(webGLProgram, 'min');\r\n                    _this.maxLoc = gpgpu.getUniformLocationNoThrow(webGLProgram, 'max');\r\n                }\r\n                gpgpu.gl.uniform1f(_this.minLoc, min);\r\n                gpgpu.gl.uniform1f(_this.maxLoc, max);\r\n            };\r\n        };\r\n        return ClipProgram;\r\n    }());\n\n    var ClipPackedProgram = (function () {\r\n        function ClipPackedProgram(aShape) {\r\n            this.variableNames = ['A'];\r\n            this.usesPackedTextures = true;\r\n            this.outputShape = aShape;\r\n            this.userCode = \"\\n      uniform float min;\\n      uniform float max;\\n\\n      void main() {\\n        vec4 value = getAAtOutCoords();\\n\\n        if (hasNaN(value)) {\\n          setOutput(value);\\n          return;\\n        }\\n\\n        setOutput(clamp(value, vec4(min), vec4(max)));\\n      }\\n    \";\r\n        }\r\n        ClipPackedProgram.prototype.getCustomSetupFunc = function (min, max) {\r\n            var _this = this;\r\n            return function (gpgpu, webGLProgram) {\r\n                if (_this.minLoc == null) {\r\n                    _this.minLoc = gpgpu.getUniformLocationNoThrow(webGLProgram, 'min');\r\n                    _this.maxLoc = gpgpu.getUniformLocationNoThrow(webGLProgram, 'max');\r\n                }\r\n                gpgpu.gl.uniform1f(_this.minLoc, min);\r\n                gpgpu.gl.uniform1f(_this.maxLoc, max);\r\n            };\r\n        };\r\n        return ClipPackedProgram;\r\n    }());\n\n    var ComplexAbsProgram = (function () {\r\n        function ComplexAbsProgram(shape) {\r\n            this.variableNames = ['real', 'imag'];\r\n            this.outputShape = shape;\r\n            this.userCode = \"\\n      void main() {\\n        float re = abs(getRealAtOutCoords());\\n        float im = abs(getImagAtOutCoords());\\n        float mx = max(re, im);\\n\\n        // sadly the length function in glsl is not underflow-safe\\n        // (at least not on Intel GPUs). So the safe solution is\\n        // to ensure underflow-safety in all cases.\\n        setOutput(\\n          mx == 0.0 ? 0.0 : mx * length(vec2(1, min(re, im)/mx))\\n        );\\n      }\\n    \";\r\n        }\r\n        return ComplexAbsProgram;\r\n    }());\n\n    var ConcatProgram = (function () {\r\n        function ConcatProgram(shapes) {\r\n            this.outputShape = [];\r\n            this.outputShape = computeOutShape(shapes, 1);\r\n            this.variableNames = shapes.map(function (_, i) { return \"T\" + i; });\r\n            var offsets = new Array(shapes.length - 1);\r\n            offsets[0] = shapes[0][1];\r\n            for (var i = 1; i < offsets.length; i++) {\r\n                offsets[i] = offsets[i - 1] + shapes[i][1];\r\n            }\r\n            var snippets = [\"if (yC < \" + offsets[0] + \") setOutput(getT0(yR, yC));\"];\r\n            for (var i = 1; i < offsets.length; i++) {\r\n                var shift = offsets[i - 1];\r\n                snippets.push(\"else if (yC < \" + offsets[i] + \") \" +\r\n                    (\"setOutput(getT\" + i + \"(yR, yC-\" + shift + \"));\"));\r\n            }\r\n            var lastIndex = offsets.length;\r\n            var lastShift = offsets[offsets.length - 1];\r\n            snippets.push(\"else setOutput(getT\" + lastIndex + \"(yR, yC-\" + lastShift + \"));\");\r\n            this.userCode = \"\\n      void main() {\\n        ivec2 coords = getOutputCoords();\\n        int yR = coords.x;\\n        int yC = coords.y;\\n\\n        \" + snippets.join('\\n        ') + \"\\n      }\\n    \";\r\n        }\r\n        return ConcatProgram;\r\n    }());\n\n    var Conv2DDerFilterProgram = (function () {\r\n        function Conv2DDerFilterProgram(convInfo) {\r\n            this.variableNames = ['x', 'dy'];\r\n            this.outputShape = convInfo.filterShape;\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var padTop = convInfo.padInfo.top;\r\n            var padLeft = convInfo.padInfo.left;\r\n            this.userCode = \"\\n      void main() {\\n        ivec4 coords = getOutputCoords();\\n        int wR = coords.x;\\n        int wC = coords.y;\\n        int d1 = coords.z;\\n        int d2 = coords.w;\\n\\n        // Convolve x(?, ?, d1) with dy(:, :, d2) to get dw(wR, wC, d1, d2).\\n        // ? = to be determined. : = across all values in that axis.\\n        float dotProd = 0.0;\\n\\n        for (int b = 0; b < \" + convInfo.batchSize + \"; b++) {\\n          for (int yR = 0; yR < \" + convInfo.outHeight + \"; yR++) {\\n            int xR = wR + yR * \" + strideHeight + \" - \" + padTop + \";\\n\\n            if (xR < 0 || xR >= \" + convInfo.inHeight + \") {\\n              continue;\\n            }\\n\\n            for (int yC = 0; yC < \" + convInfo.outWidth + \"; yC++) {\\n              int xC = wC + yC * \" + strideWidth + \" - \" + padLeft + \";\\n\\n              if (xC < 0 || xC >= \" + convInfo.inWidth + \") {\\n                continue;\\n              }\\n\\n              float dyValue = getDy(b, yR, yC, d2);\\n              float xValue = getX(b, xR, xC, d1);\\n              dotProd += (xValue * dyValue);\\n            }\\n          }\\n        }\\n        setOutput(dotProd);\\n      }\\n    \";\r\n        }\r\n        return Conv2DDerFilterProgram;\r\n    }());\r\n    var Conv2DDerInputProgram = (function () {\r\n        function Conv2DDerInputProgram(convInfo) {\r\n            this.variableNames = ['dy', 'W'];\r\n            this.outputShape = convInfo.inShape;\r\n            var filterHeight = convInfo.filterHeight;\r\n            var filterWidth = convInfo.filterWidth;\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var padTop = filterHeight - 1 - convInfo.padInfo.top;\r\n            var padLeft = filterWidth - 1 - convInfo.padInfo.left;\r\n            this.userCode = \"\\n      const ivec2 pads = ivec2(\" + padTop + \", \" + padLeft + \");\\n\\n      void main() {\\n        ivec4 coords = getOutputCoords();\\n        int batch = coords[0];\\n        int d1 = coords[3];\\n\\n        ivec2 dyCorner = coords.yz - pads;\\n        int dyRCorner = dyCorner.x;\\n        int dyCCorner = dyCorner.y;\\n\\n        // Convolve dy(?, ?, d2) with w(:, :, d1, d2) to compute dx(xR, xC, d1).\\n        // ? = to be determined. : = across all values in that axis.\\n        float dotProd = 0.0;\\n        for (int wR = 0; wR < \" + filterHeight + \"; wR++) {\\n          float dyR = float(dyRCorner + wR) / \" + strideHeight + \".0;\\n\\n          if (dyR < 0.0 || dyR >= \" + convInfo.outHeight + \".0 || fract(dyR) > 0.0) {\\n            continue;\\n          }\\n          int idyR = int(dyR);\\n\\n          int wRPerm = \" + filterHeight + \" - 1 - wR;\\n\\n          for (int wC = 0; wC < \" + filterWidth + \"; wC++) {\\n            float dyC = float(dyCCorner + wC) / \" + strideWidth + \".0;\\n\\n            if (dyC < 0.0 || dyC >= \" + convInfo.outWidth + \".0 ||\\n                fract(dyC) > 0.0) {\\n              continue;\\n            }\\n            int idyC = int(dyC);\\n\\n            int wCPerm = \" + filterWidth + \" - 1 - wC;\\n\\n            for (int d2 = 0; d2 < \" + convInfo.outChannels + \"; d2++) {\\n              float xValue = getDy(batch, idyR, idyC, d2);\\n              float wValue = getW(wRPerm, wCPerm, d1, d2);\\n              dotProd += xValue * wValue;\\n            }\\n          }\\n        }\\n        setOutput(dotProd);\\n      }\\n    \";\r\n        }\r\n        return Conv2DDerInputProgram;\r\n    }());\r\n    var Conv3DDerFilterProgram = (function () {\r\n        function Conv3DDerFilterProgram(convInfo) {\r\n            this.variableNames = ['x', 'dy'];\r\n            this.outputShape = convInfo.filterShape;\r\n            var strideDepth = convInfo.strideDepth;\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var padFront = convInfo.padInfo.front;\r\n            var padTop = convInfo.padInfo.top;\r\n            var padLeft = convInfo.padInfo.left;\r\n            this.userCode = \"\\n      void main() {\\n        ivec5 coords = getOutputCoords();\\n        int wF = coords.x;\\n        int wR = coords.y;\\n        int wC = coords.z;\\n        int d1 = coords.w;\\n        int d2 = coords.u;\\n\\n        float dotProd = 0.0;\\n\\n        for (int b = 0; b < \" + convInfo.batchSize + \"; b++) {\\n          for (int yF = 0; yF < \" + convInfo.outDepth + \"; yF++) {\\n            int xF = wF + yF * \" + strideDepth + \" - \" + padFront + \";\\n\\n            if (xF < 0 || xF >= \" + convInfo.inDepth + \") {\\n              continue;\\n            }\\n\\n            for (int yR = 0; yR < \" + convInfo.outHeight + \"; yR++) {\\n              int xR = wR + yR * \" + strideHeight + \" - \" + padTop + \";\\n\\n              if (xR < 0 || xR >= \" + convInfo.inHeight + \") {\\n                continue;\\n              }\\n\\n              for (int yC = 0; yC < \" + convInfo.outWidth + \"; yC++) {\\n                int xC = wC + yC * \" + strideWidth + \" - \" + padLeft + \";\\n\\n                if (xC < 0 || xC >= \" + convInfo.inWidth + \") {\\n                  continue;\\n                }\\n\\n                float dyValue = getDy(b, yF, yR, yC, d2);\\n                float xValue = getX(b, xF, xR, xC, d1);\\n                dotProd += (xValue * dyValue);\\n              }\\n            }\\n          }\\n        }\\n        setOutput(dotProd);\\n      }\\n    \";\r\n        }\r\n        return Conv3DDerFilterProgram;\r\n    }());\r\n    var Conv3DDerInputProgram = (function () {\r\n        function Conv3DDerInputProgram(convInfo) {\r\n            this.variableNames = ['dy', 'W'];\r\n            this.outputShape = convInfo.inShape;\r\n            var filterDepth = convInfo.filterDepth;\r\n            var filterHeight = convInfo.filterHeight;\r\n            var filterWidth = convInfo.filterWidth;\r\n            var strideDepth = convInfo.strideDepth;\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var padFront = filterDepth - 1 - convInfo.padInfo.front;\r\n            var padTop = filterHeight - 1 - convInfo.padInfo.top;\r\n            var padLeft = filterWidth - 1 - convInfo.padInfo.left;\r\n            this.userCode = \"\\n      const ivec3 pads = ivec3(\" + padFront + \", \" + padTop + \", \" + padLeft + \");\\n\\n      void main() {\\n        ivec5 coords = getOutputCoords();\\n        int batch = coords.x;\\n        int d1 = coords.u;\\n\\n\\n        ivec3 dyCorner = ivec3(coords.y, coords.z, coords.w) - pads;\\n        int dyFCorner = dyCorner.x;\\n        int dyRCorner = dyCorner.y;\\n        int dyCCorner = dyCorner.z;\\n\\n        float dotProd = 0.0;\\n        for (int wF = 0; wF < \" + filterDepth + \"; wF++) {\\n          float dyF = float(dyFCorner + wF) / \" + strideDepth + \".0;\\n\\n          if (dyF < 0.0 || dyF >= \" + convInfo.outDepth + \".0 || fract(dyF) > 0.0) {\\n            continue;\\n          }\\n          int idyF = int(dyF);\\n\\n          int wFPerm = \" + filterDepth + \" - 1 - wF;\\n\\n          for (int wR = 0; wR < \" + filterHeight + \"; wR++) {\\n            float dyR = float(dyRCorner + wR) / \" + strideHeight + \".0;\\n\\n            if (dyR < 0.0 || dyR >= \" + convInfo.outHeight + \".0 ||\\n              fract(dyR) > 0.0) {\\n              continue;\\n            }\\n            int idyR = int(dyR);\\n\\n            int wRPerm = \" + filterHeight + \" - 1 - wR;\\n\\n            for (int wC = 0; wC < \" + filterWidth + \"; wC++) {\\n              float dyC = float(dyCCorner + wC) / \" + strideWidth + \".0;\\n\\n              if (dyC < 0.0 || dyC >= \" + convInfo.outWidth + \".0 ||\\n                  fract(dyC) > 0.0) {\\n                continue;\\n              }\\n              int idyC = int(dyC);\\n\\n              int wCPerm = \" + filterWidth + \" - 1 - wC;\\n\\n              for (int d2 = 0; d2 < \" + convInfo.outChannels + \"; d2++) {\\n                float xValue = getDy(batch, idyF, idyR, idyC, d2);\\n                float wValue = getW(wFPerm, wRPerm, wCPerm, d1, d2);\\n                dotProd += xValue * wValue;\\n              }\\n            }\\n          }\\n        }\\n        setOutput(dotProd);\\n      }\\n    \";\r\n        }\r\n        return Conv3DDerInputProgram;\r\n    }());\n\n    var DepthwiseConv2DDerFilterProgram = (function () {\r\n        function DepthwiseConv2DDerFilterProgram(convInfo) {\r\n            this.variableNames = ['x', 'dy'];\r\n            this.outputShape = convInfo.filterShape;\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var padTop = convInfo.padInfo.top;\r\n            var padLeft = convInfo.padInfo.left;\r\n            var channelMul = convInfo.outChannels / convInfo.inChannels;\r\n            this.userCode = \"\\n      void main() {\\n        ivec4 coords = getOutputCoords();\\n        int wR = coords.x;\\n        int wC = coords.y;\\n        int d1 = coords.z;\\n        int dm = coords.w;\\n        int d2 = d1 * \" + channelMul + \" + dm;\\n\\n        float dotProd = 0.0;\\n\\n        // TODO: Vec4 over the batch size\\n        for (int b = 0; b < \" + convInfo.batchSize + \"; b++) {\\n          for (int yR = 0; yR < \" + convInfo.outHeight + \"; yR++) {\\n            int xR = wR + yR * \" + strideHeight + \" - \" + padTop + \";\\n\\n            if (xR < 0 || xR >= \" + convInfo.inHeight + \") {\\n              continue;\\n            }\\n\\n            for (int yC = 0; yC < \" + convInfo.outWidth + \"; yC++) {\\n              int xC = wC + yC * \" + strideWidth + \" - \" + padLeft + \";\\n\\n              if (xC < 0 || xC >= \" + convInfo.inWidth + \") {\\n                continue;\\n              }\\n\\n              float dyValue = getDy(b, yR, yC, d2);\\n              float xValue = getX(b, xR, xC, d1);\\n              dotProd += (xValue * dyValue);\\n            }\\n          }\\n        }\\n        setOutput(dotProd);\\n      }\\n    \";\r\n        }\r\n        return DepthwiseConv2DDerFilterProgram;\r\n    }());\r\n    var DepthwiseConv2DDerInputProgram = (function () {\r\n        function DepthwiseConv2DDerInputProgram(convInfo) {\r\n            this.variableNames = ['dy', 'W'];\r\n            this.outputShape = convInfo.inShape;\r\n            var filterHeight = convInfo.filterHeight;\r\n            var filterWidth = convInfo.filterWidth;\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var padTop = filterHeight - 1 - convInfo.padInfo.top;\r\n            var padLeft = filterWidth - 1 - convInfo.padInfo.left;\r\n            var channelMul = convInfo.outChannels / convInfo.inChannels;\r\n            this.userCode = \"\\n      const ivec2 pads = ivec2(\" + padTop + \", \" + padLeft + \");\\n\\n      void main() {\\n        ivec4 coords = getOutputCoords();\\n        int batch = coords[0];\\n        int d1 = coords[3];\\n        ivec2 dyCorner = coords.yz - pads;\\n        int dyRCorner = dyCorner.x;\\n        int dyCCorner = dyCorner.y;\\n\\n        float dotProd = 0.0;\\n\\n        for (int wR = 0; wR < \" + filterHeight + \"; wR++) {\\n          float dyR = float(dyRCorner + wR) / \" + strideHeight + \".0;\\n\\n          if (dyR < 0.0 || dyR >= \" + convInfo.outHeight + \".0 || fract(dyR) > 0.0) {\\n            continue;\\n          }\\n          int idyR = int(dyR);\\n\\n          int wRPerm = \" + filterHeight + \" - 1 - wR;\\n\\n          for (int wC = 0; wC < \" + filterWidth + \"; wC++) {\\n            float dyC = float(dyCCorner + wC) / \" + strideWidth + \".0;\\n\\n            if (dyC < 0.0 || dyC >= \" + convInfo.outWidth + \".0 ||\\n                fract(dyC) > 0.0) {\\n              continue;\\n            }\\n            int idyC = int(dyC);\\n\\n            int wCPerm = \" + filterWidth + \" - 1 - wC;\\n\\n            // TODO: Vec4 over the channelMul\\n            for (int dm = 0; dm < \" + channelMul + \"; dm++) {\\n              int d2 = d1 * \" + channelMul + \" + dm;\\n              float xValue = getDy(batch, idyR, idyC, d2);\\n              float wValue = getW(wRPerm, wCPerm, d1, dm);\\n              dotProd += xValue * wValue;\\n            }\\n          }\\n        }\\n        setOutput(dotProd);\\n      }\\n    \";\r\n        }\r\n        return DepthwiseConv2DDerInputProgram;\r\n    }());\n\n    var Conv2DProgram = (function () {\r\n        function Conv2DProgram(convInfo) {\r\n            this.variableNames = ['x', 'W'];\r\n            this.outputShape = convInfo.outShape;\r\n            var padTop = convInfo.padInfo.top;\r\n            var padLeft = convInfo.padInfo.left;\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var dilationHeight = convInfo.dilationHeight;\r\n            var dilationWidth = convInfo.dilationWidth;\r\n            var filterHeight = convInfo.filterHeight;\r\n            var filterWidth = convInfo.filterWidth;\r\n            var inputDepthNearestVec4 = Math.floor(convInfo.inChannels / 4) * 4;\r\n            var inputDepthVec4Remainder = convInfo.inChannels % 4;\r\n            this.userCode = \"\\n      const ivec2 strides = ivec2(\" + strideHeight + \", \" + strideWidth + \");\\n      const ivec2 pads = ivec2(\" + padTop + \", \" + padLeft + \");\\n\\n      void main() {\\n        ivec4 coords = getOutputCoords();\\n        int batch = coords[0];\\n        int d2 = coords[3];\\n\\n        ivec2 xRCCorner = coords.yz * strides - pads;\\n        int xRCorner = xRCCorner.x;\\n        int xCCorner = xRCCorner.y;\\n\\n        // Convolve x(?, ?, d1) with w(:, :, d1, d2) to get y(yR, yC, d2).\\n        // ? = to be determined. : = across all values in that axis.\\n        float dotProd = 0.0;\\n        for (int wR = 0; wR < \" + filterHeight + \"; wR++) {\\n          int xR = xRCorner + wR * \" + dilationHeight + \";\\n\\n          if (xR < 0 || xR >= \" + convInfo.inHeight + \") {\\n            continue;\\n          }\\n\\n          for (int wC = 0; wC < \" + filterWidth + \"; wC++) {\\n            int xC = xCCorner + wC * \" + dilationWidth + \";\\n\\n            if (xC < 0 || xC >= \" + convInfo.inWidth + \") {\\n              continue;\\n            }\\n\\n            for (int d1 = 0; d1 < \" + inputDepthNearestVec4 + \"; d1 += 4) {\\n              vec4 xValues = vec4(\\n                getX(batch, xR, xC, d1),\\n                getX(batch, xR, xC, d1 + 1),\\n                getX(batch, xR, xC, d1 + 2),\\n                getX(batch, xR, xC, d1 + 3)\\n              );\\n              vec4 wValues = vec4(\\n                getW(wR, wC, d1, d2),\\n                getW(wR, wC, d1 + 1, d2),\\n                getW(wR, wC, d1 + 2, d2),\\n                getW(wR, wC, d1 + 3, d2)\\n              );\\n\\n              dotProd += dot(xValues, wValues);\\n            }\\n\\n            if (\" + (inputDepthVec4Remainder === 1) + \") {\\n              dotProd +=\\n                getX(batch, xR, xC, \" + inputDepthNearestVec4 + \") *\\n                getW(wR, wC, \" + inputDepthNearestVec4 + \", d2);\\n            } else if (\" + (inputDepthVec4Remainder === 2) + \") {\\n              vec2 xValues = vec2(\\n                getX(batch, xR, xC, \" + inputDepthNearestVec4 + \"),\\n                getX(batch, xR, xC, \" + inputDepthNearestVec4 + \" + 1)\\n              );\\n              vec2 wValues = vec2(\\n                getW(wR, wC, \" + inputDepthNearestVec4 + \", d2),\\n                getW(wR, wC, \" + inputDepthNearestVec4 + \" + 1, d2)\\n              );\\n              dotProd += dot(xValues, wValues);\\n            } else if (\" + (inputDepthVec4Remainder === 3) + \") {\\n              vec3 xValues = vec3(\\n                getX(batch, xR, xC, \" + inputDepthNearestVec4 + \"),\\n                getX(batch, xR, xC, \" + inputDepthNearestVec4 + \" + 1),\\n                getX(batch, xR, xC, \" + inputDepthNearestVec4 + \" + 2)\\n              );\\n              vec3 wValues = vec3(\\n                getW(wR, wC, \" + inputDepthNearestVec4 + \", d2),\\n                getW(wR, wC, \" + inputDepthNearestVec4 + \" + 1, d2),\\n                getW(wR, wC, \" + inputDepthNearestVec4 + \" + 2, d2)\\n              );\\n              dotProd += dot(xValues, wValues);\\n            }\\n          }\\n        }\\n        setOutput(dotProd);\\n      }\\n    \";\r\n        }\r\n        return Conv2DProgram;\r\n    }());\r\n    var Conv3DProgram = (function () {\r\n        function Conv3DProgram(convInfo) {\r\n            this.variableNames = ['x', 'W'];\r\n            this.outputShape = convInfo.outShape;\r\n            var padFront = convInfo.padInfo.front;\r\n            var padTop = convInfo.padInfo.top;\r\n            var padLeft = convInfo.padInfo.left;\r\n            var strideDepth = convInfo.strideDepth;\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var dilationDepth = convInfo.dilationDepth;\r\n            var dilationHeight = convInfo.dilationHeight;\r\n            var dilationWidth = convInfo.dilationWidth;\r\n            var filterDepth = convInfo.filterDepth;\r\n            var filterHeight = convInfo.filterHeight;\r\n            var filterWidth = convInfo.filterWidth;\r\n            var inputDepthNearestVec4 = Math.floor(convInfo.inChannels / 4) * 4;\r\n            var inputDepthVec4Remainder = convInfo.inChannels % 4;\r\n            this.userCode = \"\\n      const ivec3 strides = ivec3(\" + strideDepth + \", \" + strideHeight + \", \" + strideWidth + \");\\n      const ivec3 pads = ivec3(\" + padFront + \", \" + padTop + \", \" + padLeft + \");\\n\\n      void main() {\\n        ivec5 coords = getOutputCoords();\\n        int batch = coords.x;\\n        int d2 = coords.u;\\n\\n        ivec3 xFRCCorner = ivec3(coords.y, coords.z, coords.w) * strides - pads;\\n        int xFCorner = xFRCCorner.x;\\n        int xRCorner = xFRCCorner.y;\\n        int xCCorner = xFRCCorner.z;\\n\\n        // Convolve x(?, ?, ?, d1) with w(:, :, :, d1, d2) to get\\n        // y(yF, yR, yC, d2). ? = to be determined. : = across all\\n        // values in that axis.\\n        float dotProd = 0.0;\\n        for (int wF = 0; wF < \" + filterDepth + \"; wF++) {\\n          int xF = xFCorner + wF * \" + dilationDepth + \";\\n\\n          if (xF < 0 || xF >= \" + convInfo.inDepth + \") {\\n            continue;\\n          }\\n\\n          for (int wR = 0; wR < \" + filterHeight + \"; wR++) {\\n            int xR = xRCorner + wR * \" + dilationHeight + \";\\n\\n            if (xR < 0 || xR >= \" + convInfo.inHeight + \") {\\n              continue;\\n            }\\n\\n            for (int wC = 0; wC < \" + filterWidth + \"; wC++) {\\n              int xC = xCCorner + wC * \" + dilationWidth + \";\\n\\n              if (xC < 0 || xC >= \" + convInfo.inWidth + \") {\\n                continue;\\n              }\\n\\n              for (int d1 = 0; d1 < \" + inputDepthNearestVec4 + \"; d1 += 4) {\\n                vec4 xValues = vec4(\\n                  getX(batch, xF, xR, xC, d1),\\n                  getX(batch, xF, xR, xC, d1 + 1),\\n                  getX(batch, xF, xR, xC, d1 + 2),\\n                  getX(batch, xF, xR, xC, d1 + 3)\\n                );\\n                vec4 wValues = vec4(\\n                  getW(wF, wR, wC, d1, d2),\\n                  getW(wF, wR, wC, d1 + 1, d2),\\n                  getW(wF, wR, wC, d1 + 2, d2),\\n                  getW(wF, wR, wC, d1 + 3, d2)\\n                );\\n\\n                dotProd += dot(xValues, wValues);\\n              }\\n\\n              if (\" + (inputDepthVec4Remainder === 1) + \") {\\n                dotProd +=\\n                  getX(batch, xF, xR, xC, \" + inputDepthNearestVec4 + \") *\\n                  getW(wF, wR, wC, \" + inputDepthNearestVec4 + \", d2);\\n              } else if (\" + (inputDepthVec4Remainder === 2) + \") {\\n                vec2 xValues = vec2(\\n                  getX(batch, xF, xR, xC, \" + inputDepthNearestVec4 + \"),\\n                  getX(batch, xF, xR, xC, \" + inputDepthNearestVec4 + \" + 1)\\n                );\\n                vec2 wValues = vec2(\\n                  getW(wF, wR, wC, \" + inputDepthNearestVec4 + \", d2),\\n                  getW(wF, wR, wC, \" + inputDepthNearestVec4 + \" + 1, d2)\\n                );\\n                dotProd += dot(xValues, wValues);\\n              } else if (\" + (inputDepthVec4Remainder === 3) + \") {\\n                vec3 xValues = vec3(\\n                  getX(batch, xF, xR, xC, \" + inputDepthNearestVec4 + \"),\\n                  getX(batch, xF, xR, xC, \" + inputDepthNearestVec4 + \" + 1),\\n                  getX(batch, xF, xR, xC, \" + inputDepthNearestVec4 + \" + 2)\\n                );\\n                vec3 wValues = vec3(\\n                  getW(wF, wR, wC, \" + inputDepthNearestVec4 + \", d2),\\n                  getW(wF, wR, wC, \" + inputDepthNearestVec4 + \" + 1, d2),\\n                  getW(wF, wR, wC, \" + inputDepthNearestVec4 + \" + 2, d2)\\n                );\\n                dotProd += dot(xValues, wValues);\\n              }\\n            }\\n          }\\n        }\\n        setOutput(dotProd);\\n      }\\n    \";\r\n        }\r\n        return Conv3DProgram;\r\n    }());\n\n    var DepthwiseConv2DProgram = (function () {\r\n        function DepthwiseConv2DProgram(convInfo) {\r\n            this.variableNames = ['x', 'W'];\r\n            this.outputShape = convInfo.outShape;\r\n            var xNumRows = convInfo.inHeight;\r\n            var xNumCols = convInfo.inWidth;\r\n            var padTop = convInfo.padInfo.top;\r\n            var padLeft = convInfo.padInfo.left;\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var dilationHeight = convInfo.dilationHeight;\r\n            var dilationWidth = convInfo.dilationWidth;\r\n            var filterHeight = convInfo.filterHeight;\r\n            var filterWidth = convInfo.filterWidth;\r\n            var channelMul = convInfo.outChannels / convInfo.inChannels;\r\n            this.userCode = \"\\n      const ivec2 strides = ivec2(\" + strideHeight + \", \" + strideWidth + \");\\n      const ivec2 pads = ivec2(\" + padTop + \", \" + padLeft + \");\\n\\n      void main() {\\n        ivec4 coords = getOutputCoords();\\n        int batch = coords.x;\\n        ivec2 xRCCorner = coords.yz * strides - pads;\\n        int d2 = coords.w;\\n        int d1 = d2 / \" + channelMul + \";\\n        int q = d2 - d1 * \" + channelMul + \";\\n\\n        int xRCorner = xRCCorner.x;\\n        int xCCorner = xRCCorner.y;\\n\\n        // Convolve x(?, ?, d1) with w(:, :, d1, q) to get y(yR, yC, d2).\\n        // ? = to be determined. : = across all values in that axis.\\n        float dotProd = 0.0;\\n        // TODO(dsmilkov): Flatten the two for loops and vec4 the operations.\\n        for (int wR = 0; wR < \" + filterHeight + \"; wR++) {\\n          int xR = xRCorner + wR * \" + dilationHeight + \";\\n\\n          if (xR < 0 || xR >= \" + xNumRows + \") {\\n            continue;\\n          }\\n\\n          for (int wC = 0; wC < \" + filterWidth + \"; wC++) {\\n            int xC = xCCorner + wC * \" + dilationWidth + \";\\n\\n            if (xC < 0 || xC >= \" + xNumCols + \") {\\n              continue;\\n            }\\n\\n            float xVal = getX(batch, xR, xC, d1);\\n            float wVal = getW(wR, wC, d1, q);\\n            dotProd += xVal * wVal;\\n          }\\n        }\\n        setOutput(dotProd);\\n      }\\n    \";\r\n        }\r\n        return DepthwiseConv2DProgram;\r\n    }());\n\n    var DepthwiseConvPacked2DProgram = (function () {\r\n        function DepthwiseConvPacked2DProgram(convInfo) {\r\n            this.variableNames = ['x', 'W'];\r\n            this.usesPackedTextures = true;\r\n            this.outputShape = convInfo.outShape;\r\n            var xNumRows = convInfo.inHeight;\r\n            var xNumCols = convInfo.inWidth;\r\n            var padTop = convInfo.padInfo.top;\r\n            var padLeft = convInfo.padInfo.left;\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var dilationHeight = convInfo.dilationHeight;\r\n            var dilationWidth = convInfo.dilationWidth;\r\n            var filterHeight = convInfo.filterHeight;\r\n            var filterWidth = convInfo.filterWidth;\r\n            var texelsAcross = filterWidth;\r\n            var mainLoop = \"int xR; int xC; int xCOffset;\";\r\n            for (var r = 0; r < filterHeight; r++) {\r\n                for (var c = 0; c < filterWidth; c++) {\r\n                    mainLoop += \"\\n          vec4 xTexelR\" + r + \"C\" + c * 2 + \" = vec4(0.);\\n          vec4 wR\" + r + \"C\" + c + \" = vec4(0.);\\n          vec4 xR\" + r + \"C\" + c + \" = vec4(0.);\";\r\n                }\r\n            }\r\n            for (var r = 0; r < filterHeight; r++) {\r\n                for (var texelC = 0; texelC < texelsAcross; texelC++) {\r\n                    var c = texelC * 2;\r\n                    mainLoop += \"\\n          xR = xRCorner + \" + r * dilationHeight + \";\\n          xC = xCCorner + \" + c * dilationWidth + \";\\n        \";\r\n                    if (strideWidth === 1) {\r\n                        if (c < filterWidth) {\r\n                            if (padLeft % 2 === 1) {\r\n                                mainLoop += \"\\n                xCOffset = xC + 1;\\n                if(xR >= 0 && xR < \" + xNumRows + \" && xCOffset >= 0 && xCOffset < \" + xNumCols + \") {\\n                  xTexelR\" + r + \"C\" + c + \" = getX(batch, xR, xCOffset, d1);\\n                } else {\\n                  xTexelR\" + r + \"C\" + c + \" = vec4(0.);\\n                }\\n\\n                xCOffset = xC + 1 - 2;\\n                if(xR >= 0 && xR < \" + xNumRows + \" && xCOffset >= 0 && xCOffset < \" + xNumCols + \") {\\n                  vec4 previous = getX(batch, xR, xCOffset, d1);\\n                  xR\" + r + \"C\" + c + \" = vec4(previous.zw, xTexelR\" + r + \"C\" + c + \".xy);\\n                } else {\\n                  xR\" + r + \"C\" + c + \" = vec4(0, 0, xTexelR\" + r + \"C\" + c + \".xy);\\n                }\\n              \";\r\n                            }\r\n                            else {\r\n                                mainLoop += \"\\n                if(xR >= 0 && xR < \" + xNumRows + \" && xC >= 0 && xC < \" + xNumCols + \") {\\n                  xTexelR\" + r + \"C\" + c + \" = getX(batch, xR, xC, d1);\\n                } else {\\n                  xTexelR\" + r + \"C\" + c + \" = vec4(0.);\\n                }\\n\\n                xR\" + r + \"C\" + c + \" = xTexelR\" + r + \"C\" + c + \";\\n              \";\r\n                            }\r\n                            if (c + 1 < filterWidth) {\r\n                                var nextTexelOffset = padLeft % 2 === 0 ?\r\n                                    nearestLargerEven(dilationWidth) :\r\n                                    dilationWidth;\r\n                                if ((dilationWidth % 2 === 0 && padLeft % 2 === 1) ||\r\n                                    (dilationWidth % 2 !== 0 && padLeft % 2 !== 1)) {\r\n                                    mainLoop += \"\\n                  xCOffset = xC + \" + padLeft % 2 + \" + \" + nextTexelOffset + \";\\n\\n                  if(xR >= 0 && xR < \" + xNumRows + \" &&\\n                    xCOffset >= 0 && xCOffset < \" + xNumCols + \") {\\n                    xTexelR\" + r + \"C\" + (c + 2) + \" = getX(batch, xR, xCOffset, d1);\\n                  }\\n                \";\r\n                                    if (dilationWidth > 1) {\r\n                                        mainLoop += \"\\n                    xCOffset -= 2;\\n                    if(xR >= 0 && xR < \" + xNumRows + \" &&\\n                      xCOffset >= 0 && xCOffset < \" + xNumCols + \") {\\n                      xTexelR\" + r + \"C\" + c + \" = getX(batch, xR, xCOffset, d1);\\n                    } else {\\n                      xTexelR\" + r + \"C\" + c + \" = vec4(0.);\\n                    }\\n                  \";\r\n                                    }\r\n                                    mainLoop += \"\\n                  xR\" + r + \"C\" + (c + 1) + \" = vec4(\\n                    xTexelR\" + r + \"C\" + c + \".zw, xTexelR\" + r + \"C\" + (c + 2) + \".xy);\\n                \";\r\n                                }\r\n                                else {\r\n                                    mainLoop += \"\\n                  xCOffset = xC + \" + nextTexelOffset + \";\\n\\n                  if(xR >= 0 && xR < \" + xNumRows + \" &&\\n                    xCOffset >= 0 && xCOffset < \" + xNumCols + \") {\\n                    xTexelR\" + r + \"C\" + (c + 2) + \" = getX(batch, xR, xCOffset, d1);\\n                  }\\n\\n                  xR\" + r + \"C\" + (c + 1) + \" = xTexelR\" + r + \"C\" + (c + 2) + \";\\n                \";\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                    else {\r\n                        if (c < filterWidth) {\r\n                            mainLoop += \"\\n              if(xR >= 0 && xR < \" + xNumRows + \") {\\n            \";\r\n                            if (padLeft % 2 === 1) {\r\n                                mainLoop += \"\\n                xCOffset = xC + 1 - \" + strideWidth + \";\\n                if(xCOffset >= 0 && xCOffset < \" + xNumCols + \") {\\n                  xTexelR\" + r + \"C\" + c + \" = getX(batch, xR, xCOffset, d1);\\n                } else {\\n                  xTexelR\" + r + \"C\" + c + \" = vec4(0.);\\n                }\\n\\n                if(xC + 1 >= 0 && xC + 1 < \" + xNumCols + \") {\\n                  xTexelR\" + r + \"C\" + (c + 2) + \" = getX(batch, xR, xC + 1, d1);\\n                } else {\\n                  xTexelR\" + r + \"C\" + (c + 2) + \" = vec4(0.);\\n                }\\n\\n                xR\" + r + \"C\" + c + \" = vec4(\\n                  xTexelR\" + r + \"C\" + c + \".zw, xTexelR\" + r + \"C\" + (c + 2) + \".zw);\\n              \";\r\n                                if (c + 1 < filterWidth) {\r\n                                    mainLoop += \"\\n                  vec4 final = vec4(0.);\\n                  xCOffset = xC + 1 + \" + strideWidth + \";\\n                  if(xCOffset >= 0 && xCOffset < \" + xNumCols + \") {\\n                    final = getX(batch, xR, xCOffset, d1);\\n                  }\\n                  xR\" + r + \"C\" + (c + 1) + \" = vec4(xTexelR\" + r + \"C\" + (c + 2) + \".xy, final.xy);\\n                \";\r\n                                }\r\n                            }\r\n                            else {\r\n                                mainLoop += \"\\n                if(xC >= 0 && xC < \" + xNumCols + \") {\\n                  xTexelR\" + r + \"C\" + c + \" = getX(batch, xR, xC, d1);\\n                } else {\\n                  xTexelR\" + r + \"C\" + c + \" = vec4(0.);\\n                }\\n\\n                xCOffset = xC + \" + strideWidth + \";\\n                if(xCOffset >= 0 && xCOffset < \" + xNumCols + \") {\\n                  xTexelR\" + r + \"C\" + (c + 2) + \" = getX(batch, xR, xCOffset, d1);\\n                } else {\\n                  xTexelR\" + r + \"C\" + (c + 2) + \" = vec4(0.);\\n                }\\n\\n                xR\" + r + \"C\" + c + \" = vec4(\\n                  xTexelR\" + r + \"C\" + c + \".xy, xTexelR\" + r + \"C\" + (c + 2) + \".xy);\\n              \";\r\n                                if (c + 1 < filterWidth) {\r\n                                    mainLoop += \"\\n                  xR\" + r + \"C\" + (c + 1) + \" = vec4(\\n                    xTexelR\" + r + \"C\" + c + \".zw, xTexelR\" + r + \"C\" + (c + 2) + \".zw);\\n                \";\r\n                                }\r\n                            }\r\n                            mainLoop += \"}\";\r\n                        }\r\n                    }\r\n                    if (c < filterWidth) {\r\n                        mainLoop += \"\\n            vec4 wTexelR\" + r + \"C\" + c + \" = getW(\" + r + \", \" + c + \", d1, q);\\n            wR\" + r + \"C\" + c + \" = vec4(wTexelR\" + r + \"C\" + c + \".xz, wTexelR\" + r + \"C\" + c + \".xz);\\n          \";\r\n                        if (c + 1 < filterWidth) {\r\n                            mainLoop += \"\\n              vec4 wTexelR\" + r + \"C\" + (c + 1) + \" = getW(\" + r + \", \" + (c + 1) + \", d1, q);\\n              wR\" + r + \"C\" + (c + 1) + \" =\\n                vec4(wTexelR\" + r + \"C\" + (c + 1) + \".xz, wTexelR\" + r + \"C\" + (c + 1) + \".xz);\";\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            for (var r = 0; r < filterHeight; r++) {\r\n                for (var c = 0; c < filterWidth; c++) {\r\n                    mainLoop += \"result += xR\" + r + \"C\" + c + \" * wR\" + r + \"C\" + c + \";\";\r\n                }\r\n            }\r\n            this.userCode = \"\\n      const ivec2 strides = ivec2(\" + strideHeight + \", \" + strideWidth + \");\\n      const ivec2 pads = ivec2(\" + padTop + \", \" + padLeft + \");\\n\\n      void main() {\\n\\n        ivec4 coords = getOutputCoords();\\n        int batch = coords.x;\\n        ivec2 xRCCorner = coords.yz * strides - pads;\\n        int d2 = coords.w;\\n        int d1 = d2;\\n        int q = 0;\\n        int xRCorner = xRCCorner.x;\\n        int xCCorner = xRCCorner.y;\\n\\n        vec4 result = vec4(0.);\\n\\n        \" + mainLoop + \"\\n\\n        setOutput(result);\\n      }\\n    \";\r\n        }\r\n        return DepthwiseConvPacked2DProgram;\r\n    }());\n\n    var CropAndResizeProgram = (function () {\r\n        function CropAndResizeProgram(imageShape, boxShape, cropSize, method, extrapolationValue) {\r\n            this.variableNames = ['Image', 'Boxes', 'BoxInd'];\r\n            this.outputShape = [];\r\n            var batch = imageShape[0], imageHeight = imageShape[1], imageWidth = imageShape[2], depth = imageShape[3];\r\n            var numBoxes = boxShape[0];\r\n            var cropHeight = cropSize[0], cropWidth = cropSize[1];\r\n            this.outputShape = [numBoxes, cropHeight, cropWidth, depth];\r\n            var methodId = method === 'bilinear' ? 1 : 0;\r\n            var _a = [imageHeight - 1 + \".0\", imageWidth - 1 + \".0\"], inputHeightFloat = _a[0], inputWidthFloat = _a[1];\r\n            var _b = cropHeight > 1 ?\r\n                [\r\n                    \"\" + (imageHeight - 1) / (cropHeight - 1),\r\n                    '(y2-y1) * height_ratio',\r\n                    \"y1*\" + inputHeightFloat + \" + float(y)*(height_scale)\",\r\n                ] :\r\n                [\r\n                    '0.0',\r\n                    '0.0',\r\n                    \"0.5 * (y1+y2) * \" + inputHeightFloat,\r\n                ], heightRatio = _b[0], heightScale = _b[1], inY = _b[2];\r\n            var _c = cropWidth > 1 ?\r\n                [\r\n                    \"\" + (imageWidth - 1) / (cropWidth - 1),\r\n                    '(x2-x1) * width_ratio',\r\n                    \"x1*\" + inputWidthFloat + \" + float(x)*(width_scale)\",\r\n                ] :\r\n                [\r\n                    '0.0',\r\n                    '0.0',\r\n                    \"0.5 * (x1+x2) * \" + inputWidthFloat,\r\n                ], widthRatio = _c[0], widthScale = _c[1], inX = _c[2];\r\n            this.userCode = \"\\n      const float height_ratio = float(\" + heightRatio + \");\\n      const float width_ratio = float(\" + widthRatio + \");\\n      void main() {\\n        ivec4 coords = getOutputCoords();\\n        int b = coords[0];\\n        int y = coords[1];\\n        int x = coords[2];\\n        int d = coords[3];\\n\\n        // get box vals\\n        float y1 = getBoxes(b,0);\\n        float x1 = getBoxes(b,1);\\n        float y2 = getBoxes(b,2);\\n        float x2 = getBoxes(b,3);\\n\\n        // get image in batch index\\n        int bInd = round(getBoxInd(b));\\n        if(bInd < 0 || bInd >= \" + batch + \") {\\n          return;\\n        }\\n\\n        float height_scale = \" + heightScale + \";\\n        float width_scale = \" + widthScale + \";\\n\\n        float in_y = \" + inY + \";\\n        if( in_y < 0.0 || in_y > \" + inputHeightFloat + \" ) {\\n          setOutput(float(\" + extrapolationValue + \"));\\n          return;\\n        }\\n        float in_x = \" + inX + \";\\n        if( in_x < 0.0 || in_x > \" + inputWidthFloat + \" ) {\\n          setOutput(float(\" + extrapolationValue + \"));\\n          return;\\n        }\\n\\n        vec2 sourceFracIndexRC = vec2(in_y,in_x);\\n        if(\" + methodId + \" == 1) {\\n          // Compute the four integer indices.\\n          ivec2 sourceFloorRC = ivec2(sourceFracIndexRC);\\n          ivec2 sourceCeilRC = ivec2(ceil(sourceFracIndexRC));\\n\\n          float topLeft = getImage(b, sourceFloorRC.x, sourceFloorRC.y, d);\\n          float bottomLeft = getImage(b, sourceCeilRC.x, sourceFloorRC.y, d);\\n          float topRight = getImage(b, sourceFloorRC.x, sourceCeilRC.y, d);\\n          float bottomRight = getImage(b, sourceCeilRC.x, sourceCeilRC.y, d);\\n\\n          vec2 fracRC = sourceFracIndexRC - vec2(sourceFloorRC);\\n\\n          float top = topLeft + (topRight - topLeft) * fracRC.y;\\n          float bottom = bottomLeft + (bottomRight - bottomLeft) * fracRC.y;\\n          float newValue = top + (bottom - top) * fracRC.x;\\n          setOutput(newValue);\\n        } else {\\n          // Compute the coordinators of nearest neighbor point.\\n          ivec2 sourceNearestRC = ivec2(floor(\\n            sourceFracIndexRC + vec2(0.5,0.5)));\\n          float newValue = getImage(b, sourceNearestRC.x, sourceNearestRC.y, d);\\n          setOutput(newValue);\\n        }\\n      }\\n    \";\r\n        }\r\n        return CropAndResizeProgram;\r\n    }());\n\n    function getGlslDifferences() {\r\n        var version;\r\n        var attribute;\r\n        var varyingVs;\r\n        var varyingFs;\r\n        var texture2D;\r\n        var output;\r\n        var defineOutput;\r\n        var defineRound;\r\n        if (ENV.get('WEBGL_VERSION') === 2) {\r\n            version = '#version 300 es';\r\n            attribute = 'in';\r\n            varyingVs = 'out';\r\n            varyingFs = 'in';\r\n            texture2D = 'texture';\r\n            output = 'outputColor';\r\n            defineOutput = 'out vec4 outputColor;';\r\n            defineRound = \"\\n      #define round(value) newRound(value)\\n      int newRound(float value) {\\n        return int(floor(value + 0.5));\\n      }\\n\\n      ivec4 newRound(vec4 value) {\\n        return ivec4(floor(value + vec4(0.5)));\\n      }\\n    \";\r\n        }\r\n        else {\r\n            version = '';\r\n            attribute = 'attribute';\r\n            varyingVs = 'varying';\r\n            varyingFs = 'varying';\r\n            texture2D = 'texture2D';\r\n            output = 'gl_FragColor';\r\n            defineOutput = '';\r\n            defineRound = \"\\n      int round(float value) {\\n        return int(floor(value + 0.5));\\n      }\\n\\n      ivec4 round(vec4 value) {\\n        return ivec4(floor(value + vec4(0.5)));\\n      }\\n    \";\r\n        }\r\n        return {\r\n            version: version,\r\n            attribute: attribute,\r\n            varyingVs: varyingVs,\r\n            varyingFs: varyingFs,\r\n            texture2D: texture2D,\r\n            output: output,\r\n            defineOutput: defineOutput,\r\n            defineRound: defineRound\r\n        };\r\n    }\n\n    function getLogicalCoordinatesFromFlatIndex(coords, shape, index) {\r\n        if (index === void 0) { index = 'index'; }\r\n        var strides = computeStrides(shape);\r\n        return strides\r\n            .map(function (stride, i) {\r\n            var line1 = \"int \" + coords[i] + \" = \" + index + \" / \" + stride;\r\n            var line2 = i === strides.length - 1 ?\r\n                \"int \" + coords[i + 1] + \" = \" + index + \" - \" + coords[i] + \" * \" + stride :\r\n                \"index -= \" + coords[i] + \" * \" + stride;\r\n            return line1 + \"; \" + line2 + \";\";\r\n        })\r\n            .join('');\r\n    }\r\n    function buildVec(x) {\r\n        if (x.length === 1) {\r\n            return \"\" + x[0];\r\n        }\r\n        return \"vec\" + x.length + \"(\" + x.join(',') + \")\";\r\n    }\r\n    function dotify(x, y) {\r\n        if (x.length !== y.length) {\r\n            throw new Error(\"Vectors to be dotted must be of the same length -\" +\r\n                (\"got \" + x.length + \" and \" + y.length));\r\n        }\r\n        var slices = [];\r\n        var nearestVec4 = Math.floor(x.length / 4);\r\n        var nearestVec4Remainder = x.length % 4;\r\n        for (var i = 0; i < nearestVec4; i++) {\r\n            var xSlice = x.slice(i * 4, i * 4 + 4);\r\n            var ySlice = y.slice(i * 4, i * 4 + 4);\r\n            slices.push(buildVec(xSlice) + \", \" + buildVec(ySlice));\r\n        }\r\n        if (nearestVec4Remainder !== 0) {\r\n            var xSlice = x.slice(nearestVec4 * 4);\r\n            var ySlice = y.slice(nearestVec4 * 4);\r\n            if (xSlice.length === 1) {\r\n                xSlice = xSlice.map(function (d) { return \"float(\" + d + \")\"; });\r\n                ySlice = ySlice.map(function (d) { return \"float(\" + d + \")\"; });\r\n            }\r\n            slices.push(buildVec(xSlice) + \", \" + buildVec(ySlice));\r\n        }\r\n        return slices.map(function (d, i) { return \"dot(\" + d + \")\"; }).join('+');\r\n    }\n\n    function makeShader(inputsInfo, outputShape, userCode, usesPackedTextures) {\r\n        var prefixSnippets = [];\r\n        inputsInfo.forEach(function (x) {\r\n            var size = sizeFromShape(x.shapeInfo.logicalShape);\r\n            if (x.shapeInfo.isUniform) {\r\n                prefixSnippets.push(\"uniform float \" + x.name + (size > 1 ? \"[\" + size + \"]\" : '') + \";\");\r\n            }\r\n            else {\r\n                prefixSnippets.push(\"uniform sampler2D \" + x.name + \";\");\r\n                prefixSnippets.push(\"uniform int offset\" + x.name + \";\");\r\n            }\r\n        });\r\n        var inputPrefixSnippet = prefixSnippets.join('\\n');\r\n        var inputSamplingSnippet = inputsInfo\r\n            .map(function (x) { return getInputSamplingSnippet(x, outputShape, usesPackedTextures); })\r\n            .join('\\n');\r\n        var outTexShape = outputShape.texShape;\r\n        var glsl = getGlslDifferences();\r\n        var floatTextureSampleSnippet = getFloatTextureSampleSnippet(glsl);\r\n        var outputSamplingSnippet;\r\n        var floatTextureSetOutputSnippet;\r\n        var shaderPrefix = getShaderPrefix(glsl);\r\n        if (outputShape.isPacked) {\r\n            outputSamplingSnippet =\r\n                getPackedOutputSamplingSnippet(outputShape.logicalShape, outTexShape);\r\n            floatTextureSetOutputSnippet = getFloatTextureSetRGBASnippet(glsl);\r\n        }\r\n        else {\r\n            outputSamplingSnippet =\r\n                getOutputSamplingSnippet(outputShape.logicalShape, outTexShape);\r\n            floatTextureSetOutputSnippet = getFloatTextureSetRSnippet(glsl);\r\n        }\r\n        if (usesPackedTextures) {\r\n            shaderPrefix += SHADER_PACKED_PREFIX;\r\n        }\r\n        var source = [\r\n            shaderPrefix, floatTextureSampleSnippet, floatTextureSetOutputSnippet,\r\n            inputPrefixSnippet, outputSamplingSnippet, inputSamplingSnippet, userCode\r\n        ].join('\\n');\r\n        return source;\r\n    }\r\n    function getSamplerFromInInfo(inInfo) {\r\n        var shape = inInfo.shapeInfo.logicalShape;\r\n        switch (shape.length) {\r\n            case 0:\r\n                return getSamplerScalar(inInfo);\r\n            case 1:\r\n                return getSampler1D(inInfo);\r\n            case 2:\r\n                return getSampler2D(inInfo);\r\n            case 3:\r\n                return getSampler3D(inInfo);\r\n            case 4:\r\n                return getSampler4D(inInfo);\r\n            case 5:\r\n                return getSampler5D(inInfo);\r\n            case 6:\r\n                return getSampler6D(inInfo);\r\n            default:\r\n                throw new Error(shape.length + \"-D input sampling\" +\r\n                    \" is not yet supported\");\r\n        }\r\n    }\r\n    function getPackedSamplerFromInInfo(inInfo) {\r\n        var shape = inInfo.shapeInfo.logicalShape;\r\n        switch (shape.length) {\r\n            case 0:\r\n                return getPackedSamplerScalar(inInfo);\r\n            case 1:\r\n                return getPackedSampler1D(inInfo);\r\n            case 2:\r\n                return getPackedSampler2D(inInfo);\r\n            case 3:\r\n                return getPackedSampler3D(inInfo);\r\n            default:\r\n                return getPackedSamplerND(inInfo);\r\n        }\r\n    }\r\n    function getInputSamplingSnippet(inInfo, outShapeInfo, usesPackedTextures) {\r\n        if (usesPackedTextures === void 0) { usesPackedTextures = false; }\r\n        var res = '';\r\n        if (usesPackedTextures) {\r\n            res += getPackedSamplerFromInInfo(inInfo);\r\n        }\r\n        else {\r\n            res += getSamplerFromInInfo(inInfo);\r\n        }\r\n        var inShape = inInfo.shapeInfo.logicalShape;\r\n        var outShape = outShapeInfo.logicalShape;\r\n        if (inShape.length <= outShape.length) {\r\n            if (usesPackedTextures) {\r\n                if (getBroadcastDims(inShape, outShape).length === 0) {\r\n                    res += getPackedSamplerAtOutputCoords(inInfo, outShapeInfo);\r\n                }\r\n            }\r\n            else {\r\n                res += getSamplerAtOutputCoords(inInfo, outShapeInfo);\r\n            }\r\n        }\r\n        return res;\r\n    }\r\n    function getPackedOutputSamplingSnippet(outShape, outTexShape) {\r\n        switch (outShape.length) {\r\n            case 0:\r\n                return getOutputScalarCoords();\r\n            case 1:\r\n                return getOutputPacked1DCoords(outShape, outTexShape);\r\n            case 2:\r\n                return getOutputPacked2DCoords(outShape, outTexShape);\r\n            case 3:\r\n                return getOutputPacked3DCoords(outShape, outTexShape);\r\n            default:\r\n                return getOutputPackedNDCoords(outShape, outTexShape);\r\n        }\r\n    }\r\n    function getOutputSamplingSnippet(outShape, outTexShape) {\r\n        switch (outShape.length) {\r\n            case 0:\r\n                return getOutputScalarCoords();\r\n            case 1:\r\n                return getOutput1DCoords(outShape, outTexShape);\r\n            case 2:\r\n                return getOutput2DCoords(outShape, outTexShape);\r\n            case 3:\r\n                return getOutput3DCoords(outShape, outTexShape);\r\n            case 4:\r\n                return getOutput4DCoords(outShape, outTexShape);\r\n            case 5:\r\n                return getOutput5DCoords(outShape, outTexShape);\r\n            case 6:\r\n                return getOutput6DCoords(outShape, outTexShape);\r\n            default:\r\n                throw new Error(outShape.length + \"-D output sampling is not yet supported\");\r\n        }\r\n    }\r\n    function getFloatTextureSampleSnippet(glsl) {\r\n        return \"\\n    float sampleTexture(sampler2D textureSampler, vec2 uv) {\\n      return \" + glsl.texture2D + \"(textureSampler, uv).r;\\n    }\\n  \";\r\n    }\r\n    function getFloatTextureSetRSnippet(glsl) {\r\n        return \"\\n    void setOutput(float val) {\\n      \" + glsl.output + \" = vec4(val, 0, 0, 0);\\n    }\\n  \";\r\n    }\r\n    function getFloatTextureSetRGBASnippet(glsl) {\r\n        return \"\\n    void setOutput(vec4 val) {\\n      \" + glsl.output + \" = val;\\n    }\\n  \";\r\n    }\r\n    function getShaderPrefix(glsl) {\r\n        var NAN_CHECKS = '';\r\n        if (ENV.get('PROD')) {\r\n            NAN_CHECKS = \"\\n      bool isNaN(float val) {\\n        return false;\\n      }\\n\\n      bool hasNaN(vec4 values) {\\n        return false;\\n      }\\n    \";\r\n        }\r\n        else {\r\n            NAN_CHECKS = \"\\n      bool isNaN(float val) {\\n        return (val < 1.0 || 0.0 < val || val == 0.0) ? false : true;\\n      }\\n\\n      bool hasNaN(vec4 values) {\\n        return any(bvec4(\\n          isNaN(values.x),\\n          isNaN(values.y),\\n          isNaN(values.z),\\n          isNaN(values.w)\\n        ));\\n      }\\n    \";\r\n        }\r\n        var SHADER_PREFIX = glsl.version + \"\\n    precision highp float;\\n    precision highp int;\\n    precision highp sampler2D;\\n    \" + glsl.varyingFs + \" vec2 resultUV;\\n    \" + glsl.defineOutput + \"\\n    const vec2 halfCR = vec2(0.5, 0.5);\\n\\n    struct ivec5\\n    {\\n      int x;\\n      int y;\\n      int z;\\n      int w;\\n      int u;\\n    };\\n\\n    struct ivec6\\n    {\\n      int x;\\n      int y;\\n      int z;\\n      int w;\\n      int u;\\n      int v;\\n    };\\n\\n    \" + NAN_CHECKS + \"\\n\\n    float getNaN(vec4 values) {\\n      return dot(vec4(1), values);\\n    }\\n\\n    \" + glsl.defineRound + \"\\n\\n    int imod(int x, int y) {\\n      return x - y * (x / y);\\n    }\\n\\n    //Based on the work of Dave Hoskins\\n    //https://www.shadertoy.com/view/4djSRW\\n    #define HASHSCALE1 443.8975\\n    float random(float seed){\\n      vec2 p = resultUV * seed;\\n      vec3 p3  = fract(vec3(p.xyx) * HASHSCALE1);\\n      p3 += dot(p3, p3.yzx + 19.19);\\n      return fract((p3.x + p3.y) * p3.z);\\n    }\\n\\n    \" + SAMPLE_1D_SNIPPET + \"\\n    \" + SAMPLE_2D_SNIPPET + \"\\n    \" + SAMPLE_3D_SNIPPET + \"\\n    \" + SAMPLE_5D_SNIPPET + \"\\n    \" + SAMPLE_6D_SNIPPET + \"\\n  \";\r\n        return SHADER_PREFIX;\r\n    }\r\n    var SAMPLE_1D_SNIPPET = \"\\nvec2 uvFromFlat(int texNumR, int texNumC, int index) {\\n  int texR = index / texNumC;\\n  int texC = index - texR * texNumC;\\n  return (vec2(texC, texR) + halfCR) / vec2(texNumC, texNumR);\\n}\\nvec2 packedUVfrom1D(int texNumR, int texNumC, int index) {\\n  int texelIndex = index / 2;\\n  int texR = texelIndex / texNumC;\\n  int texC = texelIndex - texR * texNumC;\\n  return (vec2(texC, texR) + halfCR) / vec2(texNumC, texNumR);\\n}\\n\";\r\n    var SAMPLE_2D_SNIPPET = \"\\nvec2 packedUVfrom2D(int texelsInLogicalRow, int texNumR,\\n  int texNumC, int row, int col) {\\n  int texelIndex = (row / 2) * texelsInLogicalRow + (col / 2);\\n  int texR = texelIndex / texNumC;\\n  int texC = texelIndex - texR * texNumC;\\n  return (vec2(texC, texR) + halfCR) / vec2(texNumC, texNumR);\\n}\\n\";\r\n    var SAMPLE_3D_SNIPPET = \"\\nvec2 packedUVfrom3D(int texNumR, int texNumC,\\n    int texelsInBatch, int texelsInLogicalRow, int b,\\n    int row, int col) {\\n  int index = b * texelsInBatch + (row / 2) * texelsInLogicalRow + (col / 2);\\n  int texR = index / texNumC;\\n  int texC = index - texR * texNumC;\\n  return (vec2(texC, texR) + halfCR) / vec2(texNumC, texNumR);\\n}\\n\";\r\n    var SAMPLE_5D_SNIPPET = \"\\nvec2 UVfrom5D(int texNumR, int texNumC, int stride0,\\n    int stride1, int stride2, int stride3, int row, int col, int depth,\\n    int depth2, int depth3) {\\n  // Explicitly use integer operations as dot() only works on floats.\\n  int index = row * stride0 + col * stride1 +\\n              depth * stride2 + depth2 * stride3 + depth3;\\n  int texR = index / texNumC;\\n  int texC = index - texR * texNumC;\\n  return (vec2(texC, texR) + halfCR) / vec2(texNumC, texNumR);\\n}\\n\";\r\n    var SAMPLE_6D_SNIPPET = \"\\nvec2 UVfrom6D(int texNumR, int texNumC, int stride0,\\n    int stride1, int stride2, int stride3, int stride4,\\n    int row, int col, int depth, int depth2, int depth3, int depth4) {\\n  // Explicitly use integer operations as dot() only works on floats.\\n  int index = row * stride0 + col * stride1 + depth * stride2 + depth2 *\\n    stride3 + depth3 * stride4 + depth4;\\n  int texR = index / texNumC;\\n  int texC = index - texR * texNumC;\\n  return (vec2(texC, texR) + halfCR) / vec2(texNumC, texNumR);\\n}\\n\";\r\n    var SHADER_PACKED_PREFIX = \"\\n  float getChannel(vec4 frag, vec2 innerDims) {\\n    vec2 modCoord = mod(innerDims, 2.);\\n    return modCoord.x == 0. ?\\n      (modCoord.y == 0. ? frag.r : frag.g) :\\n      (modCoord.y == 0. ? frag.b : frag.a);\\n  }\\n  float getChannel(vec4 frag, int dim) {\\n    float modCoord = mod(float(dim), 2.);\\n    return modCoord == 0. ? frag.r : frag.g;\\n  }\\n\";\r\n    function getOutputScalarCoords() {\r\n        return \"\\n    int getOutputCoords() {\\n      return 0;\\n    }\\n  \";\r\n    }\r\n    function getOutputPacked1DCoords(shape, texShape) {\r\n        var packedTexShape = [Math.ceil(texShape[0] / 2), Math.ceil(texShape[1] / 2)];\r\n        if (packedTexShape[0] === 1) {\r\n            return \"\\n      int getOutputCoords() {\\n        return 2 * int(resultUV.x * \" + packedTexShape[1] + \".0);\\n      }\\n    \";\r\n        }\r\n        if (packedTexShape[1] === 1) {\r\n            return \"\\n      int getOutputCoords() {\\n        return 2 * int(resultUV.y * \" + packedTexShape[0] + \".0);\\n      }\\n    \";\r\n        }\r\n        return \"\\n    int getOutputCoords() {\\n      ivec2 resTexRC = ivec2(resultUV.yx *\\n                             vec2(\" + packedTexShape[0] + \", \" + packedTexShape[1] + \"));\\n      return resTexRC.x * \" + packedTexShape[1] + \" + resTexRC.y;\\n    }\\n  \";\r\n    }\r\n    function getOutput1DCoords(shape, texShape) {\r\n        if (texShape[0] === 1) {\r\n            return \"\\n      int getOutputCoords() {\\n        return int(resultUV.x * \" + texShape[1] + \".0);\\n      }\\n    \";\r\n        }\r\n        if (texShape[1] === 1) {\r\n            return \"\\n      int getOutputCoords() {\\n        return int(resultUV.y * \" + texShape[0] + \".0);\\n      }\\n    \";\r\n        }\r\n        return \"\\n    int getOutputCoords() {\\n      ivec2 resTexRC = ivec2(resultUV.yx *\\n                             vec2(\" + texShape[0] + \", \" + texShape[1] + \"));\\n      return resTexRC.x * \" + texShape[1] + \" + resTexRC.y;\\n    }\\n  \";\r\n    }\r\n    function getOutputPacked3DCoords(shape, texShape) {\r\n        var packedTexShape = [Math.ceil(texShape[0] / 2), Math.ceil(texShape[1] / 2)];\r\n        var texelsInLogicalRow = Math.ceil(shape[2] / 2);\r\n        var texelsInBatch = texelsInLogicalRow * Math.ceil(shape[1] / 2);\r\n        return \"\\n    ivec3 getOutputCoords() {\\n      ivec2 resTexRC = ivec2(resultUV.yx *\\n                             vec2(\" + packedTexShape[0] + \", \" + packedTexShape[1] + \"));\\n      int index = resTexRC.x * \" + packedTexShape[1] + \" + resTexRC.y;\\n\\n      int b = index / \" + texelsInBatch + \";\\n      index -= b * \" + texelsInBatch + \";\\n\\n      int r = 2 * (index / \" + texelsInLogicalRow + \");\\n      int c = imod(index, \" + texelsInLogicalRow + \") * 2;\\n\\n      return ivec3(b, r, c);\\n    }\\n  \";\r\n    }\r\n    function getOutput3DCoords(shape, texShape) {\r\n        var coordsFromIndexSnippet = getLogicalCoordinatesFromFlatIndex(['r', 'c', 'd'], shape);\r\n        return \"\\n    ivec3 getOutputCoords() {\\n      ivec2 resTexRC = ivec2(resultUV.yx *\\n                             vec2(\" + texShape[0] + \", \" + texShape[1] + \"));\\n      int index = resTexRC.x * \" + texShape[1] + \" + resTexRC.y;\\n      \" + coordsFromIndexSnippet + \"\\n      return ivec3(r, c, d);\\n    }\\n  \";\r\n    }\r\n    function getOutputPackedNDCoords(shape, texShape) {\r\n        var packedTexShape = [Math.ceil(texShape[0] / 2), Math.ceil(texShape[1] / 2)];\r\n        var texelsInLogicalRow = Math.ceil(shape[shape.length - 1] / 2);\r\n        var texelsInBatch = texelsInLogicalRow * Math.ceil(shape[shape.length - 2] / 2);\r\n        var texelsInBatchN = texelsInBatch;\r\n        var batches = \"\";\r\n        var coords = 'b, r, c';\r\n        for (var b = 2; b < shape.length - 1; b++) {\r\n            texelsInBatchN *= shape[shape.length - b - 1];\r\n            batches = \"\\n      int b\" + b + \" = index / \" + texelsInBatchN + \";\\n      index -= b\" + b + \" * \" + texelsInBatchN + \";\\n    \" + batches;\r\n            coords = \"b\" + b + \", \" + coords;\r\n        }\r\n        return \"\\n    ivec\" + shape.length + \" getOutputCoords() {\\n      ivec2 resTexRC = ivec2(resultUV.yx *\\n                             vec2(\" + packedTexShape[0] + \", \" + packedTexShape[1] + \"));\\n      int index = resTexRC.x * \" + packedTexShape[1] + \" + resTexRC.y;\\n\\n      \" + batches + \"\\n\\n      int b = index / \" + texelsInBatch + \";\\n      index -= b * \" + texelsInBatch + \";\\n\\n      int r = 2 * (index / \" + texelsInLogicalRow + \");\\n      int c = imod(index, \" + texelsInLogicalRow + \") * 2;\\n\\n      return ivec\" + shape.length + \"(\" + coords + \");\\n    }\\n  \";\r\n    }\r\n    function getOutput4DCoords(shape, texShape) {\r\n        var coordsFromIndexSnippet = getLogicalCoordinatesFromFlatIndex(['r', 'c', 'd', 'd2'], shape);\r\n        return \"\\n    ivec4 getOutputCoords() {\\n      ivec2 resTexRC = ivec2(resultUV.yx *\\n        vec2(\" + texShape[0] + \", \" + texShape[1] + \"));\\n      int index = resTexRC.x * \" + texShape[1] + \" + resTexRC.y;\\n      \" + coordsFromIndexSnippet + \"\\n      return ivec4(r, c, d, d2);\\n    }\\n  \";\r\n    }\r\n    function getOutput5DCoords(shape, texShape) {\r\n        var coordsFromIndexSnippet = getLogicalCoordinatesFromFlatIndex(['r', 'c', 'd', 'd2', 'd3'], shape);\r\n        return \"\\n    ivec5 getOutputCoords() {\\n      ivec2 resTexRC = ivec2(resultUV.yx * vec2(\" + texShape[0] + \",\\n                             \" + texShape[1] + \"));\\n\\n      int index = resTexRC.x * \" + texShape[1] + \" + resTexRC.y;\\n\\n      \" + coordsFromIndexSnippet + \"\\n\\n      ivec5 outShape = ivec5(r, c, d, d2, d3);\\n      return outShape;\\n    }\\n  \";\r\n    }\r\n    function getOutput6DCoords(shape, texShape) {\r\n        var coordsFromIndexSnippet = getLogicalCoordinatesFromFlatIndex(['r', 'c', 'd', 'd2', 'd3', 'd4'], shape);\r\n        return \"\\n    ivec6 getOutputCoords() {\\n      ivec2 resTexRC = ivec2(resultUV.yx *\\n        vec2(\" + texShape[0] + \", \" + texShape[1] + \"));\\n      int index = resTexRC.x * \" + texShape[1] + \" + resTexRC.y;\\n\\n      \" + coordsFromIndexSnippet + \"\\n\\n      ivec6 result = ivec6(r, c, d, d2, d3, d4);\\n      return result;\\n    }\\n  \";\r\n    }\r\n    function getOutputPacked2DCoords(shape, texShape) {\r\n        var packedTexShape = [Math.ceil(texShape[0] / 2), Math.ceil(texShape[1] / 2)];\r\n        if (arraysEqual(shape, texShape)) {\r\n            return \"\\n      ivec2 getOutputCoords() {\\n        return 2 * ivec2(resultUV.yx * vec2(\" + packedTexShape[0] + \", \" + packedTexShape[1] + \"));\\n      }\\n    \";\r\n        }\r\n        var texelsInLogicalRow = Math.ceil(shape[1] / 2);\r\n        return \"\\n    ivec2 getOutputCoords() {\\n      ivec2 resTexRC = ivec2(resultUV.yx *\\n                             vec2(\" + packedTexShape[0] + \", \" + packedTexShape[1] + \"));\\n\\n      int index = resTexRC.x * \" + packedTexShape[1] + \" + resTexRC.y;\\n      int r = 2 * (index / \" + texelsInLogicalRow + \");\\n      int c = imod(index, \" + texelsInLogicalRow + \") * 2;\\n\\n      return ivec2(r, c);\\n    }\\n  \";\r\n    }\r\n    function getOutput2DCoords(shape, texShape) {\r\n        if (arraysEqual(shape, texShape)) {\r\n            return \"\\n      ivec2 getOutputCoords() {\\n        return ivec2(resultUV.yx * vec2(\" + texShape[0] + \", \" + texShape[1] + \"));\\n      }\\n    \";\r\n        }\r\n        if (shape[1] === 1) {\r\n            return \"\\n      ivec2 getOutputCoords() {\\n        ivec2 resTexRC = ivec2(resultUV.yx *\\n                               vec2(\" + texShape[0] + \", \" + texShape[1] + \"));\\n        int index = resTexRC.x * \" + texShape[1] + \" + resTexRC.y;\\n        return ivec2(index, 0);\\n      }\\n    \";\r\n        }\r\n        if (shape[0] === 1) {\r\n            return \"\\n      ivec2 getOutputCoords() {\\n        ivec2 resTexRC = ivec2(resultUV.yx *\\n                               vec2(\" + texShape[0] + \", \" + texShape[1] + \"));\\n        int index = resTexRC.x * \" + texShape[1] + \" + resTexRC.y;\\n        return ivec2(0, index);\\n      }\\n    \";\r\n        }\r\n        return \"\\n    ivec2 getOutputCoords() {\\n      ivec2 resTexRC = ivec2(resultUV.yx *\\n                             vec2(\" + texShape[0] + \", \" + texShape[1] + \"));\\n      int index = resTexRC.x * \" + texShape[1] + \" + resTexRC.y;\\n      int r = index / \" + shape[1] + \";\\n      int c = index - r * \" + shape[1] + \";\\n      return ivec2(r, c);\\n    }\\n  \";\r\n    }\r\n    function getFlatOffsetUniformName(texName) {\r\n        return \"offset\" + texName;\r\n    }\r\n    function getPackedSamplerScalar(inputInfo) {\r\n        var texName = inputInfo.name;\r\n        var funcName = 'get' + texName.charAt(0).toUpperCase() + texName.slice(1);\r\n        var glsl = getGlslDifferences();\r\n        return \"\\n    vec4 \" + funcName + \"() {\\n      return \" + glsl.texture2D + \"(\" + texName + \", halfCR);\\n    }\\n  \";\r\n    }\r\n    function getSamplerScalar(inputInfo) {\r\n        var texName = inputInfo.name;\r\n        var funcName = 'get' + texName.charAt(0).toUpperCase() + texName.slice(1);\r\n        if (inputInfo.shapeInfo.isUniform) {\r\n            return \"float \" + funcName + \"() {return \" + texName + \";}\";\r\n        }\r\n        var _a = inputInfo.shapeInfo.texShape, texNumR = _a[0], texNumC = _a[1];\r\n        if (texNumR === 1 && texNumC === 1) {\r\n            return \"\\n      float \" + funcName + \"() {\\n        return sampleTexture(\" + texName + \", halfCR);\\n      }\\n    \";\r\n        }\r\n        var _b = inputInfo.shapeInfo.texShape, tNumR = _b[0], tNumC = _b[1];\r\n        var offset = getFlatOffsetUniformName(texName);\r\n        return \"\\n    float \" + funcName + \"() {\\n      vec2 uv = uvFromFlat(\" + tNumR + \", \" + tNumC + \", \" + offset + \");\\n      return sampleTexture(\" + texName + \", uv);\\n    }\\n  \";\r\n    }\r\n    function getPackedSampler1D(inputInfo) {\r\n        var texName = inputInfo.name;\r\n        var funcName = 'get' + texName.charAt(0).toUpperCase() + texName.slice(1);\r\n        var texShape = inputInfo.shapeInfo.texShape;\r\n        var packedTexShape = [Math.ceil(texShape[0] / 2), Math.ceil(texShape[1] / 2)];\r\n        var glsl = getGlslDifferences();\r\n        return \"\\n    vec4 \" + funcName + \"(int index) {\\n      vec2 uv = packedUVfrom1D(\\n        \" + packedTexShape[0] + \", \" + packedTexShape[1] + \", index);\\n      return \" + glsl.texture2D + \"(\" + texName + \", uv);\\n    }\\n  \";\r\n    }\r\n    function getSampler1D(inputInfo) {\r\n        var texName = inputInfo.name;\r\n        var funcName = 'get' + texName.charAt(0).toUpperCase() + texName.slice(1);\r\n        if (inputInfo.shapeInfo.isUniform) {\r\n            return \"\\n      float \" + funcName + \"(int index) {\\n        \" + getUniformSampler(inputInfo) + \"\\n      }\\n    \";\r\n        }\r\n        var texShape = inputInfo.shapeInfo.texShape;\r\n        var tNumR = texShape[0];\r\n        var tNumC = texShape[1];\r\n        if (tNumC === 1 && tNumR === 1) {\r\n            return \"\\n      float \" + funcName + \"(int index) {\\n        return sampleTexture(\" + texName + \", halfCR);\\n      }\\n    \";\r\n        }\r\n        var offset = getFlatOffsetUniformName(texName);\r\n        if (tNumC === 1) {\r\n            return \"\\n      float \" + funcName + \"(int index) {\\n        vec2 uv = vec2(0.5, (float(index + \" + offset + \") + 0.5) / \" + tNumR + \".0);\\n        return sampleTexture(\" + texName + \", uv);\\n      }\\n    \";\r\n        }\r\n        if (tNumR === 1) {\r\n            return \"\\n      float \" + funcName + \"(int index) {\\n        vec2 uv = vec2((float(index + \" + offset + \") + 0.5) / \" + tNumC + \".0, 0.5);\\n        return sampleTexture(\" + texName + \", uv);\\n      }\\n    \";\r\n        }\r\n        return \"\\n    float \" + funcName + \"(int index) {\\n      vec2 uv = uvFromFlat(\" + tNumR + \", \" + tNumC + \", index + \" + offset + \");\\n      return sampleTexture(\" + texName + \", uv);\\n    }\\n  \";\r\n    }\r\n    function getPackedSampler2D(inputInfo) {\r\n        var shape = inputInfo.shapeInfo.logicalShape;\r\n        var texName = inputInfo.name;\r\n        var funcName = 'get' + texName.charAt(0).toUpperCase() + texName.slice(1);\r\n        var texShape = inputInfo.shapeInfo.texShape;\r\n        var texNumR = texShape[0];\r\n        var texNumC = texShape[1];\r\n        var glsl = getGlslDifferences();\r\n        if (texShape != null && arraysEqual(shape, texShape)) {\r\n            return \"\\n      vec4 \" + funcName + \"(int row, int col) {\\n        vec2 uv = (vec2(col, row) + halfCR) / vec2(\" + texNumC + \".0, \" + texNumR + \".0);\\n\\n        return \" + glsl.texture2D + \"(\" + texName + \", uv);\\n      }\\n    \";\r\n        }\r\n        var packedTexShape = [Math.ceil(texShape[0] / 2), Math.ceil(texShape[1] / 2)];\r\n        var valuesPerRow = Math.ceil(shape[1] / 2);\r\n        return \"\\n    vec4 \" + funcName + \"(int row, int col) {\\n      vec2 uv = packedUVfrom2D(\" + valuesPerRow + \", \" + packedTexShape[0] + \", \" + packedTexShape[1] + \", row, col);\\n      return \" + glsl.texture2D + \"(\" + texName + \", uv);\\n    }\\n  \";\r\n    }\r\n    function getSampler2D(inputInfo) {\r\n        var shape = inputInfo.shapeInfo.logicalShape;\r\n        var texName = inputInfo.name;\r\n        var funcName = 'get' + texName.charAt(0).toUpperCase() + texName.slice(1);\r\n        var texShape = inputInfo.shapeInfo.texShape;\r\n        if (texShape != null && arraysEqual(shape, texShape)) {\r\n            var texNumR_1 = texShape[0];\r\n            var texNumC_1 = texShape[1];\r\n            return \"\\n    float \" + funcName + \"(int row, int col) {\\n      vec2 uv = (vec2(col, row) + halfCR) / vec2(\" + texNumC_1 + \".0, \" + texNumR_1 + \".0);\\n      return sampleTexture(\" + texName + \", uv);\\n    }\\n  \";\r\n        }\r\n        var _a = squeezeShape(shape), newShape = _a.newShape, keptDims = _a.keptDims;\r\n        var squeezedShape = newShape;\r\n        if (squeezedShape.length < shape.length) {\r\n            var newInputInfo = squeezeInputInfo(inputInfo, squeezedShape);\r\n            var params = ['row', 'col'];\r\n            return \"\\n      \" + getSamplerFromInInfo(newInputInfo) + \"\\n      float \" + funcName + \"(int row, int col) {\\n        return \" + funcName + \"(\" + getSqueezedParams(params, keptDims) + \");\\n      }\\n    \";\r\n        }\r\n        if (inputInfo.shapeInfo.isUniform) {\r\n            return \"\\n      float \" + funcName + \"(int row, int col) {\\n        int index = round(dot(vec2(row, col), vec2(\" + shape[1] + \", 1)));\\n        \" + getUniformSampler(inputInfo) + \"\\n      }\\n    \";\r\n        }\r\n        var texNumR = texShape[0];\r\n        var texNumC = texShape[1];\r\n        var offset = getFlatOffsetUniformName(texName);\r\n        if (texNumC === 1) {\r\n            return \"\\n    float \" + funcName + \"(int row, int col) {\\n      float index = dot(vec3(row, col, \" + offset + \"), vec3(\" + shape[1] + \", 1, 1));\\n      vec2 uv = vec2(0.5, (index + 0.5) / \" + texNumR + \".0);\\n      return sampleTexture(\" + texName + \", uv);\\n    }\\n  \";\r\n        }\r\n        if (texNumR === 1) {\r\n            return \"\\n    float \" + funcName + \"(int row, int col) {\\n      float index = dot(vec3(row, col, \" + offset + \"), vec3(\" + shape[1] + \", 1, 1));\\n      vec2 uv = vec2((index + 0.5) / \" + texNumC + \".0, 0.5);\\n      return sampleTexture(\" + texName + \", uv);\\n    }\\n  \";\r\n        }\r\n        return \"\\n  float \" + funcName + \"(int row, int col) {\\n    // Explicitly use integer operations as dot() only works on floats.\\n    int index = row * \" + shape[1] + \" + col + \" + offset + \";\\n    vec2 uv = uvFromFlat(\" + texNumR + \", \" + texNumC + \", index);\\n    return sampleTexture(\" + texName + \", uv);\\n  }\\n\";\r\n    }\r\n    function getPackedSampler3D(inputInfo) {\r\n        var shape = inputInfo.shapeInfo.logicalShape;\r\n        var texName = inputInfo.name;\r\n        var funcName = 'get' + texName.charAt(0).toUpperCase() + texName.slice(1);\r\n        var texShape = inputInfo.shapeInfo.texShape;\r\n        var packedTexShape = [Math.ceil(texShape[0] / 2), Math.ceil(texShape[1] / 2)];\r\n        if (shape[0] === 1) {\r\n            var squeezedShape = shape.slice(1);\r\n            var keptDims = [1, 2];\r\n            var newInputInfo = squeezeInputInfo(inputInfo, squeezedShape);\r\n            var params = ['b', 'row', 'col'];\r\n            return \"\\n        \" + getPackedSamplerFromInInfo(newInputInfo) + \"\\n        vec4 \" + funcName + \"(int b, int row, int col) {\\n          return \" + funcName + \"(\" + getSqueezedParams(params, keptDims) + \");\\n        }\\n      \";\r\n        }\r\n        var texNumR = packedTexShape[0];\r\n        var texNumC = packedTexShape[1];\r\n        var valuesPerRow = Math.ceil(shape[2] / 2);\r\n        var texelsInBatch = valuesPerRow * Math.ceil(shape[1] / 2);\r\n        var glsl = getGlslDifferences();\r\n        return \"\\n    vec4 \" + funcName + \"(int b, int row, int col) {\\n      vec2 uv = packedUVfrom3D(\\n        \" + texNumR + \", \" + texNumC + \", \" + texelsInBatch + \", \" + valuesPerRow + \", b, row, col);\\n      return \" + glsl.texture2D + \"(\" + texName + \", uv);\\n    }\\n  \";\r\n    }\r\n    function getSampler3D(inputInfo) {\r\n        var shape = inputInfo.shapeInfo.logicalShape;\r\n        var texName = inputInfo.name;\r\n        var funcName = 'get' + texName.charAt(0).toUpperCase() + texName.slice(1);\r\n        var stride0 = shape[1] * shape[2];\r\n        var stride1 = shape[2];\r\n        var _a = squeezeShape(shape), newShape = _a.newShape, keptDims = _a.keptDims;\r\n        var squeezedShape = newShape;\r\n        if (squeezedShape.length < shape.length) {\r\n            var newInputInfo = squeezeInputInfo(inputInfo, squeezedShape);\r\n            var params = ['row', 'col', 'depth'];\r\n            return \"\\n        \" + getSamplerFromInInfo(newInputInfo) + \"\\n        float \" + funcName + \"(int row, int col, int depth) {\\n          return \" + funcName + \"(\" + getSqueezedParams(params, keptDims) + \");\\n        }\\n      \";\r\n        }\r\n        if (inputInfo.shapeInfo.isUniform) {\r\n            return \"\\n      float \" + funcName + \"(int row, int col, int depth) {\\n        int index = round(dot(vec3(row, col, depth),\\n                          vec3(\" + stride0 + \", \" + stride1 + \", 1)));\\n        \" + getUniformSampler(inputInfo) + \"\\n      }\\n    \";\r\n        }\r\n        var texShape = inputInfo.shapeInfo.texShape;\r\n        var texNumR = texShape[0];\r\n        var texNumC = texShape[1];\r\n        var flatOffset = inputInfo.shapeInfo.flatOffset;\r\n        if (texNumC === stride0 && flatOffset == null) {\r\n            return \"\\n        float \" + funcName + \"(int row, int col, int depth) {\\n          float texR = float(row);\\n          float texC = dot(vec2(col, depth), vec2(\" + stride1 + \", 1));\\n          vec2 uv = (vec2(texC, texR) + halfCR) /\\n                     vec2(\" + texNumC + \".0, \" + texNumR + \".0);\\n          return sampleTexture(\" + texName + \", uv);\\n        }\\n      \";\r\n        }\r\n        if (texNumC === stride1 && flatOffset == null) {\r\n            return \"\\n    float \" + funcName + \"(int row, int col, int depth) {\\n      float texR = dot(vec2(row, col), vec2(\" + shape[1] + \", 1));\\n      float texC = float(depth);\\n      vec2 uv = (vec2(texC, texR) + halfCR) / vec2(\" + texNumC + \".0, \" + texNumR + \".0);\\n      return sampleTexture(\" + texName + \", uv);\\n    }\\n  \";\r\n        }\r\n        var offset = getFlatOffsetUniformName(texName);\r\n        return \"\\n      float \" + funcName + \"(int row, int col, int depth) {\\n        // Explicitly use integer operations as dot() only works on floats.\\n        int index = row * \" + stride0 + \" + col * \" + stride1 + \" + depth + \" + offset + \";\\n        vec2 uv = uvFromFlat(\" + texNumR + \", \" + texNumC + \", index);\\n        return sampleTexture(\" + texName + \", uv);\\n      }\\n  \";\r\n    }\r\n    function getPackedSamplerND(inputInfo) {\r\n        var shape = inputInfo.shapeInfo.logicalShape;\r\n        var rank = shape.length;\r\n        var texName = inputInfo.name;\r\n        var funcName = 'get' + texName.charAt(0).toUpperCase() + texName.slice(1);\r\n        var texShape = inputInfo.shapeInfo.texShape;\r\n        var packedTexShape = [Math.ceil(texShape[0] / 2), Math.ceil(texShape[1] / 2)];\r\n        var texNumR = packedTexShape[0];\r\n        var texNumC = packedTexShape[1];\r\n        var valuesPerRow = Math.ceil(shape[rank - 1] / 2);\r\n        var texelsInBatch = valuesPerRow * Math.ceil(shape[rank - 2] / 2);\r\n        var params = \"int b, int row, int col\";\r\n        var index = \"b * \" + texelsInBatch + \" + (row / 2) * \" + valuesPerRow + \" + (col / 2)\";\r\n        for (var b = 2; b < rank - 1; b++) {\r\n            params = \"int b\" + b + \", \" + params;\r\n            texelsInBatch *= shape[rank - b - 1];\r\n            index = \"b\" + b + \" * \" + texelsInBatch + \" + \" + index;\r\n        }\r\n        var glsl = getGlslDifferences();\r\n        return \"\\n    vec4 \" + funcName + \"(\" + params + \") {\\n      int index = \" + index + \";\\n      int texR = index / \" + texNumC + \";\\n      int texC = index - texR * \" + texNumC + \";\\n      vec2 uv = (vec2(texC, texR) + halfCR) / vec2(\" + texNumC + \", \" + texNumR + \");\\n      return \" + glsl.texture2D + \"(\" + texName + \", uv);\\n    }\\n  \";\r\n    }\r\n    function getSampler4D(inputInfo) {\r\n        var shape = inputInfo.shapeInfo.logicalShape;\r\n        var texName = inputInfo.name;\r\n        var funcName = 'get' + texName.charAt(0).toUpperCase() + texName.slice(1);\r\n        var stride2 = shape[3];\r\n        var stride1 = shape[2] * stride2;\r\n        var stride0 = shape[1] * stride1;\r\n        var _a = squeezeShape(shape), newShape = _a.newShape, keptDims = _a.keptDims;\r\n        if (newShape.length < shape.length) {\r\n            var newInputInfo = squeezeInputInfo(inputInfo, newShape);\r\n            var params = ['row', 'col', 'depth', 'depth2'];\r\n            return \"\\n      \" + getSamplerFromInInfo(newInputInfo) + \"\\n      float \" + funcName + \"(int row, int col, int depth, int depth2) {\\n        return \" + funcName + \"(\" + getSqueezedParams(params, keptDims) + \");\\n      }\\n    \";\r\n        }\r\n        if (inputInfo.shapeInfo.isUniform) {\r\n            return \"\\n      float \" + funcName + \"(int row, int col, int depth, int depth2) {\\n        int index = round(dot(vec4(row, col, depth, depth2),\\n                          vec4(\" + stride0 + \", \" + stride1 + \", \" + stride2 + \", 1)));\\n        \" + getUniformSampler(inputInfo) + \"\\n      }\\n    \";\r\n        }\r\n        var flatOffset = inputInfo.shapeInfo.flatOffset;\r\n        var texShape = inputInfo.shapeInfo.texShape;\r\n        var texNumR = texShape[0];\r\n        var texNumC = texShape[1];\r\n        if (texNumC === stride0 && flatOffset == null) {\r\n            return \"\\n      float \" + funcName + \"(int row, int col, int depth, int depth2) {\\n        float texR = float(row);\\n        float texC =\\n            dot(vec3(col, depth, depth2),\\n                vec3(\" + stride1 + \", \" + stride2 + \", 1));\\n        vec2 uv = (vec2(texC, texR) + halfCR) /\\n                   vec2(\" + texNumC + \".0, \" + texNumR + \".0);\\n        return sampleTexture(\" + texName + \", uv);\\n      }\\n    \";\r\n        }\r\n        if (texNumC === stride2 && flatOffset == null) {\r\n            return \"\\n      float \" + funcName + \"(int row, int col, int depth, int depth2) {\\n        float texR = dot(vec3(row, col, depth),\\n                         vec3(\" + shape[1] * shape[2] + \", \" + shape[2] + \", 1));\\n        float texC = float(depth2);\\n        vec2 uv = (vec2(texC, texR) + halfCR) /\\n                  vec2(\" + texNumC + \".0, \" + texNumR + \".0);\\n        return sampleTexture(\" + texName + \", uv);\\n      }\\n    \";\r\n        }\r\n        var offset = getFlatOffsetUniformName(texName);\r\n        return \"\\n    float \" + funcName + \"(int row, int col, int depth, int depth2) {\\n      // Explicitly use integer operations as dot() only works on floats.\\n      int index = row * \" + stride0 + \" + col * \" + stride1 + \" +\\n          depth * \" + stride2 + \" + depth2;\\n      vec2 uv = uvFromFlat(\" + texNumR + \", \" + texNumC + \", index + \" + offset + \");\\n      return sampleTexture(\" + texName + \", uv);\\n    }\\n  \";\r\n    }\r\n    function getSampler5D(inputInfo) {\r\n        var shape = inputInfo.shapeInfo.logicalShape;\r\n        var texName = inputInfo.name;\r\n        var funcName = 'get' + texName.charAt(0).toUpperCase() + texName.slice(1);\r\n        var stride3 = shape[4];\r\n        var stride2 = shape[3] * stride3;\r\n        var stride1 = shape[2] * stride2;\r\n        var stride0 = shape[1] * stride1;\r\n        var _a = squeezeShape(shape), newShape = _a.newShape, keptDims = _a.keptDims;\r\n        if (newShape.length < shape.length) {\r\n            var newInputInfo = squeezeInputInfo(inputInfo, newShape);\r\n            var params = ['row', 'col', 'depth', 'depth2', 'depth3'];\r\n            return \"\\n      \" + getSamplerFromInInfo(newInputInfo) + \"\\n      float \" + funcName + \"(int row, int col, int depth, int depth2, int depth3) {\\n        return \" + funcName + \"(\" + getSqueezedParams(params, keptDims) + \");\\n      }\\n    \";\r\n        }\r\n        if (inputInfo.shapeInfo.isUniform) {\r\n            return \"\\n      float \" + funcName + \"(int row, int col, int depth, int depth2, int depth3) {\\n        float index = dot(\\n          vec4(row, col, depth, depth2),\\n          vec4(\" + stride0 + \", \" + stride1 + \", \" + stride2 + \", \" + stride3 + \")) +\\n          depth3;\\n        \" + getUniformSampler(inputInfo) + \"\\n      }\\n    \";\r\n        }\r\n        var flatOffset = inputInfo.shapeInfo.flatOffset;\r\n        var texShape = inputInfo.shapeInfo.texShape;\r\n        var texNumR = texShape[0];\r\n        var texNumC = texShape[1];\r\n        if (texNumC === stride0 && flatOffset == null) {\r\n            return \"\\n      float \" + funcName + \"(int row, int col, int depth, int depth2, int depth3) {\\n        int texR = row;\\n        float texC = dot(vec4(col, depth, depth2, depth3),\\n                         vec4(\" + stride1 + \", \" + stride2 + \", \" + stride3 + \", 1));\\n        vec2 uv = (vec2(texC, texR) + halfCR) /\\n                   vec2(\" + texNumC + \".0, \" + texNumR + \".0);\\n        return sampleTexture(\" + texName + \", uv);\\n      }\\n    \";\r\n        }\r\n        if (texNumC === stride3 && flatOffset == null) {\r\n            return \"\\n      float \" + funcName + \"(int row, int col, int depth, int depth2, int depth3) {\\n        float texR = dot(\\n          vec4(row, col, depth, depth2),\\n          vec4(\" + shape[1] * shape[2] * shape[3] + \",\\n               \" + shape[2] * shape[3] + \", \" + shape[3] + \", 1));\\n        int texC = depth3;\\n        vec2 uv = (vec2(texC, texR) + halfCR) /\\n                  vec2(\" + texNumC + \".0, \" + texNumR + \".0);\\n        return sampleTexture(\" + texName + \", uv);\\n      }\\n    \";\r\n        }\r\n        var offset = getFlatOffsetUniformName(texName);\r\n        return \"\\n    float \" + funcName + \"(int row, int col, int depth, int depth2, int depth3) {\\n      // Explicitly use integer operations as dot() only works on floats.\\n      int index = row * \" + stride0 + \" + col * \" + stride1 + \" + depth * \" + stride2 + \" +\\n          depth2 * \" + stride3 + \" + depth3 + \" + offset + \";\\n      vec2 uv = uvFromFlat(\" + texNumR + \", \" + texNumC + \", index);\\n      return sampleTexture(\" + texName + \", uv);\\n    }\\n  \";\r\n    }\r\n    function getSampler6D(inputInfo) {\r\n        var shape = inputInfo.shapeInfo.logicalShape;\r\n        var texName = inputInfo.name;\r\n        var funcName = 'get' + texName.charAt(0).toUpperCase() + texName.slice(1);\r\n        var _a = squeezeShape(shape), newShape = _a.newShape, keptDims = _a.keptDims;\r\n        if (newShape.length < shape.length) {\r\n            var newInputInfo = squeezeInputInfo(inputInfo, newShape);\r\n            var params = ['row', 'col', 'depth', 'depth2', 'depth3', 'depth4'];\r\n            return \"\\n      \" + getSamplerFromInInfo(newInputInfo) + \"\\n      float \" + funcName + \"(int row, int col, int depth,\\n                    int depth2, int depth3, int depth4) {\\n        return \" + funcName + \"(\" + getSqueezedParams(params, keptDims) + \");\\n      }\\n    \";\r\n        }\r\n        var stride4 = shape[5];\r\n        var stride3 = shape[4] * stride4;\r\n        var stride2 = shape[3] * stride3;\r\n        var stride1 = shape[2] * stride2;\r\n        var stride0 = shape[1] * stride1;\r\n        if (inputInfo.shapeInfo.isUniform) {\r\n            return \"\\n      float \" + funcName + \"(int row, int col, int depth,\\n                  int depth2, int depth3, int depth4) {\\n        int index = round(dot(\\n          vec4(row, col, depth, depth2),\\n          vec4(\" + stride0 + \", \" + stride1 + \", \" + stride2 + \", \" + stride3 + \")) +\\n          dot(\\n            vec2(depth3, depth4),\\n            vec2(\" + stride4 + \", 1)));\\n        \" + getUniformSampler(inputInfo) + \"\\n      }\\n    \";\r\n        }\r\n        var flatOffset = inputInfo.shapeInfo.flatOffset;\r\n        var texShape = inputInfo.shapeInfo.texShape;\r\n        var texNumR = texShape[0];\r\n        var texNumC = texShape[1];\r\n        if (texNumC === stride0 && flatOffset == null) {\r\n            return \"\\n      float \" + funcName + \"(int row, int col, int depth,\\n                    int depth2, int depth3, int depth4) {\\n        int texR = row;\\n        float texC = dot(vec4(col, depth, depth2, depth3),\\n          vec4(\" + stride1 + \", \" + stride2 + \", \" + stride3 + \", \" + stride4 + \")) +\\n               float(depth4);\\n        vec2 uv = (vec2(texC, texR) + halfCR) /\\n                   vec2(\" + texNumC + \".0, \" + texNumR + \".0);\\n        return sampleTexture(\" + texName + \", uv);\\n      }\\n    \";\r\n        }\r\n        if (texNumC === stride4 && flatOffset == null) {\r\n            return \"\\n      float \" + funcName + \"(int row, int col, int depth,\\n                    int depth2, int depth3, int depth4) {\\n        float texR = dot(vec4(row, col, depth, depth2),\\n          vec4(\" + shape[1] * shape[2] * shape[3] * shape[4] + \",\\n               \" + shape[2] * shape[3] * shape[4] + \",\\n               \" + shape[3] * shape[4] + \",\\n               \" + shape[4] + \")) + float(depth3);\\n        int texC = depth4;\\n        vec2 uv = (vec2(texC, texR) + halfCR) /\\n                  vec2(\" + texNumC + \".0, \" + texNumR + \".0);\\n        return sampleTexture(\" + texName + \", uv);\\n      }\\n    \";\r\n        }\r\n        var offset = getFlatOffsetUniformName(texName);\r\n        return \"\\n    float \" + funcName + \"(int row, int col, int depth,\\n                  int depth2, int depth3, int depth4) {\\n      // Explicitly use integer operations as dot() only works on floats.\\n      int index = row * \" + stride0 + \" + col * \" + stride1 + \" + depth * \" + stride2 + \" +\\n          depth2 * \" + stride3 + \" + depth3 * \" + stride4 + \" + depth4 + \" + offset + \";\\n      vec2 uv = uvFromFlat(\" + texNumR + \", \" + texNumC + \", index);\\n      return sampleTexture(\" + texName + \", uv);\\n    }\\n  \";\r\n    }\r\n    function getUniformSampler(inputInfo) {\r\n        var texName = inputInfo.name;\r\n        var inSize = sizeFromShape(inputInfo.shapeInfo.logicalShape);\r\n        if (inSize === 1) {\r\n            return \"return \" + texName + \";\";\r\n        }\r\n        return \"\\n    for (int i = 0; i < \" + inSize + \"; i++) {\\n      if (i == index) {\\n        return \" + texName + \"[i];\\n      }\\n    }\\n  \";\r\n    }\r\n    function getPackedSamplerAtOutputCoords(inputInfo, outShapeInfo) {\r\n        var texName = inputInfo.name;\r\n        var texFuncSnippet = texName.charAt(0).toUpperCase() + texName.slice(1);\r\n        var funcName = 'get' + texFuncSnippet + 'AtOutCoords';\r\n        var outTexShape = outShapeInfo.texShape;\r\n        var inTexShape = inputInfo.shapeInfo.texShape;\r\n        var glsl = getGlslDifferences();\r\n        var inRank = inputInfo.shapeInfo.logicalShape.length;\r\n        var outRank = outShapeInfo.logicalShape.length;\r\n        if (!inputInfo.shapeInfo.isUniform && inRank === outRank &&\r\n            inputInfo.shapeInfo.flatOffset == null &&\r\n            arraysEqual(inTexShape, outTexShape)) {\r\n            return \"\\n      vec4 \" + funcName + \"() {\\n        return \" + glsl.texture2D + \"(\" + texName + \", resultUV);\\n      }\\n    \";\r\n        }\r\n        var type = getCoordsDataType(outRank);\r\n        var broadcastDims = getBroadcastDims(inputInfo.shapeInfo.logicalShape, outShapeInfo.logicalShape);\r\n        var rankDiff = outRank - inRank;\r\n        var coordsSnippet;\r\n        var fields = ['x', 'y', 'z', 'w', 'u', 'v'];\r\n        if (broadcastDims.length) {\r\n            throw Error('Packed broadcast sampling is not implemented yet.');\r\n        }\r\n        if (inRank === 0) {\r\n            coordsSnippet = '';\r\n        }\r\n        else if (outRank < 2 && broadcastDims.length >= 1) {\r\n            coordsSnippet = 'coords = 0;';\r\n        }\r\n        else {\r\n            coordsSnippet =\r\n                broadcastDims.map(function (d) { return \"coords.\" + fields[d + rankDiff] + \" = 0;\"; })\r\n                    .join('\\n');\r\n        }\r\n        var unpackedCoordsSnippet = '';\r\n        if (outRank < 2 && inRank > 0) {\r\n            unpackedCoordsSnippet = 'coords';\r\n        }\r\n        else {\r\n            unpackedCoordsSnippet = inputInfo.shapeInfo.logicalShape\r\n                .map(function (s, i) { return \"coords.\" + fields[i + rankDiff]; })\r\n                .join(', ');\r\n        }\r\n        var output = \"return outputValue;\";\r\n        if (inRank === 1 && outRank > 1) {\r\n            output = \"\\n      return vec4(outputValue.xy, outputValue.xy);\\n    \";\r\n        }\r\n        else if (inRank === 0 && outRank > 0) {\r\n            if (outRank === 1) {\r\n                output = \"\\n        return vec4(outputValue.x, outputValue.x, 0., 0.);\\n      \";\r\n            }\r\n            else {\r\n                output = \"\\n        return vec4(outputValue.x);\\n      \";\r\n            }\r\n        }\r\n        return \"\\n    vec4 \" + funcName + \"() {\\n      \" + type + \" coords = getOutputCoords();\\n      \" + coordsSnippet + \"\\n      vec4 outputValue = get\" + texFuncSnippet + \"(\" + unpackedCoordsSnippet + \");\\n      \" + output + \"\\n    }\\n  \";\r\n    }\r\n    function getSamplerAtOutputCoords(inputInfo, outShapeInfo) {\r\n        var texName = inputInfo.name;\r\n        var texFuncSnippet = texName.charAt(0).toUpperCase() + texName.slice(1);\r\n        var funcName = 'get' + texFuncSnippet + 'AtOutCoords';\r\n        var outTexShape = outShapeInfo.texShape;\r\n        var inTexShape = inputInfo.shapeInfo.texShape;\r\n        var inRank = inputInfo.shapeInfo.logicalShape.length;\r\n        var outRank = outShapeInfo.logicalShape.length;\r\n        if (!inputInfo.shapeInfo.isUniform && inRank === outRank &&\r\n            inputInfo.shapeInfo.flatOffset == null &&\r\n            arraysEqual(inTexShape, outTexShape)) {\r\n            return \"\\n      float \" + funcName + \"() {\\n        return sampleTexture(\" + texName + \", resultUV);\\n      }\\n    \";\r\n        }\r\n        var type = getCoordsDataType(outRank);\r\n        var broadcastDims = getBroadcastDims(inputInfo.shapeInfo.logicalShape, outShapeInfo.logicalShape);\r\n        var rankDiff = outRank - inRank;\r\n        var coordsSnippet;\r\n        var fields = ['x', 'y', 'z', 'w', 'u', 'v'];\r\n        if (inRank === 0) {\r\n            coordsSnippet = '';\r\n        }\r\n        else if (outRank < 2 && broadcastDims.length >= 1) {\r\n            coordsSnippet = 'coords = 0;';\r\n        }\r\n        else {\r\n            coordsSnippet =\r\n                broadcastDims.map(function (d) { return \"coords.\" + fields[d + rankDiff] + \" = 0;\"; })\r\n                    .join('\\n');\r\n        }\r\n        var unpackedCoordsSnippet = '';\r\n        if (outRank < 2 && inRank > 0) {\r\n            unpackedCoordsSnippet = 'coords';\r\n        }\r\n        else {\r\n            unpackedCoordsSnippet = inputInfo.shapeInfo.logicalShape\r\n                .map(function (s, i) { return \"coords.\" + fields[i + rankDiff]; })\r\n                .join(', ');\r\n        }\r\n        return \"\\n    float \" + funcName + \"() {\\n      \" + type + \" coords = getOutputCoords();\\n      \" + coordsSnippet + \"\\n      return get\" + texFuncSnippet + \"(\" + unpackedCoordsSnippet + \");\\n    }\\n  \";\r\n    }\r\n    function getCoordsDataType(rank) {\r\n        if (rank <= 1) {\r\n            return 'int';\r\n        }\r\n        else if (rank === 2) {\r\n            return 'ivec2';\r\n        }\r\n        else if (rank === 3) {\r\n            return 'ivec3';\r\n        }\r\n        else if (rank === 4) {\r\n            return 'ivec4';\r\n        }\r\n        else if (rank === 5) {\r\n            return 'ivec5';\r\n        }\r\n        else if (rank === 6) {\r\n            return 'ivec6';\r\n        }\r\n        else {\r\n            throw Error(\"GPU for rank \" + rank + \" is not yet supported\");\r\n        }\r\n    }\r\n    function squeezeInputInfo(inInfo, squeezedShape) {\r\n        var newInputInfo = JSON.parse(JSON.stringify(inInfo));\r\n        newInputInfo.shapeInfo.logicalShape = squeezedShape;\r\n        return newInputInfo;\r\n    }\r\n    function getSqueezedParams(params, keptDims) {\r\n        return keptDims.map(function (d) { return params[d]; }).join(', ');\r\n    }\n\n    var CumSumProgram = (function () {\r\n        function CumSumProgram(shape, exclusive, reverse) {\r\n            this.variableNames = ['x'];\r\n            this.outputShape = shape;\r\n            var rank = shape.length;\r\n            var finalDim = shape[shape.length - 1];\r\n            var comparator = reverse ? '<' : '>';\r\n            this.userCode = \"\\n      int getIndex(int i) {\\n        \" + (reverse ? \"return \" + finalDim + \" -i - 1;\" : 'return i;') + \"\\n      }\\n\\n      void main() {\\n        \" + getCoordsDataType(rank) + \" coords = getOutputCoords();\\n        int end = \" + getFinalCoord(rank, 'coords') + \";\\n        float val = 0.0;\\n        for (int i = \" + finalDim + \" - 1; i >= 0; i -= 1) {\\n          int idx = getIndex(i);\\n          if (idx \" + comparator + \" end) {\\n            continue;\\n          }\\n          if (idx == end && \" + exclusive + \") {\\n            continue;\\n          }\\n          \" + getFinalCoord(rank, 'coords') + \" = idx;\\n          val += getX(\" + getCoords(rank, 'coords') + \");\\n        }\\n        setOutput(val);\\n      }\\n    \";\r\n        }\r\n        return CumSumProgram;\r\n    }());\r\n    function getCoords(rank, name) {\r\n        if (rank === 1) {\r\n            return \"\" + name;\r\n        }\r\n        else if (rank === 2) {\r\n            return name + \".x, \" + name + \".y\";\r\n        }\r\n        else if (rank === 3) {\r\n            return name + \".x, \" + name + \".y, \" + name + \".z\";\r\n        }\r\n        else if (rank === 4) {\r\n            return name + \".x, \" + name + \".y, \" + name + \".z, \" + name + \".w\";\r\n        }\r\n        else {\r\n            throw Error(\"Cumulative sum for rank \" + rank + \" is not yet supported\");\r\n        }\r\n    }\r\n    function getFinalCoord(rank, name) {\r\n        if (rank === 1) {\r\n            return \"\" + name;\r\n        }\r\n        else if (rank === 2) {\r\n            return name + \".y\";\r\n        }\r\n        else if (rank === 3) {\r\n            return name + \".z\";\r\n        }\r\n        else if (rank === 4) {\r\n            return name + \".w\";\r\n        }\r\n        else {\r\n            throw Error(\"Cumulative sum for rank \" + rank + \" is not yet supported\");\r\n        }\r\n    }\n\n    var DepthToSpaceProgram = (function () {\r\n        function DepthToSpaceProgram(outputShape, blockSize, dataFormat) {\r\n            this.variableNames = ['x'];\r\n            this.outputShape = [];\r\n            this.outputShape = outputShape;\r\n            this.blockSize = blockSize;\r\n            this.dataFormat = dataFormat;\r\n            this.userCode = \"\\n    void main() {\\n      ivec4 coords = getOutputCoords();\\n      int b = coords[0];\\n      int h = \" + this.getHeightCoordString() + \";\\n      int w = \" + this.getWidthCoordString() + \";\\n      int d = \" + this.getDepthCoordString() + \";\\n\\n      int in_h = h / \" + blockSize + \";\\n      int offset_h = imod(h, \" + blockSize + \");\\n      int in_w = w / \" + blockSize + \";\\n      int offset_w = imod(w, \" + blockSize + \");\\n      int offset_d = (offset_h * \" + blockSize + \" + offset_w) *\\n        \" + this.getOutputDepthSize() + \";\\n      int in_d = d + offset_d;\\n\\n      float result = \" + this.getInputSamplingString() + \";\\n      setOutput(result);\\n    }\\n  \";\r\n        }\r\n        DepthToSpaceProgram.prototype.getHeightCoordString = function () {\r\n            if (this.dataFormat === 'NHWC') {\r\n                return \"coords[1]\";\r\n            }\r\n            else {\r\n                return \"coords[2]\";\r\n            }\r\n        };\r\n        DepthToSpaceProgram.prototype.getWidthCoordString = function () {\r\n            if (this.dataFormat === 'NHWC') {\r\n                return \"coords[2]\";\r\n            }\r\n            else {\r\n                return \"coords[3]\";\r\n            }\r\n        };\r\n        DepthToSpaceProgram.prototype.getDepthCoordString = function () {\r\n            if (this.dataFormat === 'NHWC') {\r\n                return \"coords[3]\";\r\n            }\r\n            else {\r\n                return \"coords[1]\";\r\n            }\r\n        };\r\n        DepthToSpaceProgram.prototype.getOutputDepthSize = function () {\r\n            if (this.dataFormat === 'NHWC') {\r\n                return this.outputShape[3];\r\n            }\r\n            else {\r\n                return this.outputShape[1];\r\n            }\r\n        };\r\n        DepthToSpaceProgram.prototype.getInputSamplingString = function () {\r\n            if (this.dataFormat === 'NHWC') {\r\n                return \"getX(b, in_h, in_w, in_d)\";\r\n            }\r\n            else {\r\n                return \"getX(b, in_d, in_h, in_w)\";\r\n            }\r\n        };\r\n        return DepthToSpaceProgram;\r\n    }());\n\n    var EncodeFloatProgram = (function () {\r\n        function EncodeFloatProgram(outputShape) {\r\n            this.variableNames = ['A'];\r\n            var glsl = getGlslDifferences();\r\n            this.outputShape = outputShape;\r\n            this.userCode = \"\\n      const float FLOAT_MAX = 1.70141184e38;\\n      const float FLOAT_MIN = 1.17549435e-38;\\n\\n      lowp vec4 encode_float(highp float v) {\\n        if (isNaN(v)) {\\n          return vec4(255, 255, 255, 255);\\n        }\\n\\n        highp float av = abs(v);\\n\\n        if(av < FLOAT_MIN) {\\n          return vec4(0.0, 0.0, 0.0, 0.0);\\n        } else if(v > FLOAT_MAX) {\\n          return vec4(0.0, 0.0, 128.0, 127.0) / 255.0;\\n        } else if(v < -FLOAT_MAX) {\\n          return vec4(0.0, 0.0,  128.0, 255.0) / 255.0;\\n        }\\n\\n        highp vec4 c = vec4(0,0,0,0);\\n\\n        highp float e = floor(log2(av));\\n        highp float m = exp2(fract(log2(av))) - 1.0;\\n\\n        c[2] = floor(128.0 * m);\\n        m -= c[2] / 128.0;\\n        c[1] = floor(32768.0 * m);\\n        m -= c[1] / 32768.0;\\n        c[0] = floor(8388608.0 * m);\\n\\n        highp float ebias = e + 127.0;\\n        c[3] = floor(ebias / 2.0);\\n        ebias -= c[3] * 2.0;\\n        c[2] += floor(ebias) * 128.0;\\n\\n        c[3] += 128.0 * step(0.0, -v);\\n\\n        return c / 255.0;\\n      }\\n\\n      void main() {\\n        float x = getAAtOutCoords();\\n        \" + glsl.output + \" = encode_float(x);\\n      }\\n    \";\r\n        }\r\n        return EncodeFloatProgram;\r\n    }());\n\n    var COMPLEX_FFT = {\r\n        REAL: 'return real * expR - imag * expI;',\r\n        IMAG: 'return real * expI + imag * expR;'\r\n    };\r\n    var FFTProgram = (function () {\r\n        function FFTProgram(op, inputShape, inverse) {\r\n            this.variableNames = ['real', 'imag'];\r\n            var innerDim = inputShape[1];\r\n            this.outputShape = inputShape;\r\n            var exponentMultiplierSnippet = inverse ? \"2.0 * \" + Math.PI : \"-2.0 * \" + Math.PI;\r\n            var resultDenominator = inverse ? innerDim + \".0\" : '1.0';\r\n            this.userCode = \"\\n      const float exponentMultiplier = \" + exponentMultiplierSnippet + \";\\n\\n      float unaryOpComplex(float real, float expR, float imag, float expI) {\\n        \" + op + \"\\n      }\\n\\n      float mulMatDFT(int batch, int index) {\\n        float indexRatio = float(index) / float(\" + innerDim + \");\\n        float exponentMultiplierTimesIndexRatio =\\n            exponentMultiplier * indexRatio;\\n\\n        float result = 0.0;\\n\\n        for (int i = 0; i < \" + innerDim + \"; i++) {\\n          // x = (-2|2 * PI / N) * index * i;\\n          float x = exponentMultiplierTimesIndexRatio * float(i);\\n          float expR = cos(x);\\n          float expI = sin(x);\\n          float real = getReal(batch, i);\\n          float imag = getImag(batch, i);\\n\\n          result +=\\n              unaryOpComplex(real, expR, imag, expI) / \" + resultDenominator + \";\\n        }\\n\\n        return result;\\n      }\\n\\n      void main() {\\n        ivec2 coords = getOutputCoords();\\n        setOutput(mulMatDFT(coords[0], coords[1]));\\n      }\\n    \";\r\n        }\r\n        return FFTProgram;\r\n    }());\n\n    var FromPixelsProgram = (function () {\r\n        function FromPixelsProgram(outputShape) {\r\n            this.variableNames = ['A'];\r\n            var glsl = getGlslDifferences();\r\n            var height = outputShape[0], width = outputShape[1];\r\n            this.outputShape = outputShape;\r\n            this.userCode = \"\\n      void main() {\\n        ivec3 coords = getOutputCoords();\\n        int texR = coords[0];\\n        int texC = coords[1];\\n        int depth = coords[2];\\n        vec2 uv = (vec2(texC, texR) + halfCR) / vec2(\" + width + \".0, \" + height + \".0);\\n\\n        vec4 values = \" + glsl.texture2D + \"(A, uv);\\n        float value;\\n        if (depth == 0) {\\n          value = values.r;\\n        } else if (depth == 1) {\\n          value = values.g;\\n        } else if (depth == 2) {\\n          value = values.b;\\n        } else if (depth == 3) {\\n          value = values.a;\\n        }\\n\\n        setOutput(floor(value * 255.0 + 0.5));\\n      }\\n    \";\r\n        }\r\n        return FromPixelsProgram;\r\n    }());\n\n    var GatherProgram = (function () {\r\n        function GatherProgram(aShape, indicesLength, axis) {\r\n            this.variableNames = ['A', 'indices'];\r\n            var outputShape = aShape.slice();\r\n            outputShape[axis] = indicesLength;\r\n            this.outputShape = outputShape;\r\n            this.rank = outputShape.length;\r\n            var dtype = getCoordsDataType(this.rank);\r\n            var sourceCoords = getSourceCoords(aShape, axis);\r\n            this.userCode = \"\\n      void main() {\\n        \" + dtype + \" resRC = getOutputCoords();\\n        setOutput(getA(\" + sourceCoords + \"));\\n      }\\n    \";\r\n        }\r\n        return GatherProgram;\r\n    }());\r\n    function getSourceCoords(aShape, axis) {\r\n        var rank = aShape.length;\r\n        if (rank > 4) {\r\n            throw Error(\"Gather for rank \" + rank + \" is not yet supported\");\r\n        }\r\n        if (rank === 1) {\r\n            return \"int(getIndices(resRC))\";\r\n        }\r\n        var currentCoords = ['resRC.x', 'resRC.y', 'resRC.z', 'resRC.w'];\r\n        var sourceCoords = [];\r\n        for (var i = 0; i < aShape.length; i++) {\r\n            if (i === axis) {\r\n                sourceCoords.push(\"int(getIndices(\" + currentCoords[i] + \"))\");\r\n            }\r\n            else {\r\n                sourceCoords.push(\"\" + currentCoords[i]);\r\n            }\r\n        }\r\n        return sourceCoords.join();\r\n    }\n\n    var GatherNDProgram = (function () {\r\n        function GatherNDProgram(sliceDim, strides, shape) {\r\n            this.sliceDim = sliceDim;\r\n            this.strides = strides;\r\n            this.variableNames = ['x', 'indices'];\r\n            this.outputShape = shape;\r\n            var stridesType = getCoordsDataType(strides.length);\r\n            var dtype = getCoordsDataType(shape.length);\r\n            var strideString = this.sliceDim > 1 ? 'strides[j]' : 'strides';\r\n            this.userCode = \"\\n        \" + stridesType + \" strides = \" + stridesType + \"(\" + this.strides + \");\\n         void main() {\\n          \" + dtype + \" coords = getOutputCoords();\\n          int flattenIndex = 0;\\n          for (int j = 0; j < \" + this.sliceDim + \"; j++) {\\n            int index = round(getIndices(coords[0], j));\\n            flattenIndex += index * \" + strideString + \";\\n          }\\n          setOutput(getX(flattenIndex, coords[1]));\\n        }\\n      \";\r\n        }\r\n        return GatherNDProgram;\r\n    }());\n\n    var TextureUsage;\r\n    (function (TextureUsage) {\r\n        TextureUsage[TextureUsage[\"RENDER\"] = 0] = \"RENDER\";\r\n        TextureUsage[TextureUsage[\"UPLOAD\"] = 1] = \"UPLOAD\";\r\n        TextureUsage[TextureUsage[\"PIXELS\"] = 2] = \"PIXELS\";\r\n        TextureUsage[TextureUsage[\"DOWNLOAD\"] = 3] = \"DOWNLOAD\";\r\n    })(TextureUsage || (TextureUsage = {}));\r\n    var PhysicalTextureType;\r\n    (function (PhysicalTextureType) {\r\n        PhysicalTextureType[PhysicalTextureType[\"UNPACKED_FLOAT16\"] = 0] = \"UNPACKED_FLOAT16\";\r\n        PhysicalTextureType[PhysicalTextureType[\"UNPACKED_FLOAT32\"] = 1] = \"UNPACKED_FLOAT32\";\r\n        PhysicalTextureType[PhysicalTextureType[\"PACKED_4X1_UNSIGNED_BYTE\"] = 2] = \"PACKED_4X1_UNSIGNED_BYTE\";\r\n        PhysicalTextureType[PhysicalTextureType[\"PACKED_2X2_FLOAT32\"] = 3] = \"PACKED_2X2_FLOAT32\";\r\n        PhysicalTextureType[PhysicalTextureType[\"PACKED_2X2_FLOAT16\"] = 4] = \"PACKED_2X2_FLOAT16\";\r\n    })(PhysicalTextureType || (PhysicalTextureType = {}));\r\n    function getUnpackedMatrixTextureShapeWidthHeight(rows, columns) {\r\n        return [columns, rows];\r\n    }\r\n    function getUnpackedArraySizeFromMatrixSize(matrixSize, channelsPerTexture) {\r\n        return matrixSize * channelsPerTexture;\r\n    }\r\n    function getMatrixSizeFromUnpackedArraySize(unpackedSize, channelsPerTexture) {\r\n        if (unpackedSize % channelsPerTexture !== 0) {\r\n            throw new Error(\"unpackedSize (\" + unpackedSize + \") must be a multiple of \" +\r\n                (\"\" + channelsPerTexture));\r\n        }\r\n        return unpackedSize / channelsPerTexture;\r\n    }\r\n    function encodeMatrixToUnpackedArray(matrix, unpackedArray, channelsPerTexture) {\r\n        var requiredSize = getUnpackedArraySizeFromMatrixSize(matrix.length, channelsPerTexture);\r\n        if (unpackedArray.length < requiredSize) {\r\n            throw new Error(\"unpackedArray length (\" + unpackedArray.length + \") must be >= \" +\r\n                (\"\" + requiredSize));\r\n        }\r\n        var dst = 0;\r\n        for (var src = 0; src < matrix.length; ++src) {\r\n            unpackedArray[dst] = matrix[src];\r\n            dst += channelsPerTexture;\r\n        }\r\n    }\r\n    function decodeMatrixFromUnpackedArray(unpackedArray, matrix, channelsPerTexture) {\r\n        var requiredSize = getMatrixSizeFromUnpackedArraySize(unpackedArray.length, channelsPerTexture);\r\n        if (matrix.length < requiredSize) {\r\n            throw new Error(\"matrix length (\" + matrix.length + \") must be >= \" + requiredSize);\r\n        }\r\n        var dst = 0;\r\n        for (var src = 0; src < unpackedArray.length; src += channelsPerTexture) {\r\n            matrix[dst++] = unpackedArray[src];\r\n        }\r\n    }\r\n    function getPackedMatrixTextureShapeWidthHeight(rows, columns) {\r\n        return [\r\n            Math.max(1, Math.ceil(columns / 2)), Math.max(1, Math.ceil(rows / 2))\r\n        ];\r\n    }\r\n    function getPackedRGBAArraySizeFromMatrixShape(rows, columns) {\r\n        var _a = getPackedMatrixTextureShapeWidthHeight(rows, columns), w = _a[0], h = _a[1];\r\n        return w * h * 4;\r\n    }\r\n    function encodeMatrixToPackedRGBA(matrix, batches, rows, columns, packedRGBA) {\r\n        var oddWidth = (columns % 2) === 1;\r\n        var oddHeight = (rows % 2) === 1;\r\n        var widthInFullBlocks = Math.floor(columns / 2);\r\n        var heightInFullBlocks = Math.floor(rows / 2);\r\n        var texelsPerRow = Math.ceil(columns / 2);\r\n        var texelsPerBatch = texelsPerRow * Math.ceil(rows / 2);\r\n        var flattenedMatrixSize = nearestLargerEven(rows) * nearestLargerEven(columns);\r\n        for (var batch = 0; batch < batches; batch++) {\r\n            var sourceOffset = batch * rows * columns;\r\n            var batchOffset = batch * flattenedMatrixSize;\r\n            {\r\n                var dstStride = (oddWidth ? 4 : 0);\r\n                var oneRow = columns;\r\n                var dst = batchOffset;\r\n                for (var blockY = 0; blockY < heightInFullBlocks; ++blockY) {\r\n                    var matrixSrcRow = (blockY * 2 * columns);\r\n                    for (var blockX = 0; blockX < widthInFullBlocks; ++blockX) {\r\n                        var matrixSrcCol = blockX * 2;\r\n                        var src = sourceOffset + matrixSrcRow + matrixSrcCol;\r\n                        packedRGBA[dst] = matrix[src];\r\n                        packedRGBA[dst + 1] = matrix[src + 1];\r\n                        packedRGBA[dst + 2] = matrix[src + oneRow];\r\n                        packedRGBA[dst + 3] = matrix[src + oneRow + 1];\r\n                        dst += 4;\r\n                    }\r\n                    dst += dstStride;\r\n                }\r\n            }\r\n            if (oddWidth) {\r\n                var src = sourceOffset + columns - 1;\r\n                var dst = batchOffset + (texelsPerRow - 1) * 4;\r\n                var srcStride = 2 * columns;\r\n                var dstStride = texelsPerRow * 4;\r\n                for (var blockY = 0; blockY < heightInFullBlocks; ++blockY) {\r\n                    packedRGBA[dst] = matrix[src];\r\n                    packedRGBA[dst + 2] = matrix[src + columns];\r\n                    src += srcStride;\r\n                    dst += dstStride;\r\n                }\r\n            }\r\n            if (oddHeight) {\r\n                var src = sourceOffset + (rows - 1) * columns;\r\n                var dst = batchOffset + (texelsPerBatch - texelsPerRow) * 4;\r\n                for (var blockX = 0; blockX < widthInFullBlocks; ++blockX) {\r\n                    packedRGBA[dst++] = matrix[src++];\r\n                    packedRGBA[dst++] = matrix[src++];\r\n                    dst += 2;\r\n                }\r\n                if (oddWidth && oddHeight) {\r\n                    packedRGBA[batchOffset + flattenedMatrixSize - 4] = matrix[src];\r\n                }\r\n            }\r\n        }\r\n        return packedRGBA;\r\n    }\r\n    function decodeMatrixFromPackedRGBA(packedRGBA, batches, rows, columns, matrix) {\r\n        var requiredSize = rows * columns;\r\n        if (matrix.length < requiredSize) {\r\n            throw new Error(\"matrix length (\" + matrix.length + \") must be >= \" + requiredSize);\r\n        }\r\n        var oddWidth = (columns % 2) === 1;\r\n        var oddHeight = (rows % 2) === 1;\r\n        var widthInFullBlocks = Math.floor(columns / 2);\r\n        var heightInFullBlocks = Math.floor(rows / 2);\r\n        var texelsPerRow = Math.ceil(columns / 2);\r\n        var texelsPerBatch = texelsPerRow * Math.ceil(rows / 2);\r\n        var flattenedMatrixSize = nearestLargerEven(rows) * nearestLargerEven(columns);\r\n        for (var batch = 0; batch < batches; batch++) {\r\n            var batchOffset = batch * rows * columns;\r\n            var sourceOffset = batch * flattenedMatrixSize;\r\n            {\r\n                var srcStride = oddWidth ? 4 : 0;\r\n                var dstStride = columns + (oddWidth ? 1 : 0);\r\n                var src = sourceOffset;\r\n                var dstRow1 = batchOffset;\r\n                var dstRow2 = batchOffset + columns;\r\n                for (var blockY = 0; blockY < heightInFullBlocks; ++blockY) {\r\n                    for (var blockX = 0; blockX < widthInFullBlocks; ++blockX) {\r\n                        matrix[dstRow1++] = packedRGBA[src++];\r\n                        matrix[dstRow1++] = packedRGBA[src++];\r\n                        matrix[dstRow2++] = packedRGBA[src++];\r\n                        matrix[dstRow2++] = packedRGBA[src++];\r\n                    }\r\n                    src += srcStride;\r\n                    dstRow1 += dstStride;\r\n                    dstRow2 += dstStride;\r\n                }\r\n            }\r\n            if (oddWidth) {\r\n                var src = sourceOffset + (texelsPerRow - 1) * 4;\r\n                var dst = batchOffset + columns - 1;\r\n                var srcStride = texelsPerRow * 4;\r\n                var dstStride = 2 * columns;\r\n                for (var blockY = 0; blockY < heightInFullBlocks; ++blockY) {\r\n                    matrix[dst] = packedRGBA[src];\r\n                    matrix[dst + columns] = packedRGBA[src + 2];\r\n                    src += srcStride;\r\n                    dst += dstStride;\r\n                }\r\n            }\r\n            if (oddHeight) {\r\n                var src = sourceOffset + (texelsPerBatch - texelsPerRow) * 4;\r\n                var dst = batchOffset + (rows - 1) * columns;\r\n                for (var blockX = 0; blockX < widthInFullBlocks; ++blockX) {\r\n                    matrix[dst++] = packedRGBA[src++];\r\n                    matrix[dst++] = packedRGBA[src++];\r\n                    src += 2;\r\n                }\r\n                if (oddWidth) {\r\n                    matrix[batchOffset + (rows * columns) - 1] = packedRGBA[src];\r\n                }\r\n            }\r\n        }\r\n        return matrix;\r\n    }\n\n    function callAndCheck(gl, func) {\r\n        var returnValue = func();\r\n        checkWebGLError(gl);\r\n        return returnValue;\r\n    }\r\n    var webGLDebugErrorCheckingEnabled = false;\r\n    function enableDebugWebGLErrorChecking(enabled) {\r\n        webGLDebugErrorCheckingEnabled = enabled;\r\n    }\r\n    function checkWebGLError(gl) {\r\n        if (webGLDebugErrorCheckingEnabled) {\r\n            var error = gl.getError();\r\n            if (error !== gl.NO_ERROR) {\r\n                throw new Error('WebGL Error: ' + getWebGLErrorMessage(gl, error));\r\n            }\r\n        }\r\n    }\r\n    var MIN_FLOAT16 = 5.96e-8;\r\n    var MAX_FLOAT16 = 65504;\r\n    function canBeRepresented(num) {\r\n        if (ENV.get('WEBGL_RENDER_FLOAT32_ENABLED') || num === 0 ||\r\n            (MIN_FLOAT16 < Math.abs(num) && Math.abs(num) < MAX_FLOAT16)) {\r\n            return true;\r\n        }\r\n        return false;\r\n    }\r\n    function getWebGLErrorMessage(gl, status) {\r\n        switch (status) {\r\n            case gl.NO_ERROR:\r\n                return 'NO_ERROR';\r\n            case gl.INVALID_ENUM:\r\n                return 'INVALID_ENUM';\r\n            case gl.INVALID_VALUE:\r\n                return 'INVALID_VALUE';\r\n            case gl.INVALID_OPERATION:\r\n                return 'INVALID_OPERATION';\r\n            case gl.INVALID_FRAMEBUFFER_OPERATION:\r\n                return 'INVALID_FRAMEBUFFER_OPERATION';\r\n            case gl.OUT_OF_MEMORY:\r\n                return 'OUT_OF_MEMORY';\r\n            case gl.CONTEXT_LOST_WEBGL:\r\n                return 'CONTEXT_LOST_WEBGL';\r\n            default:\r\n                return \"Unknown error code \" + status;\r\n        }\r\n    }\r\n    function getExtensionOrThrow(gl, extensionName) {\r\n        return throwIfNull(gl, function () { return gl.getExtension(extensionName); }, 'Extension \"' + extensionName + '\" not supported on this browser.');\r\n    }\r\n    function createVertexShader(gl, vertexShaderSource) {\r\n        var vertexShader = throwIfNull(gl, function () { return gl.createShader(gl.VERTEX_SHADER); }, 'Unable to create vertex WebGLShader.');\r\n        callAndCheck(gl, function () { return gl.shaderSource(vertexShader, vertexShaderSource); });\r\n        callAndCheck(gl, function () { return gl.compileShader(vertexShader); });\r\n        if (gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS) === false) {\r\n            console.log(gl.getShaderInfoLog(vertexShader));\r\n            throw new Error('Failed to compile vertex shader.');\r\n        }\r\n        return vertexShader;\r\n    }\r\n    function createFragmentShader(gl, fragmentShaderSource) {\r\n        var fragmentShader = throwIfNull(gl, function () { return gl.createShader(gl.FRAGMENT_SHADER); }, 'Unable to create fragment WebGLShader.');\r\n        callAndCheck(gl, function () { return gl.shaderSource(fragmentShader, fragmentShaderSource); });\r\n        callAndCheck(gl, function () { return gl.compileShader(fragmentShader); });\r\n        if (gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS) === false) {\r\n            logShaderSourceAndInfoLog(fragmentShaderSource, gl.getShaderInfoLog(fragmentShader));\r\n            throw new Error('Failed to compile fragment shader.');\r\n        }\r\n        return fragmentShader;\r\n    }\r\n    var lineNumberRegex = /ERROR: [0-9]+:([0-9]+):/g;\r\n    function logShaderSourceAndInfoLog(shaderSource, shaderInfoLog) {\r\n        var lineNumberRegexResult = lineNumberRegex.exec(shaderInfoLog);\r\n        if (lineNumberRegexResult == null) {\r\n            console.log(\"Couldn't parse line number in error: \" + shaderInfoLog);\r\n            console.log(shaderSource);\r\n            return;\r\n        }\r\n        var lineNumber = +lineNumberRegexResult[1];\r\n        var shaderLines = shaderSource.split('\\n');\r\n        var pad = shaderLines.length.toString().length + 2;\r\n        var linesWithLineNumbers = shaderLines.map(function (line, lineNumber) {\r\n            return rightPad((lineNumber + 1).toString(), pad) + line;\r\n        });\r\n        var maxLineLength = 0;\r\n        for (var i = 0; i < linesWithLineNumbers.length; i++) {\r\n            maxLineLength = Math.max(linesWithLineNumbers[i].length, maxLineLength);\r\n        }\r\n        var beforeErrorLines = linesWithLineNumbers.slice(0, lineNumber - 1);\r\n        var errorLine = linesWithLineNumbers.slice(lineNumber - 1, lineNumber);\r\n        var afterErrorLines = linesWithLineNumbers.slice(lineNumber);\r\n        console.log(beforeErrorLines.join('\\n'));\r\n        console.log(shaderInfoLog.split('\\n')[0]);\r\n        console.log(\"%c \" + rightPad(errorLine[0], maxLineLength), 'border:1px solid red; background-color:#e3d2d2; color:#a61717');\r\n        console.log(afterErrorLines.join('\\n'));\r\n    }\r\n    function createProgram(gl) {\r\n        return throwIfNull(gl, function () { return gl.createProgram(); }, 'Unable to create WebGLProgram.');\r\n    }\r\n    function linkProgram(gl, program) {\r\n        callAndCheck(gl, function () { return gl.linkProgram(program); });\r\n        if (gl.getProgramParameter(program, gl.LINK_STATUS) === false) {\r\n            console.log(gl.getProgramInfoLog(program));\r\n            throw new Error('Failed to link vertex and fragment shaders.');\r\n        }\r\n    }\r\n    function validateProgram(gl, program) {\r\n        callAndCheck(gl, function () { return gl.validateProgram(program); });\r\n        if (gl.getProgramParameter(program, gl.VALIDATE_STATUS) === false) {\r\n            console.log(gl.getProgramInfoLog(program));\r\n            throw new Error('Shader program validation failed.');\r\n        }\r\n    }\r\n    function createStaticVertexBuffer(gl, data) {\r\n        var buffer = throwIfNull(gl, function () { return gl.createBuffer(); }, 'Unable to create WebGLBuffer');\r\n        callAndCheck(gl, function () { return gl.bindBuffer(gl.ARRAY_BUFFER, buffer); });\r\n        callAndCheck(gl, function () { return gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW); });\r\n        return buffer;\r\n    }\r\n    function createStaticIndexBuffer(gl, data) {\r\n        var buffer = throwIfNull(gl, function () { return gl.createBuffer(); }, 'Unable to create WebGLBuffer');\r\n        callAndCheck(gl, function () { return gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer); });\r\n        callAndCheck(gl, function () { return gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, data, gl.STATIC_DRAW); });\r\n        return buffer;\r\n    }\r\n    function getNumChannels() {\r\n        if (ENV.get('WEBGL_VERSION') === 2) {\r\n            return 1;\r\n        }\r\n        return 4;\r\n    }\r\n    function createTexture(gl) {\r\n        return throwIfNull(gl, function () { return gl.createTexture(); }, 'Unable to create WebGLTexture.');\r\n    }\r\n    function validateTextureSize(width, height) {\r\n        var maxTextureSize = ENV.get('WEBGL_MAX_TEXTURE_SIZE');\r\n        if ((width <= 0) || (height <= 0)) {\r\n            var requested = \"[\" + width + \"x\" + height + \"]\";\r\n            throw new Error('Requested texture size ' + requested + ' is invalid.');\r\n        }\r\n        if ((width > maxTextureSize) || (height > maxTextureSize)) {\r\n            var requested = \"[\" + width + \"x\" + height + \"]\";\r\n            var max = \"[\" + maxTextureSize + \"x\" + maxTextureSize + \"]\";\r\n            throw new Error('Requested texture size ' + requested +\r\n                ' greater than WebGL maximum on this browser / GPU ' + max + '.');\r\n        }\r\n    }\r\n    function createFramebuffer(gl) {\r\n        return throwIfNull(gl, function () { return gl.createFramebuffer(); }, 'Unable to create WebGLFramebuffer.');\r\n    }\r\n    function bindVertexBufferToProgramAttribute(gl, program, attribute, buffer, arrayEntriesPerItem, itemStrideInBytes, itemOffsetInBytes) {\r\n        var loc = gl.getAttribLocation(program, attribute);\r\n        if (loc === -1) {\r\n            return false;\r\n        }\r\n        callAndCheck(gl, function () { return gl.bindBuffer(gl.ARRAY_BUFFER, buffer); });\r\n        callAndCheck(gl, function () { return gl.vertexAttribPointer(loc, arrayEntriesPerItem, gl.FLOAT, false, itemStrideInBytes, itemOffsetInBytes); });\r\n        callAndCheck(gl, function () { return gl.enableVertexAttribArray(loc); });\r\n        return true;\r\n    }\r\n    function bindTextureUnit(gl, texture, textureUnit) {\r\n        validateTextureUnit(gl, textureUnit);\r\n        callAndCheck(gl, function () { return gl.activeTexture(gl.TEXTURE0 + textureUnit); });\r\n        callAndCheck(gl, function () { return gl.bindTexture(gl.TEXTURE_2D, texture); });\r\n    }\r\n    function unbindTextureUnit(gl, textureUnit) {\r\n        validateTextureUnit(gl, textureUnit);\r\n        callAndCheck(gl, function () { return gl.activeTexture(gl.TEXTURE0 + textureUnit); });\r\n        callAndCheck(gl, function () { return gl.bindTexture(gl.TEXTURE_2D, null); });\r\n    }\r\n    function getProgramUniformLocationOrThrow(gl, program, uniformName) {\r\n        return throwIfNull(gl, function () { return gl.getUniformLocation(program, uniformName); }, 'uniform \"' + uniformName + '\" not present in program.');\r\n    }\r\n    function getProgramUniformLocation(gl, program, uniformName) {\r\n        return gl.getUniformLocation(program, uniformName);\r\n    }\r\n    function bindTextureToProgramUniformSampler(gl, program, texture, uniformSamplerLocation, textureUnit) {\r\n        callAndCheck(gl, function () { return bindTextureUnit(gl, texture, textureUnit); });\r\n        callAndCheck(gl, function () { return gl.uniform1i(uniformSamplerLocation, textureUnit); });\r\n    }\r\n    function bindCanvasToFramebuffer(gl) {\r\n        callAndCheck(gl, function () { return gl.bindFramebuffer(gl.FRAMEBUFFER, null); });\r\n        callAndCheck(gl, function () { return gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); });\r\n        callAndCheck(gl, function () { return gl.scissor(0, 0, gl.canvas.width, gl.canvas.height); });\r\n    }\r\n    function bindColorTextureToFramebuffer(gl, texture, framebuffer) {\r\n        callAndCheck(gl, function () { return gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); });\r\n        callAndCheck(gl, function () { return gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); });\r\n    }\r\n    function unbindColorTextureFromFramebuffer(gl, framebuffer) {\r\n        callAndCheck(gl, function () { return gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); });\r\n        callAndCheck(gl, function () { return gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, null, 0); });\r\n    }\r\n    function validateFramebuffer(gl) {\r\n        var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);\r\n        if (status !== gl.FRAMEBUFFER_COMPLETE) {\r\n            throw new Error('Error binding framebuffer: ' + getFramebufferErrorMessage(gl, status));\r\n        }\r\n    }\r\n    function getFramebufferErrorMessage(gl, status) {\r\n        switch (status) {\r\n            case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:\r\n                return 'FRAMEBUFFER_INCOMPLETE_ATTACHMENT';\r\n            case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:\r\n                return 'FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT';\r\n            case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:\r\n                return 'FRAMEBUFFER_INCOMPLETE_DIMENSIONS';\r\n            case gl.FRAMEBUFFER_UNSUPPORTED:\r\n                return 'FRAMEBUFFER_UNSUPPORTED';\r\n            default:\r\n                return \"unknown error \" + status;\r\n        }\r\n    }\r\n    function throwIfNull(gl, returnTOrNull, failureMessage) {\r\n        var tOrNull = callAndCheck(gl, function () { return returnTOrNull(); });\r\n        if (tOrNull == null) {\r\n            throw new Error(failureMessage);\r\n        }\r\n        return tOrNull;\r\n    }\r\n    function validateTextureUnit(gl, textureUnit) {\r\n        var maxTextureUnit = gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1;\r\n        var glTextureUnit = textureUnit + gl.TEXTURE0;\r\n        if (glTextureUnit < gl.TEXTURE0 || glTextureUnit > maxTextureUnit) {\r\n            var textureUnitRange = \"[gl.TEXTURE0, gl.TEXTURE\" + maxTextureUnit + \"]\";\r\n            throw new Error(\"textureUnit must be in \" + textureUnitRange + \".\");\r\n        }\r\n    }\r\n    function getBatchDim(shape, dimsToSkip) {\r\n        if (dimsToSkip === void 0) { dimsToSkip = 2; }\r\n        return sizeFromShape(shape.slice(0, shape.length - dimsToSkip));\r\n    }\r\n    function getRowsCols(shape) {\r\n        if (shape.length === 0) {\r\n            throw Error('Cannot get rows and columns of an empty shape array.');\r\n        }\r\n        return [\r\n            shape.length > 1 ? shape[shape.length - 2] : 1, shape[shape.length - 1]\r\n        ];\r\n    }\r\n    function getTextureShapeFromLogicalShape(logShape, isPacked) {\r\n        if (isPacked === void 0) { isPacked = false; }\r\n        var _a;\r\n        var maxTexSize = ENV.get('WEBGL_MAX_TEXTURE_SIZE');\r\n        if (isPacked) {\r\n            maxTexSize = maxTexSize * 2;\r\n            logShape = logShape.map(function (d, i) { return i >= logShape.length - 2 ?\r\n                nearestLargerEven(logShape[i]) :\r\n                logShape[i]; });\r\n            if (logShape.length === 1) {\r\n                logShape = [2, logShape[0]];\r\n            }\r\n        }\r\n        if (logShape.length !== 2) {\r\n            var squeezeResult = squeezeShape(logShape);\r\n            logShape = squeezeResult.newShape;\r\n        }\r\n        var size = sizeFromShape(logShape);\r\n        if (logShape.length <= 1 && size <= maxTexSize) {\r\n            return [1, size];\r\n        }\r\n        else if (logShape.length === 2 && logShape[0] <= maxTexSize &&\r\n            logShape[1] <= maxTexSize) {\r\n            return logShape;\r\n        }\r\n        else if (logShape.length === 3 && logShape[0] * logShape[1] <= maxTexSize &&\r\n            logShape[2] <= maxTexSize) {\r\n            return [logShape[0] * logShape[1], logShape[2]];\r\n        }\r\n        else if (logShape.length === 3 && logShape[0] <= maxTexSize &&\r\n            logShape[1] * logShape[2] <= maxTexSize) {\r\n            return [logShape[0], logShape[1] * logShape[2]];\r\n        }\r\n        else if (logShape.length === 4 &&\r\n            logShape[0] * logShape[1] * logShape[2] <= maxTexSize &&\r\n            logShape[3] <= maxTexSize) {\r\n            return [logShape[0] * logShape[1] * logShape[2], logShape[3]];\r\n        }\r\n        else if (logShape.length === 4 && logShape[0] <= maxTexSize &&\r\n            logShape[1] * logShape[2] * logShape[3] <= maxTexSize) {\r\n            return [logShape[0], logShape[1] * logShape[2] * logShape[3]];\r\n        }\r\n        else {\r\n            if (isPacked) {\r\n                var batchDim = getBatchDim(logShape);\r\n                var rows = 2, cols = 2;\r\n                if (logShape.length) {\r\n                    _a = getRowsCols(logShape), rows = _a[0], cols = _a[1];\r\n                }\r\n                size = batchDim * (rows / 2) * (cols / 2);\r\n                return sizeToSquarishShape(size).map(function (d) { return d * 2; });\r\n            }\r\n            return sizeToSquarishShape(size);\r\n        }\r\n    }\r\n    function isEven(n) {\r\n        return n % 2 === 0;\r\n    }\r\n    function isReshapeFree(shape1, shape2) {\r\n        shape1 = shape1.slice(-2);\r\n        shape2 = shape2.slice(-2);\r\n        if (arraysEqual(shape1, shape2)) {\r\n            return true;\r\n        }\r\n        if (!shape1.length || !shape2.length) {\r\n            return true;\r\n        }\r\n        if (shape1[0] === 0 || shape1[1] === 0 || shape2[0] === 0 ||\r\n            shape2[1] === 0) {\r\n            return true;\r\n        }\r\n        if (shape1.length !== shape2.length) {\r\n            var shape1Cols = shape1.slice(-1)[0];\r\n            var shape2Cols = shape2.slice(-1)[0];\r\n            if (shape1Cols === shape2Cols) {\r\n                return true;\r\n            }\r\n            if (isEven(shape1Cols) && isEven(shape2Cols) &&\r\n                (shape1[0] === 1 || shape2[0] === 1)) {\r\n                return true;\r\n            }\r\n        }\r\n        return shape1[1] === shape2[1] && isEven(shape1[0]) && isEven(shape2[0]);\r\n    }\n\n    var webgl_util = /*#__PURE__*/Object.freeze({\n        callAndCheck: callAndCheck,\n        enableDebugWebGLErrorChecking: enableDebugWebGLErrorChecking,\n        checkWebGLError: checkWebGLError,\n        canBeRepresented: canBeRepresented,\n        getWebGLErrorMessage: getWebGLErrorMessage,\n        getExtensionOrThrow: getExtensionOrThrow,\n        createVertexShader: createVertexShader,\n        createFragmentShader: createFragmentShader,\n        createProgram: createProgram,\n        linkProgram: linkProgram,\n        validateProgram: validateProgram,\n        createStaticVertexBuffer: createStaticVertexBuffer,\n        createStaticIndexBuffer: createStaticIndexBuffer,\n        getNumChannels: getNumChannels,\n        createTexture: createTexture,\n        validateTextureSize: validateTextureSize,\n        createFramebuffer: createFramebuffer,\n        bindVertexBufferToProgramAttribute: bindVertexBufferToProgramAttribute,\n        bindTextureUnit: bindTextureUnit,\n        unbindTextureUnit: unbindTextureUnit,\n        getProgramUniformLocationOrThrow: getProgramUniformLocationOrThrow,\n        getProgramUniformLocation: getProgramUniformLocation,\n        bindTextureToProgramUniformSampler: bindTextureToProgramUniformSampler,\n        bindCanvasToFramebuffer: bindCanvasToFramebuffer,\n        bindColorTextureToFramebuffer: bindColorTextureToFramebuffer,\n        unbindColorTextureFromFramebuffer: unbindColorTextureFromFramebuffer,\n        validateFramebuffer: validateFramebuffer,\n        getFramebufferErrorMessage: getFramebufferErrorMessage,\n        getBatchDim: getBatchDim,\n        getRowsCols: getRowsCols,\n        getTextureShapeFromLogicalShape: getTextureShapeFromLogicalShape,\n        isReshapeFree: isReshapeFree\n    });\n\n    function createVertexShader$1(gl) {\r\n        var glsl = getGlslDifferences();\r\n        var vertexShaderSource = glsl.version + \"\\n    precision highp float;\\n    \" + glsl.attribute + \" vec3 clipSpacePos;\\n    \" + glsl.attribute + \" vec2 uv;\\n    \" + glsl.varyingVs + \" vec2 resultUV;\\n\\n    void main() {\\n      gl_Position = vec4(clipSpacePos, 1);\\n      resultUV = uv;\\n    }\";\r\n        return createVertexShader(gl, vertexShaderSource);\r\n    }\r\n    function createVertexBuffer(gl) {\r\n        var vertexArray = new Float32Array([-1, 1, 0, 0, 1, -1, -1, 0, 0, 0, 1, 1, 0, 1, 1, 1, -1, 0, 1, 0]);\r\n        return createStaticVertexBuffer(gl, vertexArray);\r\n    }\r\n    function createIndexBuffer(gl) {\r\n        var triangleVertexIndices = new Uint16Array([0, 1, 2, 2, 1, 3]);\r\n        return createStaticIndexBuffer(gl, triangleVertexIndices);\r\n    }\r\n    function getTextureConfig(gl, textureHalfFloatExtension) {\r\n        var glany = gl;\r\n        var internalFormatFloat;\r\n        var internalFormatHalfFloat;\r\n        var internalFormatPackedFloat;\r\n        var textureFormatFloat;\r\n        var downloadTextureFormat;\r\n        var downloadUnpackNumChannels;\r\n        var defaultNumChannels;\r\n        var textureTypeHalfFloat;\r\n        if (ENV.get('WEBGL_VERSION') === 2) {\r\n            internalFormatFloat = glany.R32F;\r\n            internalFormatHalfFloat = glany.R16F;\r\n            internalFormatPackedFloat = glany.RGBA32F;\r\n            textureFormatFloat = glany.RED;\r\n            downloadUnpackNumChannels = 4;\r\n            defaultNumChannels = 1;\r\n            textureTypeHalfFloat = glany.HALF_FLOAT;\r\n        }\r\n        else {\r\n            internalFormatFloat = gl.RGBA;\r\n            internalFormatHalfFloat = gl.RGBA;\r\n            internalFormatPackedFloat = glany.RGBA;\r\n            textureFormatFloat = gl.RGBA;\r\n            downloadUnpackNumChannels = 4;\r\n            defaultNumChannels = 4;\r\n            textureTypeHalfFloat = textureHalfFloatExtension != null ?\r\n                textureHalfFloatExtension.HALF_FLOAT_OES :\r\n                null;\r\n        }\r\n        downloadTextureFormat = gl.RGBA;\r\n        return {\r\n            internalFormatFloat: internalFormatFloat,\r\n            internalFormatHalfFloat: internalFormatHalfFloat,\r\n            internalFormatPackedFloat: internalFormatPackedFloat,\r\n            textureFormatFloat: textureFormatFloat,\r\n            downloadTextureFormat: downloadTextureFormat,\r\n            downloadUnpackNumChannels: downloadUnpackNumChannels,\r\n            defaultNumChannels: defaultNumChannels,\r\n            textureTypeHalfFloat: textureTypeHalfFloat\r\n        };\r\n    }\r\n    function createAndConfigureTexture(gl, width, height, internalFormat, textureFormat, textureType) {\r\n        validateTextureSize(width, height);\r\n        var texture = createTexture(gl);\r\n        var tex2d = gl.TEXTURE_2D;\r\n        callAndCheck(gl, function () { return gl.bindTexture(tex2d, texture); });\r\n        callAndCheck(gl, function () { return gl.texParameteri(tex2d, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); });\r\n        callAndCheck(gl, function () { return gl.texParameteri(tex2d, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); });\r\n        callAndCheck(gl, function () { return gl.texParameteri(tex2d, gl.TEXTURE_MIN_FILTER, gl.NEAREST); });\r\n        callAndCheck(gl, function () { return gl.texParameteri(tex2d, gl.TEXTURE_MAG_FILTER, gl.NEAREST); });\r\n        callAndCheck(gl, function () { return gl.texImage2D(tex2d, 0, internalFormat, width, height, 0, textureFormat, textureType, null); });\r\n        callAndCheck(gl, function () { return gl.bindTexture(gl.TEXTURE_2D, null); });\r\n        return texture;\r\n    }\r\n    function createFloat32MatrixTexture(gl, rows, columns, textureConfig) {\r\n        var _a = getUnpackedMatrixTextureShapeWidthHeight(rows, columns), width = _a[0], height = _a[1];\r\n        return createAndConfigureTexture(gl, width, height, textureConfig.internalFormatFloat, textureConfig.textureFormatFloat, gl.FLOAT);\r\n    }\r\n    function createFloat16MatrixTexture(gl, rows, columns, textureConfig) {\r\n        var _a = getUnpackedMatrixTextureShapeWidthHeight(rows, columns), width = _a[0], height = _a[1];\r\n        return createAndConfigureTexture(gl, width, height, textureConfig.internalFormatFloat, textureConfig.textureFormatFloat, textureConfig.textureTypeHalfFloat);\r\n    }\r\n    function createUnsignedBytesMatrixTexture(gl, rows, columns, textureConfig) {\r\n        var _a = getUnpackedMatrixTextureShapeWidthHeight(rows, columns), width = _a[0], height = _a[1];\r\n        return createAndConfigureTexture(gl, width, height, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE);\r\n    }\r\n    function createPackedMatrixTexture(gl, rows, columns, textureConfig) {\r\n        var _a = getPackedMatrixTextureShapeWidthHeight(rows, columns), width = _a[0], height = _a[1];\r\n        return createAndConfigureTexture(gl, width, height, textureConfig.internalFormatPackedFloat, gl.RGBA, gl.FLOAT);\r\n    }\r\n    function createFloat16PackedMatrixTexture(gl, rows, columns, textureConfig) {\r\n        var _a = getPackedMatrixTextureShapeWidthHeight(rows, columns), width = _a[0], height = _a[1];\r\n        return createAndConfigureTexture(gl, width, height, textureConfig.internalFormatHalfFloat, gl.RGBA, textureConfig.textureTypeHalfFloat);\r\n    }\r\n    function bindVertexProgramAttributeStreams(gl, program, vertexBuffer) {\r\n        var posOffset = 0;\r\n        var uvOffset = 3 * 4;\r\n        var stride = (3 * 4) + (2 * 4);\r\n        callAndCheck(gl, function () { return gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); });\r\n        var success = bindVertexBufferToProgramAttribute(gl, program, 'clipSpacePos', vertexBuffer, 3, stride, posOffset);\r\n        return success &&\r\n            bindVertexBufferToProgramAttribute(gl, program, 'uv', vertexBuffer, 2, stride, uvOffset);\r\n    }\r\n    function uploadPixelDataToTexture(gl, texture, pixels) {\r\n        callAndCheck(gl, function () { return gl.bindTexture(gl.TEXTURE_2D, texture); });\r\n        callAndCheck(gl, function () { return gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, pixels); });\r\n        callAndCheck(gl, function () { return gl.bindTexture(gl.TEXTURE_2D, null); });\r\n    }\r\n    function uploadDataToTexture(gl, texture, width, height, data, textureFormat) {\r\n        validateTextureSize(width, height);\r\n        callAndCheck(gl, function () { return gl.bindTexture(gl.TEXTURE_2D, texture); });\r\n        callAndCheck(gl, function () { return gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, textureFormat, gl.FLOAT, data); });\r\n        callAndCheck(gl, function () { return gl.bindTexture(gl.TEXTURE_2D, null); });\r\n    }\r\n    function uploadMatrixToTexture(gl, texture, rows, columns, matrix, numChannels, textureConfig) {\r\n        var _a = getUnpackedMatrixTextureShapeWidthHeight(rows, columns), w = _a[0], h = _a[1];\r\n        var unpackedArray;\r\n        var numTexels = rows * columns;\r\n        if (textureConfig.defaultNumChannels === 1 && numTexels === matrix.length) {\r\n            unpackedArray = matrix;\r\n        }\r\n        else {\r\n            unpackedArray = new Float32Array(numTexels * numChannels);\r\n            encodeMatrixToUnpackedArray(matrix, unpackedArray, numChannels);\r\n        }\r\n        uploadDataToTexture(gl, texture, w, h, unpackedArray, textureConfig.textureFormatFloat);\r\n    }\r\n    function uploadMatrixToPackedTexture(gl, texture, batch, rows, columns, physicalRows, physicalCols, matrix, textureConfig) {\r\n        var _a = getPackedMatrixTextureShapeWidthHeight(physicalRows, physicalCols), w = _a[0], h = _a[1];\r\n        var packedRGBA = new Float32Array(getPackedRGBAArraySizeFromMatrixShape(physicalRows, physicalCols));\r\n        encodeMatrixToPackedRGBA(matrix, batch, rows, columns, packedRGBA);\r\n        uploadDataToTexture(gl, texture, w, h, packedRGBA, gl.RGBA);\r\n    }\r\n    function maybeCreateBufferFromOutputTexture(gl, texture, rows, columns, textureConfig) {\r\n        var bufferOrTexture = texture;\r\n        if (ENV.get('WEBGL_VERSION') === 2) {\r\n            var gl2_1 = gl;\r\n            var buffer_1 = gl2_1.createBuffer();\r\n            callAndCheck(gl, function () { return gl.bindBuffer(gl2_1.PIXEL_PACK_BUFFER, buffer_1); });\r\n            var bytesPerFloat = 4;\r\n            var bufferSizeBytes_1 = bytesPerFloat *\r\n                getUnpackedArraySizeFromMatrixSize(rows * columns, textureConfig.downloadUnpackNumChannels);\r\n            callAndCheck(gl, function () { return gl.bufferData(gl2_1.PIXEL_PACK_BUFFER, bufferSizeBytes_1, gl2_1.STREAM_READ); });\r\n            callAndCheck(gl, function () { return gl2_1.readPixels(0, 0, columns, rows, gl.RGBA, gl.FLOAT, 0); });\r\n            callAndCheck(gl, function () { return gl.bindBuffer(gl2_1.PIXEL_PACK_BUFFER, null); });\r\n            bufferOrTexture = buffer_1;\r\n        }\r\n        return bufferOrTexture;\r\n    }\r\n    function downloadFloat32MatrixFromBuffer(gl, buffer, rows, columns, textureConfig) {\r\n        var gl2 = gl;\r\n        var downloadTarget = new Float32Array(getUnpackedArraySizeFromMatrixSize(rows * columns, textureConfig.downloadUnpackNumChannels));\r\n        gl2.bindBuffer(gl2.PIXEL_PACK_BUFFER, buffer);\r\n        gl2.getBufferSubData(gl2.PIXEL_PACK_BUFFER, 0, downloadTarget);\r\n        gl2.bindBuffer(gl2.PIXEL_PACK_BUFFER, null);\r\n        var matrix = new Float32Array(rows * columns);\r\n        decodeMatrixFromUnpackedArray(downloadTarget, matrix, textureConfig.downloadUnpackNumChannels);\r\n        return matrix;\r\n    }\r\n    function downloadFloat32MatrixFromOutputTexture(gl, rows, columns, textureConfig) {\r\n        var _a = getUnpackedMatrixTextureShapeWidthHeight(rows, columns), w = _a[0], h = _a[1];\r\n        var downloadTarget = new Float32Array(getUnpackedArraySizeFromMatrixSize(rows * columns, textureConfig.downloadUnpackNumChannels));\r\n        callAndCheck(gl, function () { return gl.readPixels(0, 0, w, h, textureConfig.downloadTextureFormat, gl.FLOAT, downloadTarget); });\r\n        var matrix = new Float32Array(rows * columns);\r\n        decodeMatrixFromUnpackedArray(downloadTarget, matrix, textureConfig.downloadUnpackNumChannels);\r\n        return matrix;\r\n    }\r\n    function downloadByteEncodedFloatMatrixFromOutputTexture(gl, rows, columns, textureConfig) {\r\n        var _a = getUnpackedMatrixTextureShapeWidthHeight(rows, columns), w = _a[0], h = _a[1];\r\n        var numChannels = 4;\r\n        var downloadTarget = new Uint8Array(getUnpackedArraySizeFromMatrixSize(rows * columns, numChannels));\r\n        callAndCheck(gl, function () { return gl.readPixels(0, 0, w, h, textureConfig.downloadTextureFormat, gl.UNSIGNED_BYTE, downloadTarget); });\r\n        return new Float32Array(downloadTarget.buffer);\r\n    }\r\n    function downloadPackedMatrixFromBuffer(gl, buffer, batch, rows, cols, physicalRows, physicalCols, textureConfig) {\r\n        var gl2 = gl;\r\n        var downloadTarget = new Float32Array(getPackedRGBAArraySizeFromMatrixShape(physicalRows, physicalCols));\r\n        gl2.bindBuffer(gl2.PIXEL_PACK_BUFFER, buffer);\r\n        gl2.getBufferSubData(gl2.PIXEL_PACK_BUFFER, 0, downloadTarget);\r\n        gl2.bindBuffer(gl2.PIXEL_PACK_BUFFER, null);\r\n        var matrix = new Float32Array(sizeFromShape([batch, rows, cols]));\r\n        decodeMatrixFromPackedRGBA(downloadTarget, batch, rows, cols, matrix);\r\n        return matrix;\r\n    }\r\n    function downloadMatrixFromPackedOutputTexture(gl, batch, rows, cols, physicalRows, physicalCols, textureConfig) {\r\n        var _a = getPackedMatrixTextureShapeWidthHeight(physicalRows, physicalCols), w = _a[0], h = _a[1];\r\n        var packedRGBA = new Float32Array(getPackedRGBAArraySizeFromMatrixShape(physicalRows, physicalCols));\r\n        callAndCheck(gl, function () { return gl.readPixels(0, 0, w, h, gl.RGBA, gl.FLOAT, packedRGBA); });\r\n        var matrix = new Float32Array(sizeFromShape([batch, rows, cols]));\r\n        return decodeMatrixFromPackedRGBA(packedRGBA, batch, rows, cols, matrix);\r\n    }\n\n    var gpgpu_util = /*#__PURE__*/Object.freeze({\n        createVertexShader: createVertexShader$1,\n        createVertexBuffer: createVertexBuffer,\n        createIndexBuffer: createIndexBuffer,\n        getTextureConfig: getTextureConfig,\n        createFloat32MatrixTexture: createFloat32MatrixTexture,\n        createFloat16MatrixTexture: createFloat16MatrixTexture,\n        createUnsignedBytesMatrixTexture: createUnsignedBytesMatrixTexture,\n        createPackedMatrixTexture: createPackedMatrixTexture,\n        createFloat16PackedMatrixTexture: createFloat16PackedMatrixTexture,\n        bindVertexProgramAttributeStreams: bindVertexProgramAttributeStreams,\n        uploadPixelDataToTexture: uploadPixelDataToTexture,\n        uploadMatrixToTexture: uploadMatrixToTexture,\n        uploadMatrixToPackedTexture: uploadMatrixToPackedTexture,\n        maybeCreateBufferFromOutputTexture: maybeCreateBufferFromOutputTexture,\n        downloadFloat32MatrixFromBuffer: downloadFloat32MatrixFromBuffer,\n        downloadFloat32MatrixFromOutputTexture: downloadFloat32MatrixFromOutputTexture,\n        downloadByteEncodedFloatMatrixFromOutputTexture: downloadByteEncodedFloatMatrixFromOutputTexture,\n        downloadPackedMatrixFromBuffer: downloadPackedMatrixFromBuffer,\n        downloadMatrixFromPackedOutputTexture: downloadMatrixFromPackedOutputTexture\n    });\n\n    var GPGPUContext = (function () {\r\n        function GPGPUContext(gl) {\r\n            this.outputTexture = null;\r\n            this.program = null;\r\n            this.disposed = false;\r\n            this.autoDebugValidate = false;\r\n            this.vertexAttrsAreBound = false;\r\n            this.itemsToPoll = [];\r\n            if (gl != null) {\r\n                this.gl = gl;\r\n            }\r\n            else {\r\n                this.gl = getWebGLContext(ENV.get('WEBGL_VERSION'));\r\n            }\r\n            if (ENV.get('WEBGL_VERSION') === 1) {\r\n                this.textureFloatExtension =\r\n                    getExtensionOrThrow(this.gl, 'OES_texture_float');\r\n                this.colorBufferFloatExtension =\r\n                    this.gl.getExtension('WEBGL_color_buffer_float');\r\n                if (!ENV.get('WEBGL_RENDER_FLOAT32_ENABLED')) {\r\n                    this.textureHalfFloatExtension =\r\n                        getExtensionOrThrow(this.gl, 'OES_texture_half_float');\r\n                    this.colorBufferHalfFloatExtension =\r\n                        this.gl.getExtension('EXT_color_buffer_half_float');\r\n                }\r\n            }\r\n            else {\r\n                this.colorBufferFloatExtension =\r\n                    getExtensionOrThrow(this.gl, 'EXT_color_buffer_float');\r\n            }\r\n            this.vertexBuffer = createVertexBuffer(this.gl);\r\n            this.indexBuffer = createIndexBuffer(this.gl);\r\n            this.framebuffer = createFramebuffer(this.gl);\r\n            this.textureConfig =\r\n                getTextureConfig(this.gl, this.textureHalfFloatExtension);\r\n        }\r\n        GPGPUContext.prototype.dispose = function () {\r\n            var _this = this;\r\n            if (this.disposed) {\r\n                return;\r\n            }\r\n            if (this.program != null) {\r\n                console.warn('Disposing a GPGPUContext that still has a bound WebGLProgram.' +\r\n                    ' This is probably a resource leak, delete the program with ' +\r\n                    'GPGPUContext.deleteProgram before disposing.');\r\n            }\r\n            if (this.outputTexture != null) {\r\n                console.warn('Disposing a GPGPUContext that still has a bound output matrix ' +\r\n                    'texture.  This is probably a resource leak, delete the output ' +\r\n                    'matrix texture with GPGPUContext.deleteMatrixTexture before ' +\r\n                    'disposing.');\r\n            }\r\n            var gl = this.gl;\r\n            callAndCheck(gl, function () { return gl.finish(); });\r\n            callAndCheck(gl, function () { return gl.bindFramebuffer(gl.FRAMEBUFFER, null); });\r\n            callAndCheck(gl, function () { return gl.deleteFramebuffer(_this.framebuffer); });\r\n            callAndCheck(gl, function () { return gl.bindBuffer(gl.ARRAY_BUFFER, null); });\r\n            callAndCheck(gl, function () { return gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); });\r\n            callAndCheck(gl, function () { return gl.deleteBuffer(_this.indexBuffer); });\r\n            this.disposed = true;\r\n        };\r\n        GPGPUContext.prototype.enableAutomaticDebugValidation = function (enabled) {\r\n            this.autoDebugValidate = enabled;\r\n            enableDebugWebGLErrorChecking(enabled);\r\n        };\r\n        GPGPUContext.prototype.createFloat32MatrixTexture = function (rows, columns) {\r\n            this.throwIfDisposed();\r\n            return createFloat32MatrixTexture(this.gl, rows, columns, this.textureConfig);\r\n        };\r\n        GPGPUContext.prototype.createFloat16MatrixTexture = function (rows, columns) {\r\n            this.throwIfDisposed();\r\n            return createFloat16MatrixTexture(this.gl, rows, columns, this.textureConfig);\r\n        };\r\n        GPGPUContext.prototype.createUnsignedBytesMatrixTexture = function (rows, columns) {\r\n            this.throwIfDisposed();\r\n            return createUnsignedBytesMatrixTexture(this.gl, rows, columns, this.textureConfig);\r\n        };\r\n        GPGPUContext.prototype.uploadPixelDataToTexture = function (texture, pixels) {\r\n            this.throwIfDisposed();\r\n            uploadPixelDataToTexture(this.gl, texture, pixels);\r\n        };\r\n        GPGPUContext.prototype.createFloat16PackedMatrixTexture = function (rows, columns) {\r\n            this.throwIfDisposed();\r\n            return createFloat16PackedMatrixTexture(this.gl, rows, columns, this.textureConfig);\r\n        };\r\n        GPGPUContext.prototype.createPackedMatrixTexture = function (rows, columns) {\r\n            this.throwIfDisposed();\r\n            return createPackedMatrixTexture(this.gl, rows, columns, this.textureConfig);\r\n        };\r\n        GPGPUContext.prototype.deleteMatrixTexture = function (texture) {\r\n            var _this = this;\r\n            this.throwIfDisposed();\r\n            if (this.outputTexture === texture) {\r\n                unbindColorTextureFromFramebuffer(this.gl, this.framebuffer);\r\n                this.outputTexture = null;\r\n            }\r\n            callAndCheck(this.gl, function () { return _this.gl.deleteTexture(texture); });\r\n        };\r\n        GPGPUContext.prototype.uploadMatrixToTexture = function (texture, rows, columns, matrix) {\r\n            this.throwIfDisposed();\r\n            var numChannels = getNumChannels();\r\n            return uploadMatrixToTexture(this.gl, texture, rows, columns, matrix, numChannels, this.textureConfig);\r\n        };\r\n        GPGPUContext.prototype.uploadMatrixToPackedTexture = function (texture, batch, rows, columns, physicalRows, physicalCols, matrix) {\r\n            this.throwIfDisposed();\r\n            return uploadMatrixToPackedTexture(this.gl, texture, batch, rows, columns, physicalRows, physicalCols, matrix, this.textureConfig);\r\n        };\r\n        GPGPUContext.prototype.downloadFloat32MatrixFromOutputTexture = function (texture, rows, columns) {\r\n            var _this = this;\r\n            return this.downloadMatrixDriver(texture, function () { return downloadFloat32MatrixFromOutputTexture(_this.gl, rows, columns, _this.textureConfig); });\r\n        };\r\n        GPGPUContext.prototype.downloadByteEncodedFloatMatrixFromOutputTexture = function (texture, rows, columns) {\r\n            var _this = this;\r\n            return this.downloadMatrixDriver(texture, function () { return downloadByteEncodedFloatMatrixFromOutputTexture(_this.gl, rows, columns, _this.textureConfig); });\r\n        };\r\n        GPGPUContext.prototype.downloadPackedMatrixFromBuffer = function (buffer, batch, rows, columns, physicalRows, physicalCols) {\r\n            return downloadPackedMatrixFromBuffer(this.gl, buffer, batch, rows, columns, physicalRows, physicalCols, this.textureConfig);\r\n        };\r\n        GPGPUContext.prototype.downloadFloat32MatrixFromBuffer = function (buffer, rows, columns) {\r\n            return downloadFloat32MatrixFromBuffer(this.gl, buffer, rows, columns, this.textureConfig);\r\n        };\r\n        GPGPUContext.prototype.maybeCreateBufferFromTexture = function (texture, rows, columns) {\r\n            this.bindTextureToFrameBuffer(texture);\r\n            var result = maybeCreateBufferFromOutputTexture(this.gl, texture, rows, columns, this.textureConfig);\r\n            this.unbindTextureToFrameBuffer();\r\n            return result;\r\n        };\r\n        GPGPUContext.prototype.createAndWaitForFence = function () {\r\n            var fenceContext = this.createFence(this.gl);\r\n            return this.pollFence(fenceContext);\r\n        };\r\n        GPGPUContext.prototype.createFence = function (gl) {\r\n            var _this = this;\r\n            var query;\r\n            var isFencePassed;\r\n            if (ENV.get('WEBGL_FENCE_API_ENABLED')) {\r\n                var gl2_1 = gl;\r\n                var sync_1 = gl2_1.fenceSync(gl2_1.SYNC_GPU_COMMANDS_COMPLETE, 0);\r\n                gl.flush();\r\n                isFencePassed = function () {\r\n                    var status = gl2_1.clientWaitSync(sync_1, 0, 0);\r\n                    return status === gl2_1.ALREADY_SIGNALED ||\r\n                        status === gl2_1.CONDITION_SATISFIED;\r\n                };\r\n                query = sync_1;\r\n            }\r\n            else if (ENV.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') > 0) {\r\n                query = this.beginQuery();\r\n                this.endQuery();\r\n                isFencePassed = function () { return _this.isQueryAvailable(query, ENV.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION')); };\r\n            }\r\n            else {\r\n                isFencePassed = function () { return true; };\r\n            }\r\n            return { query: query, isFencePassed: isFencePassed };\r\n        };\r\n        GPGPUContext.prototype.downloadMatrixFromPackedTexture = function (texture, batch, rows, columns, physicalRows, physicalCols) {\r\n            var _this = this;\r\n            return this.downloadMatrixDriver(texture, function () { return downloadMatrixFromPackedOutputTexture(_this.gl, batch, rows, columns, physicalRows, physicalCols, _this.textureConfig); });\r\n        };\r\n        GPGPUContext.prototype.createProgram = function (fragmentShaderSource) {\r\n            this.throwIfDisposed();\r\n            var gl = this.gl;\r\n            var fragmentShader = createFragmentShader(gl, fragmentShaderSource);\r\n            var vertexShader = createVertexShader$1(gl);\r\n            var program = createProgram(gl);\r\n            callAndCheck(gl, function () { return gl.attachShader(program, vertexShader); });\r\n            callAndCheck(gl, function () { return gl.attachShader(program, fragmentShader); });\r\n            linkProgram(gl, program);\r\n            if (this.autoDebugValidate) {\r\n                validateProgram(gl, program);\r\n            }\r\n            if (!this.vertexAttrsAreBound) {\r\n                this.setProgram(program);\r\n                this.vertexAttrsAreBound = bindVertexProgramAttributeStreams(gl, this.program, this.vertexBuffer);\r\n            }\r\n            return program;\r\n        };\r\n        GPGPUContext.prototype.deleteProgram = function (program) {\r\n            var _this = this;\r\n            this.throwIfDisposed();\r\n            if (program === this.program) {\r\n                this.program = null;\r\n            }\r\n            if (program != null) {\r\n                callAndCheck(this.gl, function () { return _this.gl.deleteProgram(program); });\r\n            }\r\n        };\r\n        GPGPUContext.prototype.setProgram = function (program) {\r\n            var _this = this;\r\n            this.throwIfDisposed();\r\n            this.program = program;\r\n            if ((this.program != null) && this.autoDebugValidate) {\r\n                validateProgram(this.gl, this.program);\r\n            }\r\n            callAndCheck(this.gl, function () { return _this.gl.useProgram(program); });\r\n        };\r\n        GPGPUContext.prototype.getUniformLocation = function (program, uniformName, shouldThrow) {\r\n            if (shouldThrow === void 0) { shouldThrow = true; }\r\n            this.throwIfDisposed();\r\n            if (shouldThrow) {\r\n                return getProgramUniformLocationOrThrow(this.gl, program, uniformName);\r\n            }\r\n            else {\r\n                return getProgramUniformLocation(this.gl, program, uniformName);\r\n            }\r\n        };\r\n        GPGPUContext.prototype.getAttributeLocation = function (program, attribute) {\r\n            var _this = this;\r\n            this.throwIfDisposed();\r\n            return callAndCheck(this.gl, function () { return _this.gl.getAttribLocation(program, attribute); });\r\n        };\r\n        GPGPUContext.prototype.getUniformLocationNoThrow = function (program, uniformName) {\r\n            this.throwIfDisposed();\r\n            return this.gl.getUniformLocation(program, uniformName);\r\n        };\r\n        GPGPUContext.prototype.setInputMatrixTexture = function (inputMatrixTexture, uniformLocation, textureUnit) {\r\n            this.throwIfDisposed();\r\n            this.throwIfNoProgram();\r\n            bindTextureToProgramUniformSampler(this.gl, this.program, inputMatrixTexture, uniformLocation, textureUnit);\r\n        };\r\n        GPGPUContext.prototype.setOutputMatrixTexture = function (outputMatrixTexture, rows, columns) {\r\n            this.setOutputMatrixTextureDriver(outputMatrixTexture, columns, rows);\r\n        };\r\n        GPGPUContext.prototype.setOutputPackedMatrixTexture = function (outputPackedMatrixTexture, rows, columns) {\r\n            this.throwIfDisposed();\r\n            var _a = getPackedMatrixTextureShapeWidthHeight(rows, columns), width = _a[0], height = _a[1];\r\n            this.setOutputMatrixTextureDriver(outputPackedMatrixTexture, width, height);\r\n        };\r\n        GPGPUContext.prototype.setOutputMatrixWriteRegion = function (startRow, numRows, startColumn, numColumns) {\r\n            this.setOutputMatrixWriteRegionDriver(startColumn, startRow, numColumns, numRows);\r\n        };\r\n        GPGPUContext.prototype.setOutputPackedMatrixWriteRegion = function (startRow, numRows, startColumn, numColumns) {\r\n            throw new Error('setOutputPackedMatrixWriteRegion not implemented.');\r\n        };\r\n        GPGPUContext.prototype.debugValidate = function () {\r\n            if (this.program != null) {\r\n                validateProgram(this.gl, this.program);\r\n            }\r\n            validateFramebuffer(this.gl);\r\n        };\r\n        GPGPUContext.prototype.executeProgram = function () {\r\n            this.throwIfDisposed();\r\n            this.throwIfNoProgram();\r\n            var gl = this.gl;\r\n            if (this.autoDebugValidate) {\r\n                this.debugValidate();\r\n            }\r\n            callAndCheck(gl, function () { return gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); });\r\n        };\r\n        GPGPUContext.prototype.blockUntilAllProgramsCompleted = function () {\r\n            var _this = this;\r\n            this.throwIfDisposed();\r\n            callAndCheck(this.gl, function () { return _this.gl.finish(); });\r\n        };\r\n        GPGPUContext.prototype.getQueryTimerExtension = function () {\r\n            if (this.disjointQueryTimerExtension == null) {\r\n                this.disjointQueryTimerExtension =\r\n                    getExtensionOrThrow(this.gl, ENV.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') === 2 ?\r\n                        'EXT_disjoint_timer_query_webgl2' :\r\n                        'EXT_disjoint_timer_query');\r\n            }\r\n            return this.disjointQueryTimerExtension;\r\n        };\r\n        GPGPUContext.prototype.getQueryTimerExtensionWebGL2 = function () {\r\n            return this.getQueryTimerExtension();\r\n        };\r\n        GPGPUContext.prototype.getQueryTimerExtensionWebGL1 = function () {\r\n            return this.getQueryTimerExtension();\r\n        };\r\n        GPGPUContext.prototype.beginQuery = function () {\r\n            if (ENV.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') === 2) {\r\n                var gl2 = this.gl;\r\n                var ext_1 = this.getQueryTimerExtensionWebGL2();\r\n                var query_1 = gl2.createQuery();\r\n                gl2.beginQuery(ext_1.TIME_ELAPSED_EXT, query_1);\r\n                return query_1;\r\n            }\r\n            var ext = this.getQueryTimerExtensionWebGL1();\r\n            var query = ext.createQueryEXT();\r\n            ext.beginQueryEXT(ext.TIME_ELAPSED_EXT, query);\r\n            return query;\r\n        };\r\n        GPGPUContext.prototype.endQuery = function () {\r\n            if (ENV.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') === 2) {\r\n                var gl2 = this.gl;\r\n                var ext_2 = this.getQueryTimerExtensionWebGL2();\r\n                gl2.endQuery(ext_2.TIME_ELAPSED_EXT);\r\n                return;\r\n            }\r\n            var ext = this.getQueryTimerExtensionWebGL1();\r\n            ext.endQueryEXT(ext.TIME_ELAPSED_EXT);\r\n        };\r\n        GPGPUContext.prototype.waitForQueryAndGetTime = function (query) {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var _this = this;\r\n                return __generator(this, function (_a) {\r\n                    switch (_a.label) {\r\n                        case 0: return [4, repeatedTry(function () { return _this.disposed ||\r\n                                _this.isQueryAvailable(query, ENV.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION')); })];\r\n                        case 1:\r\n                            _a.sent();\r\n                            return [2, this.getQueryTime(query, ENV.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION'))];\r\n                    }\r\n                });\r\n            });\r\n        };\r\n        GPGPUContext.prototype.getQueryTime = function (query, queryTimerVersion) {\r\n            if (queryTimerVersion === 0) {\r\n                return null;\r\n            }\r\n            if (queryTimerVersion === 2) {\r\n                var gl2 = this.gl;\r\n                var timeElapsedNanos = gl2.getQueryParameter(query, gl2.QUERY_RESULT);\r\n                return timeElapsedNanos / 1000000;\r\n            }\r\n            else {\r\n                var ext = this.getQueryTimerExtensionWebGL1();\r\n                var timeElapsedNanos = ext.getQueryObjectEXT(query, ext.QUERY_RESULT_EXT);\r\n                return timeElapsedNanos / 1000000;\r\n            }\r\n        };\r\n        GPGPUContext.prototype.isQueryAvailable = function (query, queryTimerVersion) {\r\n            if (queryTimerVersion === 0) {\r\n                return true;\r\n            }\r\n            if (queryTimerVersion === 2) {\r\n                var gl2 = this.gl;\r\n                var ext = this.getQueryTimerExtensionWebGL2();\r\n                var available = gl2.getQueryParameter(query, gl2.QUERY_RESULT_AVAILABLE);\r\n                if (this.disjoint == null) {\r\n                    this.disjoint = this.gl.getParameter(ext.GPU_DISJOINT_EXT);\r\n                }\r\n                return available && !this.disjoint;\r\n            }\r\n            else {\r\n                var ext = this.getQueryTimerExtensionWebGL1();\r\n                var available = ext.getQueryObjectEXT(query, ext.QUERY_RESULT_AVAILABLE_EXT);\r\n                if (this.disjoint == null) {\r\n                    this.disjoint = this.gl.getParameter(ext.GPU_DISJOINT_EXT);\r\n                }\r\n                return available && !this.disjoint;\r\n            }\r\n        };\r\n        GPGPUContext.prototype.pollFence = function (fenceContext) {\r\n            var _this = this;\r\n            return new Promise(function (resolve) {\r\n                _this.addItemToPoll(function () { return fenceContext.isFencePassed(); }, function () { return resolve(); });\r\n            });\r\n        };\r\n        GPGPUContext.prototype.pollItems = function () {\r\n            var index = binSearchLastTrue(this.itemsToPoll.map(function (x) { return x.isDoneFn; }));\r\n            for (var i = 0; i <= index; ++i) {\r\n                var resolveFn = this.itemsToPoll[i].resolveFn;\r\n                resolveFn();\r\n            }\r\n            this.itemsToPoll = this.itemsToPoll.slice(index + 1);\r\n        };\r\n        GPGPUContext.prototype.addItemToPoll = function (isDoneFn, resolveFn) {\r\n            var _this = this;\r\n            this.itemsToPoll.push({ isDoneFn: isDoneFn, resolveFn: resolveFn });\r\n            if (this.itemsToPoll.length > 1) {\r\n                return;\r\n            }\r\n            repeatedTry(function () {\r\n                _this.pollItems();\r\n                return _this.itemsToPoll.length === 0;\r\n            });\r\n        };\r\n        GPGPUContext.prototype.bindTextureToFrameBuffer = function (texture) {\r\n            this.throwIfDisposed();\r\n            bindColorTextureToFramebuffer(this.gl, texture, this.framebuffer);\r\n            if (this.autoDebugValidate) {\r\n                validateFramebuffer(this.gl);\r\n            }\r\n        };\r\n        GPGPUContext.prototype.unbindTextureToFrameBuffer = function () {\r\n            if (this.outputTexture != null) {\r\n                bindColorTextureToFramebuffer(this.gl, this.outputTexture, this.framebuffer);\r\n                if (this.autoDebugValidate) {\r\n                    validateFramebuffer(this.gl);\r\n                }\r\n            }\r\n            else {\r\n                unbindColorTextureFromFramebuffer(this.gl, this.framebuffer);\r\n            }\r\n        };\r\n        GPGPUContext.prototype.downloadMatrixDriver = function (texture, downloadAndDecode) {\r\n            this.bindTextureToFrameBuffer(texture);\r\n            var result = downloadAndDecode();\r\n            this.unbindTextureToFrameBuffer();\r\n            return result;\r\n        };\r\n        GPGPUContext.prototype.setOutputMatrixTextureDriver = function (outputMatrixTextureMaybePacked, width, height) {\r\n            this.throwIfDisposed();\r\n            var gl = this.gl;\r\n            bindColorTextureToFramebuffer(gl, outputMatrixTextureMaybePacked, this.framebuffer);\r\n            if (this.autoDebugValidate) {\r\n                validateFramebuffer(gl);\r\n            }\r\n            this.outputTexture = outputMatrixTextureMaybePacked;\r\n            callAndCheck(gl, function () { return gl.viewport(0, 0, width, height); });\r\n            callAndCheck(gl, function () { return gl.scissor(0, 0, width, height); });\r\n        };\r\n        GPGPUContext.prototype.setOutputMatrixWriteRegionDriver = function (x, y, width, height) {\r\n            var _this = this;\r\n            this.throwIfDisposed();\r\n            callAndCheck(this.gl, function () { return _this.gl.scissor(x, y, width, height); });\r\n        };\r\n        GPGPUContext.prototype.throwIfDisposed = function () {\r\n            if (this.disposed) {\r\n                throw new Error('Attempted to use disposed GPGPUContext.');\r\n            }\r\n        };\r\n        GPGPUContext.prototype.throwIfNoProgram = function () {\r\n            if (this.program == null) {\r\n                throw new Error('No GPU program is currently set.');\r\n            }\r\n        };\r\n        return GPGPUContext;\r\n    }());\r\n    function binSearchLastTrue(arr) {\r\n        var start = 0;\r\n        var end = arr.length - 1;\r\n        var best = -1;\r\n        while (start <= end) {\r\n            var mid = (start + end) >> 1;\r\n            var isDone = arr[mid]();\r\n            if (isDone) {\r\n                best = mid;\r\n                start = mid + 1;\r\n            }\r\n            else {\r\n                end = mid - 1;\r\n            }\r\n        }\r\n        return best;\r\n    }\n\n    function compileProgram(gpgpu, program, inputs, output) {\r\n        var userCode = program.userCode;\r\n        var inputInfos = inputs.map(function (input, i) {\r\n            var shapeInfo = {\r\n                logicalShape: input.shape,\r\n                texShape: input.isUniform ? null : input.texData.texShape,\r\n                isUniform: input.isUniform,\r\n                isPacked: input.isUniform ? false : input.texData.isPacked,\r\n                flatOffset: null\r\n            };\r\n            if (input.texData != null && input.texData.slice != null &&\r\n                input.texData.slice.flatOffset > 0) {\r\n                shapeInfo.flatOffset = input.texData.slice.flatOffset;\r\n            }\r\n            return { name: program.variableNames[i], shapeInfo: shapeInfo };\r\n        });\r\n        var inShapeInfos = inputInfos.map(function (x) { return x.shapeInfo; });\r\n        var outShapeInfo = {\r\n            logicalShape: output.shape,\r\n            texShape: output.texData.texShape,\r\n            isUniform: false,\r\n            isPacked: output.texData.isPacked,\r\n            flatOffset: null\r\n        };\r\n        var source = makeShader(inputInfos, outShapeInfo, userCode, program.usesPackedTextures);\r\n        var webGLProgram = gpgpu.createProgram(source);\r\n        var uniformLocations = {};\r\n        for (var i = 0; i < program.variableNames.length; i++) {\r\n            var varName = program.variableNames[i];\r\n            var shouldThrow = false;\r\n            uniformLocations[varName] =\r\n                gpgpu.getUniformLocation(webGLProgram, varName, shouldThrow);\r\n            uniformLocations[\"offset\" + varName] =\r\n                gpgpu.getUniformLocation(webGLProgram, \"offset\" + varName, shouldThrow);\r\n        }\r\n        return {\r\n            program: program,\r\n            source: source,\r\n            webGLProgram: webGLProgram,\r\n            uniformLocations: uniformLocations,\r\n            gpgpu: gpgpu,\r\n            inShapeInfos: inShapeInfos,\r\n            outShapeInfo: outShapeInfo\r\n        };\r\n    }\r\n    function validateBinaryAndProgram(shapeInfos, inputs) {\r\n        if (shapeInfos.length !== inputs.length) {\r\n            throw Error(\"Binary was compiled with \" + shapeInfos.length + \" inputs, but \" +\r\n                (\"was executed with \" + inputs.length + \" inputs\"));\r\n        }\r\n        shapeInfos.forEach(function (s, i) {\r\n            var shapeA = s.logicalShape;\r\n            var input = inputs[i];\r\n            var shapeB = input.shape;\r\n            if (!arraysEqual(shapeA, shapeB)) {\r\n                throw Error(\"Binary was compiled with different shapes than \" +\r\n                    (\"the current args. Shapes \" + shapeA + \" and \" + shapeB + \" must match\"));\r\n            }\r\n            if (s.isUniform && input.isUniform) {\r\n                return;\r\n            }\r\n            var texShapeA = s.texShape;\r\n            var texShapeB = input.isUniform ? null : input.texData.texShape;\r\n            if (!arraysEqual(texShapeA, texShapeB)) {\r\n                throw Error(\"Binary was compiled with different texture shapes than the\" +\r\n                    (\" current args. Shape \" + texShapeA + \" and \" + texShapeB + \" must match\"));\r\n            }\r\n        });\r\n    }\r\n    function runProgram(binary, inputs, output, customSetup) {\r\n        validateBinaryAndProgram(binary.inShapeInfos, inputs);\r\n        validateBinaryAndProgram([binary.outShapeInfo], [output]);\r\n        var outTex = output.texData.texture;\r\n        var outTexShape = output.texData.texShape;\r\n        var gpgpu = binary.gpgpu;\r\n        if (output.texData.isPacked) {\r\n            gpgpu.setOutputPackedMatrixTexture(outTex, outTexShape[0], outTexShape[1]);\r\n        }\r\n        else {\r\n            gpgpu.setOutputMatrixTexture(outTex, outTexShape[0], outTexShape[1]);\r\n        }\r\n        gpgpu.setProgram(binary.webGLProgram);\r\n        inputs.forEach(function (input, i) {\r\n            var varName = binary.program.variableNames[i];\r\n            var varLoc = binary.uniformLocations[varName];\r\n            var varOffsetLoc = binary.uniformLocations[\"offset\" + varName];\r\n            if (varLoc == null) {\r\n                return;\r\n            }\r\n            if (input.isUniform) {\r\n                if (sizeFromShape(input.shape) === 1) {\r\n                    gpgpu.gl.uniform1f(varLoc, input.uniformValues[0]);\r\n                }\r\n                else {\r\n                    var vals = input.uniformValues;\r\n                    if (!(vals instanceof Float32Array)) {\r\n                        vals = new Float32Array(vals);\r\n                    }\r\n                    gpgpu.gl.uniform1fv(varLoc, vals);\r\n                }\r\n                return;\r\n            }\r\n            if (input.texData.slice != null && varOffsetLoc != null) {\r\n                gpgpu.gl.uniform1i(varOffsetLoc, input.texData.slice.flatOffset);\r\n            }\r\n            gpgpu.setInputMatrixTexture(input.texData.texture, varLoc, i);\r\n        });\r\n        if (customSetup != null) {\r\n            customSetup(gpgpu, binary.webGLProgram);\r\n        }\r\n        gpgpu.executeProgram();\r\n    }\r\n    function makeShaderKey(program, inputs, output) {\r\n        var keyInputs = '';\r\n        inputs.concat(output).forEach(function (x) {\r\n            var hasOffset = x.texData != null && x.texData.slice != null &&\r\n                x.texData.slice.flatOffset > 0;\r\n            var texShape = x.isUniform ? 'uniform' : x.texData.texShape;\r\n            keyInputs += x.shape + \"_\" + texShape + \"_\" + hasOffset;\r\n        });\r\n        var keyUserCode = program.userCode;\r\n        var key = program.constructor.name;\r\n        key += '_' + keyInputs + '_' + keyUserCode;\r\n        return key;\r\n    }\n\n    var Im2ColProgram = (function () {\r\n        function Im2ColProgram(outputShape, inputShape, convInfo) {\r\n            this.variableNames = ['A'];\r\n            this.outputShape = outputShape;\r\n            var filterWidth = convInfo.filterWidth, inChannels = convInfo.inChannels, strideWidth = convInfo.strideWidth, strideHeight = convInfo.strideHeight, padInfo = convInfo.padInfo, outWidth = convInfo.outWidth, dilationWidth = convInfo.dilationWidth, dilationHeight = convInfo.dilationHeight;\r\n            var left = padInfo.left, top = padInfo.top;\r\n            var itemsPerBlockRow = inChannels * filterWidth;\r\n            var glsl = getGlslDifferences();\r\n            this.userCode = \"\\n      void main() {\\n        ivec2 rc = getOutputCoords();\\n\\n        vec4 result = vec4(0);\\n\\n        for(int row=0; row<=1; row++) {\\n          for(int col=0; col<=1; col++) {\\n            int blockIndex = rc.y + col;\\n            int pos = rc.x + row;\\n\\n            if(blockIndex >= \" + outputShape[1] + \" || pos >= \" + outputShape[0] + \") continue;\\n\\n            int offsetY = int(blockIndex / (\" + outWidth + \")) * \" + strideHeight + \" - \" + top + \";\\n            int d0 = offsetY + \" + dilationHeight + \" * (pos / \" + itemsPerBlockRow + \");\\n\\n            if(d0 >= \" + inputShape[0] + \" || d0 < 0) continue;\\n\\n            int offsetX = int(mod(float(blockIndex), \" + outWidth + \".) * \" + strideWidth + \". - \" + left + \".);\\n            int d1 = offsetX + \" + dilationWidth + \" * (int(mod(float(pos), \" + itemsPerBlockRow + \".) / \" + inChannels + \".));\\n\\n            if(d1 >= \" + inputShape[1] + \" || d1 < 0) continue;\\n\\n            result[row * 2 + col] = getA(d0, d1, int(mod(float(pos), \" + inChannels + \".)));\\n          }\\n        }\\n\\n        \" + glsl.output + \" = result;\\n      }\\n    \";\r\n        }\r\n        return Im2ColProgram;\r\n    }());\n\n    var LRNProgram = (function () {\r\n        function LRNProgram(xShape, radius, bias, alpha, beta) {\r\n            this.variableNames = ['x'];\r\n            this.outputShape = [];\r\n            var rad = radius;\r\n            var maxD = xShape[3] - 1;\r\n            this.outputShape = xShape;\r\n            var powOperator;\r\n            var basis = \"float(\" + bias + \") + float(\" + alpha + \") * sum\";\r\n            if (beta === 0.5) {\r\n                powOperator = \"inversesqrt(\" + basis + \")\";\r\n            }\r\n            else if (beta === 1.0) {\r\n                powOperator = \"1.0/(\" + basis + \")\";\r\n            }\r\n            else {\r\n                powOperator = \"exp(log(\" + basis + \") * float(-\" + beta + \"));\";\r\n            }\r\n            this.userCode = \"\\n      void main() {\\n        ivec4 coords = getOutputCoords();\\n        int b = coords[0];\\n        int r = coords[1];\\n        int c = coords[2];\\n        int d = coords[3];\\n        float x = getX(b, r, c, d);\\n        float sum = 0.0;\\n        for (int j = -\" + rad + \"; j <= \" + rad + \"; j++) {\\n          int idx = d + j;\\n          if (idx >= 0 && idx <=  \" + maxD + \") {\\n            float z = getX(b, r, c, idx);\\n            sum += z * z;\\n          }\\n        }\\n        float val = x * \" + powOperator + \";\\n        setOutput(val);\\n      }\\n    \";\r\n        }\r\n        return LRNProgram;\r\n    }());\n\n    var LRNGradProgram = (function () {\r\n        function LRNGradProgram(inputShape, depthRadius, bias, alpha, beta) {\r\n            this.variableNames = ['inputImage', 'outputImage', 'dy'];\r\n            this.outputShape = [];\r\n            this.outputShape = inputShape;\r\n            this.depth = inputShape[3];\r\n            this.depthRadius = depthRadius;\r\n            this.bias = bias;\r\n            this.alpha = alpha;\r\n            this.beta = beta;\r\n            this.userCode = \"\\n      void main() {\\n        ivec4 coords = getOutputCoords();\\n        int b = coords[0];\\n        int r = coords[1];\\n        int c = coords[2];\\n\\n        float result = 0.0;\\n        for (int d = 0; d < \" + this.depth + \"; ++d) {\\n          int depthBegin = int(max(0.0, float(d - \" + depthRadius + \")));\\n          int depthEnd = int(min(float(\" + this.depth + \"),\\n              float(d + \" + depthRadius + \" + 1)));\\n\\n          const int MIN_DEPTH_BEGIN = 0;\\n          const int MAX_DEPTH_END = \" + this.depth + \";\\n\\n          float norm = 0.0;\\n          for (int k = MIN_DEPTH_BEGIN; k < MAX_DEPTH_END; ++k) {\\n            if (k < depthBegin){\\n              continue;\\n            }\\n            else if (k >= depthBegin && k < depthEnd) {\\n              norm += getInputImage(b, r, c, k) * getInputImage(b, r, c, k);\\n            }\\n            else {\\n              break;\\n            }\\n          }\\n\\n          norm = float(\" + alpha + \") * norm + float(\" + bias + \");\\n\\n          for(int k = MIN_DEPTH_BEGIN; k < MAX_DEPTH_END; ++k){\\n            if (k < depthBegin){\\n              continue;\\n            }\\n            else if (k >= depthBegin && k < depthEnd){\\n              float dyi = -2.0 * float(\" + alpha + \")\\n                * float(\" + beta + \")\\n                * getInputImage(b ,r ,c, k) * getOutputImage(b, r, c, d)\\n                / norm;\\n              if (k == d) {\\n                dyi += pow(norm, -1.0 * \" + beta + \");\\n              }\\n              if (k == coords[3]) {\\n                dyi *= getDy(b, r, c, d);\\n                result += dyi;\\n              }\\n            }\\n            else {\\n              break;\\n            }\\n          }\\n      }\\n      setOutput(result);\\n      }\\n    \";\r\n        }\r\n        return LRNGradProgram;\r\n    }());\n\n    var MaxPool2DBackpropProgram = (function () {\r\n        function MaxPool2DBackpropProgram(convInfo) {\r\n            this.variableNames = ['dy', 'maxPos'];\r\n            this.outputShape = convInfo.inShape;\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var dilationHeight = convInfo.dilationHeight;\r\n            var effectiveFilterHeight = convInfo.effectiveFilterHeight;\r\n            var effectiveFilterWidth = convInfo.effectiveFilterWidth;\r\n            var padTop = effectiveFilterHeight - 1 - convInfo.padInfo.top;\r\n            var padLeft = effectiveFilterWidth - 1 - convInfo.padInfo.left;\r\n            var lastIndex = effectiveFilterHeight * effectiveFilterWidth - 1;\r\n            this.userCode = \"\\n      const ivec2 pads = ivec2(\" + padTop + \", \" + padLeft + \");\\n\\n      void main() {\\n        ivec4 coords = getOutputCoords();\\n        int b = coords[0];\\n        int d = coords[3];\\n\\n        ivec2 dyRCCorner = coords.yz - pads;\\n        int dyRCorner = dyRCCorner.x;\\n        int dyCCorner = dyRCCorner.y;\\n\\n        // Convolve dy(?, ?, d) with pos mask(:, :, d) to get dx(xR, xC, d).\\n        // ? = to be determined. : = across all values in that axis.\\n        float dotProd = 0.0;\\n        for (int wR = 0; wR < \" + effectiveFilterHeight + \";\\n          wR += \" + dilationHeight + \") {\\n          float dyR = float(dyRCorner + wR) / \" + strideHeight + \".0;\\n\\n          if (dyR < 0.0 || dyR >= \" + convInfo.outHeight + \".0 || fract(dyR) > 0.0) {\\n            continue;\\n          }\\n          int idyR = int(dyR);\\n\\n          for (int wC = 0; wC < \" + effectiveFilterWidth + \"; wC++) {\\n            float dyC = float(dyCCorner + wC) / \" + strideWidth + \".0;\\n\\n            if (dyC < 0.0 || dyC >= \" + convInfo.outWidth + \".0 ||\\n                fract(dyC) > 0.0) {\\n              continue;\\n            }\\n            int idyC = int(dyC);\\n\\n            float dyValue = getDy(b, idyR, idyC, d);\\n            int maxPosValue = \" + lastIndex + \" - int(getMaxPos(b, idyR, idyC, d));\\n\\n            // Get the current value, check it against the value from the\\n            // position matrix.\\n            int curPosValue = wR * \" + effectiveFilterWidth + \" + wC;\\n            float mask = float(maxPosValue == curPosValue ? 1.0 : 0.0);\\n\\n            dotProd += dyValue * mask;\\n          }\\n        }\\n        setOutput(dotProd);\\n      }\\n    \";\r\n        }\r\n        return MaxPool2DBackpropProgram;\r\n    }());\n\n    var MatMulProgram = (function () {\r\n        function MatMulProgram(aShape, bShape, transposeA, transposeB, addBias, activation) {\r\n            if (transposeA === void 0) { transposeA = false; }\r\n            if (transposeB === void 0) { transposeB = false; }\r\n            if (addBias === void 0) { addBias = false; }\r\n            if (activation === void 0) { activation = null; }\r\n            this.variableNames = ['matrixA', 'matrixB'];\r\n            var batchSize = aShape[0];\r\n            var outerShapeA = transposeA ? aShape[2] : aShape[1];\r\n            var outerShapeB = transposeB ? bShape[1] : bShape[2];\r\n            var sharedDim = transposeA ? aShape[1] : aShape[2];\r\n            this.outputShape = [batchSize, outerShapeA, outerShapeB];\r\n            var aSnippetFromOffset = function (vec4Offset, indexVar) {\r\n                return transposeA ? \"batch, \" + indexVar + \" + \" + vec4Offset + \", aRow\" :\r\n                    \"batch, aRow, \" + indexVar + \" + \" + vec4Offset;\r\n            };\r\n            var bSnippetFromOffset = function (vec4Offset, indexVar) {\r\n                return transposeB ? \"batch, bCol, \" + indexVar + \" + \" + vec4Offset :\r\n                    \"batch, \" + indexVar + \" + \" + vec4Offset + \", bCol\";\r\n            };\r\n            var sharedDimNearestVec4 = Math.floor(sharedDim / 4) * 4;\r\n            var sharedDimVec4Remainder = sharedDim % 4;\r\n            var activationSnippet = '', applyActivationSnippet = '';\r\n            if (activation) {\r\n                activationSnippet = \"float activation(float x) {\\n        \" + activation + \"\\n      }\";\r\n                applyActivationSnippet = \"result = activation(result);\";\r\n            }\r\n            var addBiasSnippet = addBias ? 'result += getBiasAtOutCoords();' : '';\r\n            if (addBias) {\r\n                this.variableNames.push('bias');\r\n            }\r\n            this.userCode = \"\\n      \" + activationSnippet + \"\\n\\n      float dotARowBCol(int batch, int aRow, int bCol) {\\n        float result = 0.0;\\n        for (int i = 0; i < \" + sharedDimNearestVec4 + \"; i += 4) {\\n          vec4 a = vec4(\\n            getMatrixA(\" + aSnippetFromOffset(0, 'i') + \"),\\n            getMatrixA(\" + aSnippetFromOffset(1, 'i') + \"),\\n            getMatrixA(\" + aSnippetFromOffset(2, 'i') + \"),\\n            getMatrixA(\" + aSnippetFromOffset(3, 'i') + \")\\n          );\\n          vec4 b = vec4(\\n            getMatrixB(\" + bSnippetFromOffset(0, 'i') + \"),\\n            getMatrixB(\" + bSnippetFromOffset(1, 'i') + \"),\\n            getMatrixB(\" + bSnippetFromOffset(2, 'i') + \"),\\n            getMatrixB(\" + bSnippetFromOffset(3, 'i') + \")\\n          );\\n\\n          result += dot(a, b);\\n        }\\n\\n        if (\" + (sharedDimVec4Remainder === 1) + \") {\\n          result += getMatrixA(\" + aSnippetFromOffset(0, sharedDimNearestVec4) + \") *\\n            getMatrixB(\" + bSnippetFromOffset(0, sharedDimNearestVec4) + \");\\n        } else if (\" + (sharedDimVec4Remainder === 2) + \") {\\n          vec2 a = vec2(\\n            getMatrixA(\" + aSnippetFromOffset(0, sharedDimNearestVec4) + \"),\\n            getMatrixA(\" + aSnippetFromOffset(1, sharedDimNearestVec4) + \")\\n          );\\n          vec2 b = vec2(\\n            getMatrixB(\" + bSnippetFromOffset(0, sharedDimNearestVec4) + \"),\\n            getMatrixB(\" + bSnippetFromOffset(1, sharedDimNearestVec4) + \")\\n          );\\n          result += dot(a, b);\\n        } else if (\" + (sharedDimVec4Remainder === 3) + \") {\\n          vec3 a = vec3(\\n            getMatrixA(\" + aSnippetFromOffset(0, sharedDimNearestVec4) + \"),\\n            getMatrixA(\" + aSnippetFromOffset(1, sharedDimNearestVec4) + \"),\\n            getMatrixA(\" + aSnippetFromOffset(2, sharedDimNearestVec4) + \")\\n          );\\n          vec3 b = vec3(\\n            getMatrixB(\" + bSnippetFromOffset(0, sharedDimNearestVec4) + \"),\\n            getMatrixB(\" + bSnippetFromOffset(1, sharedDimNearestVec4) + \"),\\n            getMatrixB(\" + bSnippetFromOffset(2, sharedDimNearestVec4) + \")\\n          );\\n          result += dot(a, b);\\n        }\\n\\n        return result;\\n      }\\n\\n      void main() {\\n        ivec3 resBRC = getOutputCoords();\\n        float result = dotARowBCol(resBRC.x, resBRC.y, resBRC.z);\\n\\n        \" + addBiasSnippet + \"\\n\\n        \" + applyActivationSnippet + \"\\n\\n        setOutput(result);\\n      }\\n    \";\r\n        }\r\n        return MatMulProgram;\r\n    }());\n\n    var MatMulPackedProgram = (function () {\r\n        function MatMulPackedProgram(aShape, bShape, outputShape, transposeA, transposeB, addBias, activation) {\r\n            if (transposeA === void 0) { transposeA = false; }\r\n            if (transposeB === void 0) { transposeB = false; }\r\n            if (addBias === void 0) { addBias = false; }\r\n            if (activation === void 0) { activation = null; }\r\n            this.variableNames = ['matrixA', 'matrixB'];\r\n            this.usesPackedTextures = true;\r\n            this.outputShape = outputShape;\r\n            var sharedDim = transposeA ? aShape[0] : aShape[1];\r\n            var sharedDimensionPacked = Math.ceil(sharedDim / 2);\r\n            var aSample = transposeA ? 'i * 2, rc.x' : 'rc.x, i * 2';\r\n            var bSample = transposeB ? 'rc.y, i * 2' : 'i * 2, rc.y';\r\n            var aSwizzle = transposeA ? ['a.xxyy', 'a.zzww'] : ['a.xxzz', 'a.yyww'];\r\n            var bSwizzle = transposeB ? ['b.xzxz', 'b.ywyw'] : ['b.xyxy', 'b.zwzw'];\r\n            var activationSnippet = '', applyActivationSnippet = '';\r\n            if (activation) {\r\n                activationSnippet = \"vec4 activation(vec4 x) {\\n        \" + activation + \"\\n      }\";\r\n                applyActivationSnippet = \"result = activation(result);\";\r\n            }\r\n            var addBiasSnippet = addBias ? 'result += getBiasAtOutCoords();' : '';\r\n            if (addBias) {\r\n                this.variableNames.push('bias');\r\n            }\r\n            this.userCode = \"\\n      \" + activationSnippet + \"\\n\\n      const float sharedDimension = \" + sharedDimensionPacked + \".0;\\n\\n      vec4 dot2x2ARowBCol(ivec2 rc) {\\n        vec4 result = vec4(0);\\n        for (int i = 0; i < \" + sharedDimensionPacked + \"; i++) {\\n          vec4 a = getMatrixA(\" + aSample + \");\\n          vec4 b = getMatrixB(\" + bSample + \");\\n\\n          result += (\" + aSwizzle[0] + \" * \" + bSwizzle[0] + \") + (\" + aSwizzle[1] + \" * \" + bSwizzle[1] + \");\\n        }\\n        return result;\\n      }\\n\\n      void main() {\\n        ivec2 rc = getOutputCoords();\\n        vec4 result = dot2x2ARowBCol(rc);\\n\\n        \" + addBiasSnippet + \"\\n\\n        \" + applyActivationSnippet + \"\\n\\n        setOutput(result);\\n      }\\n    \";\r\n        }\r\n        return MatMulPackedProgram;\r\n    }());\n\n    var MultinomialProgram = (function () {\r\n        function MultinomialProgram(batchSize, numOutcomes, numSamples) {\r\n            this.variableNames = ['probs'];\r\n            this.outputShape = [batchSize, numSamples];\r\n            this.userCode = \"\\n      uniform float seed;\\n\\n      void main() {\\n        ivec2 coords = getOutputCoords();\\n        int batch = coords[0];\\n\\n        float r = random(seed);\\n        float cdf = 0.0;\\n\\n        for (int i = 0; i < \" + (numOutcomes - 1) + \"; i++) {\\n          cdf += getProbs(batch, i);\\n\\n          if (r < cdf) {\\n            setOutput(float(i));\\n            return;\\n          }\\n        }\\n\\n        // If no other event happened, last event happened.\\n        setOutput(float(\" + (numOutcomes - 1) + \"));\\n      }\\n    \";\r\n        }\r\n        MultinomialProgram.prototype.getCustomSetupFunc = function (seed) {\r\n            var _this = this;\r\n            return function (gpgpu, webGLProgram) {\r\n                if (_this.seedLoc == null) {\r\n                    _this.seedLoc = gpgpu.getUniformLocation(webGLProgram, 'seed');\r\n                }\r\n                gpgpu.gl.uniform1f(_this.seedLoc, seed);\r\n            };\r\n        };\r\n        return MultinomialProgram;\r\n    }());\n\n    var OneHotProgram = (function () {\r\n        function OneHotProgram(numIndices, depth, onValue, offValue) {\r\n            this.variableNames = ['indices'];\r\n            this.outputShape = [numIndices, depth];\r\n            this.userCode = \"\\n      void main() {\\n        ivec2 coords = getOutputCoords();\\n        int index = round(getIndices(coords.x));\\n        setOutput(mix(float(\" + offValue + \"), float(\" + onValue + \"),\\n                      float(index == coords.y)));\\n      }\\n    \";\r\n        }\r\n        return OneHotProgram;\r\n    }());\n\n    function getVecChannels(name, rank) {\r\n        return ['x', 'y', 'z', 'w', 'u', 'v'].slice(0, rank).map(function (d) { return name + \".\" + d; });\r\n    }\r\n    function getChannels(name, rank) {\r\n        if (rank === 1) {\r\n            return [name];\r\n        }\r\n        return getVecChannels(name, rank);\r\n    }\r\n    function getSourceCoords$1(rank, dims) {\r\n        if (rank === 1) {\r\n            return 'rc';\r\n        }\r\n        var coords = '';\r\n        for (var i = 0; i < rank; i++) {\r\n            coords += dims[i];\r\n            if (i < rank - 1) {\r\n                coords += ',';\r\n            }\r\n        }\r\n        return coords;\r\n    }\n\n    var PackProgram = (function () {\r\n        function PackProgram(outputShape) {\r\n            this.variableNames = ['A'];\r\n            this.isPackShader = true;\r\n            this.outputShape = outputShape;\r\n            var rank = outputShape.length;\r\n            if (rank === 0) {\r\n                this.userCode = \"\\n        void main() {\\n          setOutput(vec4(getA(), 0., 0., 0.));\\n        }\\n      \";\r\n            }\r\n            else {\r\n                var channels = getChannels('rc', rank);\r\n                var dtype = getCoordsDataType(rank);\r\n                var outOfBoundsCondition = getOutOfBoundsCondition(rank, outputShape, channels);\r\n                var setup = getSetup(rank, outputShape[outputShape.length - 1], outputShape[outputShape.length - 2], channels);\r\n                var output = getOutput(outputShape, channels);\r\n                this.userCode = \"\\n        void main() {\\n          \" + dtype + \" rc = getOutputCoords();\\n\\n          if(\" + outOfBoundsCondition + \") {\\n            setOutput(vec4(0));\\n          } else {\\n            \" + setup + \"\\n\\n            setOutput(vec4(\" + output + \"));\\n          }\\n        }\\n      \";\r\n            }\r\n        }\r\n        return PackProgram;\r\n    }());\r\n    function getSourceCoordsArr(rank, dims) {\r\n        var coords = [];\r\n        for (var row = 0; row <= 1; row++) {\r\n            for (var col = 0; col <= 1; col++) {\r\n                var coord = (row === 0 ? 'r' : 'rp1') + \", \" + (col === 0 ? 'c' : 'cp1');\r\n                for (var d = 2; d < rank; d++) {\r\n                    coord = dims[dims.length - 1 - d] + \",\" + coord;\r\n                }\r\n                coords.push(coord);\r\n            }\r\n        }\r\n        return coords;\r\n    }\r\n    function getOutOfBoundsCondition(rank, shape, dims) {\r\n        if (rank === 1) {\r\n            return \"rc > \" + shape[0];\r\n        }\r\n        var cond = '';\r\n        for (var i = rank - 2; i < rank; i++) {\r\n            cond += dims[i] + \" >= \" + shape[i];\r\n            if (i < rank - 1) {\r\n                cond += '||';\r\n            }\r\n        }\r\n        return cond;\r\n    }\r\n    function getSetup(rank, cols, rows, dims) {\r\n        if (rank === 1) {\r\n            return '';\r\n        }\r\n        var innerDims = dims.slice(-2);\r\n        return \"\\n    int r = \" + innerDims[0] + \";\\n    int c = \" + innerDims[1] + \";\\n    int rp1 = r + 1;\\n    int cp1 = c + 1;\\n\\n    bool cEdge = cp1 >= \" + cols + \";\\n    bool rEdge = rp1 >= \" + rows + \";\\n  \";\r\n    }\r\n    function getOutput(shape, dims) {\r\n        var rank = shape.length;\r\n        var sourceCoords = getSourceCoordsArr(rank, dims);\r\n        if (rank === 1) {\r\n            return \"getA(rc),\\n            rc + 1 >= \" + shape[0] + \" ? 0. : getA(rc + 1),\\n            0, 0\";\r\n        }\r\n        return \"getA(\" + sourceCoords[0] + \"),\\n          cEdge ? 0. : getA(\" + sourceCoords[1] + \"),\\n          rEdge ? 0. : getA(\" + sourceCoords[2] + \"),\\n          rEdge || cEdge ? 0. : getA(\" + sourceCoords[3] + \")\";\r\n    }\n\n    var PadProgram = (function () {\r\n        function PadProgram(xShape, paddings, constantValue) {\r\n            this.variableNames = ['x'];\r\n            this.outputShape = paddings.map(function (p, i) { return p[0] + xShape[i] + p[1]; });\r\n            var rank = xShape.length;\r\n            var type = getCoordsDataType(rank);\r\n            var start = paddings.map(function (p) { return p[0]; }).join(',');\r\n            var end = paddings.map(function (p, i) { return p[0] + xShape[i]; }).join(',');\r\n            var unpackedCoords = ['coords[0]', 'coords[1]', 'coords[2]', 'coords[3]'].slice(0, rank);\r\n            if (rank === 1) {\r\n                this.userCode = \"\\n        int start = \" + start + \";\\n        int end = \" + end + \";\\n\\n        void main() {\\n          int outC = getOutputCoords();\\n          if (outC < start || outC >= end) {\\n            setOutput(float(\" + constantValue + \"));\\n          } else {\\n            setOutput(getX(outC - start));\\n          }\\n        }\\n      \";\r\n                return;\r\n            }\r\n            this.userCode = \"\\n      \" + type + \" start = \" + type + \"(\" + start + \");\\n      \" + type + \" end = \" + type + \"(\" + end + \");\\n\\n      void main() {\\n        \" + type + \" outC = getOutputCoords();\\n        if (any(lessThan(outC, start)) || any(greaterThanEqual(outC, end))) {\\n          setOutput(float(\" + constantValue + \"));\\n        } else {\\n          \" + type + \" coords = outC - start;\\n          setOutput(getX(\" + unpackedCoords + \"));\\n        }\\n      }\\n    \";\r\n        }\r\n        return PadProgram;\r\n    }());\n\n    var PadPackedProgram = (function () {\r\n        function PadPackedProgram(xShape, paddings, constantValue) {\r\n            this.variableNames = ['x'];\r\n            this.usesPackedTextures = true;\r\n            this.outputShape = paddings.map(function (p, i) { return p[0] + xShape[i] + p[1]; });\r\n            var rank = xShape.length;\r\n            var dtype = getCoordsDataType(rank);\r\n            var start = paddings.map(function (p) { return p[0]; }).join(',');\r\n            var end = paddings.map(function (p, i) { return p[0] + xShape[i]; }).join(',');\r\n            var coords = getChannels('rc', rank);\r\n            var source = getChannels('source', rank);\r\n            var cLimit = coords[rank - 1] + \" < \" + this.outputShape[rank - 1];\r\n            var innerDims = rank === 1 ? 'source' : \"vec2(\" + source.slice(-2).join() + \")\";\r\n            var componentSetup = [\r\n                dtype + \" rc = outputLoc;\",\r\n                coords[rank - 1] + \" += 1;\\n       if(\" + cLimit + \") {\\n      \",\r\n                rank === 1 ? '' :\r\n                    \"}\\n       rc = outputLoc;\\n       \" + coords[rank - 2] + \" += 1;\\n       if(\" + coords[rank - 2] + \" < \" + this.outputShape[rank - 2] + \") {\",\r\n                rank === 1 ? '' :\r\n                    \"  \" + coords[rank - 1] + \" += 1;\\n         if(\" + cLimit + \") {\"\r\n            ];\r\n            var paddingArea = rank === 1 ?\r\n                'rc < start || rc >= end' :\r\n                'any(lessThan(rc, start)) || any(greaterThanEqual(rc, end))';\r\n            var mainLoop = '';\r\n            for (var i = 0, j = rank === 1 ? 2 : 4; i < j; i++) {\r\n                mainLoop += \"\\n        \" + componentSetup[i] + \"\\n        if (\" + paddingArea + \") {\\n          result[\" + i + \"] = float(\" + constantValue + \");\\n        } else {\\n          \" + dtype + \" source = rc - start;\\n          result[\" + i + \"] = getChannel(getX(\" + source.join() + \"), \" + innerDims + \");\\n        }\\n      \";\r\n            }\r\n            mainLoop += (rank === 1 ? \"} \" : \"}}\");\r\n            this.userCode = \"\\n      const \" + dtype + \" start = \" + dtype + \"(\" + start + \");\\n      const \" + dtype + \" end = \" + dtype + \"(\" + end + \");\\n\\n      void main() {\\n        \" + dtype + \" outputLoc = getOutputCoords();\\n        vec4 result = vec4(0.);\\n        \" + mainLoop + \"\\n        setOutput(result);\\n      }\\n    \";\r\n        }\r\n        return PadPackedProgram;\r\n    }());\n\n    var Pool2DProgram = (function () {\r\n        function Pool2DProgram(convInfo, poolType, computePositions) {\r\n            this.variableNames = ['x'];\r\n            if (poolType === 'avg' && computePositions) {\r\n                throw new Error('Cannot compute positions for average pool.');\r\n            }\r\n            var filterWidth = convInfo.filterWidth;\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var dilationHeight = convInfo.dilationHeight;\r\n            var dilationWidth = convInfo.dilationWidth;\r\n            var effectiveFilterHeight = convInfo.effectiveFilterHeight;\r\n            var effectiveFilterWidth = convInfo.effectiveFilterWidth;\r\n            var padTop = convInfo.padInfo.top;\r\n            var padLeft = convInfo.padInfo.left;\r\n            this.outputShape = convInfo.outShape;\r\n            var isAvgPool = poolType === 'avg';\r\n            var initializationValue = '0.0';\r\n            if (!isAvgPool) {\r\n                initializationValue = '-1.0 / 1e-20';\r\n            }\r\n            if (computePositions) {\r\n                var compareOp_1 = '>=';\r\n                this.userCode = \"\\n        const ivec2 strides = ivec2(\" + strideHeight + \", \" + strideWidth + \");\\n        const ivec2 pads = ivec2(\" + padTop + \", \" + padLeft + \");\\n\\n        void main() {\\n          ivec4 coords = getOutputCoords();\\n          int batch = coords[0];\\n          int d = coords[3];\\n\\n          ivec2 xRCCorner = coords.yz * strides - pads;\\n          int xRCorner = xRCCorner.x;\\n          int xCCorner = xRCCorner.y;\\n\\n          // max/min x(?, ?, d) to get y(yR, yC, d).\\n          // ? = to be determined\\n          float minMaxValue = 0.0;\\n          float minMaxValueFound = 0.0;\\n          int minMaxPosition = 0;\\n          float avgValue = 0.0;\\n\\n          for (int wR = 0; wR < \" + effectiveFilterHeight + \";\\n              wR += \" + dilationHeight + \") {\\n            int xR = xRCorner + wR;\\n\\n            if (xR < 0 || xR >= \" + convInfo.inHeight + \") {\\n              continue;\\n            }\\n\\n            for (int wC = 0; wC < \" + effectiveFilterWidth + \";\\n                wC += \" + dilationWidth + \") {\\n              int xC = xCCorner + wC;\\n\\n              if (xC < 0 || xC >= \" + convInfo.inWidth + \") {\\n                continue;\\n              }\\n\\n              float value = getX(batch, xR, xC, d);\\n\\n              // If a min / max value has already been found, use it. If not,\\n              // use the current value.\\n              float currMinMaxValue = mix(\\n                  value, minMaxValue, minMaxValueFound);\\n              if (value \" + compareOp_1 + \" currMinMaxValue) {\\n                minMaxValue = value;\\n                minMaxValueFound = 1.0;\\n                minMaxPosition = wR * \" + effectiveFilterWidth + \" + wC;\\n              }\\n            }\\n          }\\n          setOutput(float(minMaxPosition));\\n        }\\n      \";\r\n                return;\r\n            }\r\n            var compareOp = 'max';\r\n            var returnValue = poolType + \"(\" + poolType + \"(\" + poolType + \"(\" +\r\n                'minMaxValue[0], minMaxValue[1]), minMaxValue[2]), minMaxValue[3])';\r\n            if (poolType === 'avg') {\r\n                returnValue = \"avgValue / count\";\r\n            }\r\n            var filterWidthNearestVec4 = Math.floor(filterWidth / 4) * 4;\r\n            var filterWidthVec4Remainder = filterWidth % 4;\r\n            var updateSnippet = \"\\n      if (\" + isAvgPool + \") {\\n        avgValue += dot(values, ones);\\n      } else {\\n        minMaxValue = \" + compareOp + \"(values, minMaxValue);\\n      }\\n    \";\r\n            this.userCode = \"\\n      const ivec2 strides = ivec2(\" + strideHeight + \", \" + strideWidth + \");\\n      const ivec2 pads = ivec2(\" + padTop + \", \" + padLeft + \");\\n      const float initializationValue = \" + initializationValue + \";\\n      const vec4 ones = vec4(1.0, 1.0, 1.0, 1.0);\\n\\n      float count = 0.0;\\n\\n      float getValue(int batch, int xR, int xC, int d) {\\n        if (xC < 0 || xC >= \" + convInfo.inWidth + \") {\\n          return initializationValue;\\n        }\\n        count += 1.0;\\n        return getX(batch, xR, xC, d);\\n      }\\n\\n      void main() {\\n        ivec4 coords = getOutputCoords();\\n        int batch = coords[0];\\n        int d = coords[3];\\n\\n        ivec2 xRCCorner = coords.yz * strides - pads;\\n        int xRCorner = xRCCorner.x;\\n        int xCCorner = xRCCorner.y;\\n\\n        // max/min x(?, ?, d) to get y(yR, yC, d).\\n        // ? = to be determined\\n        vec4 minMaxValue = vec4(\" + initializationValue + \");\\n        float avgValue = 0.0;\\n        count = 0.0;\\n\\n        for (int wR = 0; wR < \" + effectiveFilterHeight + \";\\n            wR += \" + dilationHeight + \") {\\n          int xR = xRCorner + wR;\\n\\n          if (xR < 0 || xR >= \" + convInfo.inHeight + \") {\\n            continue;\\n          }\\n\\n          for (int wC = 0; wC < \" + filterWidthNearestVec4 + \"; wC += 4) {\\n            int xC = xCCorner + wC * \" + dilationWidth + \";\\n\\n            vec4 values = vec4(\\n              getValue(batch, xR, xC, d),\\n              getValue(batch, xR, xC + \" + dilationWidth + \", d),\\n              getValue(batch, xR, xC + 2 * \" + dilationWidth + \", d),\\n              getValue(batch, xR, xC + 3 * \" + dilationWidth + \", d)\\n            );\\n\\n            \" + updateSnippet + \"\\n          }\\n\\n          int xC = xCCorner + \" + filterWidthNearestVec4 + \";\\n          if (\" + (filterWidthVec4Remainder === 1) + \") {\\n            vec4 values = vec4(\\n              getValue(batch, xR, xC, d),\\n              initializationValue,\\n              initializationValue,\\n              initializationValue\\n            );\\n\\n            \" + updateSnippet + \"\\n          } else if (\" + (filterWidthVec4Remainder === 2) + \") {\\n            vec4 values = vec4(\\n              getValue(batch, xR, xC, d),\\n              getValue(batch, xR, xC + \" + dilationWidth + \", d),\\n              initializationValue,\\n              initializationValue\\n            );\\n\\n            \" + updateSnippet + \"\\n          } else if (\" + (filterWidthVec4Remainder === 3) + \") {\\n            vec4 values = vec4(\\n              getValue(batch, xR, xC, d),\\n              getValue(batch, xR, xC + \" + dilationWidth + \", d),\\n              getValue(batch, xR, xC + 2 * \" + dilationWidth + \", d),\\n              initializationValue\\n            );\\n\\n            \" + updateSnippet + \"\\n          }\\n        }\\n        setOutput(\" + returnValue + \");\\n      }\\n    \";\r\n        }\r\n        return Pool2DProgram;\r\n    }());\n\n    var ReduceProgram = (function () {\r\n        function ReduceProgram(reduceInfo, reduceType) {\r\n            this.variableNames = ['x'];\r\n            var windowSize = reduceInfo.windowSize;\r\n            var batchSize = reduceInfo.batchSize;\r\n            var inSize = reduceInfo.inSize;\r\n            var outSize = Math.ceil(inSize / windowSize);\r\n            this.outputShape = [batchSize, outSize];\r\n            var initializationValue = '0.0';\r\n            var compareOp = \"\";\r\n            if (reduceType === 'prod') {\r\n                initializationValue = '1.0';\r\n            }\r\n            else if (reduceType === 'min') {\r\n                initializationValue = '1.0 / 1e-20';\r\n                compareOp = \"min\";\r\n            }\r\n            else if (reduceType === 'max') {\r\n                initializationValue = '-1.0 / 1e-20';\r\n                compareOp = \"max\";\r\n            }\r\n            var returnValue = reduceType + \"(\" + reduceType + \"(\" + reduceType + \"(\" +\r\n                'minMaxValue[0], minMaxValue[1]), minMaxValue[2]), minMaxValue[3])';\r\n            if (reduceType === 'sum') {\r\n                returnValue = \"sumValue\";\r\n            }\r\n            else if (reduceType === 'prod') {\r\n                returnValue = \"prodValue\";\r\n            }\r\n            else if (reduceType === 'all') {\r\n                returnValue = \"allValue\";\r\n            }\r\n            else if (reduceType === 'any') {\r\n                returnValue = \"anyValue\";\r\n            }\r\n            var windowSizeNearestVec4 = Math.floor(windowSize / 4) * 4;\r\n            var windowSizeVec4Remainder = windowSize % 4;\r\n            var updateSnippet = \"\\n      if (\" + (reduceType === 'sum') + \") {\\n        sumValue += dot(values, ones);\\n      } else if (\" + (reduceType === 'prod') + \") {\\n        vec2 tmp = vec2(values[0], values[1]) * vec2(values[2], values[3]);\\n        prodValue *= tmp[0] * tmp[1];\\n      } else {\\n        minMaxValue = \" + compareOp + \"(values, minMaxValue);\\n      }\\n    \";\r\n            var vecType = \"vec4\";\r\n            if (reduceType === 'all') {\r\n                initializationValue = '1.0';\r\n                updateSnippet = \"\\n        bool reducedAllValue = all(values);\\n        float floatedReducedAllValue = float(reducedAllValue);\\n        allValue = float(allValue >= 1.0 && floatedReducedAllValue >= 1.0);\\n      \";\r\n                vecType = \"bvec4\";\r\n            }\r\n            else if (reduceType === 'any') {\r\n                initializationValue = '0.0';\r\n                updateSnippet = \"\\n        bool reducedAnyValue = any(values);\\n        float floatedReducedAnyValue = float(reducedAnyValue);\\n        anyValue = float(anyValue >= 1.0 || floatedReducedAnyValue >= 1.0);\\n      \";\r\n                vecType = \"bvec4\";\r\n            }\r\n            var checkOutOfBounds = '';\r\n            if (inSize % windowSize > 0) {\r\n                checkOutOfBounds = \"\\n        if (inIdx < 0 || inIdx >= \" + inSize + \") {\\n          return initializationValue;\\n        }\\n      \";\r\n            }\r\n            this.userCode = \"\\n      const float initializationValue = \" + initializationValue + \";\\n      const vec4 ones = vec4(1.0, 1.0, 1.0, 1.0);\\n\\n      float getValue(int batch, int inIdx) {\\n        \" + checkOutOfBounds + \"\\n        return getX(batch, inIdx);\\n      }\\n\\n      void main() {\\n        ivec2 coords = getOutputCoords();\\n        int batch = coords[0];\\n        int outIdx = coords[1];\\n        int inOffset = outIdx * \" + windowSize + \";\\n\\n        vec4 minMaxValue = vec4(\" + initializationValue + \");\\n        float prodValue = 1.0;\\n        float sumValue = 0.0;\\n        float allValue = 1.0;\\n        float anyValue = 0.0;\\n\\n        for (int i = 0; i < \" + windowSizeNearestVec4 + \"; i += 4) {\\n          int inIdx = inOffset + i;\\n          \" + vecType + \" values = \" + vecType + \"(\\n            getValue(batch, inIdx),\\n            getValue(batch, inIdx + 1),\\n            getValue(batch, inIdx + 2),\\n            getValue(batch, inIdx + 3)\\n          );\\n\\n          \" + updateSnippet + \"\\n        }\\n\\n        int inIdx = inOffset + \" + windowSizeNearestVec4 + \";\\n        if (\" + (windowSizeVec4Remainder === 1) + \") {\\n          \" + vecType + \" values = \" + vecType + \"(\\n            getValue(batch, inIdx),\\n            initializationValue,\\n            initializationValue,\\n            initializationValue\\n          );\\n\\n          \" + updateSnippet + \"\\n        } else if (\" + (windowSizeVec4Remainder === 2) + \") {\\n          \" + vecType + \" values = \" + vecType + \"(\\n            getValue(batch, inIdx),\\n            getValue(batch, inIdx + 1),\\n            initializationValue,\\n            initializationValue\\n          );\\n\\n          \" + updateSnippet + \"\\n        } else if (\" + (windowSizeVec4Remainder === 3) + \") {\\n          \" + vecType + \" values = \" + vecType + \"(\\n            getValue(batch, inIdx),\\n            getValue(batch, inIdx + 1),\\n            getValue(batch, inIdx + 2),\\n            initializationValue\\n          );\\n\\n          \" + updateSnippet + \"\\n        }\\n        setOutput(\" + returnValue + \");\\n      }\\n    \";\r\n        }\r\n        return ReduceProgram;\r\n    }());\n\n    var ReshapePackedProgram = (function () {\r\n        function ReshapePackedProgram(outputShape, inputShape) {\r\n            this.variableNames = ['A'];\r\n            this.usesPackedTextures = true;\r\n            this.outputShape = outputShape;\r\n            var mainLoop = \"\";\r\n            for (var i = 0; i < 4; i++) {\r\n                var thisRC = \"thisRC = rc;\";\r\n                if (i % 2 === 1) {\r\n                    thisRC += \"thisRC.z += 1;\";\r\n                }\r\n                if (i > 1) {\r\n                    thisRC += \"thisRC.y += 1;\";\r\n                }\r\n                mainLoop += \"\\n        \" + thisRC + \"\\n        \" + (i > 0 ? \"if(thisRC.y < rows && thisRC.z < cols){\" : '') + \"\\n          int flatIndex = getFlatIndex(thisRC);\\n\\n          ivec3 inputRC = inputCoordsFromReshapedOutCoords(flatIndex);\\n          vec2 inputRCInnerDims = vec2(float(inputRC.y),float(inputRC.z));\\n\\n          result[\" + i + \"] =\\n            getChannel(getA(inputRC.x, inputRC.y, inputRC.z), inputRCInnerDims);\\n        \" + (i > 0 ? '}' : '') + \"\\n      \";\r\n            }\r\n            this.userCode = \"\\n      \" + getReshapedInputCoords(inputShape) + \"\\n      \" + getFlatIndex(outputShape) + \"\\n\\n      void main() {\\n        ivec3 rc = getOutputCoords();\\n\\n        vec4 result = vec4(0.);\\n\\n        ivec3 thisRC;\\n        int rows = \" + outputShape[1] + \";\\n        int cols = \" + outputShape[2] + \";\\n\\n        \" + mainLoop + \"\\n\\n        setOutput(result);\\n      }\\n    \";\r\n        }\r\n        return ReshapePackedProgram;\r\n    }());\r\n    function getFlatIndex(shape) {\r\n        var dotCoordsWithStrides = dotify(['coords.x', 'coords.y', 'coords.z'], computeStrides(shape).map(function (d) { return d.toString(); }).concat(['1.']));\r\n        return \"\\n    int getFlatIndex(ivec3 coords) {\\n      return round(\" + dotCoordsWithStrides + \");\\n    }\\n  \";\r\n    }\r\n    function getReshapedInputCoords(shape) {\r\n        var coordsFromIndexSnippet = getLogicalCoordinatesFromFlatIndex(['r', 'c', 'd'], shape);\r\n        return \"\\n    ivec3 inputCoordsFromReshapedOutCoords(int index) {\\n      \" + coordsFromIndexSnippet + \"\\n      return ivec3(r, c, d);\\n    }\\n  \";\r\n    }\n\n    var ResizeBilinearBackpropProgram = (function () {\r\n        function ResizeBilinearBackpropProgram(dy, x, alignCorners) {\r\n            this.variableNames = ['dy'];\r\n            this.outputShape = [];\r\n            this.outputShape = x.shape;\r\n            var _a = x.shape, xHeight = _a[1], xWidth = _a[2];\r\n            var _b = dy.shape, yHeight = _b[1], yWidth = _b[2];\r\n            var effectiveXSize = [\r\n                (alignCorners && yHeight > 1) ? xHeight - 1 : xHeight,\r\n                (alignCorners && yWidth > 1) ? xWidth - 1 : xWidth\r\n            ];\r\n            var effectiveYSize = [\r\n                (alignCorners && yHeight > 1) ? yHeight - 1 : yHeight,\r\n                (alignCorners && yWidth > 1) ? yWidth - 1 : yWidth\r\n            ];\r\n            var heightScale = effectiveXSize[0] / effectiveYSize[0];\r\n            var widthScale = effectiveXSize[1] / effectiveYSize[1];\r\n            var invHeightScale = 1 / heightScale;\r\n            var invWidthScale = 1 / widthScale;\r\n            var winHeight = (Math.ceil(invHeightScale) * 2) + 2;\r\n            var winWidth = (Math.ceil(invWidthScale) * 2) + 2;\r\n            this.userCode = \"\\n      void main() {\\n        ivec4 coords = getOutputCoords();\\n        int b = coords[0];\\n        int d = coords[3];\\n        int r = coords[1];\\n        int c = coords[2];\\n\\n        float accumulator = 0.0;\\n\\n        const float heightScale = float(\" + heightScale + \");\\n        const float widthScale = float(\" + widthScale + \");\\n\\n        const float invHeightScale = float(\" + invHeightScale + \");\\n        const float invWidthScale = float(\" + invWidthScale + \");\\n\\n        const int winHeight = int(\" + winHeight + \");\\n        const int winWidth = int(\" + winWidth + \");\\n\\n        // Compute bounds for where in dy we will look\\n        float startRLerp = floor(float(r) * invHeightScale);\\n        int startDyR = int(startRLerp - float(winHeight / 2));\\n\\n        float startCLerp = floor(float(c) * invWidthScale);\\n        int startDyC = int(startCLerp - float(winWidth / 2));\\n\\n        // Loop over dy\\n        for (int dyROffset = 0; dyROffset < winHeight; dyROffset++) {\\n          int dyR = dyROffset + startDyR;\\n\\n          // Guard against the window exceeding the bounds of dy\\n          if (dyR < 0 || dyR >= \" + yHeight + \") {\\n            continue;\\n          }\\n\\n          for (int dyCOffset = 0; dyCOffset < winWidth; dyCOffset++) {\\n            int dyC = dyCOffset + startDyC;\\n\\n            // Guard against the window exceeding the bounds of dy\\n            if (dyC < 0 || dyC >= \" + yWidth + \") {\\n              continue;\\n            }\\n\\n            float dxR = float(dyR) * heightScale;\\n            int topDxRIndex = int(floor(dxR));\\n            int bottomDxRIndex = int(min(ceil(dxR), \" + (xHeight - 1) + \".0));\\n            float dxRLerp = dxR - float(topDxRIndex);\\n            float inverseDxRLerp = 1.0 - dxRLerp;\\n\\n            float dxC = float(dyC) * widthScale;\\n            int leftDxCIndex = int(floor(dxC));\\n            int rightDxCIndex = int(min(ceil(dxC), \" + (xWidth - 1) + \".0));\\n            float dxCLerp = dxC - float(leftDxCIndex);\\n            float inverseDxCLerp = 1.0 - dxCLerp;\\n\\n            if (r == topDxRIndex && c == leftDxCIndex) {\\n              // topLeft\\n              accumulator +=\\n                getDy(b, dyR, dyC, d) * inverseDxRLerp * inverseDxCLerp;\\n            }\\n\\n            if (r == topDxRIndex && c == rightDxCIndex) {\\n              // topRight\\n              accumulator += getDy(b, dyR, dyC, d) * inverseDxRLerp * dxCLerp;\\n            }\\n\\n            if (r == bottomDxRIndex && c == leftDxCIndex) {\\n              // bottomLeft\\n              accumulator += getDy(b, dyR, dyC, d) * dxRLerp * inverseDxCLerp;\\n            }\\n\\n            if (r == bottomDxRIndex && c == rightDxCIndex) {\\n              // bottomRight\\n              accumulator += getDy(b, dyR, dyC, d) * dxRLerp * dxCLerp;\\n            }\\n          }\\n        }\\n        // End loop over dy\\n\\n        setOutput(accumulator);\\n      }\\n    \";\r\n        }\r\n        return ResizeBilinearBackpropProgram;\r\n    }());\n\n    var ResizeBilinearProgram = (function () {\r\n        function ResizeBilinearProgram(inputShape, newHeight, newWidth, alignCorners) {\r\n            this.variableNames = ['A'];\r\n            this.outputShape = [];\r\n            var batch = inputShape[0], oldHeight = inputShape[1], oldWidth = inputShape[2], depth = inputShape[3];\r\n            this.outputShape = [batch, newHeight, newWidth, depth];\r\n            var effectiveInSize = [\r\n                (alignCorners && newHeight > 1) ? oldHeight - 1 : oldHeight,\r\n                (alignCorners && newWidth > 1) ? oldWidth - 1 : oldWidth\r\n            ];\r\n            var effectiveOutSize = [\r\n                (alignCorners && newHeight > 1) ? newHeight - 1 : newHeight,\r\n                (alignCorners && newWidth > 1) ? newWidth - 1 : newWidth\r\n            ];\r\n            this.userCode = \"\\n      const vec2 effectiveInputOverOutputRatioRC = vec2(\\n          \" + effectiveInSize[0] / effectiveOutSize[0] + \",\\n          \" + effectiveInSize[1] / effectiveOutSize[1] + \");\\n      const vec2 inputShapeRC = vec2(\" + oldHeight + \".0, \" + oldWidth + \".0);\\n\\n      void main() {\\n        ivec4 coords = getOutputCoords();\\n        int b = coords[0];\\n        int d = coords[3];\\n        ivec2 yRC = coords.yz;\\n\\n        // Fractional source index.\\n        vec2 sourceFracIndexRC = vec2(yRC) * effectiveInputOverOutputRatioRC;\\n\\n        // Compute the four integer indices.\\n        ivec2 sourceFloorRC = ivec2(sourceFracIndexRC);\\n        ivec2 sourceCeilRC = ivec2(\\n          min(inputShapeRC - 1.0, ceil(sourceFracIndexRC)));\\n\\n        float topLeft = getA(b, sourceFloorRC.x, sourceFloorRC.y, d);\\n        float bottomLeft = getA(b, sourceCeilRC.x, sourceFloorRC.y, d);\\n        float topRight = getA(b, sourceFloorRC.x, sourceCeilRC.y, d);\\n        float bottomRight = getA(b, sourceCeilRC.x, sourceCeilRC.y, d);\\n\\n        vec2 fracRC = sourceFracIndexRC - vec2(sourceFloorRC);\\n\\n        float top = topLeft + (topRight - topLeft) * fracRC.y;\\n        float bottom = bottomLeft + (bottomRight - bottomLeft) * fracRC.y;\\n        float newValue = top + (bottom - top) * fracRC.x;\\n\\n        setOutput(newValue);\\n      }\\n    \";\r\n        }\r\n        return ResizeBilinearProgram;\r\n    }());\n\n    var ResizeNearestNeigborBackpropProgram = (function () {\r\n        function ResizeNearestNeigborBackpropProgram(dy, x, alignCorners) {\r\n            this.variableNames = ['dy'];\r\n            this.outputShape = [];\r\n            this.outputShape = x.shape;\r\n            var _a = x.shape, xHeight = _a[1], xWidth = _a[2];\r\n            var _b = dy.shape, yHeight = _b[1], yWidth = _b[2];\r\n            var effectiveXSize = [\r\n                (alignCorners && yHeight > 1) ? xHeight - 1 : xHeight,\r\n                (alignCorners && yWidth > 1) ? xWidth - 1 : xWidth\r\n            ];\r\n            var effectiveYSize = [\r\n                (alignCorners && yHeight > 1) ? yHeight - 1 : yHeight,\r\n                (alignCorners && yWidth > 1) ? yWidth - 1 : yWidth\r\n            ];\r\n            var heightScale = effectiveXSize[0] / effectiveYSize[0];\r\n            var widthScale = effectiveXSize[1] / effectiveYSize[1];\r\n            var invHeightScale = 1 / heightScale;\r\n            var invWidthScale = 1 / widthScale;\r\n            var winHeight = (Math.ceil(invHeightScale) * 2) + 2;\r\n            var winWidth = (Math.ceil(invWidthScale) * 2) + 2;\r\n            this.userCode = \"\\n      void main() {\\n        ivec4 coords = getOutputCoords();\\n        int b = coords[0];\\n        int d = coords[3];\\n        int r = coords[1];\\n        int c = coords[2];\\n\\n        float accumulator = 0.0;\\n\\n        const float heightScale = float(\" + heightScale + \");\\n        const float widthScale = float(\" + widthScale + \");\\n\\n        const float invHeightScale = float(\" + invHeightScale + \");\\n        const float invWidthScale = float(\" + invWidthScale + \");\\n\\n        const int winHeight = int(\" + winHeight + \");\\n        const int winWidth = int(\" + winWidth + \");\\n\\n        // Compute bounds for where in dy we will look\\n        float startRLerp = floor(float(r) * invHeightScale);\\n        int startDyR = int(floor(startRLerp - float(winHeight / 2)));\\n\\n        float startCLerp = floor(float(c) * invWidthScale);\\n        int startDyC = int(floor(startCLerp - float(winWidth / 2)));\\n\\n        // Loop over dy\\n        for (int dyROffset = 0; dyROffset < winHeight; dyROffset++) {\\n          int dyR = dyROffset + startDyR;\\n\\n          // Guard against the window exceeding the bounds of dy\\n          if (dyR < 0 || dyR >= \" + yHeight + \") {\\n            continue;\\n          }\\n\\n          for (int dyCOffset = 0; dyCOffset < winWidth; dyCOffset++) {\\n            int dyC = dyCOffset + startDyC;\\n\\n            // Guard against the window exceeding the bounds of dy\\n            if (dyC < 0 || dyC >= \" + yWidth + \") {\\n              continue;\\n            }\\n\\n            float sourceFracRow =\\n              float(\" + effectiveXSize[0] + \") *\\n                (float(dyR) / float(\" + effectiveYSize[0] + \"));\\n\\n            float sourceFracCol =\\n                float(\" + effectiveXSize[1] + \") *\\n                  (float(dyC) / float(\" + effectiveYSize[1] + \"));\\n\\n            int sourceNearestRow = int(min(\\n                float(int(\" + xHeight + \") - 1),\\n                \" + alignCorners + \" ? float(round(sourceFracRow)) :\\n                                  float(floor(sourceFracRow))));\\n\\n            int sourceNearestCol = int(min(\\n                float(int(\" + xWidth + \") - 1),\\n                \" + alignCorners + \" ? float(round(sourceFracCol)) :\\n                                  float(floor(sourceFracCol))));\\n\\n            if (r == sourceNearestRow && c == sourceNearestCol) {\\n              accumulator += getDy(b, dyR, dyC, d);\\n            }\\n          }\\n        }\\n        // End loop over dy\\n\\n        setOutput(accumulator);\\n      }\\n    \";\r\n        }\r\n        return ResizeNearestNeigborBackpropProgram;\r\n    }());\n\n    var ResizeNearestNeighborProgram = (function () {\r\n        function ResizeNearestNeighborProgram(inputShape, newHeight, newWidth, alignCorners) {\r\n            this.variableNames = ['A'];\r\n            this.outputShape = [];\r\n            var batch = inputShape[0], oldHeight = inputShape[1], oldWidth = inputShape[2], depth = inputShape[3];\r\n            this.outputShape = [batch, newHeight, newWidth, depth];\r\n            var effectiveInSize = [\r\n                (alignCorners && newHeight > 1) ? oldHeight - 1 : oldHeight,\r\n                (alignCorners && newWidth > 1) ? oldWidth - 1 : oldWidth\r\n            ];\r\n            var effectiveOutSize = [\r\n                (alignCorners && newHeight > 1) ? newHeight - 1 : newHeight,\r\n                (alignCorners && newWidth > 1) ? newWidth - 1 : newWidth\r\n            ];\r\n            var roundBase = alignCorners ? '0.5' : '0.0';\r\n            this.userCode = \"\\n      const vec2 effectiveInputOverOutputRatioRC = vec2(\\n          \" + effectiveInSize[0] / effectiveOutSize[0] + \",\\n          \" + effectiveInSize[1] / effectiveOutSize[1] + \");\\n      const vec2 inputShapeRC = vec2(\" + oldHeight + \".0, \" + oldWidth + \".0);\\n\\n      void main() {\\n        ivec4 coords = getOutputCoords();\\n        int b = coords[0];\\n        int d = coords[3];\\n        ivec2 yRC = coords.yz;\\n\\n        // Fractional source index.\\n        vec2 sourceFracIndexRC = vec2(yRC) * effectiveInputOverOutputRatioRC;\\n\\n        // Compute the coordinators of nearest neighbor point.\\n        ivec2 sourceNearestRC = ivec2(\\n          min(inputShapeRC - 1.0, floor(sourceFracIndexRC + \" + roundBase + \")));\\n\\n        float newValue = getA(b, sourceNearestRC.x, sourceNearestRC.y, d);\\n\\n        setOutput(newValue);\\n      }\\n    \";\r\n        }\r\n        return ResizeNearestNeighborProgram;\r\n    }());\n\n    var ReverseProgram = (function () {\r\n        function ReverseProgram(xShape, axis) {\r\n            this.variableNames = ['x'];\r\n            var rank = xShape.length;\r\n            if (rank > 4) {\r\n                throw new Error(\"WebGL backend: Reverse of rank-\" + rank + \" tensor is not yet supported\");\r\n            }\r\n            this.outputShape = xShape;\r\n            if (rank === 1) {\r\n                this.userCode = \"\\n        void main() {\\n          int coord = getOutputCoords();\\n          setOutput(getX(\" + xShape[0] + \" - coord - 1));\\n        }\\n      \";\r\n                return;\r\n            }\r\n            var getInCoord = function (i) {\r\n                if (axis.indexOf(i) !== -1 && xShape[i] !== 1) {\r\n                    return xShape[i] + \" - coords[\" + i + \"] - 1\";\r\n                }\r\n                return \"coords[\" + i + \"]\";\r\n            };\r\n            var inCoords = xShape.map(function (_, i) { return getInCoord(i); }).join(',');\r\n            var type = getCoordsDataType(rank);\r\n            this.userCode = \"\\n      void main() {\\n        \" + type + \" coords = getOutputCoords();\\n        setOutput(getX(\" + inCoords + \"));\\n      }\\n    \";\r\n        }\r\n        return ReverseProgram;\r\n    }());\n\n    var ScatterProgram = (function () {\r\n        function ScatterProgram(updateSize, sliceDim, indicesRank, updatesRank, strides, shape, summingDupeIndex) {\r\n            if (summingDupeIndex === void 0) { summingDupeIndex = true; }\r\n            this.variableNames = ['updates', 'indices', 'defaultValue'];\r\n            this.outputShape = shape;\r\n            var stridesType = getCoordsDataType(strides.length);\r\n            var dtype = getCoordsDataType(shape.length);\r\n            var indicesString = '';\r\n            if (indicesRank === 1) {\r\n                indicesString = 'i';\r\n            }\r\n            else if (indicesRank === 2) {\r\n                indicesString = 'i, j';\r\n            }\r\n            var indicesSnippet = \"getIndices(\" + indicesString + \")\";\r\n            var updatesString = '';\r\n            if (updatesRank === 1) {\r\n                updatesString = 'i';\r\n            }\r\n            else if (updatesRank === 2) {\r\n                updatesString = 'i, coords[1]';\r\n            }\r\n            var updatesSnippet = \"getUpdates(\" + updatesString + \")\";\r\n            var strideString = sliceDim > 1 ? 'strides[j]' : 'strides';\r\n            this.userCode = \"\\n        \" + stridesType + \" strides = \" + stridesType + \"(\" + strides + \");\\n\\n        void main() {\\n          \" + dtype + \" coords = getOutputCoords();\\n          float sum = 0.0;\\n          bool found = false;\\n          for (int i = 0; i < \" + updateSize + \"; i++) {\\n            int flattenedIndex = 0;\\n            for (int j = 0; j < \" + sliceDim + \"; j++) {\\n              int index = round(\" + indicesSnippet + \");\\n              flattenedIndex += index * \" + strideString + \";\\n            }\\n            if (flattenedIndex == coords[0]) {\\n              sum += \" + updatesSnippet + \";\\n              found = true;\\n            }\\n          }\\n          setOutput(mix(getDefaultValue(), sum, float(found)));\\n        }\\n      \";\r\n        }\r\n        return ScatterProgram;\r\n    }());\n\n    var SegmentOpProgram = (function () {\r\n        function SegmentOpProgram(segOpInfo, segOpType) {\r\n            this.variableNames = ['x', 'segmentIds'];\r\n            var windowSize = segOpInfo.windowSize;\r\n            var batchSize = segOpInfo.batchSize;\r\n            var inSize = segOpInfo.inSize;\r\n            var numSegments = segOpInfo.numSegments;\r\n            var outSize = numSegments * Math.ceil(inSize / windowSize);\r\n            this.outputShape = [batchSize, outSize];\r\n            var initializationValue = '0.0';\r\n            var returnValue = \"sumValue\";\r\n            var windowSizeNearestVec4 = Math.floor(windowSize / 4) * 4;\r\n            var windowSizeVec4Remainder = windowSize % 4;\r\n            var updateSnippet = \"\\n        sumValue += dot(values, segFilter);\\n    \";\r\n            var checkValueOutOfBounds = '';\r\n            if (inSize % windowSize > 0) {\r\n                checkValueOutOfBounds = \"\\n        if (inIdx < 0 || inIdx >= \" + inSize + \") {\\n          return initializationValue;\\n        }\\n      \";\r\n            }\r\n            var checkSegmentIdOutOfBounds = '';\r\n            if (inSize % windowSize > 0) {\r\n                checkSegmentIdOutOfBounds = \"\\n        if (inIdx < 0 || inIdx >= \" + inSize + \") {\\n          return -1.0;\\n        }\\n      \";\r\n            }\r\n            this.userCode = \"\\n      const float initializationValue = \" + initializationValue + \";\\n\\n      float getValue(int batch, int inIdx) {\\n        \" + checkValueOutOfBounds + \"\\n        return getX(batch, inIdx);\\n      }\\n\\n      float getSegmentIdAtIndex(int inIdx) {\\n        \" + checkSegmentIdOutOfBounds + \"\\n        return getSegmentIds(inIdx);\\n      }\\n\\n      void main() {\\n        ivec2 coords = getOutputCoords();\\n        int batch = coords[0];\\n        int outIdx = coords[1];\\n        int inOffset = int(floor(float(outIdx) / float(\\n          \" + numSegments + \")) * float(\" + windowSize + \"));\\n        int currentSeg = int(mod(float(outIdx), float(\" + numSegments + \")));\\n\\n        float sumValue = 0.0;\\n\\n        for (int i = 0; i < \" + windowSizeNearestVec4 + \"; i += 4) {\\n          int inIdx = inOffset + i;\\n          vec4 values = vec4(\\n            getValue(batch, inIdx),\\n            getValue(batch, inIdx + 1),\\n            getValue(batch, inIdx + 2),\\n            getValue(batch, inIdx + 3)\\n          );\\n\\n          vec4 segFilter = vec4(\\n            int(getSegmentIdAtIndex(inIdx)) == currentSeg ? 1 : 0,\\n            int(getSegmentIdAtIndex(inIdx + 1)) == currentSeg ? 1 : 0,\\n            int(getSegmentIdAtIndex(inIdx + 2)) == currentSeg ? 1 : 0,\\n            int(getSegmentIdAtIndex(inIdx + 3)) == currentSeg ? 1 : 0\\n          );\\n\\n          \" + updateSnippet + \"\\n        }\\n\\n        int inIdx = inOffset + \" + windowSizeNearestVec4 + \";\\n        if (\" + (windowSizeVec4Remainder === 1) + \") {\\n          vec4 values = vec4(\\n            getValue(batch, inIdx),\\n            initializationValue,\\n            initializationValue,\\n            initializationValue\\n          );\\n\\n          int inIdxSeg = int(getSegmentIdAtIndex(inIdx));\\n\\n          vec4 segFilter = vec4(\\n            int(getSegmentIdAtIndex(inIdx)) == currentSeg ? 1 : 0,\\n            0,\\n            0,\\n            0\\n          );\\n\\n          \" + updateSnippet + \"\\n        } else if (\" + (windowSizeVec4Remainder === 2) + \") {\\n          vec4 values = vec4(\\n            getValue(batch, inIdx),\\n            getValue(batch, inIdx + 1),\\n            initializationValue,\\n            initializationValue\\n          );\\n\\n          vec4 segFilter = vec4(\\n            int(getSegmentIdAtIndex(inIdx)) == currentSeg ? 1 : 0,\\n            int(getSegmentIdAtIndex(inIdx + 1)) == currentSeg ? 1 : 0,\\n              0,\\n              0\\n          );\\n\\n          \" + updateSnippet + \"\\n        } else if (\" + (windowSizeVec4Remainder === 3) + \") {\\n          vec4 values = vec4(\\n            getValue(batch, inIdx),\\n            getValue(batch, inIdx + 1),\\n            getValue(batch, inIdx + 2),\\n            initializationValue\\n          );\\n\\n          vec4 segFilter = vec4(\\n            int(getSegmentIdAtIndex(inIdx)) == currentSeg ? 1 : 0,\\n            int(getSegmentIdAtIndex(inIdx + 1)) == currentSeg ? 1 : 0,\\n            int(getSegmentIdAtIndex(inIdx + 2)) == currentSeg ? 1 : 0,\\n            0\\n          );\\n\\n          \" + updateSnippet + \"\\n        }\\n        setOutput(\" + returnValue + \");\\n      }\\n    \";\r\n        }\r\n        return SegmentOpProgram;\r\n    }());\n\n    var SelectProgram = (function () {\r\n        function SelectProgram(cRank, shape, rank) {\r\n            this.variableNames = ['c', 'a', 'b'];\r\n            this.outputShape = shape;\r\n            var cCoords;\r\n            var abCoords;\r\n            if (rank > 4) {\r\n                throw Error(\"Where for rank \" + rank + \" is not yet supported\");\r\n            }\r\n            if (rank === 1) {\r\n                abCoords = \"resRC\";\r\n                cCoords = \"resRC\";\r\n            }\r\n            else {\r\n                var currentCoords = ['resRC.x', 'resRC.y', 'resRC.z', 'resRC.w'];\r\n                var cCoordVars = [];\r\n                var abCoordVars = [];\r\n                for (var i = 0; i < shape.length; i++) {\r\n                    abCoordVars.push(\"\" + currentCoords[i]);\r\n                    if (i < cRank) {\r\n                        cCoordVars.push(\"\" + currentCoords[i]);\r\n                    }\r\n                }\r\n                cCoords = cCoordVars.join();\r\n                abCoords = abCoordVars.join();\r\n            }\r\n            var dtype = getCoordsDataType(rank);\r\n            this.userCode = \"\\n      void main() {\\n        \" + dtype + \" resRC = getOutputCoords();\\n        float cVal = getC(\" + cCoords + \");\\n        if (cVal >= 1.0) {\\n          setOutput(getA(\" + abCoords + \"));\\n        } else {\\n          setOutput(getB(\" + abCoords + \"));\\n        }\\n      }\\n    \";\r\n        }\r\n        return SelectProgram;\r\n    }());\n\n    var SliceProgram = (function () {\r\n        function SliceProgram(destSize) {\r\n            this.variableNames = ['source'];\r\n            this.outputShape = destSize;\r\n            this.rank = destSize.length;\r\n            var dtype = getCoordsDataType(this.rank);\r\n            var uniformPart = \"uniform int start[\" + this.rank + \"];\";\r\n            var sourceCoords = getCoords$1(this.rank);\r\n            var body;\r\n            var coordSum = destSize.map(function (_, i) {\r\n                return \"sourceLoc.\" + coords[i] + \" = start[\" + i + \"] + coords.\" + coords[i] + \";\";\r\n            });\r\n            body = \"\\n        \" + dtype + \" sourceLoc;\\n        \" + dtype + \" coords = getOutputCoords();\\n        \" + coordSum.join('\\n') + \"\\n      \";\r\n            this.userCode = \"\\n      \" + uniformPart + \"\\n      void main() {\\n        \" + body + \"\\n        setOutput(getSource(\" + sourceCoords + \"));\\n      }\\n    \";\r\n        }\r\n        SliceProgram.prototype.getCustomSetupFunc = function (start) {\r\n            var _this = this;\r\n            if (start.length !== this.rank) {\r\n                throw Error(\"The rank (\" + this.rank + \") of the program must match the \" +\r\n                    (\"length of start (\" + start.length + \")\"));\r\n            }\r\n            return function (gpgpu, webGLProgram) {\r\n                if (_this.startLoc == null) {\r\n                    _this.startLoc = gpgpu.getUniformLocationNoThrow(webGLProgram, 'start');\r\n                    if (_this.startLoc == null) {\r\n                        return;\r\n                    }\r\n                }\r\n                gpgpu.gl.uniform1iv(_this.startLoc, start);\r\n            };\r\n        };\r\n        return SliceProgram;\r\n    }());\r\n    var coords = ['x', 'y', 'z', 'w', 'u', 'v'];\r\n    function getCoords$1(rank) {\r\n        if (rank === 1) {\r\n            return 'sourceLoc';\r\n        }\r\n        else if (rank <= 6) {\r\n            return coords.slice(0, rank).map(function (x) { return 'sourceLoc.' + x; }).join(',');\r\n        }\r\n        else {\r\n            throw Error(\"Slicing for rank \" + rank + \" is not yet supported\");\r\n        }\r\n    }\n\n    var SlicePackedProgram = (function () {\r\n        function SlicePackedProgram(destSize) {\r\n            this.variableNames = ['source'];\r\n            this.usesPackedTextures = true;\r\n            this.outputShape = destSize;\r\n            this.rank = destSize.length;\r\n            var dtype = getCoordsDataType(this.rank);\r\n            var coords = getChannels('coords', this.rank);\r\n            var sourceLoc = getChannels('sourceLoc', this.rank);\r\n            var innerDims = this.rank === 1 ? 'sourceLoc' : \"vec2(\" + sourceLoc.slice(-2).join() + \")\";\r\n            var getChannel = \"getChannel(getSource(\" + sourceLoc.join() + \"), \" + innerDims + \")\";\r\n            var upperRow = \"\\n      result.x = \" + getChannel + \";\\n      if (++\" + coords[this.rank - 1] + \" < \" + destSize[this.rank - 1] + \") {\\n        ++\" + sourceLoc[this.rank - 1] + \";\\n        result.y = \" + getChannel + \";\\n        --\" + sourceLoc[this.rank - 1] + \";\\n      }\\n    \";\r\n            var lowerRow = this.rank === 1 ? '' : \"\\n      --\" + coords[this.rank - 1] + \";\\n      if (++\" + coords[this.rank - 2] + \" < \" + destSize[this.rank - 2] + \") {\\n        ++\" + sourceLoc[this.rank - 2] + \";\\n        result.z = \" + getChannel + \";\\n        if (++\" + coords[this.rank - 1] + \" < \" + destSize[this.rank - 1] + \") {\\n          ++\" + sourceLoc[this.rank - 1] + \";\\n          result.w = \" + getChannel + \";\\n        }\\n      }\\n    \";\r\n            var sourceLocSetup = this.rank <= 4 ?\r\n                \"sourceLoc = coords +\\n            \" + dtype + \"(\" + destSize.map(function (_, i) { return \"start[\" + i + \"]\"; }).join() + \");\" :\r\n                destSize.map(function (_, i) { return sourceLoc[i] + \" = \" + coords[i] + \" + start[\" + i + \"];\"; })\r\n                    .join('\\n');\r\n            this.userCode = \"\\n      uniform int start[\" + this.rank + \"];\\n      void main() {\\n        \" + dtype + \" coords = getOutputCoords();\\n        \" + dtype + \" sourceLoc;\\n        \" + sourceLocSetup + \" \\n        vec4 result = vec4(0.);\\n        \" + upperRow + \"\\n        \" + lowerRow + \"\\n        setOutput(result);\\n      }\\n    \";\r\n        }\r\n        SlicePackedProgram.prototype.getCustomSetupFunc = function (start) {\r\n            var _this = this;\r\n            if (start.length !== this.rank) {\r\n                throw Error(\"The rank (\" + this.rank + \") of the program must match the \" +\r\n                    (\"length of start (\" + start.length + \")\"));\r\n            }\r\n            return function (gpgpu, webGLProgram) {\r\n                if (_this.startLoc == null) {\r\n                    _this.startLoc = gpgpu.getUniformLocationNoThrow(webGLProgram, 'start');\r\n                    if (_this.startLoc == null) {\r\n                        return;\r\n                    }\r\n                }\r\n                gpgpu.gl.uniform1iv(_this.startLoc, start);\r\n            };\r\n        };\r\n        return SlicePackedProgram;\r\n    }());\n\n    var StridedSliceProgram = (function () {\r\n        function StridedSliceProgram(begin, strides, size, shrinkAxis) {\r\n            this.variableNames = ['x'];\r\n            var shape = size.filter(function (v, index) { return shrinkAxis.indexOf(index) === -1; });\r\n            this.outputShape = shape;\r\n            var rank = size.length;\r\n            var inputDtype = getCoordsDataType(size.length);\r\n            var dtype = getCoordsDataType(shape.length);\r\n            var newCoords = '';\r\n            if (rank === 1) {\r\n                newCoords = 'coords * strides + begin';\r\n            }\r\n            else {\r\n                var outputAxis_1 = 0;\r\n                newCoords =\r\n                    size.map(function (_, i) {\r\n                        if (shrinkAxis.indexOf(i) === -1) {\r\n                            outputAxis_1++;\r\n                            return shape.length === 1 ?\r\n                                \"coords * strides[\" + i + \"] + begin[\" + i + \"]\" :\r\n                                \"coords[\" + (outputAxis_1 - 1) + \"] * strides[\" + i + \"] + begin[\" + i + \"]\";\r\n                        }\r\n                        else {\r\n                            return \"begin[\" + i + \"]\";\r\n                        }\r\n                    })\r\n                        .join(',');\r\n            }\r\n            this.userCode = \"\\n      \" + inputDtype + \" begin = \" + inputDtype + \"(\" + begin + \");\\n      \" + inputDtype + \" strides = \" + inputDtype + \"(\" + strides + \");\\n\\n      void main() {\\n        \" + dtype + \" coords = getOutputCoords();\\n        setOutput(getX(\" + newCoords + \"));\\n      }\\n    \";\r\n        }\r\n        return StridedSliceProgram;\r\n    }());\n\n    var TextureManager = (function () {\r\n        function TextureManager(gpgpu) {\r\n            this.gpgpu = gpgpu;\r\n            this.numUsedTextures = 0;\r\n            this.numFreeTextures = 0;\r\n            this.freeTextures = {};\r\n            this.logEnabled = false;\r\n            this.usedTextures = {};\r\n        }\r\n        TextureManager.prototype.acquireTexture = function (shapeRC, usage, isPacked) {\r\n            var physicalTexType = getPhysicalFromLogicalTextureType(usage, isPacked);\r\n            var shapeKey = getKeyFromTextureShape(shapeRC, physicalTexType, isPacked);\r\n            if (!(shapeKey in this.freeTextures)) {\r\n                this.freeTextures[shapeKey] = [];\r\n            }\r\n            if (!(shapeKey in this.usedTextures)) {\r\n                this.usedTextures[shapeKey] = [];\r\n            }\r\n            if (this.freeTextures[shapeKey].length > 0) {\r\n                this.numFreeTextures--;\r\n                this.numUsedTextures++;\r\n                this.log();\r\n                var newTexture_1 = this.freeTextures[shapeKey].shift();\r\n                this.usedTextures[shapeKey].push(newTexture_1);\r\n                return newTexture_1;\r\n            }\r\n            this.numUsedTextures++;\r\n            this.log();\r\n            var newTexture;\r\n            if (physicalTexType === PhysicalTextureType.PACKED_2X2_FLOAT32) {\r\n                newTexture = this.gpgpu.createPackedMatrixTexture(shapeRC[0], shapeRC[1]);\r\n            }\r\n            else if (physicalTexType === PhysicalTextureType.PACKED_2X2_FLOAT16) {\r\n                newTexture =\r\n                    this.gpgpu.createFloat16PackedMatrixTexture(shapeRC[0], shapeRC[1]);\r\n            }\r\n            else if (physicalTexType === PhysicalTextureType.UNPACKED_FLOAT32) {\r\n                newTexture =\r\n                    this.gpgpu.createFloat32MatrixTexture(shapeRC[0], shapeRC[1]);\r\n            }\r\n            else if (physicalTexType === PhysicalTextureType.UNPACKED_FLOAT16) {\r\n                newTexture =\r\n                    this.gpgpu.createFloat16MatrixTexture(shapeRC[0], shapeRC[1]);\r\n            }\r\n            else if (physicalTexType === PhysicalTextureType.PACKED_4X1_UNSIGNED_BYTE) {\r\n                newTexture =\r\n                    this.gpgpu.createUnsignedBytesMatrixTexture(shapeRC[0], shapeRC[1]);\r\n            }\r\n            this.usedTextures[shapeKey].push(newTexture);\r\n            return newTexture;\r\n        };\r\n        TextureManager.prototype.releaseTexture = function (texture, shape, logicalTexType, isPacked) {\r\n            if (this.freeTextures == null) {\r\n                return;\r\n            }\r\n            var physicalTexType = getPhysicalFromLogicalTextureType(logicalTexType, isPacked);\r\n            var shapeKey = getKeyFromTextureShape(shape, physicalTexType, isPacked);\r\n            if (!(shapeKey in this.freeTextures)) {\r\n                this.freeTextures[shapeKey] = [];\r\n            }\r\n            this.freeTextures[shapeKey].push(texture);\r\n            this.numFreeTextures++;\r\n            this.numUsedTextures--;\r\n            var texList = this.usedTextures[shapeKey];\r\n            var texIndex = texList.indexOf(texture);\r\n            if (texIndex < 0) {\r\n                throw new Error('Cannot release a texture that was never provided by this ' +\r\n                    'texture manager');\r\n            }\r\n            texList.splice(texIndex, 1);\r\n            this.log();\r\n        };\r\n        TextureManager.prototype.log = function () {\r\n            if (!this.logEnabled) {\r\n                return;\r\n            }\r\n            var total = this.numFreeTextures + this.numUsedTextures;\r\n            console.log('Free/Used', this.numFreeTextures + \" / \" + this.numUsedTextures, \"(\" + total + \")\");\r\n        };\r\n        TextureManager.prototype.getNumUsedTextures = function () {\r\n            return this.numUsedTextures;\r\n        };\r\n        TextureManager.prototype.getNumFreeTextures = function () {\r\n            return this.numFreeTextures;\r\n        };\r\n        TextureManager.prototype.dispose = function () {\r\n            var _this = this;\r\n            if (this.freeTextures == null) {\r\n                return;\r\n            }\r\n            for (var texShape in this.freeTextures) {\r\n                this.freeTextures[texShape].forEach(function (tex) {\r\n                    _this.gpgpu.deleteMatrixTexture(tex);\r\n                });\r\n            }\r\n            for (var texShape in this.usedTextures) {\r\n                this.usedTextures[texShape].forEach(function (tex) {\r\n                    _this.gpgpu.deleteMatrixTexture(tex);\r\n                });\r\n            }\r\n            this.freeTextures = null;\r\n            this.usedTextures = null;\r\n            this.numUsedTextures = 0;\r\n            this.numFreeTextures = 0;\r\n        };\r\n        return TextureManager;\r\n    }());\r\n    function getPhysicalFromLogicalTextureType(logicalTexType, isPacked) {\r\n        if (logicalTexType === TextureUsage.UPLOAD) {\r\n            return isPacked ? PhysicalTextureType.PACKED_2X2_FLOAT32 :\r\n                PhysicalTextureType.UNPACKED_FLOAT32;\r\n        }\r\n        else if (logicalTexType === TextureUsage.RENDER || logicalTexType == null) {\r\n            if (isPacked) {\r\n                return ENV.get('WEBGL_RENDER_FLOAT32_ENABLED') ?\r\n                    PhysicalTextureType.PACKED_2X2_FLOAT32 :\r\n                    PhysicalTextureType.PACKED_2X2_FLOAT16;\r\n            }\r\n            return ENV.get('WEBGL_RENDER_FLOAT32_ENABLED') ?\r\n                PhysicalTextureType.UNPACKED_FLOAT32 :\r\n                PhysicalTextureType.UNPACKED_FLOAT16;\r\n        }\r\n        else if (logicalTexType === TextureUsage.DOWNLOAD ||\r\n            logicalTexType === TextureUsage.PIXELS) {\r\n            return PhysicalTextureType.PACKED_4X1_UNSIGNED_BYTE;\r\n        }\r\n        throw new Error(\"Unknown logical texture type \" + logicalTexType);\r\n    }\r\n    function getKeyFromTextureShape(shapeRowsCol, physicalTexType, isPacked) {\r\n        return shapeRowsCol[0] + \"_\" + shapeRowsCol[1] + \"_\" + physicalTexType + \"_\" + isPacked;\r\n    }\n\n    var TileProgram = (function () {\r\n        function TileProgram(aShape, reps) {\r\n            this.variableNames = ['A'];\r\n            var outputShape = new Array(aShape.length);\r\n            for (var i = 0; i < outputShape.length; i++) {\r\n                outputShape[i] = aShape[i] * reps[i];\r\n            }\r\n            this.outputShape = outputShape;\r\n            this.rank = outputShape.length;\r\n            var dtype = getCoordsDataType(this.rank);\r\n            var sourceCoords = getSourceCoords$2(aShape);\r\n            this.userCode = \"\\n      void main() {\\n        \" + dtype + \" resRC = getOutputCoords();\\n        setOutput(getA(\" + sourceCoords + \"));\\n      }\\n    \";\r\n        }\r\n        return TileProgram;\r\n    }());\r\n    function getSourceCoords$2(aShape) {\r\n        var rank = aShape.length;\r\n        if (rank > 5) {\r\n            throw Error(\"Tile for rank \" + rank + \" is not yet supported\");\r\n        }\r\n        if (rank === 1) {\r\n            return \"imod(resRC, \" + aShape[0] + \")\";\r\n        }\r\n        var currentCoords = ['resRC.x', 'resRC.y', 'resRC.z', 'resRC.w', 'resRC.u'];\r\n        var sourceCoords = [];\r\n        for (var i = 0; i < aShape.length; i++) {\r\n            sourceCoords.push(\"imod(\" + currentCoords[i] + \", \" + aShape[i] + \")\");\r\n        }\r\n        return sourceCoords.join();\r\n    }\n\n    var TransposeProgram = (function () {\r\n        function TransposeProgram(aShape, newDim) {\r\n            this.variableNames = ['A'];\r\n            var outputShape = new Array(aShape.length);\r\n            for (var i = 0; i < outputShape.length; i++) {\r\n                outputShape[i] = aShape[newDim[i]];\r\n            }\r\n            this.outputShape = outputShape;\r\n            this.rank = outputShape.length;\r\n            var dtype = getCoordsDataType(this.rank);\r\n            var switched = getSwitchedCoords(newDim);\r\n            this.userCode = \"\\n    void main() {\\n      \" + dtype + \" resRC = getOutputCoords();\\n      setOutput(getA(\" + switched + \"));\\n    }\\n    \";\r\n        }\r\n        return TransposeProgram;\r\n    }());\r\n    function getSwitchedCoords(newDim) {\r\n        var rank = newDim.length;\r\n        if (rank > 6) {\r\n            throw Error(\"Transpose for rank \" + rank + \" is not yet supported\");\r\n        }\r\n        var originalOrder = ['resRC.x', 'resRC.y', 'resRC.z', 'resRC.w', 'resRC.u', 'resRC.v'];\r\n        var switchedCoords = new Array(rank);\r\n        for (var i = 0; i < newDim.length; i++) {\r\n            switchedCoords[newDim[i]] = originalOrder[i];\r\n        }\r\n        return switchedCoords.join();\r\n    }\n\n    var TransposePackedProgram = (function () {\r\n        function TransposePackedProgram(aShape, newDim) {\r\n            this.variableNames = ['A'];\r\n            this.usesPackedTextures = true;\r\n            var outputShape = new Array(aShape.length);\r\n            for (var i = 0; i < outputShape.length; i++) {\r\n                outputShape[i] = aShape[newDim[i]];\r\n            }\r\n            this.outputShape = outputShape;\r\n            this.rank = outputShape.length;\r\n            if (this.rank > 6) {\r\n                throw Error(\"Packed transpose for rank \" + this.rank + \" is not yet supported.\");\r\n            }\r\n            var dtype = getCoordsDataType(this.rank);\r\n            var outputOrder = getVecChannels('rc', this.rank);\r\n            var switchedOrder = new Array(this.rank);\r\n            for (var i = 0; i < newDim.length; i++) {\r\n                switchedOrder[newDim[i]] = outputOrder[i];\r\n            }\r\n            var innerDims = \"vec2(\" + switchedOrder.slice(-2).join() + \")\";\r\n            var nextColumn = \"++\" + outputOrder[this.rank - 1] + \" < \" + outputShape[this.rank - 1];\r\n            var getc = \"getChannel(getA(\" + switchedOrder.join() + \"), \" + innerDims + \")\";\r\n            this.userCode = \"\\n    void main() {\\n      \" + dtype + \" rc = getOutputCoords();\\n      vec4 result = vec4(0.);\\n      result[0] = \" + getc + \";\\n      if(\" + nextColumn + \") {\\n        result[1] = \" + getc + \";\\n      }\\n      --\" + outputOrder[this.rank - 1] + \";\\n      if(++\" + outputOrder[this.rank - 2] + \" < \" + outputShape[this.rank - 2] + \") {\\n        result[2] = \" + getc + \";\\n        if(\" + nextColumn + \") {\\n          result[3] = \" + getc + \";\\n        }\\n      }  \\n      setOutput(result);\\n    }\\n    \";\r\n        }\r\n        return TransposePackedProgram;\r\n    }());\n\n    var ERF_P = 0.3275911;\r\n    var ERF_A1 = 0.254829592;\r\n    var ERF_A2 = -0.284496736;\r\n    var ERF_A3 = 1.421413741;\r\n    var ERF_A4 = -1.453152027;\r\n    var ERF_A5 = 1.061405429;\n\n    var SELU_SCALEALPHA = 1.7580993408473768599402175208123;\r\n    var SELU_SCALE = 1.0507009873554804934193349852946;\n\n    var UnaryOpProgram = (function () {\r\n        function UnaryOpProgram(aShape, opSnippet) {\r\n            this.variableNames = ['A'];\r\n            this.outputShape = aShape;\r\n            this.userCode = \"\\n      uniform float NAN;\\n      float unaryOperation(float x) {\\n        \" + opSnippet + \"\\n      }\\n\\n      void main() {\\n        float x = getAAtOutCoords();\\n        float y = unaryOperation(x);\\n\\n        setOutput(y);\\n      }\\n    \";\r\n        }\r\n        UnaryOpProgram.prototype.getCustomSetupFunc = function () {\r\n            var _this = this;\r\n            return function (gpgpu, webGLProgram) {\r\n                if (_this.startLoc == null) {\r\n                    _this.startLoc = gpgpu.getUniformLocationNoThrow(webGLProgram, 'NAN');\r\n                    if (_this.startLoc == null) {\r\n                        return;\r\n                    }\r\n                }\r\n                gpgpu.gl.uniform1f(_this.startLoc, NaN);\r\n            };\r\n        };\r\n        return UnaryOpProgram;\r\n    }());\r\n    var CHECK_NAN_SNIPPET$1 = \"if (isNaN(x)) return x;\";\r\n    var LINEAR = \"return x;\";\r\n    var ABS = \"return abs(x);\";\r\n    var RELU = CHECK_NAN_SNIPPET$1 + \"\\n  return (x < 0.0) ? 0.0 : x;\\n\";\r\n    var ELU = \"return (x >= 0.0) ? x : (exp(x) - 1.0);\";\r\n    var SELU = \"\\n  // Stable and Attracting Fixed Point (0, 1) for Normalized Weights.\\n  // see: https://arxiv.org/abs/1706.02515\\n  float scaleAlpha = \" + SELU_SCALEALPHA + \";\\n  float scale = \" + SELU_SCALE + \";\\n  return (x >= 0.0) ? scale * x : scaleAlpha * (exp(x) - 1.0);\\n\";\r\n    function STEP(alpha) {\r\n        if (alpha === void 0) { alpha = 0.0; }\r\n        return CHECK_NAN_SNIPPET$1 + (\"\\n    return x > 0.0 ? 1.0 : float(\" + alpha + \");\\n  \");\r\n    }\r\n    var NEG = \"return -x;\";\r\n    var CEIL = \"return ceil(x);\";\r\n    var FLOOR = \"return floor(x);\";\r\n    var SIGN = \"\\n  if (isNaN(x)) { return 0.0; }\\n  return sign(x);\\n\";\r\n    var ROUND = \"\\n  // OpenGL ES does not support round function.\\n  // The algorithm is based on banker's rounding.\\n  float base = floor(x);\\n  if ((x - base) < 0.5) {\\n    return floor(x);\\n  } else if ((x - base) > 0.5) {\\n    return ceil(x);\\n  } else {\\n    if (mod(base, 2.0) == 0.0) {\\n      return base;\\n    } else {\\n      return base + 1.0;\\n    }\\n  }\\n\";\r\n    var EXP = \"return exp(x);\";\r\n    var EXPM1 = \"return exp(x) - 1.0;\";\r\n    var LOG = \"if (x < 0.0) return NAN;\\n  return log(x);\";\r\n    var LOG1P = \"return log(1.0 + x);\";\r\n    var SQRT = \"return sqrt(x);\";\r\n    var RSQRT = \"return inversesqrt(x);\";\r\n    var SIGMOID = \"return 1.0 / (1.0 + exp(-1.0 * x));\";\r\n    var SOFTPLUS = \"\\n  float epsilon = 1.1920928955078125e-7;\\n  float threshold = log(epsilon) + 2.0;\\n\\n  bool too_large = x > -threshold;\\n  bool too_small = x < threshold;\\n\\n  float result;\\n  float exp_x = exp(x);\\n\\n  if (too_large){\\n    result = x;\\n  }\\n  else if (too_small){\\n    result = exp_x;\\n  }\\n  else{\\n    result = log(exp_x + 1.0);\\n  }\\n  return result;\\n\";\r\n    var SIN = CHECK_NAN_SNIPPET$1 + \"\\n  return sin(x);\\n\";\r\n    var COS = CHECK_NAN_SNIPPET$1 + \"\\n  return cos(x);\\n\";\r\n    var TAN = \"return tan(x);\";\r\n    var ASIN = \"return asin(x);\";\r\n    var ACOS = \"return acos(x);\";\r\n    var ATAN = CHECK_NAN_SNIPPET$1 + \"\\n  return atan(x);\\n\";\r\n    var SINH = \"\\n  float e2x = exp(x);\\n  return (e2x - 1.0 / e2x) / 2.0;\\n\";\r\n    var COSH = \"\\n  float e2x = exp(-x);\\n  return (e2x + 1.0 / e2x) / 2.0;\\n\";\r\n    var TANH = \"\\n  float e2x = exp(-2.0 * abs(x));\\n  return sign(x) * (1.0 - e2x) / (1.0 + e2x);\\n\";\r\n    var ASINH = \"return log(x + sqrt(x * x + 1.0));\";\r\n    var ACOSH = CHECK_NAN_SNIPPET$1 + \"\\n  if (x < 1.0) return NAN;\\n  return log(x + sqrt(x * x - 1.0));\";\r\n    var ATANH = CHECK_NAN_SNIPPET$1 + \"\\n  if ((x < -1.0) || (x > 1.0)) return NAN;\\n  return (log(1.0 + x) - log(1.0 - x)) / 2.0;\";\r\n    var ERF = \"\\n  // Error function is calculated approximately with elementary function.\\n  // See \\\"Handbook of Mathematical Functions with Formulas,\\n  // Graphs, and Mathematical Tables\\\", Abramowitz and Stegun.\\n  float p = \" + ERF_P + \";\\n  float a1 = \" + ERF_A1 + \";\\n  float a2 = \" + ERF_A2 + \";\\n  float a3 = \" + ERF_A3 + \";\\n  float a4 = \" + ERF_A4 + \";\\n  float a5 = \" + ERF_A5 + \";\\n\\n  float t = 1.0 / (1.0 + p * x);\\n  return 1.0 - (((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*exp(-x*x);\\n\";\r\n    var SQUARE = \"return x * x;\";\r\n    var RECIPROCAL = \"return 1.0 / x;\";\r\n    var LOGICAL_NOT = \"return float(!(x >= 1.0));\";\r\n    var TO_INT = \"return float(int(x));\";\r\n    var CLONE = 'return x;';\n\n    var LINEAR$1 = \"return x;\";\r\n    var LOG$1 = \"\\n  vec4 result = log(x);\\n  vec4 isNaN = vec4(lessThan(x, vec4(0.0)));\\n  result.r = isNaN.r == 1.0 ? NAN : result.r;\\n  result.g = isNaN.g == 1.0 ? NAN : result.g;\\n  result.b = isNaN.b == 1.0 ? NAN : result.b;\\n  result.a = isNaN.a == 1.0 ? NAN : result.a;\\n\\n  return result;\\n\";\r\n    var RELU$1 = \"\\n  vec4 result = x * vec4(greaterThanEqual(x, vec4(0.0)));\\n\\n  result.r = isNaN(x.r) ? x.r : result.r;\\n  result.g = isNaN(x.g) ? x.g : result.g;\\n  result.b = isNaN(x.b) ? x.b : result.b;\\n  result.a = isNaN(x.a) ? x.a : result.a;\\n\\n  return result;\\n\";\r\n    var UnaryOpPackedProgram = (function () {\r\n        function UnaryOpPackedProgram(aShape, opSnippet) {\r\n            this.variableNames = ['A'];\r\n            this.usesPackedTextures = true;\r\n            this.outputShape = aShape;\r\n            this.userCode = \"\\n      uniform float NAN;\\n      vec4 unaryOperation(vec4 x) {\\n        \" + opSnippet + \"\\n      }\\n\\n      void main() {\\n        vec4 x = getAAtOutCoords();\\n        vec4 y = unaryOperation(x);\\n\\n        setOutput(y);\\n      }\\n    \";\r\n        }\r\n        UnaryOpPackedProgram.prototype.getCustomSetupFunc = function () {\r\n            var _this = this;\r\n            return function (gpgpu, webGLProgram) {\r\n                if (_this.startLoc == null) {\r\n                    _this.startLoc = gpgpu.getUniformLocationNoThrow(webGLProgram, 'NAN');\r\n                    if (_this.startLoc == null) {\r\n                        return;\r\n                    }\r\n                }\r\n                gpgpu.gl.uniform1f(_this.startLoc, NaN);\r\n            };\r\n        };\r\n        return UnaryOpPackedProgram;\r\n    }());\n\n    var UnpackProgram = (function () {\r\n        function UnpackProgram(outputShape) {\r\n            this.variableNames = ['A'];\r\n            this.usesPackedTextures = true;\r\n            this.outputShape = outputShape;\r\n            var rank = outputShape.length;\r\n            var channels = getChannels('rc', rank);\r\n            var dtype = getCoordsDataType(rank);\r\n            var sourceCoords = getSourceCoords$1(rank, channels);\r\n            var innerDims = channels.slice(-2);\r\n            var coords = rank <= 1 ? 'rc' : \"vec2(\" + innerDims.join(',') + \")\";\r\n            this.userCode = \"\\n      void main() {\\n        \" + dtype + \" rc = getOutputCoords();\\n        vec4 packedInput = getA(\" + sourceCoords + \");\\n\\n        setOutput(getChannel(packedInput, \" + coords + \"));\\n      }\\n    \";\r\n        }\r\n        return UnpackProgram;\r\n    }());\n\n    function concat1d_(tensors) {\r\n        return concat(tensors, 0);\r\n    }\r\n    function concat2d_(tensors, axis) {\r\n        return concat(tensors, axis);\r\n    }\r\n    function concat3d_(tensors, axis) {\r\n        return concat(tensors, axis);\r\n    }\r\n    function concat4d_(tensors, axis) {\r\n        return concat(tensors, axis);\r\n    }\r\n    function concat_(tensors, axis) {\r\n        if (axis === void 0) { axis = 0; }\r\n        assert(tensors.length >= 1, 'Pass at least one tensor to concat');\r\n        var $tensors = convertToTensorArray(tensors, 'tensors', 'concat');\r\n        axis = parseAxisParam(axis, $tensors[0].shape)[0];\r\n        var outShape = computeOutShape($tensors.map(function (t) { return t.shape; }), axis);\r\n        if (sizeFromShape(outShape) === 0) {\r\n            return tensor([], outShape);\r\n        }\r\n        $tensors = $tensors.filter(function (t) { return t.size > 0; });\r\n        if ($tensors.length === 1) {\r\n            return $tensors[0];\r\n        }\r\n        var shapes = $tensors.map(function (t) { return t.shape; });\r\n        assertParamsConsistent(shapes, axis);\r\n        var der = function (dy) {\r\n            var sizeSplits = shapes.map(function (s) { return s[axis]; });\r\n            var derTensors = split$1(dy, sizeSplits, axis);\r\n            return derTensors.map(function (t) { return function () { return t; }; });\r\n        };\r\n        var inputs = $tensors;\r\n        return ENV.engine.runKernel(function (backend) { return backend.concat($tensors, axis); }, inputs, der);\r\n    }\r\n    function split_(x, numOrSizeSplits, axis) {\r\n        if (axis === void 0) { axis = 0; }\r\n        var $x = convertToTensor(x, 'x', 'split');\r\n        axis = parseAxisParam(axis, $x.shape)[0];\r\n        var splitSizes;\r\n        if (typeof (numOrSizeSplits) === 'number') {\r\n            assert($x.shape[axis] % numOrSizeSplits === 0, 'Number of splits must evenly divide the axis.');\r\n            splitSizes =\r\n                new Array(numOrSizeSplits).fill($x.shape[axis] / numOrSizeSplits);\r\n        }\r\n        else {\r\n            assert($x.shape[axis] === numOrSizeSplits.reduce(function (a, b) { return a + b; }), 'The sum of sizes must match the size of the axis dimension.');\r\n            splitSizes = numOrSizeSplits;\r\n        }\r\n        var der = function (dy) { return ({ $x: function () { return concat(dy, axis); } }); };\r\n        return ENV.engine.runKernel(function (backend) { return backend.split($x, splitSizes, axis); }, { $x: $x }, der);\r\n    }\r\n    var concat = op({ concat_: concat_ });\r\n    var concat1d = op({ concat1d_: concat1d_ });\r\n    var concat2d = op({ concat2d_: concat2d_ });\r\n    var concat3d = op({ concat3d_: concat3d_ });\r\n    var concat4d = op({ concat4d_: concat4d_ });\r\n    var split$1 = op({ split_: split_ });\n\n    var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};\n\n    function createCommonjsModule(fn, module) {\n    \treturn module = { exports: {} }, fn(module, module.exports), module.exports;\n    }\n\n    var alea = createCommonjsModule(function (module) {\n    // A port of an algorithm by Johannes Baagøe <baagoe@baagoe.com>, 2010\n    // http://baagoe.com/en/RandomMusings/javascript/\n    // https://github.com/nquinlan/better-random-numbers-for-javascript-mirror\n    // Original work is under MIT license -\n\n    // Copyright (C) 2010 by Johannes Baagøe <baagoe@baagoe.org>\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    (function(global, module, define) {\n\n    function Alea(seed) {\n      var me = this, mash = Mash();\n\n      me.next = function() {\n        var t = 2091639 * me.s0 + me.c * 2.3283064365386963e-10; // 2^-32\n        me.s0 = me.s1;\n        me.s1 = me.s2;\n        return me.s2 = t - (me.c = t | 0);\n      };\n\n      // Apply the seeding algorithm from Baagoe.\n      me.c = 1;\n      me.s0 = mash(' ');\n      me.s1 = mash(' ');\n      me.s2 = mash(' ');\n      me.s0 -= mash(seed);\n      if (me.s0 < 0) { me.s0 += 1; }\n      me.s1 -= mash(seed);\n      if (me.s1 < 0) { me.s1 += 1; }\n      me.s2 -= mash(seed);\n      if (me.s2 < 0) { me.s2 += 1; }\n      mash = null;\n    }\n\n    function copy(f, t) {\n      t.c = f.c;\n      t.s0 = f.s0;\n      t.s1 = f.s1;\n      t.s2 = f.s2;\n      return t;\n    }\n\n    function impl(seed, opts) {\n      var xg = new Alea(seed),\n          state = opts && opts.state,\n          prng = xg.next;\n      prng.int32 = function() { return (xg.next() * 0x100000000) | 0; };\n      prng.double = function() {\n        return prng() + (prng() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53\n      };\n      prng.quick = prng;\n      if (state) {\n        if (typeof(state) == 'object') copy(state, xg);\n        prng.state = function() { return copy(xg, {}); };\n      }\n      return prng;\n    }\n\n    function Mash() {\n      var n = 0xefc8249d;\n\n      var mash = function(data) {\n        data = data.toString();\n        for (var i = 0; i < data.length; i++) {\n          n += data.charCodeAt(i);\n          var h = 0.02519603282416938 * n;\n          n = h >>> 0;\n          h -= n;\n          h *= n;\n          n = h >>> 0;\n          h -= n;\n          n += h * 0x100000000; // 2^32\n        }\n        return (n >>> 0) * 2.3283064365386963e-10; // 2^-32\n      };\n\n      return mash;\n    }\n\n\n    if (module && module.exports) {\n      module.exports = impl;\n    } else if (define && define.amd) {\n      define(function() { return impl; });\n    } else {\n      this.alea = impl;\n    }\n\n    })(\n      commonjsGlobal,\n      module,    // present in node.js\n      (typeof undefined) == 'function' && undefined   // present with an AMD loader\n    );\n    });\n\n    var xor128 = createCommonjsModule(function (module) {\n    // A Javascript implementaion of the \"xor128\" prng algorithm by\n    // George Marsaglia.  See http://www.jstatsoft.org/v08/i14/paper\n\n    (function(global, module, define) {\n\n    function XorGen(seed) {\n      var me = this, strseed = '';\n\n      me.x = 0;\n      me.y = 0;\n      me.z = 0;\n      me.w = 0;\n\n      // Set up generator function.\n      me.next = function() {\n        var t = me.x ^ (me.x << 11);\n        me.x = me.y;\n        me.y = me.z;\n        me.z = me.w;\n        return me.w ^= (me.w >>> 19) ^ t ^ (t >>> 8);\n      };\n\n      if (seed === (seed | 0)) {\n        // Integer seed.\n        me.x = seed;\n      } else {\n        // String seed.\n        strseed += seed;\n      }\n\n      // Mix in string seed, then discard an initial batch of 64 values.\n      for (var k = 0; k < strseed.length + 64; k++) {\n        me.x ^= strseed.charCodeAt(k) | 0;\n        me.next();\n      }\n    }\n\n    function copy(f, t) {\n      t.x = f.x;\n      t.y = f.y;\n      t.z = f.z;\n      t.w = f.w;\n      return t;\n    }\n\n    function impl(seed, opts) {\n      var xg = new XorGen(seed),\n          state = opts && opts.state,\n          prng = function() { return (xg.next() >>> 0) / 0x100000000; };\n      prng.double = function() {\n        do {\n          var top = xg.next() >>> 11,\n              bot = (xg.next() >>> 0) / 0x100000000,\n              result = (top + bot) / (1 << 21);\n        } while (result === 0);\n        return result;\n      };\n      prng.int32 = xg.next;\n      prng.quick = prng;\n      if (state) {\n        if (typeof(state) == 'object') copy(state, xg);\n        prng.state = function() { return copy(xg, {}); };\n      }\n      return prng;\n    }\n\n    if (module && module.exports) {\n      module.exports = impl;\n    } else if (define && define.amd) {\n      define(function() { return impl; });\n    } else {\n      this.xor128 = impl;\n    }\n\n    })(\n      commonjsGlobal,\n      module,    // present in node.js\n      (typeof undefined) == 'function' && undefined   // present with an AMD loader\n    );\n    });\n\n    var xorwow = createCommonjsModule(function (module) {\n    // A Javascript implementaion of the \"xorwow\" prng algorithm by\n    // George Marsaglia.  See http://www.jstatsoft.org/v08/i14/paper\n\n    (function(global, module, define) {\n\n    function XorGen(seed) {\n      var me = this, strseed = '';\n\n      // Set up generator function.\n      me.next = function() {\n        var t = (me.x ^ (me.x >>> 2));\n        me.x = me.y; me.y = me.z; me.z = me.w; me.w = me.v;\n        return (me.d = (me.d + 362437 | 0)) +\n           (me.v = (me.v ^ (me.v << 4)) ^ (t ^ (t << 1))) | 0;\n      };\n\n      me.x = 0;\n      me.y = 0;\n      me.z = 0;\n      me.w = 0;\n      me.v = 0;\n\n      if (seed === (seed | 0)) {\n        // Integer seed.\n        me.x = seed;\n      } else {\n        // String seed.\n        strseed += seed;\n      }\n\n      // Mix in string seed, then discard an initial batch of 64 values.\n      for (var k = 0; k < strseed.length + 64; k++) {\n        me.x ^= strseed.charCodeAt(k) | 0;\n        if (k == strseed.length) {\n          me.d = me.x << 10 ^ me.x >>> 4;\n        }\n        me.next();\n      }\n    }\n\n    function copy(f, t) {\n      t.x = f.x;\n      t.y = f.y;\n      t.z = f.z;\n      t.w = f.w;\n      t.v = f.v;\n      t.d = f.d;\n      return t;\n    }\n\n    function impl(seed, opts) {\n      var xg = new XorGen(seed),\n          state = opts && opts.state,\n          prng = function() { return (xg.next() >>> 0) / 0x100000000; };\n      prng.double = function() {\n        do {\n          var top = xg.next() >>> 11,\n              bot = (xg.next() >>> 0) / 0x100000000,\n              result = (top + bot) / (1 << 21);\n        } while (result === 0);\n        return result;\n      };\n      prng.int32 = xg.next;\n      prng.quick = prng;\n      if (state) {\n        if (typeof(state) == 'object') copy(state, xg);\n        prng.state = function() { return copy(xg, {}); };\n      }\n      return prng;\n    }\n\n    if (module && module.exports) {\n      module.exports = impl;\n    } else if (define && define.amd) {\n      define(function() { return impl; });\n    } else {\n      this.xorwow = impl;\n    }\n\n    })(\n      commonjsGlobal,\n      module,    // present in node.js\n      (typeof undefined) == 'function' && undefined   // present with an AMD loader\n    );\n    });\n\n    var xorshift7 = createCommonjsModule(function (module) {\n    // A Javascript implementaion of the \"xorshift7\" algorithm by\n    // François Panneton and Pierre L'ecuyer:\n    // \"On the Xorgshift Random Number Generators\"\n    // http://saluc.engr.uconn.edu/refs/crypto/rng/panneton05onthexorshift.pdf\n\n    (function(global, module, define) {\n\n    function XorGen(seed) {\n      var me = this;\n\n      // Set up generator function.\n      me.next = function() {\n        // Update xor generator.\n        var X = me.x, i = me.i, t, v;\n        t = X[i]; t ^= (t >>> 7); v = t ^ (t << 24);\n        t = X[(i + 1) & 7]; v ^= t ^ (t >>> 10);\n        t = X[(i + 3) & 7]; v ^= t ^ (t >>> 3);\n        t = X[(i + 4) & 7]; v ^= t ^ (t << 7);\n        t = X[(i + 7) & 7]; t = t ^ (t << 13); v ^= t ^ (t << 9);\n        X[i] = v;\n        me.i = (i + 1) & 7;\n        return v;\n      };\n\n      function init(me, seed) {\n        var j, w, X = [];\n\n        if (seed === (seed | 0)) {\n          // Seed state array using a 32-bit integer.\n          w = X[0] = seed;\n        } else {\n          // Seed state using a string.\n          seed = '' + seed;\n          for (j = 0; j < seed.length; ++j) {\n            X[j & 7] = (X[j & 7] << 15) ^\n                (seed.charCodeAt(j) + X[(j + 1) & 7] << 13);\n          }\n        }\n        // Enforce an array length of 8, not all zeroes.\n        while (X.length < 8) X.push(0);\n        for (j = 0; j < 8 && X[j] === 0; ++j);\n        if (j == 8) w = X[7] = -1; else w = X[j];\n\n        me.x = X;\n        me.i = 0;\n\n        // Discard an initial 256 values.\n        for (j = 256; j > 0; --j) {\n          me.next();\n        }\n      }\n\n      init(me, seed);\n    }\n\n    function copy(f, t) {\n      t.x = f.x.slice();\n      t.i = f.i;\n      return t;\n    }\n\n    function impl(seed, opts) {\n      if (seed == null) seed = +(new Date);\n      var xg = new XorGen(seed),\n          state = opts && opts.state,\n          prng = function() { return (xg.next() >>> 0) / 0x100000000; };\n      prng.double = function() {\n        do {\n          var top = xg.next() >>> 11,\n              bot = (xg.next() >>> 0) / 0x100000000,\n              result = (top + bot) / (1 << 21);\n        } while (result === 0);\n        return result;\n      };\n      prng.int32 = xg.next;\n      prng.quick = prng;\n      if (state) {\n        if (state.x) copy(state, xg);\n        prng.state = function() { return copy(xg, {}); };\n      }\n      return prng;\n    }\n\n    if (module && module.exports) {\n      module.exports = impl;\n    } else if (define && define.amd) {\n      define(function() { return impl; });\n    } else {\n      this.xorshift7 = impl;\n    }\n\n    })(\n      commonjsGlobal,\n      module,    // present in node.js\n      (typeof undefined) == 'function' && undefined   // present with an AMD loader\n    );\n    });\n\n    var xor4096 = createCommonjsModule(function (module) {\n    // A Javascript implementaion of Richard Brent's Xorgens xor4096 algorithm.\n    //\n    // This fast non-cryptographic random number generator is designed for\n    // use in Monte-Carlo algorithms. It combines a long-period xorshift\n    // generator with a Weyl generator, and it passes all common batteries\n    // of stasticial tests for randomness while consuming only a few nanoseconds\n    // for each prng generated.  For background on the generator, see Brent's\n    // paper: \"Some long-period random number generators using shifts and xors.\"\n    // http://arxiv.org/pdf/1004.3115v1.pdf\n    //\n    // Usage:\n    //\n    // var xor4096 = require('xor4096');\n    // random = xor4096(1);                        // Seed with int32 or string.\n    // assert.equal(random(), 0.1520436450538547); // (0, 1) range, 53 bits.\n    // assert.equal(random.int32(), 1806534897);   // signed int32, 32 bits.\n    //\n    // For nonzero numeric keys, this impelementation provides a sequence\n    // identical to that by Brent's xorgens 3 implementaion in C.  This\n    // implementation also provides for initalizing the generator with\n    // string seeds, or for saving and restoring the state of the generator.\n    //\n    // On Chrome, this prng benchmarks about 2.1 times slower than\n    // Javascript's built-in Math.random().\n\n    (function(global, module, define) {\n\n    function XorGen(seed) {\n      var me = this;\n\n      // Set up generator function.\n      me.next = function() {\n        var w = me.w,\n            X = me.X, i = me.i, t, v;\n        // Update Weyl generator.\n        me.w = w = (w + 0x61c88647) | 0;\n        // Update xor generator.\n        v = X[(i + 34) & 127];\n        t = X[i = ((i + 1) & 127)];\n        v ^= v << 13;\n        t ^= t << 17;\n        v ^= v >>> 15;\n        t ^= t >>> 12;\n        // Update Xor generator array state.\n        v = X[i] = v ^ t;\n        me.i = i;\n        // Result is the combination.\n        return (v + (w ^ (w >>> 16))) | 0;\n      };\n\n      function init(me, seed) {\n        var t, v, i, j, w, X = [], limit = 128;\n        if (seed === (seed | 0)) {\n          // Numeric seeds initialize v, which is used to generates X.\n          v = seed;\n          seed = null;\n        } else {\n          // String seeds are mixed into v and X one character at a time.\n          seed = seed + '\\0';\n          v = 0;\n          limit = Math.max(limit, seed.length);\n        }\n        // Initialize circular array and weyl value.\n        for (i = 0, j = -32; j < limit; ++j) {\n          // Put the unicode characters into the array, and shuffle them.\n          if (seed) v ^= seed.charCodeAt((j + 32) % seed.length);\n          // After 32 shuffles, take v as the starting w value.\n          if (j === 0) w = v;\n          v ^= v << 10;\n          v ^= v >>> 15;\n          v ^= v << 4;\n          v ^= v >>> 13;\n          if (j >= 0) {\n            w = (w + 0x61c88647) | 0;     // Weyl.\n            t = (X[j & 127] ^= (v + w));  // Combine xor and weyl to init array.\n            i = (0 == t) ? i + 1 : 0;     // Count zeroes.\n          }\n        }\n        // We have detected all zeroes; make the key nonzero.\n        if (i >= 128) {\n          X[(seed && seed.length || 0) & 127] = -1;\n        }\n        // Run the generator 512 times to further mix the state before using it.\n        // Factoring this as a function slows the main generator, so it is just\n        // unrolled here.  The weyl generator is not advanced while warming up.\n        i = 127;\n        for (j = 4 * 128; j > 0; --j) {\n          v = X[(i + 34) & 127];\n          t = X[i = ((i + 1) & 127)];\n          v ^= v << 13;\n          t ^= t << 17;\n          v ^= v >>> 15;\n          t ^= t >>> 12;\n          X[i] = v ^ t;\n        }\n        // Storing state as object members is faster than using closure variables.\n        me.w = w;\n        me.X = X;\n        me.i = i;\n      }\n\n      init(me, seed);\n    }\n\n    function copy(f, t) {\n      t.i = f.i;\n      t.w = f.w;\n      t.X = f.X.slice();\n      return t;\n    }\n    function impl(seed, opts) {\n      if (seed == null) seed = +(new Date);\n      var xg = new XorGen(seed),\n          state = opts && opts.state,\n          prng = function() { return (xg.next() >>> 0) / 0x100000000; };\n      prng.double = function() {\n        do {\n          var top = xg.next() >>> 11,\n              bot = (xg.next() >>> 0) / 0x100000000,\n              result = (top + bot) / (1 << 21);\n        } while (result === 0);\n        return result;\n      };\n      prng.int32 = xg.next;\n      prng.quick = prng;\n      if (state) {\n        if (state.X) copy(state, xg);\n        prng.state = function() { return copy(xg, {}); };\n      }\n      return prng;\n    }\n\n    if (module && module.exports) {\n      module.exports = impl;\n    } else if (define && define.amd) {\n      define(function() { return impl; });\n    } else {\n      this.xor4096 = impl;\n    }\n\n    })(\n      commonjsGlobal,                                     // window object or global\n      module,    // present in node.js\n      (typeof undefined) == 'function' && undefined   // present with an AMD loader\n    );\n    });\n\n    var tychei = createCommonjsModule(function (module) {\n    // A Javascript implementaion of the \"Tyche-i\" prng algorithm by\n    // Samuel Neves and Filipe Araujo.\n    // See https://eden.dei.uc.pt/~sneves/pubs/2011-snfa2.pdf\n\n    (function(global, module, define) {\n\n    function XorGen(seed) {\n      var me = this, strseed = '';\n\n      // Set up generator function.\n      me.next = function() {\n        var b = me.b, c = me.c, d = me.d, a = me.a;\n        b = (b << 25) ^ (b >>> 7) ^ c;\n        c = (c - d) | 0;\n        d = (d << 24) ^ (d >>> 8) ^ a;\n        a = (a - b) | 0;\n        me.b = b = (b << 20) ^ (b >>> 12) ^ c;\n        me.c = c = (c - d) | 0;\n        me.d = (d << 16) ^ (c >>> 16) ^ a;\n        return me.a = (a - b) | 0;\n      };\n\n      /* The following is non-inverted tyche, which has better internal\n       * bit diffusion, but which is about 25% slower than tyche-i in JS.\n      me.next = function() {\n        var a = me.a, b = me.b, c = me.c, d = me.d;\n        a = (me.a + me.b | 0) >>> 0;\n        d = me.d ^ a; d = d << 16 ^ d >>> 16;\n        c = me.c + d | 0;\n        b = me.b ^ c; b = b << 12 ^ d >>> 20;\n        me.a = a = a + b | 0;\n        d = d ^ a; me.d = d = d << 8 ^ d >>> 24;\n        me.c = c = c + d | 0;\n        b = b ^ c;\n        return me.b = (b << 7 ^ b >>> 25);\n      }\n      */\n\n      me.a = 0;\n      me.b = 0;\n      me.c = 2654435769 | 0;\n      me.d = 1367130551;\n\n      if (seed === Math.floor(seed)) {\n        // Integer seed.\n        me.a = (seed / 0x100000000) | 0;\n        me.b = seed | 0;\n      } else {\n        // String seed.\n        strseed += seed;\n      }\n\n      // Mix in string seed, then discard an initial batch of 64 values.\n      for (var k = 0; k < strseed.length + 20; k++) {\n        me.b ^= strseed.charCodeAt(k) | 0;\n        me.next();\n      }\n    }\n\n    function copy(f, t) {\n      t.a = f.a;\n      t.b = f.b;\n      t.c = f.c;\n      t.d = f.d;\n      return t;\n    }\n    function impl(seed, opts) {\n      var xg = new XorGen(seed),\n          state = opts && opts.state,\n          prng = function() { return (xg.next() >>> 0) / 0x100000000; };\n      prng.double = function() {\n        do {\n          var top = xg.next() >>> 11,\n              bot = (xg.next() >>> 0) / 0x100000000,\n              result = (top + bot) / (1 << 21);\n        } while (result === 0);\n        return result;\n      };\n      prng.int32 = xg.next;\n      prng.quick = prng;\n      if (state) {\n        if (typeof(state) == 'object') copy(state, xg);\n        prng.state = function() { return copy(xg, {}); };\n      }\n      return prng;\n    }\n\n    if (module && module.exports) {\n      module.exports = impl;\n    } else if (define && define.amd) {\n      define(function() { return impl; });\n    } else {\n      this.tychei = impl;\n    }\n\n    })(\n      commonjsGlobal,\n      module,    // present in node.js\n      (typeof undefined) == 'function' && undefined   // present with an AMD loader\n    );\n    });\n\n    var seedrandom = createCommonjsModule(function (module) {\n    /*\n    Copyright 2014 David Bau.\n\n    Permission is hereby granted, free of charge, to any person obtaining\n    a copy of this software and associated documentation files (the\n    \"Software\"), to deal in the Software without restriction, including\n    without limitation the rights to use, copy, modify, merge, publish,\n    distribute, sublicense, and/or sell copies of the Software, and to\n    permit persons to whom the Software is furnished to do so, subject to\n    the following conditions:\n\n    The above copyright notice and this permission notice shall be\n    included in all copies or substantial portions of the Software.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n    */\n\n    (function (pool, math) {\n    //\n    // The following constants are related to IEEE 754 limits.\n    //\n    var global = this,\n        width = 256,        // each RC4 output is 0 <= x < 256\n        chunks = 6,         // at least six RC4 outputs for each double\n        digits = 52,        // there are 52 significant digits in a double\n        rngname = 'random', // rngname: name for Math.random and Math.seedrandom\n        startdenom = math.pow(width, chunks),\n        significance = math.pow(2, digits),\n        overflow = significance * 2,\n        mask = width - 1,\n        nodecrypto;         // node.js crypto module, initialized at the bottom.\n\n    //\n    // seedrandom()\n    // This is the seedrandom function described above.\n    //\n    function seedrandom(seed, options, callback) {\n      var key = [];\n      options = (options == true) ? { entropy: true } : (options || {});\n\n      // Flatten the seed string or build one from local entropy if needed.\n      var shortseed = mixkey(flatten(\n        options.entropy ? [seed, tostring(pool)] :\n        (seed == null) ? autoseed() : seed, 3), key);\n\n      // Use the seed to initialize an ARC4 generator.\n      var arc4 = new ARC4(key);\n\n      // This function returns a random double in [0, 1) that contains\n      // randomness in every bit of the mantissa of the IEEE 754 value.\n      var prng = function() {\n        var n = arc4.g(chunks),             // Start with a numerator n < 2 ^ 48\n            d = startdenom,                 //   and denominator d = 2 ^ 48.\n            x = 0;                          //   and no 'extra last byte'.\n        while (n < significance) {          // Fill up all significant digits by\n          n = (n + x) * width;              //   shifting numerator and\n          d *= width;                       //   denominator and generating a\n          x = arc4.g(1);                    //   new least-significant-byte.\n        }\n        while (n >= overflow) {             // To avoid rounding up, before adding\n          n /= 2;                           //   last byte, shift everything\n          d /= 2;                           //   right using integer math until\n          x >>>= 1;                         //   we have exactly the desired bits.\n        }\n        return (n + x) / d;                 // Form the number within [0, 1).\n      };\n\n      prng.int32 = function() { return arc4.g(4) | 0; };\n      prng.quick = function() { return arc4.g(4) / 0x100000000; };\n      prng.double = prng;\n\n      // Mix the randomness into accumulated entropy.\n      mixkey(tostring(arc4.S), pool);\n\n      // Calling convention: what to return as a function of prng, seed, is_math.\n      return (options.pass || callback ||\n          function(prng, seed, is_math_call, state) {\n            if (state) {\n              // Load the arc4 state from the given state if it has an S array.\n              if (state.S) { copy(state, arc4); }\n              // Only provide the .state method if requested via options.state.\n              prng.state = function() { return copy(arc4, {}); };\n            }\n\n            // If called as a method of Math (Math.seedrandom()), mutate\n            // Math.random because that is how seedrandom.js has worked since v1.0.\n            if (is_math_call) { math[rngname] = prng; return seed; }\n\n            // Otherwise, it is a newer calling convention, so return the\n            // prng directly.\n            else return prng;\n          })(\n      prng,\n      shortseed,\n      'global' in options ? options.global : (this == math),\n      options.state);\n    }\n    math['seed' + rngname] = seedrandom;\n\n    //\n    // ARC4\n    //\n    // An ARC4 implementation.  The constructor takes a key in the form of\n    // an array of at most (width) integers that should be 0 <= x < (width).\n    //\n    // The g(count) method returns a pseudorandom integer that concatenates\n    // the next (count) outputs from ARC4.  Its return value is a number x\n    // that is in the range 0 <= x < (width ^ count).\n    //\n    function ARC4(key) {\n      var t, keylen = key.length,\n          me = this, i = 0, j = me.i = me.j = 0, s = me.S = [];\n\n      // The empty key [] is treated as [0].\n      if (!keylen) { key = [keylen++]; }\n\n      // Set up S using the standard key scheduling algorithm.\n      while (i < width) {\n        s[i] = i++;\n      }\n      for (i = 0; i < width; i++) {\n        s[i] = s[j = mask & (j + key[i % keylen] + (t = s[i]))];\n        s[j] = t;\n      }\n\n      // The \"g\" method returns the next (count) outputs as one number.\n      (me.g = function(count) {\n        // Using instance members instead of closure state nearly doubles speed.\n        var t, r = 0,\n            i = me.i, j = me.j, s = me.S;\n        while (count--) {\n          t = s[i = mask & (i + 1)];\n          r = r * width + s[mask & ((s[i] = s[j = mask & (j + t)]) + (s[j] = t))];\n        }\n        me.i = i; me.j = j;\n        return r;\n        // For robust unpredictability, the function call below automatically\n        // discards an initial batch of values.  This is called RC4-drop[256].\n        // See http://google.com/search?q=rsa+fluhrer+response&btnI\n      })(width);\n    }\n\n    //\n    // copy()\n    // Copies internal state of ARC4 to or from a plain object.\n    //\n    function copy(f, t) {\n      t.i = f.i;\n      t.j = f.j;\n      t.S = f.S.slice();\n      return t;\n    }\n    //\n    // flatten()\n    // Converts an object tree to nested arrays of strings.\n    //\n    function flatten(obj, depth) {\n      var result = [], typ = (typeof obj), prop;\n      if (depth && typ == 'object') {\n        for (prop in obj) {\n          try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {}\n        }\n      }\n      return (result.length ? result : typ == 'string' ? obj : obj + '\\0');\n    }\n\n    //\n    // mixkey()\n    // Mixes a string seed into a key that is an array of integers, and\n    // returns a shortened string seed that is equivalent to the result key.\n    //\n    function mixkey(seed, key) {\n      var stringseed = seed + '', smear, j = 0;\n      while (j < stringseed.length) {\n        key[mask & j] =\n          mask & ((smear ^= key[mask & j] * 19) + stringseed.charCodeAt(j++));\n      }\n      return tostring(key);\n    }\n\n    //\n    // autoseed()\n    // Returns an object for autoseeding, using window.crypto and Node crypto\n    // module if available.\n    //\n    function autoseed() {\n      try {\n        var out;\n        if (nodecrypto && (out = nodecrypto.randomBytes)) {\n          // The use of 'out' to remember randomBytes makes tight minified code.\n          out = out(width);\n        } else {\n          out = new Uint8Array(width);\n          (global.crypto || global.msCrypto).getRandomValues(out);\n        }\n        return tostring(out);\n      } catch (e) {\n        var browser = global.navigator,\n            plugins = browser && browser.plugins;\n        return [+new Date, global, plugins, global.screen, tostring(pool)];\n      }\n    }\n\n    //\n    // tostring()\n    // Converts an array of charcodes to a string\n    //\n    function tostring(a) {\n      return String.fromCharCode.apply(0, a);\n    }\n\n    //\n    // When seedrandom.js is loaded, we immediately mix a few bits\n    // from the built-in RNG into the entropy pool.  Because we do\n    // not want to interfere with deterministic PRNG state later,\n    // seedrandom will not call math.random on its own again after\n    // initialization.\n    //\n    mixkey(math.random(), pool);\n\n    //\n    // Nodejs and AMD support: export the implementation as a module using\n    // either convention.\n    //\n    if (module.exports) {\n      module.exports = seedrandom;\n      // When in node.js, try using crypto package for autoseeding.\n      try {\n        nodecrypto = require('crypto');\n      } catch (ex) {}\n    } else if ((typeof undefined) == 'function' && undefined.amd) {\n      undefined(function() { return seedrandom; });\n    }\n\n    // End anonymous scope, and pass initial values.\n    })(\n      [],     // pool: entropy pool starts empty\n      Math    // math: package containing random, pow, and seedrandom\n    );\n    });\n\n    // A library of seedable RNGs implemented in Javascript.\n    //\n    // Usage:\n    //\n    // var seedrandom = require('seedrandom');\n    // var random = seedrandom(1); // or any seed.\n    // var x = random();       // 0 <= x < 1.  Every bit is random.\n    // var x = random.quick(); // 0 <= x < 1.  32 bits of randomness.\n\n    // alea, a 53-bit multiply-with-carry generator by Johannes Baagøe.\n    // Period: ~2^116\n    // Reported to pass all BigCrush tests.\n\n\n    // xor128, a pure xor-shift generator by George Marsaglia.\n    // Period: 2^128-1.\n    // Reported to fail: MatrixRank and LinearComp.\n\n\n    // xorwow, George Marsaglia's 160-bit xor-shift combined plus weyl.\n    // Period: 2^192-2^32\n    // Reported to fail: CollisionOver, SimpPoker, and LinearComp.\n\n\n    // xorshift7, by François Panneton and Pierre L'ecuyer, takes\n    // a different approach: it adds robustness by allowing more shifts\n    // than Marsaglia's original three.  It is a 7-shift generator\n    // with 256 bits, that passes BigCrush with no systmatic failures.\n    // Period 2^256-1.\n    // No systematic BigCrush failures reported.\n\n\n    // xor4096, by Richard Brent, is a 4096-bit xor-shift with a\n    // very long period that also adds a Weyl generator. It also passes\n    // BigCrush with no systematic failures.  Its long period may\n    // be useful if you have many generators and need to avoid\n    // collisions.\n    // Period: 2^4128-2^32.\n    // No systematic BigCrush failures reported.\n\n\n    // Tyche-i, by Samuel Neves and Filipe Araujo, is a bit-shifting random\n    // number generator derived from ChaCha, a modern stream cipher.\n    // https://eden.dei.uc.pt/~sneves/pubs/2011-snfa2.pdf\n    // Period: ~2^127\n    // No systematic BigCrush failures reported.\n\n\n    // The original ARC4-based prng included in this library.\n    // Period: ~2^1600\n\n\n    seedrandom.alea = alea;\n    seedrandom.xor128 = xor128;\n    seedrandom.xorwow = xorwow;\n    seedrandom.xorshift7 = xorshift7;\n    seedrandom.xor4096 = xor4096;\n    seedrandom.tychei = tychei;\n\n    var seedrandom$1 = seedrandom;\n    var seedrandom_1 = seedrandom$1.alea;\n\n    var MPRandGauss = (function () {\r\n        function MPRandGauss(mean, stdDeviation, dtype, truncated, seed) {\r\n            this.mean = mean;\r\n            this.stdDev = stdDeviation;\r\n            this.dtype = dtype;\r\n            this.nextVal = NaN;\r\n            this.truncated = truncated;\r\n            if (this.truncated) {\r\n                this.upper = this.mean + this.stdDev * 2;\r\n                this.lower = this.mean - this.stdDev * 2;\r\n            }\r\n            var seedValue = seed ? seed : Math.random();\r\n            this.random = seedrandom_1(seedValue.toString());\r\n        }\r\n        MPRandGauss.prototype.nextValue = function () {\r\n            if (!isNaN(this.nextVal)) {\r\n                var value = this.nextVal;\r\n                this.nextVal = NaN;\r\n                return value;\r\n            }\r\n            var resultX, resultY;\r\n            var isValid = false;\r\n            while (!isValid) {\r\n                var v1 = void 0, v2 = void 0, s = void 0;\r\n                do {\r\n                    v1 = 2 * this.random() - 1;\r\n                    v2 = 2 * this.random() - 1;\r\n                    s = v1 * v1 + v2 * v2;\r\n                } while (s >= 1 || s === 0);\r\n                var mul = Math.sqrt(-2.0 * Math.log(s) / s);\r\n                resultX = this.mean + this.stdDev * v1 * mul;\r\n                resultY = this.mean + this.stdDev * v2 * mul;\r\n                if (!this.truncated || this.isValidTruncated(resultX)) {\r\n                    isValid = true;\r\n                }\r\n            }\r\n            if (!this.truncated || this.isValidTruncated(resultY)) {\r\n                this.nextVal = this.convertValue(resultY);\r\n            }\r\n            return this.convertValue(resultX);\r\n        };\r\n        MPRandGauss.prototype.convertValue = function (value) {\r\n            if (this.dtype == null || this.dtype === 'float32') {\r\n                return value;\r\n            }\r\n            return Math.round(value);\r\n        };\r\n        MPRandGauss.prototype.isValidTruncated = function (value) {\r\n            return value <= this.upper && value >= this.lower;\r\n        };\r\n        return MPRandGauss;\r\n    }());\n\n    function clone_(x) {\r\n        var $x = convertToTensor(x, 'x', 'clone', null);\r\n        var der = function (dy) {\r\n            return { $x: function () { return dy.toFloat(); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) {\r\n            return Tensor.make($x.shape, { dataId: $x.dataId }, $x.dtype);\r\n        }, { $x: $x }, der);\r\n    }\r\n    function eye_(numRows, numColumns, batchShape, dtype) {\r\n        if (dtype === void 0) { dtype = 'float32'; }\r\n        if (numColumns == null) {\r\n            numColumns = numRows;\r\n        }\r\n        var buff = buffer([numRows, numColumns], dtype);\r\n        var n = numRows <= numColumns ? numRows : numColumns;\r\n        for (var i = 0; i < n; ++i) {\r\n            buff.set(1, i, i);\r\n        }\r\n        var out = buff.toTensor().as2D(numRows, numColumns);\r\n        if (batchShape == null) {\r\n            return out;\r\n        }\r\n        else {\r\n            if (batchShape.length === 1) {\r\n                return tile(expandDims(out, 0), [batchShape[0], 1, 1]);\r\n            }\r\n            else if (batchShape.length === 2) {\r\n                return tile(expandDims(expandDims(out, 0), 0), [batchShape[0], batchShape[1], 1, 1]);\r\n            }\r\n            else if (batchShape.length === 3) {\r\n                return tile(expandDims(expandDims(expandDims(out, 0), 0), 0), [batchShape[0], batchShape[1], batchShape[2], 1, 1]);\r\n            }\r\n            else {\r\n                throw new Error(\"eye() currently supports only 1D and 2D \" +\r\n                    (\"batchShapes, but received \" + batchShape.length + \"D.\"));\r\n            }\r\n        }\r\n    }\r\n    function randomNormal_(shape, mean, stdDev, dtype, seed) {\r\n        if (mean === void 0) { mean = 0; }\r\n        if (stdDev === void 0) { stdDev = 1; }\r\n        if (dtype != null && dtype === 'bool') {\r\n            throw new Error(\"Unsupported data type \" + dtype);\r\n        }\r\n        var randGauss = new MPRandGauss(mean, stdDev, dtype, false, seed);\r\n        var res = buffer(shape, dtype);\r\n        for (var i = 0; i < res.values.length; i++) {\r\n            res.values[i] = randGauss.nextValue();\r\n        }\r\n        return res.toTensor();\r\n    }\r\n    function truncatedNormal_(shape, mean, stdDev, dtype, seed) {\r\n        if (mean === void 0) { mean = 0; }\r\n        if (stdDev === void 0) { stdDev = 1; }\r\n        if (dtype != null && dtype === 'bool') {\r\n            throw new Error(\"Unsupported data type \" + dtype);\r\n        }\r\n        var randGauss = new MPRandGauss(mean, stdDev, dtype, true, seed);\r\n        var res = buffer(shape, dtype);\r\n        for (var i = 0; i < res.values.length; i++) {\r\n            res.values[i] = randGauss.nextValue();\r\n        }\r\n        return res.toTensor();\r\n    }\r\n    function randomUniform_(shape, minval, maxval, dtype) {\r\n        if (minval === void 0) { minval = 0; }\r\n        if (maxval === void 0) { maxval = 1; }\r\n        if (dtype === void 0) { dtype = 'float32'; }\r\n        var res = buffer(shape, dtype);\r\n        for (var i = 0; i < res.values.length; i++) {\r\n            res.values[i] = randUniform(minval, maxval);\r\n        }\r\n        return res.toTensor();\r\n    }\r\n    function rand_(shape, randFunction, dtype) {\r\n        var size = sizeFromShape(shape);\r\n        var values = null;\r\n        if (dtype == null || dtype === 'float32') {\r\n            values = new Float32Array(size);\r\n        }\r\n        else if (dtype === 'int32') {\r\n            values = new Int32Array(size);\r\n        }\r\n        else if (dtype === 'bool') {\r\n            values = new Uint8Array(size);\r\n        }\r\n        else {\r\n            throw new Error(\"Unknown data type \" + dtype);\r\n        }\r\n        for (var i = 0; i < size; i++) {\r\n            values[i] = randFunction();\r\n        }\r\n        return Tensor.make(shape, { values: values }, dtype);\r\n    }\r\n    function multinomial_(logits, numSamples, seed, normalized) {\r\n        if (normalized === void 0) { normalized = false; }\r\n        var $logits = convertToTensor(logits, 'logits', 'multinomial');\r\n        var numOutcomes = $logits.size;\r\n        var origRank = $logits.rank;\r\n        if (numOutcomes < 2) {\r\n            throw new Error(\"Error in multinomial: you need at least 2 outcomes, but got \" +\r\n                (numOutcomes + \".\"));\r\n        }\r\n        if (origRank > 2) {\r\n            throw new Error(\"Rank of probabilities must be 1 or 2, but is \" + origRank);\r\n        }\r\n        seed = seed || Math.random();\r\n        var logits2D = origRank === 1 ? $logits.as2D(1, -1) : $logits;\r\n        var res = ENV.engine.runKernel(function (backend) { return backend.multinomial(logits2D, normalized, numSamples, seed); }, { logits2D: logits2D });\r\n        return origRank === 1 ? res.as1D() : res;\r\n    }\r\n    function oneHot_(indices, depth, onValue, offValue) {\r\n        if (onValue === void 0) { onValue = 1; }\r\n        if (offValue === void 0) { offValue = 0; }\r\n        if (depth < 2) {\r\n            throw new Error(\"Error in oneHot: depth must be >=2, but it is \" + depth);\r\n        }\r\n        var $indices = convertToTensor(indices, 'indices', 'oneHot', 'int32');\r\n        var outShape = $indices.shape.concat([depth]);\r\n        $indices = $indices.flatten();\r\n        var grad = function (dy) {\r\n            return { $indices: function () { return zeros($indices.shape, 'float32'); } };\r\n        };\r\n        var result = ENV.engine.runKernel(function (backend) { return backend.oneHot($indices, depth, onValue, offValue); }, { $indices: $indices }, grad);\r\n        return result.reshape(outShape);\r\n    }\r\n    function fromPixels_(pixels, numChannels) {\r\n        if (numChannels === void 0) { numChannels = 3; }\r\n        if (numChannels > 4) {\r\n            throw new Error('Cannot construct Tensor with more than 4 channels from pixels.');\r\n        }\r\n        return ENV.engine.fromPixels(pixels, numChannels);\r\n    }\r\n    function toPixels(img, canvas) {\r\n        return __awaiter(this, void 0, void 0, function () {\r\n            var $img, _a, height, width, depth, minTensor, maxTensor, min, max, data, multiplier, bytes, i, r, g, b, a, j, ctx, imageData;\r\n            return __generator(this, function (_b) {\r\n                switch (_b.label) {\r\n                    case 0:\r\n                        $img = convertToTensor(img, 'img', 'toPixels');\r\n                        if (!(img instanceof Tensor)) {\r\n                            $img = $img.toInt();\r\n                        }\r\n                        if ($img.rank !== 2 && $img.rank !== 3) {\r\n                            throw new Error(\"toPixels only supports rank 2 or 3 tensors, got rank \" + $img.rank + \".\");\r\n                        }\r\n                        _a = $img.shape.slice(0, 2), height = _a[0], width = _a[1];\r\n                        depth = $img.rank === 2 ? 1 : $img.shape[2];\r\n                        if (depth > 4 || depth === 2) {\r\n                            throw new Error(\"toPixels only supports depth of size \" +\r\n                                (\"1, 3 or 4 but got \" + depth));\r\n                        }\r\n                        minTensor = $img.min();\r\n                        maxTensor = $img.max();\r\n                        return [4, minTensor.data()];\r\n                    case 1:\r\n                        min = (_b.sent())[0];\r\n                        return [4, maxTensor.data()];\r\n                    case 2:\r\n                        max = (_b.sent())[0];\r\n                        minTensor.dispose();\r\n                        maxTensor.dispose();\r\n                        if ($img.dtype === 'float32') {\r\n                            if (min < 0 || max > 1) {\r\n                                throw new Error(\"Tensor values for a float32 Tensor must be in the \" +\r\n                                    (\"range [0 - 1] but got range [\" + min + \" - \" + max + \"].\"));\r\n                            }\r\n                        }\r\n                        else if ($img.dtype === 'int32') {\r\n                            if (min < 0 || max > 255) {\r\n                                throw new Error(\"Tensor values for a int32 Tensor must be in the \" +\r\n                                    (\"range [0 - 255] but got range [\" + min + \" - \" + max + \"].\"));\r\n                            }\r\n                        }\r\n                        else {\r\n                            throw new Error(\"Unsupported type for toPixels: \" + $img.dtype + \".\" +\r\n                                \" Please use float32 or int32 tensors.\");\r\n                        }\r\n                        return [4, $img.data()];\r\n                    case 3:\r\n                        data = _b.sent();\r\n                        multiplier = $img.dtype === 'float32' ? 255 : 1;\r\n                        bytes = new Uint8ClampedArray(width * height * 4);\r\n                        for (i = 0; i < height * width; ++i) {\r\n                            r = void 0, g = void 0, b = void 0, a = void 0;\r\n                            if (depth === 1) {\r\n                                r = data[i] * multiplier;\r\n                                g = data[i] * multiplier;\r\n                                b = data[i] * multiplier;\r\n                                a = 255;\r\n                            }\r\n                            else if (depth === 3) {\r\n                                r = data[i * 3] * multiplier;\r\n                                g = data[i * 3 + 1] * multiplier;\r\n                                b = data[i * 3 + 2] * multiplier;\r\n                                a = 255;\r\n                            }\r\n                            else if (depth === 4) {\r\n                                r = data[i * 4] * multiplier;\r\n                                g = data[i * 4 + 1] * multiplier;\r\n                                b = data[i * 4 + 2] * multiplier;\r\n                                a = data[i * 4 + 3] * multiplier;\r\n                            }\r\n                            j = i * 4;\r\n                            bytes[j + 0] = Math.round(r);\r\n                            bytes[j + 1] = Math.round(g);\r\n                            bytes[j + 2] = Math.round(b);\r\n                            bytes[j + 3] = Math.round(a);\r\n                        }\r\n                        if (canvas != null) {\r\n                            canvas.width = width;\r\n                            canvas.height = height;\r\n                            ctx = canvas.getContext('2d');\r\n                            imageData = new ImageData(bytes, width, height);\r\n                            ctx.putImageData(imageData, 0, 0);\r\n                        }\r\n                        if ($img !== img) {\r\n                            $img.dispose();\r\n                        }\r\n                        return [2, bytes];\r\n                }\r\n            });\r\n        });\r\n    }\r\n    function reshape_(x, shape) {\r\n        var $x = convertToTensor(x, 'x', 'reshape', null);\r\n        shape = inferFromImplicitShape(shape, $x.size);\r\n        assert($x.size === sizeFromShape(shape), 'new shape and old shape must have the same number of elements.');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.reshape($x.shape); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.reshape($x, shape); }, { $x: $x }, grad);\r\n    }\r\n    function squeeze_(x, axis) {\r\n        var $x = convertToTensor(x, 'x', 'squeeze');\r\n        return reshape($x, squeezeShape($x.shape, axis).newShape);\r\n    }\r\n    function cast_(x, dtype) {\r\n        var $x = convertToTensor(x, 'x', 'cast');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.clone(); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.cast($x, dtype); }, { $x: $x }, grad);\r\n    }\r\n    function tile_(x, reps) {\r\n        var $x = convertToTensor(x, 'x', 'tile');\r\n        assert($x.rank === reps.length, \"Error in transpose: rank of input \" + $x.rank + \" \" +\r\n            (\"must match length of reps \" + reps + \".\"));\r\n        var grad = function (dy) {\r\n            var derX = function () {\r\n                var xGrad = zerosLike($x);\r\n                if ($x.rank === 1) {\r\n                    for (var i = 0; i < reps[0]; ++i) {\r\n                        xGrad = xGrad.add(dy.slice([i * $x.shape[0]], [$x.shape[0]]));\r\n                    }\r\n                }\r\n                else if ($x.rank === 2) {\r\n                    for (var i = 0; i < reps[0]; ++i) {\r\n                        for (var j = 0; j < reps[1]; ++j) {\r\n                            xGrad = xGrad.add(dy.slice([i * $x.shape[0], j * $x.shape[1]], [$x.shape[0], $x.shape[1]]));\r\n                        }\r\n                    }\r\n                }\r\n                else if ($x.rank === 3) {\r\n                    for (var i = 0; i < reps[0]; ++i) {\r\n                        for (var j = 0; j < reps[1]; ++j) {\r\n                            for (var k = 0; k < reps[2]; ++k) {\r\n                                xGrad = xGrad.add(dy.slice([i * $x.shape[0], j * $x.shape[1], k * $x.shape[2]], [$x.shape[0], $x.shape[1], $x.shape[2]]));\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n                else if ($x.rank === 4) {\r\n                    for (var i = 0; i < reps[0]; ++i) {\r\n                        for (var j = 0; j < reps[1]; ++j) {\r\n                            for (var k = 0; k < reps[2]; ++k) {\r\n                                for (var l = 0; l < reps[3]; ++l) {\r\n                                    xGrad = xGrad.add(dy.slice([\r\n                                        i * $x.shape[0], j * $x.shape[1], k * $x.shape[2],\r\n                                        l * $x.shape[3]\r\n                                    ], [$x.shape[0], $x.shape[1], $x.shape[2], $x.shape[3]]));\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n                else {\r\n                    throw new Error(\"Gradient for tile operation is not implemented for rank-\" +\r\n                        ($x.rank + \" tensors yet.\"));\r\n                }\r\n                return xGrad;\r\n            };\r\n            return { $x: derX };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.tile($x, reps); }, { $x: $x }, grad);\r\n    }\r\n    function pad1d_(x, paddings, constantValue) {\r\n        if (constantValue === void 0) { constantValue = 0; }\r\n        assert(paddings.length === 2, 'Invalid number of paddings. Must be length of 2.');\r\n        return pad(x, [paddings], constantValue);\r\n    }\r\n    function pad2d_(x, paddings, constantValue) {\r\n        if (constantValue === void 0) { constantValue = 0; }\r\n        assert(paddings.length === 2 && paddings[0].length === 2 &&\r\n            paddings[1].length === 2, 'Invalid number of paddings. Must be length of 2 each.');\r\n        return pad(x, paddings, constantValue);\r\n    }\r\n    function pad3d_(x, paddings, constantValue) {\r\n        if (constantValue === void 0) { constantValue = 0; }\r\n        assert(paddings.length === 3 && paddings[0].length === 2 &&\r\n            paddings[1].length === 2 && paddings[2].length === 2, 'Invalid number of paddings. Must be length of 2 each.');\r\n        return pad(x, paddings, constantValue);\r\n    }\r\n    function pad4d_(x, paddings, constantValue) {\r\n        if (constantValue === void 0) { constantValue = 0; }\r\n        assert(paddings.length === 4 && paddings[0].length === 2 &&\r\n            paddings[1].length === 2 && paddings[2].length === 2 &&\r\n            paddings[3].length === 2, 'Invalid number of paddings. Must be length of 2 each.');\r\n        return pad(x, paddings, constantValue);\r\n    }\r\n    function pad_(x, paddings, constantValue) {\r\n        if (constantValue === void 0) { constantValue = 0; }\r\n        var $x = convertToTensor(x, 'x', 'pad');\r\n        if ($x.rank === 0) {\r\n            throw new Error('pad(scalar) is not defined. Pass non-scalar to pad');\r\n        }\r\n        var begin = paddings.map(function (p) { return p[0]; });\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.slice(begin, $x.shape); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.pad($x, paddings, constantValue); }, { $x: $x }, grad);\r\n    }\r\n    function stack_(tensors, axis) {\r\n        if (axis === void 0) { axis = 0; }\r\n        var $tensors = convertToTensorArray(tensors, 'tensors', 'stack');\r\n        assert($tensors.length >= 1, 'Pass at least one tensor to tf.stack');\r\n        if ($tensors.length === 1) {\r\n            return $tensors[0].expandDims(axis);\r\n        }\r\n        var rank = $tensors[0].rank;\r\n        var shape = $tensors[0].shape;\r\n        var dtype = $tensors[0].dtype;\r\n        assert(axis <= rank, 'Axis must be <= rank of the tensor');\r\n        $tensors.forEach(function (t) {\r\n            assertShapesMatch(shape, t.shape, 'All tensors passed to stack must have matching shapes');\r\n        });\r\n        $tensors.forEach(function (t) {\r\n            assert(dtype === t.dtype, 'All tensors passed to stack must have matching dtypes');\r\n        });\r\n        var expandedTensors = $tensors.map(function (t) { return t.expandDims(axis); });\r\n        return concat(expandedTensors, axis);\r\n    }\r\n    function batchToSpaceND_(x, blockShape, crops) {\r\n        var $x = convertToTensor(x, 'x', 'batchToSpaceND');\r\n        var prod = blockShape.reduce(function (a, b) { return a * b; });\r\n        assert($x.rank >= 1 + blockShape.length, \"input rank is \" + $x.rank + \" but should be > than blockShape.length \" + blockShape.length);\r\n        assert(crops.length === blockShape.length, \"crops.length is \" + crops.length + \" but should be equal to blockShape.length  \" + blockShape.length);\r\n        assert($x.shape[0] % prod === 0, \"input tensor batch is \" + $x.shape[0] + \" but is not divisible by the product of \" +\r\n            (\"the elements of blockShape \" + blockShape.join(' * ') + \" === \" + prod));\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.spaceToBatchND(blockShape, crops); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.batchToSpaceND($x, blockShape, crops); }, { $x: $x }, grad);\r\n    }\r\n    function spaceToBatchND_(x, blockShape, paddings) {\r\n        var $x = convertToTensor(x, 'x', 'spaceToBatchND');\r\n        assert($x.rank >= 1 + blockShape.length, \"input rank \" + $x.rank + \" should be > than [blockShape] \" + blockShape.length);\r\n        assert(paddings.length === blockShape.length, \"paddings.shape[0] \" + paddings.length + \" must be equal to [blockShape] \" + blockShape.length);\r\n        assert($x.shape.reduce(function (a, b, i) {\r\n            if (i > 0 && i <= blockShape.length) {\r\n                return a &&\r\n                    ((b + paddings[i - 1][0] + paddings[i - 1][1]) %\r\n                        blockShape[i - 1] ===\r\n                        0);\r\n            }\r\n            return a;\r\n        }, true), \"input spatial dimensions \" + $x.shape.slice(1) + \" with paddings \" + paddings.toString() + \" must be divisible by blockShapes \" + blockShape.toString());\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.batchToSpaceND(blockShape, paddings); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.spaceToBatchND($x, blockShape, paddings); }, { $x: $x }, grad);\r\n    }\r\n    function unstack_(x, axis) {\r\n        if (axis === void 0) { axis = 0; }\r\n        axis = axis || 0;\r\n        var $x = convertToTensor(x, 'x', 'unstack');\r\n        assert(axis < $x.shape.length, \"Axis \" + axis + \" is >= to tensor shape length \" + $x.shape.length);\r\n        var grad = function (dy) {\r\n            return { $x: function () { return stack(dy, axis); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.unstack($x, axis); }, { $x: $x }, grad);\r\n    }\r\n    function cumsum_(x, axis, exclusive, reverse) {\r\n        if (axis === void 0) { axis = 0; }\r\n        if (exclusive === void 0) { exclusive = false; }\r\n        if (reverse === void 0) { reverse = false; }\r\n        var $x = convertToTensor(x, 'x', 'cumsum');\r\n        axis = axis | 0;\r\n        var permutation = getAxesPermutation([axis], $x.rank);\r\n        var permutedX = $x;\r\n        if (permutation != null) {\r\n            permutedX = $x.transpose(permutation);\r\n        }\r\n        var permutedAxis = getInnerMostAxes(1, $x.rank)[0];\r\n        var grad = function (dy) {\r\n            return { permutedX: function () { return dy.cumsum(axis, exclusive, !reverse); } };\r\n        };\r\n        var value = ENV.engine.runKernel(function (backend) { return backend.cumsum(permutedX, permutedAxis, exclusive, reverse); }, { permutedX: permutedX }, grad);\r\n        if (permutation != null) {\r\n            value = value.transpose(permutation);\r\n        }\r\n        return value;\r\n    }\r\n    function expandDims_(x, axis) {\r\n        if (axis === void 0) { axis = 0; }\r\n        var $x = convertToTensor(x, 'x', 'expandDims');\r\n        assert(axis <= $x.rank, 'Axis must be <= rank of the tensor');\r\n        var newShape = $x.shape.slice();\r\n        if (axis < 0) {\r\n            assert(-($x.rank + 1) <= axis, \"Axis must be in the interval [\" + -($x.rank + 1) + \", \" + $x.rank + \"]\");\r\n            axis = $x.rank + axis + 1;\r\n        }\r\n        newShape.splice(axis, 0, 1);\r\n        return reshape($x, newShape);\r\n    }\r\n    function depthToSpace_(x, blockSize, dataFormat) {\r\n        if (dataFormat === void 0) { dataFormat = 'NHWC'; }\r\n        var $x = convertToTensor(x, 'x', 'depthToSpace');\r\n        var inputHeight = (dataFormat === 'NHWC') ? $x.shape[1] : $x.shape[2];\r\n        var inputWidth = (dataFormat === 'NHWC') ? $x.shape[2] : $x.shape[3];\r\n        var inputDepth = (dataFormat === 'NHWC') ? $x.shape[3] : $x.shape[1];\r\n        assert(inputHeight * blockSize >= 0, \"Negative dimension size caused by overflow when multiplying\\n      \" + inputHeight + \" and \" + blockSize + \"  for depthToSpace with input shape\\n      \" + $x.shape);\r\n        assert(inputWidth * blockSize >= 0, \"Negative dimension size caused by overflow when multiplying\\n      \" + inputWidth + \" and \" + blockSize + \" for depthToSpace with input shape\\n          \" + $x.shape);\r\n        assert((inputDepth % (blockSize * blockSize) === 0), \"Dimension size must be evenly divisible by \" + blockSize * blockSize + \" but is \" + inputDepth + \" for depthToSpace with input shape \" + $x.shape);\r\n        return ENV.engine.runKernel(function (backend) { return backend.depthToSpace($x, blockSize, dataFormat); }, { $x: $x });\r\n    }\r\n    function setdiff1dAsync_(x, y) {\r\n        return __awaiter(this, void 0, void 0, function () {\r\n            var $x, $y, xVals, yVals, ySet, outputSize, i, buffer, indices, i, p;\r\n            return __generator(this, function (_a) {\r\n                switch (_a.label) {\r\n                    case 0:\r\n                        $x = convertToTensor(x, 'x', 'setdiff1d');\r\n                        $y = convertToTensor(y, 'y', 'setdiff1d');\r\n                        assert($x.dtype === $y.dtype, \"x and y should have the same dtype, but got x (\" + $x.dtype + \") and y (\" + $y.dtype + \").\");\r\n                        assert($x.rank === 1, \"x should be 1D tensor, but got x (\" + $x.shape + \").\");\r\n                        assert($y.rank === 1, \"y should be 1D tensor, but got y (\" + $y.shape + \").\");\r\n                        return [4, $x.data()];\r\n                    case 1:\r\n                        xVals = _a.sent();\r\n                        return [4, $y.data()];\r\n                    case 2:\r\n                        yVals = _a.sent();\r\n                        ySet = new Set(yVals);\r\n                        outputSize = 0;\r\n                        for (i = 0; i < xVals.length; i++) {\r\n                            if (!ySet.has(xVals[i])) {\r\n                                outputSize++;\r\n                            }\r\n                        }\r\n                        buffer = new TensorBuffer([outputSize], $x.dtype);\r\n                        indices = new TensorBuffer([outputSize], 'int32');\r\n                        for (i = 0, p = 0; i < xVals.length; i++) {\r\n                            if (!ySet.has(xVals[i])) {\r\n                                buffer.values[p] = xVals[i];\r\n                                indices.values[p] = i;\r\n                                p++;\r\n                            }\r\n                        }\r\n                        return [2, [buffer.toTensor(), indices.toTensor()]];\r\n                }\r\n            });\r\n        });\r\n    }\r\n    function buffer(shape, dtype, values) {\r\n        if (dtype === void 0) { dtype = 'float32'; }\r\n        dtype = dtype || 'float32';\r\n        return new TensorBuffer(shape, dtype, values);\r\n    }\r\n    function print(x, verbose) {\r\n        if (verbose === void 0) { verbose = false; }\r\n        console.log(x.toString(verbose));\r\n    }\r\n    var batchToSpaceND = op({ batchToSpaceND_: batchToSpaceND_ });\r\n    var cast = op({ cast_: cast_ });\r\n    var clone = op({ clone_: clone_ });\r\n    var cumsum = op({ cumsum_: cumsum_ });\r\n    var depthToSpace = op({ depthToSpace_: depthToSpace_ });\r\n    var expandDims = op({ expandDims_: expandDims_ });\r\n    var eye = op({ eye_: eye_ });\r\n    var fromPixels = op({ fromPixels_: fromPixels_ });\r\n    var multinomial = op({ multinomial_: multinomial_ });\r\n    var oneHot = op({ oneHot_: oneHot_ });\r\n    var pad = op({ pad_: pad_ });\r\n    var pad1d = op({ pad1d_: pad1d_ });\r\n    var pad2d = op({ pad2d_: pad2d_ });\r\n    var pad3d = op({ pad3d_: pad3d_ });\r\n    var pad4d = op({ pad4d_: pad4d_ });\r\n    var rand = op({ rand_: rand_ });\r\n    var randomNormal = op({ randomNormal_: randomNormal_ });\r\n    var randomUniform = op({ randomUniform_: randomUniform_ });\r\n    var reshape = op({ reshape_: reshape_ });\r\n    var spaceToBatchND = op({ spaceToBatchND_: spaceToBatchND_ });\r\n    var squeeze = op({ squeeze_: squeeze_ });\r\n    var stack = op({ stack_: stack_ });\r\n    var tile = op({ tile_: tile_ });\r\n    var truncatedNormal = op({ truncatedNormal_: truncatedNormal_ });\r\n    var unstack = op({ unstack_: unstack_ });\r\n    var setdiff1dAsync = setdiff1dAsync_;\n\n    function whereImpl(condShape, condVals) {\r\n        var indices = [];\r\n        for (var i = 0; i < condVals.length; i++) {\r\n            if (condVals[i]) {\r\n                indices.push(i);\r\n            }\r\n        }\r\n        var inBuffer = buffer(condShape, 'int32');\r\n        var out = buffer([indices.length, condShape.length], 'int32');\r\n        for (var i = 0; i < indices.length; i++) {\r\n            var loc = inBuffer.indexToLoc(indices[i]);\r\n            var offset = i * condShape.length;\r\n            out.values.set(loc, offset);\r\n        }\r\n        return out.toTensor();\r\n    }\n\n    function mapActivationToShaderProgram(activation, packed) {\r\n        if (packed === void 0) { packed = false; }\r\n        if (activation === 'linear') {\r\n            if (packed) {\r\n                return LINEAR$1;\r\n            }\r\n            return LINEAR;\r\n        }\r\n        else if (activation === 'relu') {\r\n            if (packed) {\r\n                return RELU$1;\r\n            }\r\n            return RELU;\r\n        }\r\n        throw new Error(\"Activation \" + activation + \" has not been implemented for the WebGL backend.\");\r\n    }\r\n    var CPU_HANDOFF_SIZE_THRESHOLD = 10;\r\n    var MATMUL_SHARED_DIM_THRESHOLD = 1000;\r\n    var MathBackendWebGL = (function () {\r\n        function MathBackendWebGL(gpgpu, delayedStorage) {\r\n            if (delayedStorage === void 0) { delayedStorage = true; }\r\n            this.gpgpu = gpgpu;\r\n            this.delayedStorage = delayedStorage;\r\n            this.pendingRead = new WeakMap();\r\n            this.pendingDisposal = new WeakSet();\r\n            this.dataRefCount = new WeakMap();\r\n            this.lruDataGPU = [];\r\n            this.numBytesInGPU = 0;\r\n            this.uploadWaitMs = 0;\r\n            this.downloadWaitMs = 0;\r\n            this.binaryCache = {};\r\n            this.disposed = false;\r\n            if (ENV.get('WEBGL_VERSION') < 1) {\r\n                throw new Error('WebGL is not supported on this device');\r\n            }\r\n            if (gpgpu == null) {\r\n                var gl = getWebGLContext(ENV.get('WEBGL_VERSION'));\r\n                this.gpgpu = new GPGPUContext(gl);\r\n                this.canvas = gl.canvas;\r\n                this.gpgpuCreatedLocally = true;\r\n            }\r\n            else {\r\n                this.gpgpuCreatedLocally = false;\r\n                this.canvas = gpgpu.gl.canvas;\r\n            }\r\n            this.textureManager = new TextureManager(this.gpgpu);\r\n        }\r\n        MathBackendWebGL.prototype.register = function (dataId, shape, dtype) {\r\n            if (this.texData.has(dataId)) {\r\n                throw new Error('Data buffer is already registered');\r\n            }\r\n            this.texData.set(dataId, { shape: shape, dtype: dtype });\r\n        };\r\n        MathBackendWebGL.prototype.setDataMover = function (dataMover) {\r\n            this.texData = new DataStorage(dataMover);\r\n        };\r\n        MathBackendWebGL.prototype.fromPixels = function (pixels, numChannels) {\r\n            if (pixels == null) {\r\n                throw new Error('pixels passed to tf.fromPixels() can not be null');\r\n            }\r\n            var texShape = [pixels.height, pixels.width];\r\n            var outShape = [pixels.height, pixels.width, numChannels];\r\n            if (!(pixels instanceof HTMLVideoElement) &&\r\n                !(pixels instanceof HTMLImageElement) &&\r\n                !(pixels instanceof HTMLCanvasElement) &&\r\n                !(pixels instanceof ImageData)) {\r\n                throw new Error('pixels passed to tf.fromPixels() must be either an ' +\r\n                    \"HTMLVideoElement, HTMLImageElement, HTMLCanvasElement or \" +\r\n                    (\"ImageData, but was \" + pixels.constructor.name));\r\n            }\r\n            if (pixels instanceof HTMLVideoElement) {\r\n                if (this.fromPixels2DContext == null) {\r\n                    if (!ENV.get('IS_BROWSER')) {\r\n                        throw new Error('Can\\'t read pixels from HTMLImageElement outside the browser.');\r\n                    }\r\n                    if (document.readyState !== 'complete') {\r\n                        throw new Error('The DOM is not ready yet. Please call tf.fromPixels() ' +\r\n                            'once the DOM is ready. One way to do that is to add an event ' +\r\n                            'listener for `DOMContentLoaded` on the document object');\r\n                    }\r\n                    this.fromPixels2DContext =\r\n                        document.createElement('canvas').getContext('2d');\r\n                }\r\n                this.fromPixels2DContext.canvas.width = pixels.width;\r\n                this.fromPixels2DContext.canvas.height = pixels.height;\r\n                this.fromPixels2DContext.drawImage(pixels, 0, 0, pixels.width, pixels.height);\r\n                pixels = this.fromPixels2DContext.canvas;\r\n            }\r\n            var tempPixelHandle = this.makeTensorHandle(texShape, 'int32');\r\n            this.texData.get(tempPixelHandle.dataId).usage = TextureUsage.PIXELS;\r\n            this.gpgpu.uploadPixelDataToTexture(this.getTexture(tempPixelHandle.dataId), pixels);\r\n            var program = new FromPixelsProgram(outShape);\r\n            var res = this.compileAndRun(program, [tempPixelHandle]);\r\n            this.disposeData(tempPixelHandle.dataId);\r\n            return res;\r\n        };\r\n        MathBackendWebGL.prototype.makeTensorHandle = function (shape, dtype) {\r\n            var dataId = {};\r\n            this.register(dataId, shape, dtype);\r\n            return { dataId: dataId, shape: shape, dtype: dtype };\r\n        };\r\n        MathBackendWebGL.prototype.write = function (dataId, values) {\r\n            if (values == null) {\r\n                throw new Error('MathBackendWebGL.write(): values can not be null');\r\n            }\r\n            if (ENV.get('DEBUG')) {\r\n                for (var i = 0; i < values.length; i++) {\r\n                    var num = values[i];\r\n                    if (!canBeRepresented(num)) {\r\n                        throw Error(\"The value \" + num + \" cannot be represented on this device.\");\r\n                    }\r\n                }\r\n            }\r\n            var texData = this.texData.get(dataId);\r\n            var texture = texData.texture, texShape = texData.texShape, usage = texData.usage, dtype = texData.dtype, isPacked = texData.isPacked;\r\n            if (dtype === 'complex64') {\r\n                throw new Error(\"Cannot write to a complex64 dtype. \" +\r\n                    \"Please use tf.complex(real, imag).\");\r\n            }\r\n            if (texture != null) {\r\n                this.releaseTexture(dataId, texture, texShape, usage, isPacked);\r\n                texData.texture = null;\r\n                texData.texShape = null;\r\n            }\r\n            texData.usage = TextureUsage.UPLOAD;\r\n            texData.values = values;\r\n            if (!this.delayedStorage) {\r\n                this.uploadToGPU(dataId);\r\n            }\r\n        };\r\n        MathBackendWebGL.prototype.readSync = function (dataId) {\r\n            var texData = this.texData.get(dataId);\r\n            var values = texData.values, dtype = texData.dtype, complexTensors = texData.complexTensors, slice = texData.slice, shape = texData.shape;\r\n            if (slice != null) {\r\n                var program = new UnaryOpProgram(shape, CLONE);\r\n                var res = this.compileAndRun(program, [{ dataId: dataId, shape: shape, dtype: dtype }]);\r\n                return this.readSync(res.dataId);\r\n            }\r\n            if (values != null) {\r\n                return this.convertAndCacheOnCPU(dataId);\r\n            }\r\n            if (dtype === 'string') {\r\n                return values;\r\n            }\r\n            var shouldTimeProgram = this.activeTimers != null;\r\n            var start;\r\n            if (shouldTimeProgram) {\r\n                start = performance.now();\r\n            }\r\n            var result;\r\n            if (dtype === 'complex64') {\r\n                var realValues = complexTensors.real.dataSync();\r\n                var imagValues = complexTensors.imag.dataSync();\r\n                result = mergeRealAndImagArrays(realValues, imagValues);\r\n            }\r\n            else {\r\n                result = this.getValuesFromTexture(dataId);\r\n            }\r\n            if (shouldTimeProgram) {\r\n                this.downloadWaitMs += performance.now() - start;\r\n            }\r\n            return this.convertAndCacheOnCPU(dataId, result);\r\n        };\r\n        MathBackendWebGL.prototype.read = function (dataId) {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var _a, _b, subscribers_1, texData, texture, values, texShape, isPacked, shape, slice, dtype, program, res, width, height, bufferOrTexture, vals, size, batch, rows, cols, dTypeVals, subscribers;\r\n                return __generator(this, function (_c) {\r\n                    switch (_c.label) {\r\n                        case 0:\r\n                            if (this.pendingRead.has(dataId)) {\r\n                                subscribers_1 = this.pendingRead.get(dataId);\r\n                                return [2, new Promise(function (resolve) { return subscribers_1.push(resolve); })];\r\n                            }\r\n                            texData = this.texData.get(dataId);\r\n                            texture = texData.texture, values = texData.values, texShape = texData.texShape, isPacked = texData.isPacked, shape = texData.shape, slice = texData.slice, dtype = texData.dtype;\r\n                            if (slice != null) {\r\n                                program = new UnaryOpProgram(shape, CLONE);\r\n                                res = this.compileAndRun(program, [{ dataId: dataId, shape: shape, dtype: dtype }]);\r\n                                return [2, this.read(res.dataId)];\r\n                            }\r\n                            if (values != null) {\r\n                                return [2, this.convertAndCacheOnCPU(dataId)];\r\n                            }\r\n                            this.pendingRead.set(dataId, []);\r\n                            if (!ENV.get('WEBGL_DOWNLOAD_FLOAT_ENABLED') &&\r\n                                ENV.get('WEBGL_VERSION') === 2) {\r\n                                throw new Error(\"tensor.data() with WEBGL_DOWNLOAD_FLOAT_ENABLED=false and \" +\r\n                                    \"WEBGL_VERSION=2 not yet supported.\");\r\n                            }\r\n                            width = texShape[1];\r\n                            height = texShape[0];\r\n                            if (isPacked) {\r\n                                _a = getPackedMatrixTextureShapeWidthHeight(texShape[0], texShape[1]), width = _a[0], height = _a[1];\r\n                            }\r\n                            bufferOrTexture = this.gpgpu.maybeCreateBufferFromTexture(texture, height, width);\r\n                            return [4, this.gpgpu.createAndWaitForFence()];\r\n                        case 1:\r\n                            _c.sent();\r\n                            if (bufferOrTexture instanceof WebGLTexture) {\r\n                                vals = this.getValuesFromTexture(dataId);\r\n                            }\r\n                            else {\r\n                                size = sizeFromShape(shape);\r\n                                if (isPacked) {\r\n                                    batch = getBatchDim(shape);\r\n                                    rows = 1, cols = 1;\r\n                                    if (shape.length) {\r\n                                        _b = getRowsCols(shape), rows = _b[0], cols = _b[1];\r\n                                    }\r\n                                    vals = this.gpgpu\r\n                                        .downloadPackedMatrixFromBuffer(bufferOrTexture, batch, rows, cols, texShape[0], texShape[1])\r\n                                        .subarray(0, size);\r\n                                }\r\n                                else {\r\n                                    vals = this.gpgpu\r\n                                        .downloadFloat32MatrixFromBuffer(bufferOrTexture, texShape[0], texShape[1])\r\n                                        .subarray(0, size);\r\n                                }\r\n                            }\r\n                            dTypeVals = this.convertAndCacheOnCPU(dataId, vals);\r\n                            subscribers = this.pendingRead.get(dataId);\r\n                            this.pendingRead.delete(dataId);\r\n                            subscribers.forEach(function (resolve) { return resolve(dTypeVals); });\r\n                            if (this.pendingDisposal.has(dataId)) {\r\n                                this.pendingDisposal.delete(dataId);\r\n                                this.disposeData(dataId);\r\n                            }\r\n                            return [2, dTypeVals];\r\n                    }\r\n                });\r\n            });\r\n        };\r\n        MathBackendWebGL.prototype.getValuesFromTexture = function (dataId) {\r\n            var _a;\r\n            var _b = this.texData.get(dataId), shape = _b.shape, dtype = _b.dtype, texture = _b.texture, texShape = _b.texShape;\r\n            var size = sizeFromShape(shape);\r\n            if (ENV.get('WEBGL_DOWNLOAD_FLOAT_ENABLED')) {\r\n                if (this.texData.get(dataId).isPacked) {\r\n                    var batch = getBatchDim(shape);\r\n                    var rows = 1, cols = 1;\r\n                    if (shape.length) {\r\n                        _a = getRowsCols(shape), rows = _a[0], cols = _a[1];\r\n                    }\r\n                    return this.gpgpu\r\n                        .downloadMatrixFromPackedTexture(texture, batch, rows, cols, texShape[0], texShape[1])\r\n                        .subarray(0, size);\r\n                }\r\n                else {\r\n                    return this.gpgpu\r\n                        .downloadFloat32MatrixFromOutputTexture(texture, texShape[0], texShape[1])\r\n                        .subarray(0, size);\r\n                }\r\n            }\r\n            var tmpTarget = this.makeTensorHandle(shape, 'float32');\r\n            tmpTarget.size = sizeFromShape(shape);\r\n            this.texData.get(tmpTarget.dataId).usage = TextureUsage.DOWNLOAD;\r\n            var program = new EncodeFloatProgram(shape);\r\n            var pageToCpu = false;\r\n            this.compileAndRun(program, [{ shape: shape, dtype: dtype, dataId: dataId }], tmpTarget, null, pageToCpu);\r\n            var tmpData = this.texData.get(tmpTarget.dataId);\r\n            var vals = this.gpgpu\r\n                .downloadByteEncodedFloatMatrixFromOutputTexture(tmpData.texture, tmpData.texShape[0], tmpData.texShape[1])\r\n                .subarray(0, size);\r\n            this.disposeData(tmpTarget.dataId);\r\n            return vals;\r\n        };\r\n        MathBackendWebGL.prototype.time = function (f) {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var oldActiveTimers, newActiveTimers, outerMostTime, flattenedActiveTimerQueries, flattenedActiveTimerNames, kernelMs, res;\r\n                return __generator(this, function (_a) {\r\n                    switch (_a.label) {\r\n                        case 0:\r\n                            oldActiveTimers = this.activeTimers;\r\n                            newActiveTimers = [];\r\n                            outerMostTime = false;\r\n                            if (this.programTimersStack == null) {\r\n                                this.programTimersStack = newActiveTimers;\r\n                                outerMostTime = true;\r\n                            }\r\n                            else {\r\n                                this.activeTimers.push(newActiveTimers);\r\n                            }\r\n                            this.activeTimers = newActiveTimers;\r\n                            f();\r\n                            flattenedActiveTimerQueries = flatten(this.activeTimers.map(function (d) { return d.query; }))\r\n                                .filter(function (d) { return d != null; });\r\n                            flattenedActiveTimerNames = flatten(this.activeTimers.map(function (d) { return d.name; }))\r\n                                .filter(function (d) { return d != null; });\r\n                            this.activeTimers = oldActiveTimers;\r\n                            if (outerMostTime) {\r\n                                this.programTimersStack = null;\r\n                            }\r\n                            return [4, Promise.all(flattenedActiveTimerQueries)];\r\n                        case 1:\r\n                            kernelMs = _a.sent();\r\n                            res = {\r\n                                uploadWaitMs: this.uploadWaitMs,\r\n                                downloadWaitMs: this.downloadWaitMs,\r\n                                kernelMs: sum(kernelMs),\r\n                                getExtraProfileInfo: function () {\r\n                                    return kernelMs.map(function (d, i) { return ({ name: flattenedActiveTimerNames[i], ms: d }); })\r\n                                        .map(function (d) { return d.name + \": \" + d.ms; })\r\n                                        .join(', ');\r\n                                },\r\n                                wallMs: null\r\n                            };\r\n                            this.uploadWaitMs = 0;\r\n                            this.downloadWaitMs = 0;\r\n                            return [2, res];\r\n                    }\r\n                });\r\n            });\r\n        };\r\n        MathBackendWebGL.prototype.memory = function () {\r\n            return { unreliable: false, numBytesInGPU: this.numBytesInGPU };\r\n        };\r\n        MathBackendWebGL.prototype.startTimer = function () {\r\n            if (ENV.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') > 0) {\r\n                return this.gpgpu.beginQuery();\r\n            }\r\n            return { startMs: performance.now(), endMs: null };\r\n        };\r\n        MathBackendWebGL.prototype.endTimer = function (query) {\r\n            if (ENV.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') > 0) {\r\n                this.gpgpu.endQuery();\r\n                return query;\r\n            }\r\n            query.endMs = performance.now();\r\n            return query;\r\n        };\r\n        MathBackendWebGL.prototype.getQueryTime = function (query) {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var timerQuery;\r\n                return __generator(this, function (_a) {\r\n                    if (ENV.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') > 0) {\r\n                        return [2, this.gpgpu.waitForQueryAndGetTime(query)];\r\n                    }\r\n                    timerQuery = query;\r\n                    return [2, timerQuery.endMs - timerQuery.startMs];\r\n                });\r\n            });\r\n        };\r\n        MathBackendWebGL.prototype.disposeData = function (dataId) {\r\n            if (this.pendingDisposal.has(dataId)) {\r\n                return;\r\n            }\r\n            if (this.pendingRead.has(dataId)) {\r\n                this.pendingDisposal.add(dataId);\r\n                return;\r\n            }\r\n            if (this.texData.has(dataId)) {\r\n                var _a = this.texData.get(dataId), texture = _a.texture, texShape = _a.texShape, usage = _a.usage, complexTensors = _a.complexTensors, isPacked = _a.isPacked, slice = _a.slice;\r\n                if (texture != null) {\r\n                    var key = slice && slice.origDataId || dataId;\r\n                    var refCount = this.dataRefCount.get(key);\r\n                    if (refCount > 1) {\r\n                        this.dataRefCount.set(key, refCount - 1);\r\n                    }\r\n                    else {\r\n                        this.dataRefCount.delete(key);\r\n                        this.releaseTexture(dataId, texture, texShape, usage, isPacked);\r\n                        this.texData.delete(dataId);\r\n                    }\r\n                }\r\n                if (complexTensors != null) {\r\n                    complexTensors.real.dispose();\r\n                    complexTensors.imag.dispose();\r\n                }\r\n            }\r\n        };\r\n        MathBackendWebGL.prototype.getTexture = function (dataId) {\r\n            this.uploadToGPU(dataId);\r\n            return this.texData.get(dataId).texture;\r\n        };\r\n        MathBackendWebGL.prototype.getCPUBackend = function () {\r\n            if (!ENV.get('WEBGL_CPU_FORWARD')) {\r\n                return null;\r\n            }\r\n            if (this.cpuBackend == null) {\r\n                this.cpuBackend = ENV.findBackend('cpu');\r\n            }\r\n            return this.cpuBackend;\r\n        };\r\n        MathBackendWebGL.prototype.shouldExecuteOnCPU = function (inputs, sizeThreshold) {\r\n            var _this = this;\r\n            if (sizeThreshold === void 0) { sizeThreshold = CPU_HANDOFF_SIZE_THRESHOLD; }\r\n            return this.getCPUBackend() != null &&\r\n                inputs.every(function (input) { return _this.texData.get(input.dataId).texture == null &&\r\n                    input.size < sizeThreshold; });\r\n        };\r\n        MathBackendWebGL.prototype.getGPGPUContext = function () {\r\n            return this.gpgpu;\r\n        };\r\n        MathBackendWebGL.prototype.getCanvas = function () {\r\n            return this.canvas;\r\n        };\r\n        MathBackendWebGL.prototype.complex = function (real, imag) {\r\n            var result = this.makeOutputArray(real.shape, 'complex64');\r\n            var resultData = this.texData.get(result.dataId);\r\n            resultData.complexTensors = {\r\n                real: ENV.engine.keep(real.clone()),\r\n                imag: ENV.engine.keep(imag.clone())\r\n            };\r\n            return result;\r\n        };\r\n        MathBackendWebGL.prototype.real = function (input) {\r\n            var resultData = this.texData.get(input.dataId);\r\n            return resultData.complexTensors.real.clone();\r\n        };\r\n        MathBackendWebGL.prototype.imag = function (input) {\r\n            var resultData = this.texData.get(input.dataId);\r\n            return resultData.complexTensors.imag.clone();\r\n        };\r\n        MathBackendWebGL.prototype.slice = function (x, begin, size) {\r\n            if (this.shouldExecuteOnCPU([x])) {\r\n                return this.cpuBackend.slice(x, begin, size);\r\n            }\r\n            var isPacked = this.texData.get(x.dataId).isPacked;\r\n            var isContinous = isSliceContinous(x.shape, begin, size);\r\n            if (isPacked || !isContinous) {\r\n                var program = ENV.get('WEBGL_PACK_ARRAY_OPERATIONS') ?\r\n                    new SlicePackedProgram(size) :\r\n                    new SliceProgram(size);\r\n                var customSetup = program.getCustomSetupFunc(begin);\r\n                return this.compileAndRun(program, [x], null, customSetup);\r\n            }\r\n            this.uploadToGPU(x.dataId);\r\n            return this.shallowSlice(x, begin, size);\r\n        };\r\n        MathBackendWebGL.prototype.shallowSlice = function (x, begin, size) {\r\n            var xTexData = this.texData.get(x.dataId);\r\n            var t = Tensor.make(size, {}, xTexData.dtype);\r\n            var newTexData = this.texData.get(t.dataId);\r\n            Object.assign(newTexData, xTexData);\r\n            newTexData.shape = size;\r\n            var flatOffset = computeFlatOffset(begin, x.strides);\r\n            if (xTexData.slice) {\r\n                flatOffset += xTexData.slice.flatOffset;\r\n            }\r\n            newTexData.slice = {\r\n                flatOffset: flatOffset,\r\n                origDataId: xTexData.slice && xTexData.slice.origDataId || x.dataId\r\n            };\r\n            var refCount = this.dataRefCount.get(newTexData.slice.origDataId) || 1;\r\n            this.dataRefCount.set(newTexData.slice.origDataId, refCount + 1);\r\n            return t;\r\n        };\r\n        MathBackendWebGL.prototype.stridedSlice = function (x, begin, end, strides, beginMask, endMask, ellipsisMask, newAxisMask, shrinkAxisMask) {\r\n            if (this.shouldExecuteOnCPU([x])) {\r\n                return this.cpuBackend.stridedSlice(x, begin, end, strides, beginMask, endMask, ellipsisMask, newAxisMask, shrinkAxisMask);\r\n            }\r\n            var _a = getStridedSlicedInfo(x.shape, begin, end, strides, beginMask, endMask, ellipsisMask, newAxisMask, shrinkAxisMask), beginIndex = _a[0], size = _a[1], shrinkAxis = _a[2];\r\n            var shape = size.filter(function (v, index) { return shrinkAxis.indexOf(index) === -1; });\r\n            if (shape.some(function (axis) { return axis === 0; })) {\r\n                return tensor([], shape);\r\n            }\r\n            var program = new StridedSliceProgram(beginIndex, strides, size, shrinkAxis);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.reverse = function (x, axis) {\r\n            var program = new ReverseProgram(x.shape, axis);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.concat = function (tensors, axis) {\r\n            if (this.shouldExecuteOnCPU(tensors)) {\r\n                return this.cpuBackend.concat(tensors, axis);\r\n            }\r\n            if (tensors.length === 1) {\r\n                return tensors[0];\r\n            }\r\n            if (tensors.length > ENV.get('WEBGL_MAX_TEXTURES_IN_SHADER')) {\r\n                var midIndex = Math.floor(tensors.length / 2);\r\n                var leftSide = this.concat(tensors.slice(0, midIndex), axis);\r\n                var rightSide = this.concat(tensors.slice(midIndex), axis);\r\n                return this.concat([leftSide, rightSide], axis);\r\n            }\r\n            var outShape = computeOutShape(tensors.map(function (t) { return t.shape; }), axis);\r\n            var tensors2D = tensors.map(function (t) { return t.as2D(-1, sizeFromShape(t.shape.slice(axis))); });\r\n            var program = new ConcatProgram(tensors2D.map(function (t) { return t.shape; }));\r\n            var res = this.compileAndRun(program, tensors2D);\r\n            return res.reshape(outShape);\r\n        };\r\n        MathBackendWebGL.prototype.neg = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, NEG);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.batchMatMul = function (a, b, transposeA, transposeB) {\r\n            var outerShapeA = transposeA ? a.shape[2] : a.shape[1];\r\n            var outerShapeB = transposeB ? b.shape[1] : b.shape[2];\r\n            var sharedDim = transposeA ? a.shape[1] : a.shape[2];\r\n            var _a = a.shape, batch = _a[0];\r\n            if ((outerShapeA === 1 || outerShapeB === 1) &&\r\n                sharedDim > MATMUL_SHARED_DIM_THRESHOLD) {\r\n                if (transposeA) {\r\n                    a = a.transpose([0, 2, 1]);\r\n                }\r\n                if (transposeB) {\r\n                    b = b.transpose([0, 2, 1]);\r\n                }\r\n                var a3D = outerShapeB === 1 ? a : a.as3D(batch, sharedDim, 1);\r\n                var axis = outerShapeB === 1 ? 2 : 1;\r\n                var b3D = outerShapeB === 1 ? b.as3D(batch, 1, sharedDim) : b;\r\n                return this.multiply(a3D, b3D).sum(axis, true);\r\n            }\r\n            var dtype = upcastType(a.dtype, b.dtype);\r\n            if (batch === 1) {\r\n                var aSqueezed = a.as2D(a.shape[1], a.shape[2]);\r\n                var bSqueezed = b.as2D(b.shape[1], b.shape[2]);\r\n                var program = new MatMulPackedProgram(aSqueezed.shape, bSqueezed.shape, [outerShapeA, outerShapeB], transposeA, transposeB);\r\n                var output = this.makePackedTensor(program.outputShape, dtype);\r\n                var result = this.compileAndRun(program, [aSqueezed, bSqueezed], output);\r\n                return result.reshape([1, result.shape[0], result.shape[1]]);\r\n            }\r\n            else {\r\n                var program = new MatMulProgram(a.shape, b.shape, transposeA, transposeB);\r\n                var output = this.makeOutputArray(program.outputShape, dtype);\r\n                return this.compileAndRun(program, [a, b], output);\r\n            }\r\n        };\r\n        MathBackendWebGL.prototype.fusedBatchMatMul = function (a, b, transposeA, transposeB, bias, activation) {\r\n            var outerShapeA = transposeA ? a.shape[2] : a.shape[1];\r\n            var outerShapeB = transposeB ? b.shape[1] : b.shape[2];\r\n            var _a = a.shape, batch = _a[0];\r\n            var dtype = upcastType(a.dtype, b.dtype);\r\n            if (batch === 1) {\r\n                var aSqueezed = a.as2D(a.shape[1], a.shape[2]);\r\n                var bSqueezed = b.as2D(b.shape[1], b.shape[2]);\r\n                var program = new MatMulPackedProgram(aSqueezed.shape, bSqueezed.shape, [outerShapeA, outerShapeB], transposeA, transposeB, !!bias, activation ? mapActivationToShaderProgram(activation, true) : null);\r\n                var output = this.makePackedTensor(program.outputShape, dtype);\r\n                var inputs = [aSqueezed, bSqueezed];\r\n                if (bias) {\r\n                    inputs.push(bias);\r\n                }\r\n                var result = this.compileAndRun(program, inputs, output);\r\n                return result.reshape([1, result.shape[0], result.shape[1]]);\r\n            }\r\n            else {\r\n                var program = new MatMulProgram(a.shape, b.shape, transposeA, transposeB, !!bias, activation ? mapActivationToShaderProgram(activation) : null);\r\n                var inputs = [a, b];\r\n                if (bias) {\r\n                    inputs.push(bias);\r\n                }\r\n                var output = this.makeOutputArray(program.outputShape, dtype);\r\n                return this.compileAndRun(program, inputs, output);\r\n            }\r\n        };\r\n        MathBackendWebGL.prototype.multiply = function (a, b) {\r\n            if (a.dtype === 'complex64') {\r\n                var aData = this.texData.get(a.dataId);\r\n                var bData = this.texData.get(b.dataId);\r\n                var realProgram = new BinaryOpComplexProgram(COMPLEX_MULTIPLY.REAL, a.shape, b.shape);\r\n                var imagProgram = new BinaryOpComplexProgram(COMPLEX_MULTIPLY.IMAG, a.shape, b.shape);\r\n                var inputs = [\r\n                    this.makeComplexComponentTensorHandle(a, aData.complexTensors.real),\r\n                    this.makeComplexComponentTensorHandle(a, aData.complexTensors.imag),\r\n                    this.makeComplexComponentTensorHandle(b, bData.complexTensors.real),\r\n                    this.makeComplexComponentTensorHandle(b, bData.complexTensors.imag)\r\n                ];\r\n                var real = this.compileAndRun(realProgram, inputs);\r\n                var imag = this.compileAndRun(imagProgram, inputs);\r\n                var complex = this.complex(real, imag);\r\n                real.dispose();\r\n                imag.dispose();\r\n                return complex;\r\n            }\r\n            if (this.shouldExecuteOnCPU([a, b])) {\r\n                return this.cpuBackend.multiply(a, b);\r\n            }\r\n            if (this.usePackedBinaryOp(a, b)) {\r\n                return this.packedBinaryOp(a, b, MUL, a.dtype);\r\n            }\r\n            var program = new BinaryOpProgram(MUL, a.shape, b.shape);\r\n            var output = this.makeOutputArray(program.outputShape, a.dtype);\r\n            return this.compileAndRun(program, [a, b], output);\r\n        };\r\n        MathBackendWebGL.prototype.batchNormalization = function (x, mean, variance, varianceEpsilon, scale, offset) {\r\n            var inputs = [x, mean, variance];\r\n            var offsetShape = null;\r\n            if (offset != null) {\r\n                offsetShape = offset.shape;\r\n                inputs.push(offset);\r\n            }\r\n            var scaleShape = null;\r\n            if (scale != null) {\r\n                scaleShape = scale.shape;\r\n                inputs.push(scale);\r\n            }\r\n            if (ENV.get('WEBGL_PACK_BATCHNORMALIZATION')) {\r\n                var batchNormPackedProgram = new BatchNormPackedProgram(x.shape, mean.shape, variance.shape, offsetShape, scaleShape, varianceEpsilon);\r\n                return this.compileAndRun(batchNormPackedProgram, inputs);\r\n            }\r\n            var batchNormProgram = new BatchNormProgram(x.shape, mean.shape, variance.shape, offsetShape, scaleShape, varianceEpsilon);\r\n            return this.compileAndRun(batchNormProgram, inputs);\r\n        };\r\n        MathBackendWebGL.prototype.localResponseNormalization4D = function (x, radius, bias, alpha, beta) {\r\n            var program = new LRNProgram(x.shape, radius, bias, alpha, beta);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.LRNGrad = function (dy, inputImage, outputImage, depthRadius, bias, alpha, beta) {\r\n            var program = new LRNGradProgram(inputImage.shape, depthRadius, bias, alpha, beta);\r\n            return this.compileAndRun(program, [inputImage, outputImage, dy]);\r\n        };\r\n        MathBackendWebGL.prototype.tile = function (x, reps) {\r\n            var program = new TileProgram(x.shape, reps);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.pad = function (x, paddings, constantValue) {\r\n            var program = ENV.get('WEBGL_PACK_ARRAY_OPERATIONS') ?\r\n                new PadPackedProgram(x.shape, paddings, constantValue) :\r\n                new PadProgram(x.shape, paddings, constantValue);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.transpose = function (x, perm) {\r\n            var program = ENV.get('WEBGL_PACK_ARRAY_OPERATIONS') ?\r\n                new TransposePackedProgram(x.shape, perm) :\r\n                new TransposeProgram(x.shape, perm);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.gather = function (x, indices, axis) {\r\n            var program = new GatherProgram(x.shape, indices.size, axis);\r\n            return this.compileAndRun(program, [x, indices]);\r\n        };\r\n        MathBackendWebGL.prototype.batchToSpaceND = function (x, blockShape, crops) {\r\n            assert(x.rank <= 4, 'batchToSpaceND for rank > 4 with a WebGL backend not implemented yet');\r\n            var prod = blockShape.reduce(function (a, b) { return a * b; });\r\n            var reshaped = getReshaped(x.shape, blockShape, prod);\r\n            var permuted = getPermuted(reshaped.length, blockShape.length);\r\n            var reshapedPermuted = getReshapedPermuted(x.shape, blockShape, prod);\r\n            var sliceBeginCoords = getSliceBeginCoords(crops, blockShape.length);\r\n            var sliceSize = getSliceSize(reshapedPermuted, crops, blockShape.length);\r\n            return x.reshape(reshaped)\r\n                .transpose(permuted)\r\n                .reshape(reshapedPermuted)\r\n                .slice(sliceBeginCoords, sliceSize);\r\n        };\r\n        MathBackendWebGL.prototype.spaceToBatchND = function (x, blockShape, paddings) {\r\n            assert(x.rank <= 4, 'spaceToBatchND for rank > 4 with a WebGL backend not implemented yet');\r\n            var prod = blockShape.reduce(function (a, b) { return a * b; });\r\n            var completePaddings = [[0, 0]];\r\n            completePaddings.push.apply(completePaddings, paddings);\r\n            for (var i = 1 + blockShape.length; i < x.shape.length; ++i) {\r\n                completePaddings.push([0, 0]);\r\n            }\r\n            var paddedX = x.pad(completePaddings);\r\n            var reshapedPaddedShape = getReshaped(paddedX.shape, blockShape, prod, false);\r\n            var permutedReshapedPaddedPermutation = getPermuted(reshapedPaddedShape.length, blockShape.length, false);\r\n            var flattenShape = getReshapedPermuted(paddedX.shape, blockShape, prod, false);\r\n            return paddedX.reshape(reshapedPaddedShape)\r\n                .transpose(permutedReshapedPaddedPermutation)\r\n                .reshape(flattenShape);\r\n        };\r\n        MathBackendWebGL.prototype.reduce = function (x, reduceType, dtype) {\r\n            var batchSize = x.shape[0];\r\n            var inSize = x.shape[1];\r\n            var windowSize = computeOptimalWindowSize(inSize);\r\n            var reduceInfo = { windowSize: windowSize, inSize: inSize, batchSize: batchSize };\r\n            var program = new ReduceProgram(reduceInfo, reduceType);\r\n            var _a = program.outputShape, rows = _a[0], cols = _a[1];\r\n            var output = this.makeOutputArray([rows, cols], dtype);\r\n            this.compileAndRun(program, [x], output);\r\n            if (output.shape[1] === 1) {\r\n                return output;\r\n            }\r\n            return this.reduce(output, reduceType, dtype);\r\n        };\r\n        MathBackendWebGL.prototype.argReduce = function (x, reduceType, bestIndicesA) {\r\n            if (bestIndicesA === void 0) { bestIndicesA = null; }\r\n            var batchSize = x.shape[0];\r\n            var inSize = x.shape[1];\r\n            if (bestIndicesA != null) {\r\n                batchSize = bestIndicesA.shape[0];\r\n                inSize = bestIndicesA.shape[1];\r\n            }\r\n            var windowSize = computeOptimalWindowSize(inSize);\r\n            var reduceInfo = { windowSize: windowSize, inSize: inSize, batchSize: batchSize };\r\n            var program = new ArgMinMaxProgram(reduceInfo, reduceType, bestIndicesA == null);\r\n            var _a = program.outputShape, rows = _a[0], cols = _a[1];\r\n            var output = this.makeOutputArray([rows, cols], 'int32');\r\n            var inputs = [x];\r\n            if (bestIndicesA != null) {\r\n                inputs.push(bestIndicesA);\r\n            }\r\n            this.compileAndRun(program, inputs, output);\r\n            if (output.shape[1] === 1) {\r\n                return output;\r\n            }\r\n            return this.argReduce(x, reduceType, output);\r\n        };\r\n        MathBackendWebGL.prototype.sum = function (x, axes) {\r\n            assertAxesAreInnerMostDims('sum', axes, x.rank);\r\n            var _a = computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1];\r\n            var inSize = sizeFromShape(reduceShape);\r\n            var a2D = x.as2D(-1, inSize);\r\n            var outputDType = sumOutType(x.dtype);\r\n            return this.reduce(a2D, 'sum', outputDType).reshape(outShape);\r\n        };\r\n        MathBackendWebGL.prototype.prod = function (x, axes) {\r\n            var _a = computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1];\r\n            var inSize = sizeFromShape(reduceShape);\r\n            var a2D = x.as2D(-1, inSize);\r\n            var outputDType = sumOutType(x.dtype);\r\n            return this.reduce(a2D, 'prod', outputDType).reshape(outShape);\r\n        };\r\n        MathBackendWebGL.prototype.unsortedSegmentSum = function (x, segmentIds, numSegments) {\r\n            var axis = 0;\r\n            var permutation = getAxesPermutation([axis], x.rank);\r\n            var permutedX = x;\r\n            if (permutation != null) {\r\n                permutedX = x.transpose(permutation);\r\n                axis = getInnerMostAxes(1, x.rank)[0];\r\n            }\r\n            var outShape = computeOutShape$1(permutedX.shape, axis, numSegments);\r\n            var inSize = sizeFromShape([permutedX.shape[axis]]);\r\n            var a2D = permutedX.as2D(-1, inSize);\r\n            var outputDType = sumOutType(x.dtype);\r\n            var result = this.segOpCompute(a2D, 'unsortedSegmentSum', segmentIds, outputDType, numSegments)\r\n                .reshape(outShape);\r\n            if (permutation != null) {\r\n                result = result.transpose(getUndoAxesPermutation(permutation));\r\n            }\r\n            return result;\r\n        };\r\n        MathBackendWebGL.prototype.segOpCompute = function (x, segOpType, segmentIds, dtype, numSegments) {\r\n            var batchSize = x.shape[0];\r\n            var inSize = x.shape[1];\r\n            var windowSize = segOpComputeOptimalWindowSize(inSize, numSegments);\r\n            var segOpInfo = { windowSize: windowSize, inSize: inSize, batchSize: batchSize, numSegments: numSegments };\r\n            var program = new SegmentOpProgram(segOpInfo, segOpType);\r\n            var _a = program.outputShape, rows = _a[0], cols = _a[1];\r\n            var output = this.makeOutputArray([rows, cols], dtype);\r\n            this.compileAndRun(program, [x, segmentIds], output);\r\n            if (output.shape[1] === numSegments) {\r\n                return output;\r\n            }\r\n            segmentIds = range(0, numSegments).tile([inSize / windowSize]);\r\n            return this.segOpCompute(output, segOpType, segmentIds, dtype, numSegments);\r\n        };\r\n        MathBackendWebGL.prototype.argMin = function (x, axis) {\r\n            var axes = [axis];\r\n            assertAxesAreInnerMostDims('argMin', axes, x.rank);\r\n            var _a = computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1];\r\n            var inSize = sizeFromShape(reduceShape);\r\n            var a2D = x.as2D(-1, inSize);\r\n            return this.argReduce(a2D, 'min').reshape(outShape);\r\n        };\r\n        MathBackendWebGL.prototype.argMax = function (x, axis) {\r\n            var axes = [axis];\r\n            assertAxesAreInnerMostDims('argMax', axes, x.rank);\r\n            var _a = computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1];\r\n            var inSize = sizeFromShape(reduceShape);\r\n            var a2D = x.as2D(-1, inSize);\r\n            return this.argReduce(a2D, 'max').reshape(outShape);\r\n        };\r\n        MathBackendWebGL.prototype.cumsum = function (x, axis, exclusive, reverse) {\r\n            if (axis !== x.rank - 1) {\r\n                throw new Error(\"WebGL cumsum shader expects an inner-most axis=\" + (x.rank - 1) + \" \" +\r\n                    (\"but got axis=\" + axis));\r\n            }\r\n            var program = new CumSumProgram(x.shape, exclusive, reverse);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.equal = function (a, b) {\r\n            var program = new BinaryOpProgram(EQUAL, a.shape, b.shape);\r\n            var output = this.makeOutputArray(program.outputShape, 'bool');\r\n            return this.compileAndRun(program, [a, b], output);\r\n        };\r\n        MathBackendWebGL.prototype.notEqual = function (a, b) {\r\n            var program = new BinaryOpProgram(NOT_EQUAL, a.shape, b.shape);\r\n            var output = this.makeOutputArray(program.outputShape, 'bool');\r\n            return this.compileAndRun(program, [a, b], output);\r\n        };\r\n        MathBackendWebGL.prototype.less = function (a, b) {\r\n            if (this.shouldExecuteOnCPU([a, b])) {\r\n                return this.cpuBackend.less(a, b);\r\n            }\r\n            var program = new BinaryOpProgram(LESS, a.shape, b.shape);\r\n            var output = this.makeOutputArray(program.outputShape, 'bool');\r\n            return this.compileAndRun(program, [a, b], output);\r\n        };\r\n        MathBackendWebGL.prototype.lessEqual = function (a, b) {\r\n            var program = new BinaryOpProgram(LESS_EQUAL, a.shape, b.shape);\r\n            var output = this.makeOutputArray(program.outputShape, 'bool');\r\n            return this.compileAndRun(program, [a, b], output);\r\n        };\r\n        MathBackendWebGL.prototype.greater = function (a, b) {\r\n            if (this.shouldExecuteOnCPU([a, b])) {\r\n                return this.cpuBackend.greater(a, b);\r\n            }\r\n            var program = new BinaryOpProgram(GREATER, a.shape, b.shape);\r\n            var output = this.makeOutputArray(program.outputShape, 'bool');\r\n            return this.compileAndRun(program, [a, b], output);\r\n        };\r\n        MathBackendWebGL.prototype.greaterEqual = function (a, b) {\r\n            var program = new BinaryOpProgram(GREATER_EQUAL, a.shape, b.shape);\r\n            var output = this.makeOutputArray(program.outputShape, 'bool');\r\n            return this.compileAndRun(program, [a, b], output);\r\n        };\r\n        MathBackendWebGL.prototype.logicalNot = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, LOGICAL_NOT);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.logicalAnd = function (a, b) {\r\n            var program = new BinaryOpProgram(LOGICAL_AND, a.shape, b.shape);\r\n            var output = this.makeOutputArray(program.outputShape, 'bool');\r\n            return this.compileAndRun(program, [a, b], output);\r\n        };\r\n        MathBackendWebGL.prototype.logicalOr = function (a, b) {\r\n            var program = new BinaryOpProgram(LOGICAL_OR, a.shape, b.shape);\r\n            var output = this.makeOutputArray(program.outputShape, 'bool');\r\n            return this.compileAndRun(program, [a, b], output);\r\n        };\r\n        MathBackendWebGL.prototype.select = function (condition, a, b) {\r\n            var program = new SelectProgram(condition.rank, a.shape, a.rank);\r\n            var output = this.makeOutputArray(program.outputShape, upcastType(a.dtype, b.dtype));\r\n            return this.compileAndRun(program, [condition, a, b], output);\r\n        };\r\n        MathBackendWebGL.prototype.where = function (condition) {\r\n            warn('tf.where() in webgl locks the UI thread. ' +\r\n                'Call tf.whereAsync() instead');\r\n            var condVals = condition.dataSync();\r\n            return whereImpl(condition.shape, condVals);\r\n        };\r\n        MathBackendWebGL.prototype.topk = function (x, k, sorted) {\r\n            var xVals = x.dataSync();\r\n            return topkImpl(xVals, x.shape, x.dtype, k, sorted);\r\n        };\r\n        MathBackendWebGL.prototype.min = function (x, axes) {\r\n            assertAxesAreInnerMostDims('min', axes, x.rank);\r\n            var _a = computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1];\r\n            var inSize = sizeFromShape(reduceShape);\r\n            var a2D = x.as2D(-1, inSize);\r\n            return this.reduce(a2D, 'min', a2D.dtype).reshape(outShape);\r\n        };\r\n        MathBackendWebGL.prototype.minimum = function (a, b) {\r\n            if (this.shouldExecuteOnCPU([a, b])) {\r\n                return this.cpuBackend.minimum(a, b);\r\n            }\r\n            var program = new BinaryOpProgram(MIN, a.shape, b.shape);\r\n            return this.compileAndRun(program, [a, b]);\r\n        };\r\n        MathBackendWebGL.prototype.mod = function (a, b) {\r\n            var program = new BinaryOpProgram(MOD, a.shape, b.shape);\r\n            var customSetup = program.getCustomSetupFunc();\r\n            return this.compileAndRun(program, [a, b], null, customSetup);\r\n        };\r\n        MathBackendWebGL.prototype.max = function (x, axes) {\r\n            assertAxesAreInnerMostDims('max', axes, x.rank);\r\n            var _a = computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1];\r\n            var inSize = sizeFromShape(reduceShape);\r\n            var a2D = x.as2D(-1, inSize);\r\n            return this.reduce(a2D, 'max', a2D.dtype).reshape(outShape);\r\n        };\r\n        MathBackendWebGL.prototype.maximum = function (a, b) {\r\n            if (this.shouldExecuteOnCPU([a, b])) {\r\n                return this.cpuBackend.maximum(a, b);\r\n            }\r\n            var program = new BinaryOpProgram(MAX, a.shape, b.shape);\r\n            return this.compileAndRun(program, [a, b]);\r\n        };\r\n        MathBackendWebGL.prototype.all = function (x, axes) {\r\n            assertAxesAreInnerMostDims('all', axes, x.rank);\r\n            var _a = computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1];\r\n            var inSize = sizeFromShape(reduceShape);\r\n            var a2D = x.as2D(-1, inSize);\r\n            return this.reduce(a2D, 'all', a2D.dtype).reshape(outShape);\r\n        };\r\n        MathBackendWebGL.prototype.any = function (x, axes) {\r\n            assertAxesAreInnerMostDims('any', axes, x.rank);\r\n            var _a = computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1];\r\n            var inSize = sizeFromShape(reduceShape);\r\n            var a2D = x.as2D(-1, inSize);\r\n            return this.reduce(a2D, 'any', a2D.dtype).reshape(outShape);\r\n        };\r\n        MathBackendWebGL.prototype.squaredDifference = function (a, b) {\r\n            var program = new BinaryOpProgram(SQUARED_DIFFERENCE, a.shape, b.shape);\r\n            return this.compileAndRun(program, [a, b]);\r\n        };\r\n        MathBackendWebGL.prototype.realDivide = function (a, b) {\r\n            var op = DIV;\r\n            var outputDtype = 'float32';\r\n            if (this.usePackedBinaryOp(a, b)) {\r\n                return this.packedBinaryOp(a, b, PACKED_DIV, outputDtype);\r\n            }\r\n            var program = new BinaryOpProgram(op, a.shape, b.shape);\r\n            var output = this.makeOutputArray(program.outputShape, outputDtype);\r\n            return this.compileAndRun(program, [a, b], output);\r\n        };\r\n        MathBackendWebGL.prototype.floorDiv = function (a, b) {\r\n            var op = INT_DIV;\r\n            var outputDtype = 'int32';\r\n            if (this.usePackedBinaryOp(a, b)) {\r\n                return this.packedBinaryOp(a, b, PACKED_INT_DIV, outputDtype);\r\n            }\r\n            var program = new BinaryOpProgram(op, a.shape, b.shape);\r\n            var output = this.makeOutputArray(program.outputShape, outputDtype);\r\n            return this.compileAndRun(program, [a, b], output);\r\n        };\r\n        MathBackendWebGL.prototype.add = function (a, b) {\r\n            if (a.dtype === 'complex64' && b.dtype === 'complex64') {\r\n                return this.complexSeparableBinaryOp(a, b, ADD);\r\n            }\r\n            var dtype = upcastType(a.dtype, b.dtype);\r\n            if (this.usePackedBinaryOp(a, b)) {\r\n                return this.packedBinaryOp(a, b, ADD, dtype);\r\n            }\r\n            var program = new BinaryOpProgram(ADD, a.shape, b.shape);\r\n            var output = this.makeOutputArray(program.outputShape, dtype);\r\n            return this.compileAndRun(program, [a, b], output);\r\n        };\r\n        MathBackendWebGL.prototype.usePackedBinaryOp = function (a, b) {\r\n            if (!ENV.get('WEBGL_PACK_BINARY_OPERATIONS')) {\r\n                return false;\r\n            }\r\n            var outputShape = assertAndGetBroadcastShape(a.shape, b.shape);\r\n            if (outputShape.length > 4) {\r\n                return false;\r\n            }\r\n            if (getBroadcastDims(a.shape, outputShape).length ||\r\n                getBroadcastDims(b.shape, outputShape).length) {\r\n                return false;\r\n            }\r\n            return true;\r\n        };\r\n        MathBackendWebGL.prototype.packedBinaryOp = function (a, b, op, dtype) {\r\n            var program = new BinaryOpPackedProgram(op, a.shape, b.shape);\r\n            var output = this.makePackedTensor(program.outputShape, dtype);\r\n            return this.compileAndRun(program, [a, b], output);\r\n        };\r\n        MathBackendWebGL.prototype.complexSeparableBinaryOp = function (a, b, op) {\r\n            var _this = this;\r\n            var aData = this.texData.get(a.dataId);\r\n            var bData = this.texData.get(b.dataId);\r\n            var _a = [\r\n                [aData.complexTensors.real, bData.complexTensors.real],\r\n                [aData.complexTensors.imag, bData.complexTensors.imag]\r\n            ].map(function (complexParts) {\r\n                var aPart = complexParts[0], bPart = complexParts[1];\r\n                var program = new BinaryOpProgram(op, a.shape, b.shape);\r\n                var output = _this.makeOutputArray(program.outputShape, upcastType(aPart.dtype, bPart.dtype));\r\n                var aHandle = _this.makeComplexComponentTensorHandle(a, aPart);\r\n                var bHandle = _this.makeComplexComponentTensorHandle(b, bPart);\r\n                return _this.compileAndRun(program, [aHandle, bHandle], output);\r\n            }), real = _a[0], imag = _a[1];\r\n            var complex = this.complex(real, imag);\r\n            real.dispose();\r\n            imag.dispose();\r\n            return complex;\r\n        };\r\n        MathBackendWebGL.prototype.makeComplexComponentTensorHandle = function (complexTensor, complexPart) {\r\n            return {\r\n                dataId: complexPart.dataId,\r\n                dtype: complexPart.dtype,\r\n                shape: complexTensor.shape\r\n            };\r\n        };\r\n        MathBackendWebGL.prototype.addN = function (tensors) {\r\n            var res = tensors[0];\r\n            for (var i = 1; i < tensors.length; i++) {\r\n                res = this.add(res, tensors[i]);\r\n            }\r\n            return res;\r\n        };\r\n        MathBackendWebGL.prototype.subtract = function (a, b) {\r\n            if (a.dtype === 'complex64' && b.dtype === 'complex64') {\r\n                return this.complexSeparableBinaryOp(a, b, SUB);\r\n            }\r\n            if (this.shouldExecuteOnCPU([a, b])) {\r\n                return this.cpuBackend.subtract(a, b);\r\n            }\r\n            var dtype = upcastType(a.dtype, b.dtype);\r\n            if (this.usePackedBinaryOp(a, b)) {\r\n                return this.packedBinaryOp(a, b, SUB, a.dtype);\r\n            }\r\n            var program = new BinaryOpProgram(SUB, a.shape, b.shape);\r\n            var output = this.makeOutputArray(program.outputShape, dtype);\r\n            return this.compileAndRun(program, [a, b], output);\r\n        };\r\n        MathBackendWebGL.prototype.pow = function (a, b) {\r\n            var usePackedOp = this.usePackedBinaryOp(a, b);\r\n            var program = usePackedOp ?\r\n                new BinaryOpPackedProgram(PACKED_POW, a.shape, b.shape) :\r\n                new BinaryOpProgram(POW, a.shape, b.shape);\r\n            var dtype = upcastType(a.dtype, b.dtype);\r\n            var output = usePackedOp ?\r\n                this.makePackedTensor(program.outputShape, dtype) :\r\n                this.makeOutputArray(program.outputShape, dtype);\r\n            var customSetup = program.getCustomSetupFunc();\r\n            return this.compileAndRun(program, [a, b], output, customSetup);\r\n        };\r\n        MathBackendWebGL.prototype.ceil = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, CEIL);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.floor = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, FLOOR);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.sign = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, SIGN);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.round = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, ROUND);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.exp = function (x) {\r\n            var program;\r\n            if (ENV.get('WEBGL_PACK')) {\r\n                program = new UnaryOpPackedProgram(x.shape, EXP);\r\n            }\r\n            else {\r\n                program = new UnaryOpProgram(x.shape, EXP);\r\n            }\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.expm1 = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, EXPM1);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.log = function (x) {\r\n            var program;\r\n            if (ENV.get('WEBGL_PACK')) {\r\n                program = new UnaryOpPackedProgram(x.shape, LOG$1);\r\n            }\r\n            else {\r\n                program = new UnaryOpProgram(x.shape, LOG);\r\n            }\r\n            var customSetup = program.getCustomSetupFunc();\r\n            return this.compileAndRun(program, [x], null, customSetup);\r\n        };\r\n        MathBackendWebGL.prototype.log1p = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, LOG1P);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.sqrt = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, SQRT);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.rsqrt = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, RSQRT);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.square = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, SQUARE);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.reciprocal = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, RECIPROCAL);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.relu = function (x) {\r\n            var program;\r\n            if (ENV.get('WEBGL_PACK')) {\r\n                program = new UnaryOpPackedProgram(x.shape, RELU$1);\r\n            }\r\n            else {\r\n                program = new UnaryOpProgram(x.shape, RELU);\r\n            }\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.prelu = function (x, alpha) {\r\n            var program = new BinaryOpProgram(PRELU, x.shape, alpha.shape);\r\n            return this.compileAndRun(program, [x, alpha]);\r\n        };\r\n        MathBackendWebGL.prototype.elu = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, ELU);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.eluDer = function (dy, y) {\r\n            var program = new BinaryOpProgram(ELU_DER, dy.shape, y.shape);\r\n            return this.compileAndRun(program, [dy, y]);\r\n        };\r\n        MathBackendWebGL.prototype.selu = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, SELU);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.int = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, TO_INT);\r\n            var output = this.makeOutputArray(program.outputShape, 'int32');\r\n            return this.compileAndRun(program, [x], output);\r\n        };\r\n        MathBackendWebGL.prototype.clip = function (x, min, max) {\r\n            var program;\r\n            if (ENV.get('WEBGL_PACK_CLIP')) {\r\n                program = new ClipPackedProgram(x.shape);\r\n            }\r\n            else {\r\n                program = new ClipProgram(x.shape);\r\n            }\r\n            var customSetup = program.getCustomSetupFunc(min, max);\r\n            return this.compileAndRun(program, [x], null, customSetup);\r\n        };\r\n        MathBackendWebGL.prototype.abs = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, ABS);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.complexAbs = function (x) {\r\n            var xData = this.texData.get(x.dataId);\r\n            var program = new ComplexAbsProgram(x.shape);\r\n            var inputs = [\r\n                this.makeComplexComponentTensorHandle(x, xData.complexTensors.real),\r\n                this.makeComplexComponentTensorHandle(x, xData.complexTensors.imag),\r\n            ];\r\n            return this.compileAndRun(program, inputs);\r\n        };\r\n        MathBackendWebGL.prototype.sigmoid = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, SIGMOID);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.softplus = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, SOFTPLUS);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.sin = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, SIN);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.cos = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, COS);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.tan = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, TAN);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.asin = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, ASIN);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.acos = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, ACOS);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.atan = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, ATAN);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.atan2 = function (a, b) {\r\n            var program = new BinaryOpProgram(ATAN2, a.shape, b.shape);\r\n            return this.compileAndRun(program, [a, b]);\r\n        };\r\n        MathBackendWebGL.prototype.sinh = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, SINH);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.cosh = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, COSH);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.tanh = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, TANH);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.asinh = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, ASINH);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.acosh = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, ACOSH);\r\n            var customSetup = program.getCustomSetupFunc();\r\n            return this.compileAndRun(program, [x], null, customSetup);\r\n        };\r\n        MathBackendWebGL.prototype.atanh = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, ATANH);\r\n            var customSetup = program.getCustomSetupFunc();\r\n            return this.compileAndRun(program, [x], null, customSetup);\r\n        };\r\n        MathBackendWebGL.prototype.erf = function (x) {\r\n            var program = new UnaryOpProgram(x.shape, ERF);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.step = function (x, alpha) {\r\n            var program = new UnaryOpProgram(x.shape, STEP(alpha));\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.conv2dByMatMul = function (x, filter, convInfo) {\r\n            if (!ENV.get('WEBGL_LAZILY_UNPACK') ||\r\n                !ENV.get('WEBGL_PACK_BINARY_OPERATIONS')) {\r\n                var $x_1 = this.reshape(x, [1, x.shape[0] * x.shape[1] * x.shape[2],\r\n                    convInfo.inChannels]);\r\n                var $filter_1 = this.reshape(filter, [1, convInfo.inChannels, convInfo.outChannels]);\r\n                return this.batchMatMul($x_1, $filter_1, false, false).reshape(convInfo.outShape);\r\n            }\r\n            var xshape = x.shape;\r\n            var xTexData = this.texData.get(x.dataId);\r\n            var packedXRowPad = xshape[2] % 2 === 1 && xTexData.isPacked ? 1 : 0;\r\n            var $x = Tensor.make([1, xshape[0] * xshape[1] * (xshape[2] + packedXRowPad),\r\n                convInfo.inChannels], { dataId: x.dataId }, x.dtype);\r\n            if (packedXRowPad) {\r\n                xTexData.shape[xTexData.shape.length - 2]++;\r\n                assert(isReshapeFree(xTexData.shape, $x.shape), \"packed reshape from \" + xTexData.shape + \" to \" + $x.shape + \" isn't free\");\r\n            }\r\n            var $filter = this.reshape(filter, [1, convInfo.inChannels, convInfo.outChannels]);\r\n            var xf = this.batchMatMul($x, $filter, false, false);\r\n            var xfTexData = this.texData.get(xf.dataId);\r\n            assert(xfTexData.isPacked, 'expected packed result of batchMatMul');\r\n            if (packedXRowPad) {\r\n                xTexData.shape[xTexData.shape.length - 2]--;\r\n                xfTexData.shape = convInfo.outShape;\r\n                return Tensor.make(convInfo.outShape, { dataId: xf.dataId }, xf.dtype);\r\n            }\r\n            return this.reshape(xf, convInfo.outShape);\r\n        };\r\n        MathBackendWebGL.prototype.conv2dWithIm2Row = function (x, filter, convInfo) {\r\n            var filterWidth = convInfo.filterWidth, filterHeight = convInfo.filterHeight, inChannels = convInfo.inChannels, outWidth = convInfo.outWidth, outHeight = convInfo.outHeight;\r\n            var sharedDim = filterWidth * filterHeight * inChannels;\r\n            var numCols = outHeight * outWidth;\r\n            var x2ColShape = [sharedDim, numCols];\r\n            var xSqueezed = x.squeeze([0]);\r\n            var w2Row = filter.reshape([sharedDim, -1]);\r\n            var im2ColProgram = new Im2ColProgram(x2ColShape, xSqueezed.shape, convInfo);\r\n            var im2Col = this.compileAndRun(im2ColProgram, [xSqueezed]);\r\n            var matmulProgram = new MatMulPackedProgram(im2Col.shape, w2Row.shape, [numCols, convInfo.outChannels], true, false);\r\n            var product = this.compileAndRun(matmulProgram, [im2Col, w2Row]);\r\n            return product.reshape([1, outHeight, outWidth, convInfo.outChannels]);\r\n        };\r\n        MathBackendWebGL.prototype.conv2d = function (x, filter, convInfo) {\r\n            if (convInfo.filterHeight === 1 && convInfo.filterWidth === 1 &&\r\n                convInfo.dilationHeight === 1 && convInfo.dilationWidth === 1 &&\r\n                convInfo.strideHeight === 1 && convInfo.strideWidth === 1 &&\r\n                (convInfo.padInfo.type === 'SAME' ||\r\n                    convInfo.padInfo.type === 'VALID')) {\r\n                return this.conv2dByMatMul(x, filter, convInfo);\r\n            }\r\n            if (ENV.get('WEBGL_CONV_IM2COL') && x.shape[0] === 1) {\r\n                return this.conv2dWithIm2Row(x, filter, convInfo);\r\n            }\r\n            var program = new Conv2DProgram(convInfo);\r\n            return this.compileAndRun(program, [x, filter]);\r\n        };\r\n        MathBackendWebGL.prototype.conv2dDerInput = function (dy, filter, convInfo) {\r\n            var program = new Conv2DDerInputProgram(convInfo);\r\n            return this.compileAndRun(program, [dy, filter]);\r\n        };\r\n        MathBackendWebGL.prototype.conv2dDerFilter = function (x, dy, convInfo) {\r\n            var program = new Conv2DDerFilterProgram(convInfo);\r\n            return this.compileAndRun(program, [x, dy]);\r\n        };\r\n        MathBackendWebGL.prototype.depthwiseConv2D = function (x, filter, convInfo) {\r\n            var program;\r\n            if (ENV.get('WEBGL_PACK_DEPTHWISECONV') && convInfo.strideWidth <= 2 &&\r\n                convInfo.outChannels / convInfo.inChannels === 1) {\r\n                program = new DepthwiseConvPacked2DProgram(convInfo);\r\n                return this.compileAndRun(program, [x, filter], this.makePackedTensor(convInfo.outShape, x.dtype));\r\n            }\r\n            program = new DepthwiseConv2DProgram(convInfo);\r\n            return this.compileAndRun(program, [x, filter]);\r\n        };\r\n        MathBackendWebGL.prototype.depthwiseConv2DDerInput = function (dy, filter, convInfo) {\r\n            var program = new DepthwiseConv2DDerInputProgram(convInfo);\r\n            return this.compileAndRun(program, [dy, filter]);\r\n        };\r\n        MathBackendWebGL.prototype.depthwiseConv2DDerFilter = function (x, dy, convInfo) {\r\n            var program = new DepthwiseConv2DDerFilterProgram(convInfo);\r\n            return this.compileAndRun(program, [x, dy]);\r\n        };\r\n        MathBackendWebGL.prototype.conv3d = function (x, filter, convInfo) {\r\n            var program = new Conv3DProgram(convInfo);\r\n            return this.compileAndRun(program, [x, filter]);\r\n        };\r\n        MathBackendWebGL.prototype.conv3dDerInput = function (dy, filter, convInfo) {\r\n            var program = new Conv3DDerInputProgram(convInfo);\r\n            return this.compileAndRun(program, [dy, filter]);\r\n        };\r\n        MathBackendWebGL.prototype.conv3dDerFilter = function (x, dy, convInfo) {\r\n            var program = new Conv3DDerFilterProgram(convInfo);\r\n            return this.compileAndRun(program, [x, dy]);\r\n        };\r\n        MathBackendWebGL.prototype.maxPool = function (x, convInfo) {\r\n            var program = new Pool2DProgram(convInfo, 'max', false);\r\n            var output = this.makeOutputArray(program.outputShape, x.dtype);\r\n            return this.compileAndRun(program, [x], output);\r\n        };\r\n        MathBackendWebGL.prototype.avgPool = function (x, convInfo) {\r\n            var program = new Pool2DProgram(convInfo, 'avg', false);\r\n            var output = this.makeOutputArray(program.outputShape, 'float32');\r\n            return this.compileAndRun(program, [x], output);\r\n        };\r\n        MathBackendWebGL.prototype.maxPoolBackprop = function (dy, x, y, convInfo) {\r\n            var getPositions = true;\r\n            var maxPoolPositionsProgram = new Pool2DProgram(convInfo, 'max', getPositions);\r\n            var maxPoolPositions = this.compileAndRun(maxPoolPositionsProgram, [x]);\r\n            var maxPoolBackPropProgram = new MaxPool2DBackpropProgram(convInfo);\r\n            var output = this.makeOutputArray(maxPoolBackPropProgram.outputShape, x.dtype);\r\n            var result = this.compileAndRun(maxPoolBackPropProgram, [dy, maxPoolPositions], output);\r\n            maxPoolPositions.dispose();\r\n            return result;\r\n        };\r\n        MathBackendWebGL.prototype.avgPoolBackprop = function (dy, x, convInfo) {\r\n            var avgPoolBackpropProgram = new AvgPool2DBackpropProgram(convInfo);\r\n            var output = this.makeOutputArray(avgPoolBackpropProgram.outputShape, x.dtype);\r\n            return this.compileAndRun(avgPoolBackpropProgram, [dy], output);\r\n        };\r\n        MathBackendWebGL.prototype.cast = function (x, dtype) {\r\n            return castTensor(x, dtype, this);\r\n        };\r\n        MathBackendWebGL.prototype.unstack = function (x, axis) {\r\n            var num = x.shape[axis];\r\n            var outShape = new Array(x.rank - 1);\r\n            var outIndex = 0;\r\n            for (var i = 0; i < x.rank; i++) {\r\n                if (i !== axis) {\r\n                    outShape[outIndex++] = x.shape[i];\r\n                }\r\n            }\r\n            var begin = new Array(x.rank).fill(0);\r\n            var size = x.shape.slice();\r\n            size[axis] = 1;\r\n            var res = new Array(num);\r\n            for (var i = 0; i < res.length; i++) {\r\n                begin[axis] = i;\r\n                res[i] = this.slice(x, begin, size).reshape(outShape);\r\n            }\r\n            return res;\r\n        };\r\n        MathBackendWebGL.prototype.reshape = function (x, shape) {\r\n            var texData = this.texData.get(x.dataId);\r\n            if (texData.isPacked && !isReshapeFree(x.shape, shape)\r\n                && !(texData.texture !== null &&\r\n                    isReshapeFree(texData.shape, shape))) {\r\n                return this.packedReshape(x, shape);\r\n            }\r\n            return reshapeTensor(x, shape);\r\n        };\r\n        MathBackendWebGL.prototype.resizeBilinear = function (x, newHeight, newWidth, alignCorners) {\r\n            var program = new ResizeBilinearProgram(x.shape, newHeight, newWidth, alignCorners);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.resizeBilinearBackprop = function (dy, x, alignCorners) {\r\n            var program = new ResizeBilinearBackpropProgram(dy, x, alignCorners);\r\n            return this.compileAndRun(program, [dy]);\r\n        };\r\n        MathBackendWebGL.prototype.resizeNearestNeighbor = function (x, newHeight, newWidth, alignCorners) {\r\n            var program = new ResizeNearestNeighborProgram(x.shape, newHeight, newWidth, alignCorners);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.resizeNearestNeighborBackprop = function (dy, x, alignCorners) {\r\n            var program = new ResizeNearestNeigborBackpropProgram(dy, x, alignCorners);\r\n            return this.compileAndRun(program, [dy]);\r\n        };\r\n        MathBackendWebGL.prototype.multinomial = function (logits, normalized, numSamples, seed) {\r\n            var probs = normalized ? logits : softmax(logits);\r\n            var batchSize = probs.shape[0];\r\n            var numOutcomes = probs.shape[1];\r\n            var program = new MultinomialProgram(batchSize, numOutcomes, numSamples);\r\n            var output = this.makeOutputArray(program.outputShape, 'int32');\r\n            var customSetup = program.getCustomSetupFunc(seed);\r\n            return this.compileAndRun(program, [probs], output, customSetup);\r\n        };\r\n        MathBackendWebGL.prototype.oneHot = function (indices, depth, onValue, offValue) {\r\n            var program = new OneHotProgram(indices.size, depth, onValue, offValue);\r\n            return this.compileAndRun(program, [indices]);\r\n        };\r\n        MathBackendWebGL.prototype.nonMaxSuppression = function (boxes, scores, maxOutputSize, iouThreshold, scoreThreshold) {\r\n            warn('tf.nonMaxSuppression() in webgl locks the UI thread. ' +\r\n                'Call tf.nonMaxSuppressionAsync() instead');\r\n            var boxesVals = boxes.dataSync();\r\n            var scoresVals = scores.dataSync();\r\n            return nonMaxSuppressionImpl(boxesVals, scoresVals, maxOutputSize, iouThreshold, scoreThreshold);\r\n        };\r\n        MathBackendWebGL.prototype.cropAndResize = function (image, boxes, boxIndex, cropSize, method, extrapolationValue) {\r\n            var program = new CropAndResizeProgram(image.shape, boxes.shape, cropSize, method, extrapolationValue);\r\n            return this.compileAndRun(program, [image, boxes, boxIndex]);\r\n        };\r\n        MathBackendWebGL.prototype.depthToSpace = function (x, blockSize, dataFormat) {\r\n            assert(blockSize > 1, \"blockSize should be > 1 for depthToSpace, but was: \" + blockSize);\r\n            var batchSize = x.shape[0];\r\n            var inputHeight = (dataFormat === 'NHWC') ? x.shape[1] : x.shape[2];\r\n            var inputWidth = (dataFormat === 'NHWC') ? x.shape[2] : x.shape[3];\r\n            var inputDepth = (dataFormat === 'NHWC') ? x.shape[3] : x.shape[1];\r\n            var outputHeight = inputHeight * blockSize;\r\n            var outputWidth = inputWidth * blockSize;\r\n            var outputDepth = inputDepth / (blockSize * blockSize);\r\n            var outputShape = (dataFormat === 'NHWC') ?\r\n                [batchSize, outputHeight, outputWidth, outputDepth] :\r\n                [batchSize, outputDepth, outputHeight, outputWidth];\r\n            var program = new DepthToSpaceProgram(outputShape, blockSize, dataFormat);\r\n            return this.compileAndRun(program, [x]);\r\n        };\r\n        MathBackendWebGL.prototype.split = function (x, sizeSplits, axis) {\r\n            return split(x, sizeSplits, axis);\r\n        };\r\n        MathBackendWebGL.prototype.scatterND = function (indices, updates, shape) {\r\n            var _a = calculateShapes(updates, indices, shape), sliceRank = _a.sliceRank, numUpdates = _a.numUpdates, sliceSize = _a.sliceSize, strides = _a.strides, outputSize = _a.outputSize;\r\n            var flattenShape = [outputSize / sliceSize, sliceSize];\r\n            var flattenIndices = indices.reshape([numUpdates, sliceRank]);\r\n            var flattenX = updates.reshape([numUpdates, sliceSize]);\r\n            if (outputSize === 0) {\r\n                return reshapeTensor(tensor([]), shape);\r\n            }\r\n            var defaultValue = scalar(0);\r\n            var program = new ScatterProgram(numUpdates, sliceRank, flattenIndices.rank, flattenX.rank, strides, flattenShape);\r\n            return this.compileAndRun(program, [flattenX, flattenIndices, defaultValue])\r\n                .reshape(shape);\r\n        };\r\n        MathBackendWebGL.prototype.sparseToDense = function (sparseIndices, sparseValues, outputShape, defaultValue) {\r\n            var _a = calculateShapes(sparseValues, sparseIndices, outputShape), sliceRank = _a.sliceRank, numUpdates = _a.numUpdates, strides = _a.strides, outputSize = _a.outputSize;\r\n            var sumDupeIndices = false;\r\n            var program = new ScatterProgram(numUpdates, sliceRank, sparseIndices.rank, sparseValues.rank, strides, [outputSize, 1], sumDupeIndices);\r\n            return this.compileAndRun(program, [sparseValues, sparseIndices, defaultValue])\r\n                .reshape(outputShape);\r\n        };\r\n        MathBackendWebGL.prototype.fft = function (x) {\r\n            var inverse = false;\r\n            return this.fftImpl(x, inverse);\r\n        };\r\n        MathBackendWebGL.prototype.ifft = function (x) {\r\n            var inverse = true;\r\n            return this.fftImpl(x, inverse);\r\n        };\r\n        MathBackendWebGL.prototype.fftImpl = function (x, inverse) {\r\n            var xData = this.texData.get(x.dataId);\r\n            var realProgram = new FFTProgram(COMPLEX_FFT.REAL, x.shape, inverse);\r\n            var imagProgram = new FFTProgram(COMPLEX_FFT.IMAG, x.shape, inverse);\r\n            var inputs = [\r\n                this.makeComplexComponentTensorHandle(x, xData.complexTensors.real),\r\n                this.makeComplexComponentTensorHandle(x, xData.complexTensors.imag),\r\n            ];\r\n            var real = this.compileAndRun(realProgram, inputs);\r\n            var imag = this.compileAndRun(imagProgram, inputs);\r\n            var complex = this.complex(real, imag).as2D(x.shape[0], x.shape[1]);\r\n            real.dispose();\r\n            imag.dispose();\r\n            return complex;\r\n        };\r\n        MathBackendWebGL.prototype.gatherND = function (x, indices) {\r\n            var indicesShape = indices.shape;\r\n            var sliceRank = indicesShape[indicesShape.length - 1];\r\n            var _a = prepareAndValidate(x, indices), resultShape = _a[0], numSlices = _a[1], sliceSize = _a[2], strides = _a[3];\r\n            var flattenIndices = indices.reshape([numSlices, sliceRank]);\r\n            var flattenX = x.reshape([x.size / sliceSize, sliceSize]);\r\n            var program = new GatherNDProgram(sliceRank, strides, [numSlices, sliceSize]);\r\n            return this.compileAndRun(program, [flattenX, flattenIndices])\r\n                .reshape(resultShape);\r\n        };\r\n        MathBackendWebGL.prototype.makeOutputArray = function (shape, dtype) {\r\n            return Tensor.make(shape, {}, dtype);\r\n        };\r\n        MathBackendWebGL.prototype.makePackedTensor = function (shape, dtype) {\r\n            var packedTensor = Tensor.make(shape, {}, dtype);\r\n            this.texData.get(packedTensor.dataId).isPacked = true;\r\n            return packedTensor;\r\n        };\r\n        MathBackendWebGL.prototype.unpackTensor = function (input) {\r\n            var program = new UnpackProgram(input.shape);\r\n            return this.compileAndRun(program, [input], Tensor.make(program.outputShape, {}, input.dtype));\r\n        };\r\n        MathBackendWebGL.prototype.packTensor = function (input) {\r\n            var program = new PackProgram(input.shape);\r\n            return this.compileAndRun(program, [input], this.makePackedTensor(input.shape, input.dtype));\r\n        };\r\n        MathBackendWebGL.prototype.packedReshape = function (input, afterShape) {\r\n            var inputAs3D = input.reshape([\r\n                getBatchDim(input.shape)\r\n            ].concat(getRowsCols(input.shape)));\r\n            var afterShapeAs3D = [\r\n                getBatchDim(afterShape)\r\n            ].concat(getRowsCols(afterShape));\r\n            var program = new ReshapePackedProgram(afterShapeAs3D, inputAs3D.shape);\r\n            return this.compileAndRun(program, [inputAs3D])\r\n                .reshape(afterShape);\r\n        };\r\n        MathBackendWebGL.prototype.compileAndRun = function (program, inputs, output, customSetup, pageToCpu) {\r\n            var _this = this;\r\n            if (pageToCpu === void 0) { pageToCpu = true; }\r\n            if (output == null) {\r\n                if (program.usesPackedTextures) {\r\n                    output = this.makePackedTensor(program.outputShape, inputs[0].dtype);\r\n                }\r\n                else {\r\n                    output = this.makeOutputArray(program.outputShape, inputs[0].dtype);\r\n                }\r\n            }\r\n            if (output.size === 0) {\r\n                this.texData.get(output.dataId).values =\r\n                    getTypedArrayFromDType(output.dtype, 0);\r\n                return output;\r\n            }\r\n            var inputsData = inputs.map(function (input) {\r\n                if (input.dtype === 'complex64') {\r\n                    throw new Error(\"GPGPUProgram does not support complex64 input. For complex64 \" +\r\n                        \"dtypes, please separate the program into real and imaginary \" +\r\n                        \"parts.\");\r\n                }\r\n                var texData = _this.texData.get(input.dataId);\r\n                if (texData.texture == null) {\r\n                    if (!program.usesPackedTextures &&\r\n                        sizeFromShape(input.shape) <=\r\n                            ENV.get('WEBGL_SIZE_UPLOAD_UNIFORM')) {\r\n                        return {\r\n                            shape: input.shape,\r\n                            texData: null,\r\n                            isUniform: true,\r\n                            uniformValues: _this.readSync(input.dataId)\r\n                        };\r\n                    }\r\n                    if (program.usesPackedTextures) {\r\n                        texData.isPacked = true;\r\n                        texData.shape = input.shape;\r\n                    }\r\n                }\r\n                else if (!!texData.isPacked !== !!program.usesPackedTextures) {\r\n                    input = texData.isPacked ?\r\n                        _this.unpackTensor(input) : _this.packTensor(input);\r\n                    texData = _this.texData.get(input.dataId);\r\n                }\r\n                else if (texData.isPacked &&\r\n                    !isReshapeFree(texData.shape, input.shape)) {\r\n                    _this.delayedStorage = false;\r\n                    var inputValues = input.dataSync();\r\n                    _this.delayedStorage = true;\r\n                    input = Tensor.make(input.shape, { values: inputValues }, input.dtype);\r\n                    texData = _this.texData.get(input.dataId);\r\n                    texData.isPacked = true;\r\n                }\r\n                _this.uploadToGPU(input.dataId);\r\n                return { shape: input.shape, texData: texData, isUniform: false };\r\n            });\r\n            this.uploadToGPU(output.dataId);\r\n            var outputData = {\r\n                shape: output.shape,\r\n                texData: this.texData.get(output.dataId),\r\n                isUniform: false\r\n            };\r\n            var key = makeShaderKey(program, inputsData, outputData);\r\n            var binary = this.getAndSaveBinary(key, function () {\r\n                return compileProgram(_this.gpgpu, program, inputsData, outputData);\r\n            });\r\n            var shouldTimeProgram = this.activeTimers != null;\r\n            var query;\r\n            if (shouldTimeProgram) {\r\n                query = this.startTimer();\r\n            }\r\n            runProgram(binary, inputsData, outputData, customSetup);\r\n            var numBytesBeforePaging = ENV.get('WEBGL_NUM_MB_BEFORE_PAGING') * 1024;\r\n            if (pageToCpu && this.numBytesInGPU > numBytesBeforePaging) {\r\n                var numBytesToPage = this.numBytesInGPU - numBytesBeforePaging;\r\n                while (numBytesToPage > 0 && this.lruDataGPU.length > 0) {\r\n                    var dataId = this.lruDataGPU.shift();\r\n                    var _a = this.texData.get(dataId), shape = _a.shape, dtype = _a.dtype;\r\n                    numBytesToPage -= this.computeBytes(shape, dtype);\r\n                    this.read(dataId);\r\n                }\r\n            }\r\n            if (shouldTimeProgram) {\r\n                query = this.endTimer(query);\r\n                this.activeTimers.push({ name: program.constructor.name, query: this.getQueryTime(query) });\r\n            }\r\n            if (!ENV.get('WEBGL_LAZILY_UNPACK') &&\r\n                this.texData.get(output.dataId).isPacked && !program.isPackShader) {\r\n                return this.unpackTensor(output);\r\n            }\r\n            return output;\r\n        };\r\n        MathBackendWebGL.prototype.getAndSaveBinary = function (key, getBinary) {\r\n            if (!(key in this.binaryCache)) {\r\n                this.binaryCache[key] = getBinary();\r\n            }\r\n            return this.binaryCache[key];\r\n        };\r\n        MathBackendWebGL.prototype.getTextureManager = function () {\r\n            return this.textureManager;\r\n        };\r\n        MathBackendWebGL.prototype.dispose = function () {\r\n            if (this.disposed) {\r\n                return;\r\n            }\r\n            for (var key in this.binaryCache) {\r\n                this.gpgpu.deleteProgram(this.binaryCache[key].webGLProgram);\r\n            }\r\n            this.textureManager.dispose();\r\n            this.canvas.remove();\r\n            if (this.fromPixels2DContext != null) {\r\n                this.fromPixels2DContext.canvas.remove();\r\n            }\r\n            if (this.gpgpuCreatedLocally) {\r\n                this.gpgpu.dispose();\r\n            }\r\n            this.disposed = true;\r\n        };\r\n        MathBackendWebGL.prototype.floatPrecision = function () {\r\n            var _this = this;\r\n            return tidy(function () {\r\n                var debugFlag = ENV.get('DEBUG');\r\n                ENV.set('DEBUG', false);\r\n                var underflowCheckVluae = _this.abs(scalar(1e-8)).get();\r\n                ENV.set('DEBUG', debugFlag);\r\n                if (underflowCheckVluae > 0) {\r\n                    return 32;\r\n                }\r\n                return 16;\r\n            });\r\n        };\r\n        MathBackendWebGL.prototype.uploadToGPU = function (dataId) {\r\n            var _a;\r\n            var texData = this.texData.get(dataId);\r\n            var shape = texData.shape, values = texData.values, texture = texData.texture, usage = texData.usage, isPacked = texData.isPacked;\r\n            if (texture != null) {\r\n                if (ENV.get('WEBGL_NUM_MB_BEFORE_PAGING') < Number.POSITIVE_INFINITY) {\r\n                    var index = this.lruDataGPU.indexOf(dataId);\r\n                    if (index >= 0) {\r\n                        this.lruDataGPU.splice(this.lruDataGPU.indexOf(dataId), 1);\r\n                        this.lruDataGPU.push(dataId);\r\n                    }\r\n                }\r\n                return;\r\n            }\r\n            var shouldTimeProgram = this.activeTimers != null;\r\n            var start;\r\n            if (shouldTimeProgram) {\r\n                start = performance.now();\r\n            }\r\n            var texShape = getTextureShapeFromLogicalShape(shape, isPacked);\r\n            texData.texShape = texShape;\r\n            var newTexture = this.acquireTexture(dataId, texShape, usage, isPacked);\r\n            texData.texture = newTexture;\r\n            if (values != null) {\r\n                if (isPacked) {\r\n                    var batch = getBatchDim(shape);\r\n                    var rows = 1, cols = 1;\r\n                    if (shape.length) {\r\n                        _a = getRowsCols(shape), rows = _a[0], cols = _a[1];\r\n                    }\r\n                    this.gpgpu.uploadMatrixToPackedTexture(newTexture, batch, rows, cols, texShape[0], texShape[1], typedArrayToFloat32(values));\r\n                }\r\n                else {\r\n                    this.gpgpu.uploadMatrixToTexture(newTexture, texShape[0], texShape[1], typedArrayToFloat32(values));\r\n                }\r\n                texData.values = null;\r\n                if (shouldTimeProgram) {\r\n                    this.uploadWaitMs += performance.now() - start;\r\n                }\r\n            }\r\n        };\r\n        MathBackendWebGL.prototype.convertAndCacheOnCPU = function (dataId, float32Values) {\r\n            var dontKeepCopyOnGPU = this.delayedStorage;\r\n            var texData = this.texData.get(dataId);\r\n            var texture = texData.texture, texShape = texData.texShape, dtype = texData.dtype, usage = texData.usage, isPacked = texData.isPacked;\r\n            if (dontKeepCopyOnGPU && texture != null) {\r\n                this.releaseTexture(dataId, texture, texShape, usage, isPacked);\r\n                texData.texture = null;\r\n                texData.texShape = null;\r\n                texData.isPacked = false;\r\n            }\r\n            texData.usage = TextureUsage.UPLOAD;\r\n            if (float32Values != null) {\r\n                texData.values = float32ToTypedArray(float32Values, dtype);\r\n            }\r\n            return texData.values;\r\n        };\r\n        MathBackendWebGL.prototype.releaseTexture = function (dataId, texture, texShape, texType, isPacked) {\r\n            var _a = this.texData.get(dataId), shape = _a.shape, dtype = _a.dtype;\r\n            if (ENV.get('WEBGL_NUM_MB_BEFORE_PAGING') < Number.POSITIVE_INFINITY) {\r\n                var idx = this.lruDataGPU.indexOf(dataId);\r\n                if (idx >= 0) {\r\n                    this.lruDataGPU.splice(idx, 1);\r\n                }\r\n            }\r\n            this.numBytesInGPU -= this.computeBytes(shape, dtype);\r\n            this.textureManager.releaseTexture(texture, texShape, texType, isPacked);\r\n        };\r\n        MathBackendWebGL.prototype.acquireTexture = function (dataId, texShape, texType, isPacked) {\r\n            var _a = this.texData.get(dataId), shape = _a.shape, dtype = _a.dtype;\r\n            if (ENV.get('WEBGL_NUM_MB_BEFORE_PAGING') < Number.POSITIVE_INFINITY) {\r\n                this.lruDataGPU.push(dataId);\r\n            }\r\n            this.numBytesInGPU += this.computeBytes(shape, dtype);\r\n            return this.textureManager.acquireTexture(texShape, texType, isPacked);\r\n        };\r\n        MathBackendWebGL.prototype.computeBytes = function (shape, dtype) {\r\n            return sizeFromShape(shape) * bytesPerElement(dtype);\r\n        };\r\n        return MathBackendWebGL;\r\n    }());\r\n    if (ENV.get('IS_BROWSER')) {\r\n        ENV.registerBackend('webgl', function () { return new MathBackendWebGL(); }, 2, setTensorTracker);\r\n    }\r\n    function float32ToTypedArray(a, dtype) {\r\n        if (dtype === 'float32' || dtype === 'complex64') {\r\n            return a;\r\n        }\r\n        else if (dtype === 'int32' || dtype === 'bool') {\r\n            var result = (dtype === 'int32') ? new Int32Array(a.length) :\r\n                new Uint8Array(a.length);\r\n            for (var i = 0; i < result.length; ++i) {\r\n                result[i] = Math.round(a[i]);\r\n            }\r\n            return result;\r\n        }\r\n        else {\r\n            throw new Error(\"Unknown dtype \" + dtype);\r\n        }\r\n    }\r\n    function typedArrayToFloat32(a) {\r\n        return (a instanceof Float32Array) ? a : new Float32Array(a);\r\n    }\n\n    function neg_(x) {\r\n        var $x = convertToTensor(x, 'x', 'neg');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.neg(); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.neg($x); }, { $x: $x }, grad);\r\n    }\r\n    function ceil_(x) {\r\n        var $x = convertToTensor(x, 'x', 'ceil');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return zerosLike(dy); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.ceil($x); }, { $x: $x }, grad);\r\n    }\r\n    function floor_(x) {\r\n        var $x = convertToTensor(x, 'x', 'floor');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return zerosLike(dy); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.floor($x); }, { $x: $x }, grad);\r\n    }\r\n    function sign_(x) {\r\n        var $x = convertToTensor(x, 'x', 'sign');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return zerosLike(dy); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.sign($x); }, { $x: $x }, grad);\r\n    }\r\n    function round_(x) {\r\n        var $x = convertToTensor(x, 'x', 'round');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return zerosLike(dy); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.round($x); }, { $x: $x }, grad);\r\n    }\r\n    function exp_(x) {\r\n        var $x = convertToTensor(x, 'x', 'exp');\r\n        var bck = function (dy, saved) {\r\n            var y = saved[0];\r\n            return { $x: function () { return dy.mulStrict(y); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend, save) { return save(backend.exp($x)); }, { $x: $x }, bck);\r\n    }\r\n    function expm1_(x) {\r\n        var $x = convertToTensor(x, 'x', 'expm1');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.mulStrict($x.exp()); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.expm1($x); }, { $x: $x }, grad);\r\n    }\r\n    function log_(x) {\r\n        var $x = convertToTensor(x, 'x', 'log');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.divStrict($x.toFloat()); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.log($x); }, { $x: $x }, grad);\r\n    }\r\n    function log1p_(x) {\r\n        var $x = convertToTensor(x, 'x', 'log1p');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.div($x.add(1)); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.log1p($x); }, { $x: $x }, grad);\r\n    }\r\n    function sqrt_(x) {\r\n        var $x = convertToTensor(x, 'x', 'sqrt');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.div($x.toFloat().sqrt().mul(2)); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.sqrt($x); }, { $x: $x }, grad);\r\n    }\r\n    function rsqrt_(x) {\r\n        var $x = convertToTensor(x, 'x', 'rsqrt');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.div($x.pow(1.5).mul(2)).neg(); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.rsqrt($x); }, { $x: $x }, grad);\r\n    }\r\n    function square_(x) {\r\n        var $x = convertToTensor(x, 'x', 'square');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.mul($x.toFloat().mul(2)); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.square($x); }, { $x: $x }, grad);\r\n    }\r\n    function reciprocal_(x) {\r\n        var $x = convertToTensor(x, 'x', 'reciprocal');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.divStrict($x.square().neg()); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.reciprocal($x); }, { $x: $x }, grad);\r\n    }\r\n    function abs_(x) {\r\n        var $x = convertToTensor(x, 'x', 'abs');\r\n        if ($x.dtype === 'complex64') {\r\n            return ENV.engine.runKernel(function (backend) { return backend.complexAbs($x); }, { $x: $x });\r\n        }\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.mulStrict($x.toFloat().step(-1)); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.abs($x); }, { $x: $x }, grad);\r\n    }\r\n    function clipByValue_(x, clipValueMin, clipValueMax) {\r\n        var $x = convertToTensor(x, 'x', 'clipByValue');\r\n        assert((clipValueMin <= clipValueMax), \"Error in clip: min (\" + clipValueMin + \") must be \" +\r\n            (\"less than or equal to max (\" + clipValueMax + \").\"));\r\n        var grad = function (dy) {\r\n            return {\r\n                $x: function () { return dy.where($x.greaterEqual(clipValueMin)\r\n                    .logicalAnd($x.lessEqual(clipValueMax)), zerosLike(dy)); },\r\n            };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.clip($x, clipValueMin, clipValueMax); }, { $x: $x }, grad);\r\n    }\r\n    function sigmoid_(x) {\r\n        var $x = convertToTensor(x, 'x', 'sigmoid');\r\n        var grad = function (dy, saved) {\r\n            var y = saved[0];\r\n            return { $x: function () { return dy.mul(y.mul(scalar(1).sub(y))); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend, save) { return save(backend.sigmoid($x)); }, { $x: $x }, grad);\r\n    }\r\n    function logSigmoid_(x) {\r\n        var $x = convertToTensor(x, 'x', 'logSigmoid');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.mulStrict($x.neg().sigmoid()); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.softplus($x.neg()).neg(); }, { $x: $x }, grad);\r\n    }\r\n    function softplus_(x) {\r\n        var $x = convertToTensor(x, 'x', 'softplus');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.mulStrict($x.sigmoid()); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.softplus($x); }, { $x: $x }, grad);\r\n    }\r\n    function sin_(x) {\r\n        var $x = convertToTensor(x, 'x', 'sin');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return $x.toFloat().cos().mulStrict(dy); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.sin($x); }, { $x: $x }, grad);\r\n    }\r\n    function cos_(x) {\r\n        var $x = convertToTensor(x, 'x', 'cos');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return $x.toFloat().sin().neg().mulStrict(dy); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.cos($x); }, { $x: $x }, grad);\r\n    }\r\n    function tan_(x) {\r\n        var $x = convertToTensor(x, 'x', 'tan');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.divStrict($x.cos().square()); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.tan($x); }, { $x: $x }, grad);\r\n    }\r\n    function asin_(x) {\r\n        var $x = convertToTensor(x, 'x', 'asin');\r\n        var grad = function (dy) {\r\n            return {\r\n                $x: function () { return dy.divStrict(scalar(1).sub($x.toFloat().square()).sqrt()); }\r\n            };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.asin($x); }, { $x: $x }, grad);\r\n    }\r\n    function acos_(x) {\r\n        var $x = convertToTensor(x, 'x', 'acos');\r\n        var grad = function (dy) {\r\n            return {\r\n                $x: function () {\r\n                    return dy.divStrict(scalar(1).sub($x.toFloat().square()).sqrt()).neg();\r\n                }\r\n            };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.acos($x); }, { $x: $x }, grad);\r\n    }\r\n    function atan_(x) {\r\n        var $x = convertToTensor(x, 'x', 'atan');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.div($x.toFloat().square().add(1)); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.atan($x); }, { $x: $x }, grad);\r\n    }\r\n    function sinh_(x) {\r\n        var $x = convertToTensor(x, 'x', 'sinh');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return $x.toFloat().cosh().mulStrict(dy); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.sinh($x); }, { $x: $x }, grad);\r\n    }\r\n    function cosh_(x) {\r\n        var $x = convertToTensor(x, 'x', 'cosh');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return $x.toFloat().sinh().mulStrict(dy); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.cosh($x); }, { $x: $x }, grad);\r\n    }\r\n    function tanh_(x) {\r\n        var $x = convertToTensor(x, 'x', 'tanh');\r\n        var grad = function (dy, saved) {\r\n            var y = saved[0];\r\n            return { $x: function () { return scalar(1).sub(y.square()).mulStrict(dy); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend, save) { return save(backend.tanh($x)); }, { $x: $x }, grad);\r\n    }\r\n    function asinh_(x) {\r\n        var $x = convertToTensor(x, 'x', 'asinh');\r\n        var grad = function (dy) {\r\n            return {\r\n                $x: function () { return dy.divStrict(scalar(1).add($x.toFloat().square()).sqrt()); }\r\n            };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.asinh($x); }, { $x: $x }, grad);\r\n    }\r\n    function acosh_(x) {\r\n        var $x = convertToTensor(x, 'x', 'acosh');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.divStrict($x.toFloat().square().sub(1).sqrt()); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.acosh($x); }, { $x: $x }, grad);\r\n    }\r\n    function atanh_(x) {\r\n        var $x = convertToTensor(x, 'x', 'atanh');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.div(scalar(1).sub($x.toFloat().square())); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.atanh($x); }, { $x: $x }, grad);\r\n    }\r\n    function erf_(x) {\r\n        var $x = convertToTensor(x, 'x', 'erf');\r\n        assert($x.dtype === 'int32' || $x.dtype === 'float32', 'Input dtype must be `int32` or `float32`.');\r\n        if ($x.dtype === 'int32') {\r\n            $x = $x.toFloat();\r\n        }\r\n        var grad = function (dy) {\r\n            return {\r\n                $x: function () { return dy.mul($x.square().neg().exp().mul(2 / Math.sqrt(Math.PI))); }\r\n            };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.erf($x); }, { $x: $x }, grad);\r\n    }\r\n    function step_(x, alpha) {\r\n        if (alpha === void 0) { alpha = 0.0; }\r\n        var $x = convertToTensor(x, 'x', 'step');\r\n        var grad = function (dy) {\r\n            return { $x: function () { return zerosLike(dy); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.step($x, alpha); }, { $x: $x }, grad);\r\n    }\r\n    var abs = op({ abs_: abs_ });\r\n    var acos = op({ acos_: acos_ });\r\n    var acosh = op({ acosh_: acosh_ });\r\n    var asin = op({ asin_: asin_ });\r\n    var asinh = op({ asinh_: asinh_ });\r\n    var atan = op({ atan_: atan_ });\r\n    var atanh = op({ atanh_: atanh_ });\r\n    var ceil = op({ ceil_: ceil_ });\r\n    var clipByValue = op({ clipByValue_: clipByValue_ });\r\n    var cos = op({ cos_: cos_ });\r\n    var cosh = op({ cosh_: cosh_ });\r\n    var erf = op({ erf_: erf_ });\r\n    var exp = op({ exp_: exp_ });\r\n    var expm1 = op({ expm1_: expm1_ });\r\n    var floor = op({ floor_: floor_ });\r\n    var log$1 = op({ log_: log_ });\r\n    var log1p = op({ log1p_: log1p_ });\r\n    var logSigmoid = op({ logSigmoid_: logSigmoid_ });\r\n    var neg = op({ neg_: neg_ });\r\n    var reciprocal = op({ reciprocal_: reciprocal_ });\r\n    var round = op({ round_: round_ });\r\n    var rsqrt = op({ rsqrt_: rsqrt_ });\r\n    var sigmoid = op({ sigmoid_: sigmoid_ });\r\n    var sign = op({ sign_: sign_ });\r\n    var sin = op({ sin_: sin_ });\r\n    var sinh = op({ sinh_: sinh_ });\r\n    var softplus = op({ softplus_: softplus_ });\r\n    var sqrt = op({ sqrt_: sqrt_ });\r\n    var square = op({ square_: square_ });\r\n    var step = op({ step_: step_ });\r\n    var tan = op({ tan_: tan_ });\r\n    var tanh$1 = op({ tanh_: tanh_ });\n\n    function batchNormalization2d_(x, mean, variance, varianceEpsilon, scale, offset) {\r\n        if (varianceEpsilon === void 0) { varianceEpsilon = .001; }\r\n        var $x = convertToTensor(x, 'x', 'batchNormalization');\r\n        var $mean = convertToTensor(mean, 'mean', 'batchNormalization');\r\n        var $variance = convertToTensor(variance, 'variance', 'batchNormalization');\r\n        var $scale;\r\n        if (scale != null) {\r\n            $scale = convertToTensor(scale, 'scale', 'batchNormalization');\r\n        }\r\n        var $offset;\r\n        if (offset != null) {\r\n            $offset = convertToTensor(offset, 'offset', 'batchNormalization');\r\n        }\r\n        assert($x.rank === 2, \"Error in batchNormalization3D: x must be rank 3 but got rank \" +\r\n            ($x.rank + \".\"));\r\n        assert($mean.rank === 2 || $mean.rank === 1, \"Error in batchNormalization2D: mean must be rank 2 or rank 1 but \" +\r\n            (\"got rank \" + $mean.rank + \".\"));\r\n        assert($variance.rank === 2 || $variance.rank === 1, \"Error in batchNormalization2D: variance must be rank 2 or rank 1 \" +\r\n            (\"but got rank \" + $variance.rank + \".\"));\r\n        if ($scale != null) {\r\n            assert($scale.rank === 2 || $scale.rank === 1, \"Error in batchNormalization2D: scale must be rank 2 or rank 1 \" +\r\n                (\"but got rank \" + $scale.rank + \".\"));\r\n        }\r\n        if ($offset != null) {\r\n            assert($offset.rank === 2 || $offset.rank === 1, \"Error in batchNormalization2D: offset must be rank 2 or rank 1 \" +\r\n                (\"but got rank \" + $offset.rank + \".\"));\r\n        }\r\n        return batchNormalization($x, $mean, $variance, varianceEpsilon, $scale, $offset);\r\n    }\r\n    function batchNormalization3d_(x, mean, variance, varianceEpsilon, scale, offset) {\r\n        if (varianceEpsilon === void 0) { varianceEpsilon = .001; }\r\n        var $x = convertToTensor(x, 'x', 'batchNormalization');\r\n        var $mean = convertToTensor(mean, 'mean', 'batchNormalization');\r\n        var $variance = convertToTensor(variance, 'variance', 'batchNormalization');\r\n        var $scale;\r\n        if (scale != null) {\r\n            $scale = convertToTensor(scale, 'scale', 'batchNormalization');\r\n        }\r\n        var $offset;\r\n        if (offset != null) {\r\n            $offset = convertToTensor(offset, 'offset', 'batchNormalization');\r\n        }\r\n        assert($x.rank === 3, \"Error in batchNormalization3D: x must be rank 3 but got rank \" +\r\n            ($x.rank + \".\"));\r\n        assert($mean.rank === 3 || $mean.rank === 1, \"Error in batchNormalization3D: mean must be rank 3 or rank 1 but \" +\r\n            (\"got rank \" + $mean.rank + \".\"));\r\n        assert($variance.rank === 3 || $variance.rank === 1, \"Error in batchNormalization3D: variance must be rank 3 or rank 1 \" +\r\n            (\"but got rank \" + $variance.rank + \".\"));\r\n        if ($scale != null) {\r\n            assert($scale.rank === 3 || $scale.rank === 1, \"Error in batchNormalization3D: scale must be rank 3 or rank 1 \" +\r\n                (\"but got rank \" + $scale.rank + \".\"));\r\n        }\r\n        if ($offset != null) {\r\n            assert($offset.rank === 3 || $offset.rank === 1, \"Error in batchNormalization3D: offset must be rank 3 or rank 1 \" +\r\n                (\"but got rank \" + $offset.rank + \".\"));\r\n        }\r\n        return batchNormalization($x, $mean, $variance, varianceEpsilon, $scale, $offset);\r\n    }\r\n    function batchNormalization4d_(x, mean, variance, varianceEpsilon, scale, offset) {\r\n        if (varianceEpsilon === void 0) { varianceEpsilon = .001; }\r\n        var $x = convertToTensor(x, 'x', 'batchNormalization');\r\n        var $mean = convertToTensor(mean, 'mean', 'batchNormalization');\r\n        var $variance = convertToTensor(variance, 'variance', 'batchNormalization');\r\n        var $scale;\r\n        if (scale != null) {\r\n            $scale = convertToTensor(scale, 'scale', 'batchNormalization');\r\n        }\r\n        var $offset;\r\n        if (offset != null) {\r\n            $offset = convertToTensor(offset, 'offset', 'batchNormalization');\r\n        }\r\n        assert($x.rank === 4, \"Error in batchNormalization4D: x must be rank 4 but got rank \" +\r\n            ($x.rank + \".\"));\r\n        assert($mean.rank === 4 || $mean.rank === 1, \"Error in batchNormalization4D: mean must be rank 4 or rank 1 but \" +\r\n            (\"got rank \" + $mean.rank + \".\"));\r\n        assert($variance.rank === 4 || $variance.rank === 1, \"Error in batchNormalization4D: variance must be rank 4 or rank 1 \" +\r\n            (\"but got rank \" + $variance.rank + \".\"));\r\n        if ($scale != null) {\r\n            assert($scale.rank === 4 || $scale.rank === 1, \"Error in batchNormalization4D: scale must be rank 4 or rank 1 \" +\r\n                (\"but got rank \" + $scale.rank + \".\"));\r\n        }\r\n        if ($offset != null) {\r\n            assert($offset.rank === 4 || $offset.rank === 1, \"Error in batchNormalization4D: offset must be rank 4 or rank 1 \" +\r\n                (\"but got rank \" + $offset.rank + \".\"));\r\n        }\r\n        return batchNormalization($x, $mean, $variance, varianceEpsilon, $scale, $offset);\r\n    }\r\n    function batchNormalization_(x, mean, variance, varianceEpsilon, scale, offset) {\r\n        if (varianceEpsilon === void 0) { varianceEpsilon = .001; }\r\n        var $x = convertToTensor(x, 'x', 'batchNormalization');\r\n        var $mean = convertToTensor(mean, 'mean', 'batchNormalization');\r\n        var $variance = convertToTensor(variance, 'variance', 'batchNormalization');\r\n        var $scale;\r\n        if (scale != null) {\r\n            $scale = convertToTensor(scale, 'scale', 'batchNormalization');\r\n        }\r\n        var $offset;\r\n        if (offset != null) {\r\n            $offset = convertToTensor(offset, 'offset', 'batchNormalization');\r\n        }\r\n        assert($mean.rank === $variance.rank, 'Batch normalization gradient requires mean and variance to have ' +\r\n            'equal ranks.');\r\n        assert($offset == null || $mean.rank === $offset.rank, 'Batch normalization gradient requires mean and offset to have ' +\r\n            'equal ranks.');\r\n        assert($scale == null || $mean.rank === $scale.rank, 'Batch normalization gradient requires mean and scale to have ' +\r\n            'equal ranks.');\r\n        var x4D;\r\n        if ($x.rank === 0 || $x.rank === 1) {\r\n            x4D = $x.as4D(1, 1, 1, $x.size);\r\n        }\r\n        else if ($x.rank === 2) {\r\n            x4D = $x.as4D(1, 1, $x.shape[0], $x.shape[1]);\r\n        }\r\n        else if ($x.rank === 3) {\r\n            x4D = $x.as4D(1, $x.shape[0], $x.shape[1], $x.shape[2]);\r\n        }\r\n        else {\r\n            x4D = $x;\r\n        }\r\n        var der = function (dy) {\r\n            var scaleValue = $scale == null ? scalar(1) : $scale;\r\n            var reductionAxes = getReductionAxes($mean.shape, x4D.shape);\r\n            var tileShape = [];\r\n            if ($mean.rank === 1) {\r\n                for (var i = 0; i < x4D.shape.length - 1; ++i) {\r\n                    tileShape.push(x4D.shape[i]);\r\n                }\r\n                tileShape.push(1);\r\n            }\r\n            var xMinusMean = $x.sub($mean);\r\n            var dyTimesScaleValue = dy.mul(scaleValue);\r\n            var oneOverSqrtVariance = rsqrt($variance.add(scalar(varianceEpsilon)));\r\n            var minusHalfRCube = oneOverSqrtVariance.mul(oneOverSqrtVariance)\r\n                .mul(oneOverSqrtVariance)\r\n                .mul(scalar(-0.5));\r\n            var derX = function () {\r\n                if ($mean.rank === 1) {\r\n                    return dy\r\n                        .mul(tile(oneOverSqrtVariance.as4D(1, 1, 1, $mean.shape[0]), tileShape))\r\n                        .mul(scaleValue)\r\n                        .reshape($x.shape);\r\n                }\r\n                else {\r\n                    return dy.mul(oneOverSqrtVariance).mul(scaleValue).reshape($x.shape);\r\n                }\r\n            };\r\n            var derMean = function () {\r\n                var meanDer = oneOverSqrtVariance.mul(scalar(-1)).mul(dyTimesScaleValue);\r\n                if ($mean.rank === 1) {\r\n                    meanDer = meanDer.sum(reductionAxes);\r\n                }\r\n                return meanDer.reshape($mean.shape);\r\n            };\r\n            var derVariance = function () {\r\n                var varianceDer = minusHalfRCube.mul(xMinusMean).mul(dyTimesScaleValue);\r\n                if ($mean.rank === 1) {\r\n                    varianceDer = varianceDer.sum(reductionAxes);\r\n                }\r\n                return varianceDer.reshape($mean.shape);\r\n            };\r\n            var derScale = function () {\r\n                var xMinusMean2TimesRsqrt = xMinusMean.mul(oneOverSqrtVariance);\r\n                var scaleDer = dy.mul(xMinusMean2TimesRsqrt);\r\n                if ($mean.rank === 1) {\r\n                    scaleDer = scaleDer.sum(reductionAxes);\r\n                }\r\n                return scaleDer.reshape($mean.shape);\r\n            };\r\n            var derOffset = function () {\r\n                var offsetDer = dy;\r\n                if ($mean.rank === 1) {\r\n                    offsetDer = offsetDer.sum(reductionAxes);\r\n                }\r\n                return offsetDer.reshape($mean.shape);\r\n            };\r\n            return {\r\n                $x: derX,\r\n                $mean: derMean,\r\n                $variance: derVariance,\r\n                $scale: derScale,\r\n                $offset: derOffset\r\n            };\r\n        };\r\n        var res = ENV.engine.runKernel(function (backend) { return backend.batchNormalization(x4D, batchnormReshape4D($mean), batchnormReshape4D($variance), varianceEpsilon, batchnormReshape4D($scale), batchnormReshape4D($offset)); }, { $x: $x, $mean: $mean, $variance: $variance, $scale: $scale, $offset: $offset }, der);\r\n        return res.reshape($x.shape);\r\n    }\r\n    function batchnormReshape4D(x) {\r\n        if (x == null) {\r\n            return null;\r\n        }\r\n        if (x.rank === 0) {\r\n            return x.as1D();\r\n        }\r\n        else if (x.rank === 1) {\r\n            return x;\r\n        }\r\n        else if (x.rank === 2) {\r\n            return x.as4D(1, 1, x.shape[0], x.shape[1]);\r\n        }\r\n        else if (x.rank === 3) {\r\n            return x.as4D(1, x.shape[0], x.shape[1], x.shape[2]);\r\n        }\r\n        return x;\r\n    }\r\n    var batchNormalization2d = op({ batchNormalization2d_: batchNormalization2d_ });\r\n    var batchNormalization3d = op({ batchNormalization3d_: batchNormalization3d_ });\r\n    var batchNormalization4d = op({ batchNormalization4d_: batchNormalization4d_ });\r\n    var batchNormalization = op({ batchNormalization_: batchNormalization_ });\n\n    function computePool2DInfo(inShape, filterSize, strides, dilations, pad, roundingMode, dataFormat) {\r\n        if (dataFormat === void 0) { dataFormat = 'channelsLast'; }\r\n        var _a = parseTupleParam(filterSize), filterHeight = _a[0], filterWidth = _a[1];\r\n        var filterShape;\r\n        if (dataFormat === 'channelsLast') {\r\n            filterShape = [filterHeight, filterWidth, inShape[3], inShape[3]];\r\n        }\r\n        else if (dataFormat === 'channelsFirst') {\r\n            filterShape = [filterHeight, filterWidth, inShape[1], inShape[1]];\r\n        }\r\n        else {\r\n            throw new Error(\"Unknown dataFormat \" + dataFormat);\r\n        }\r\n        return computeConv2DInfo(inShape, filterShape, strides, dilations, pad, roundingMode, false, dataFormat);\r\n    }\r\n    function computeConv2DInfo(inShape, filterShape, strides, dilations, pad, roundingMode, depthwise, dataFormat) {\r\n        if (depthwise === void 0) { depthwise = false; }\r\n        if (dataFormat === void 0) { dataFormat = 'channelsLast'; }\r\n        var _a = [-1, -1, -1, -1], batchSize = _a[0], inHeight = _a[1], inWidth = _a[2], inChannels = _a[3];\r\n        if (dataFormat === 'channelsLast') {\r\n            batchSize = inShape[0], inHeight = inShape[1], inWidth = inShape[2], inChannels = inShape[3];\r\n        }\r\n        else if (dataFormat === 'channelsFirst') {\r\n            batchSize = inShape[0], inChannels = inShape[1], inHeight = inShape[2], inWidth = inShape[3];\r\n        }\r\n        else {\r\n            throw new Error(\"Unknown dataFormat \" + dataFormat);\r\n        }\r\n        var filterHeight = filterShape[0], filterWidth = filterShape[1], filterChannels = filterShape[3];\r\n        var _b = parseTupleParam(strides), strideHeight = _b[0], strideWidth = _b[1];\r\n        var _c = parseTupleParam(dilations), dilationHeight = _c[0], dilationWidth = _c[1];\r\n        var effectiveFilterHeight = getEffectiveFilterSize(filterHeight, dilationHeight);\r\n        var effectiveFilterWidth = getEffectiveFilterSize(filterWidth, dilationWidth);\r\n        var _d = getPadAndOutInfo(pad, inHeight, inWidth, strideHeight, strideWidth, effectiveFilterHeight, effectiveFilterWidth, roundingMode), padInfo = _d.padInfo, outHeight = _d.outHeight, outWidth = _d.outWidth;\r\n        var outChannels = depthwise ? filterChannels * inChannels : filterChannels;\r\n        var outShape;\r\n        if (dataFormat === 'channelsFirst') {\r\n            outShape = [batchSize, outChannels, outHeight, outWidth];\r\n        }\r\n        else if (dataFormat === 'channelsLast') {\r\n            outShape = [batchSize, outHeight, outWidth, outChannels];\r\n        }\r\n        return {\r\n            batchSize: batchSize,\r\n            dataFormat: dataFormat,\r\n            inHeight: inHeight,\r\n            inWidth: inWidth,\r\n            inChannels: inChannels,\r\n            outHeight: outHeight,\r\n            outWidth: outWidth,\r\n            outChannels: outChannels,\r\n            padInfo: padInfo,\r\n            strideHeight: strideHeight,\r\n            strideWidth: strideWidth,\r\n            filterHeight: filterHeight,\r\n            filterWidth: filterWidth,\r\n            effectiveFilterHeight: effectiveFilterHeight,\r\n            effectiveFilterWidth: effectiveFilterWidth,\r\n            dilationHeight: dilationHeight,\r\n            dilationWidth: dilationWidth,\r\n            inShape: inShape,\r\n            outShape: outShape,\r\n            filterShape: filterShape\r\n        };\r\n    }\r\n    function computeConv3DInfo(inShape, filterShape, strides, dilations, pad, depthwise, dataFormat) {\r\n        if (depthwise === void 0) { depthwise = false; }\r\n        if (dataFormat === void 0) { dataFormat = 'channelsLast'; }\r\n        var _a = [-1, -1, -1, -1, -1], batchSize = _a[0], inDepth = _a[1], inHeight = _a[2], inWidth = _a[3], inChannels = _a[4];\r\n        if (dataFormat === 'channelsLast') {\r\n            batchSize = inShape[0], inDepth = inShape[1], inHeight = inShape[2], inWidth = inShape[3], inChannels = inShape[4];\r\n        }\r\n        else if (dataFormat === 'channelsFirst') {\r\n            batchSize = inShape[0], inChannels = inShape[1], inDepth = inShape[2], inHeight = inShape[3], inWidth = inShape[4];\r\n        }\r\n        else {\r\n            throw new Error(\"Unknown dataFormat \" + dataFormat);\r\n        }\r\n        var filterDepth = filterShape[0], filterHeight = filterShape[1], filterWidth = filterShape[2], filterChannels = filterShape[4];\r\n        var _b = parse3TupleParam(strides), strideDepth = _b[0], strideHeight = _b[1], strideWidth = _b[2];\r\n        var _c = parse3TupleParam(dilations), dilationDepth = _c[0], dilationHeight = _c[1], dilationWidth = _c[2];\r\n        var effectiveFilterDepth = getEffectiveFilterSize(filterDepth, dilationDepth);\r\n        var effectiveFilterHeight = getEffectiveFilterSize(filterHeight, dilationHeight);\r\n        var effectiveFilterWidth = getEffectiveFilterSize(filterWidth, dilationWidth);\r\n        var _d = get3DPadAndOutInfo(pad, inDepth, inHeight, inWidth, strideDepth, strideHeight, strideWidth, effectiveFilterDepth, effectiveFilterHeight, effectiveFilterWidth), padInfo = _d.padInfo, outDepth = _d.outDepth, outHeight = _d.outHeight, outWidth = _d.outWidth;\r\n        var outChannels = depthwise ? filterChannels * inChannels : filterChannels;\r\n        var outShape;\r\n        if (dataFormat === 'channelsFirst') {\r\n            outShape = [batchSize, outChannels, outDepth, outHeight, outWidth];\r\n        }\r\n        else if (dataFormat === 'channelsLast') {\r\n            outShape = [batchSize, outDepth, outHeight, outWidth, outChannels];\r\n        }\r\n        return {\r\n            batchSize: batchSize,\r\n            dataFormat: dataFormat,\r\n            inDepth: inDepth,\r\n            inHeight: inHeight,\r\n            inWidth: inWidth,\r\n            inChannels: inChannels,\r\n            outDepth: outDepth,\r\n            outHeight: outHeight,\r\n            outWidth: outWidth,\r\n            outChannels: outChannels,\r\n            padInfo: padInfo,\r\n            strideDepth: strideDepth,\r\n            strideHeight: strideHeight,\r\n            strideWidth: strideWidth,\r\n            filterDepth: filterDepth,\r\n            filterHeight: filterHeight,\r\n            filterWidth: filterWidth,\r\n            dilationDepth: dilationDepth,\r\n            dilationHeight: dilationHeight,\r\n            dilationWidth: dilationWidth,\r\n            inShape: inShape,\r\n            outShape: outShape,\r\n            filterShape: filterShape\r\n        };\r\n    }\r\n    function computeOutputShape3D(inShape, fieldSize, outDepth, stride, zeroPad, roundingMode) {\r\n        if (zeroPad == null) {\r\n            zeroPad = computeDefaultPad(inShape, fieldSize, stride);\r\n        }\r\n        var inputRows = inShape[0];\r\n        var inputCols = inShape[1];\r\n        var outputRows = conditionalRound((inputRows - fieldSize + 2 * zeroPad) / stride + 1, roundingMode);\r\n        assert(isInt(outputRows), \"The output # of rows (\" + outputRows + \") must be an integer. Change the \" +\r\n            \"stride and/or zero pad parameters\");\r\n        var outputCols = conditionalRound((inputCols - fieldSize + 2 * zeroPad) / stride + 1, roundingMode);\r\n        assert(isInt(outputCols), \"The output # of columns (\" + outputCols + \") must be an integer. Change \" +\r\n            \"the stride and/or zero pad parameters\");\r\n        return [outputRows, outputCols, outDepth];\r\n    }\r\n    function computeDefaultPad(inputShape, fieldSize, stride, dilation) {\r\n        if (dilation === void 0) { dilation = 1; }\r\n        var effectiveFieldSize = getEffectiveFilterSize(fieldSize, dilation);\r\n        return Math.floor((inputShape[0] * (stride - 1) - stride + effectiveFieldSize) / 2);\r\n    }\r\n    function parseTupleParam(param) {\r\n        return typeof param === 'number' ? [param, param] : param;\r\n    }\r\n    function parse3TupleParam(param) {\r\n        return typeof param === 'number' ? [param, param, param] : param;\r\n    }\r\n    function getEffectiveFilterSize(filterSize, dilation) {\r\n        if (dilation <= 1) {\r\n            return filterSize;\r\n        }\r\n        return filterSize + (filterSize - 1) * (dilation - 1);\r\n    }\r\n    function getPadAndOutInfo(pad, inHeight, inWidth, strideHeight, strideWidth, filterHeight, filterWidth, roundingMode) {\r\n        var padInfo;\r\n        var outHeight;\r\n        var outWidth;\r\n        if (typeof pad === 'number') {\r\n            var padType = (pad === 0) ? 'VALID' : 'NUMBER';\r\n            padInfo = { top: pad, bottom: pad, left: pad, right: pad, type: padType };\r\n            var outShape = computeOutputShape3D([inHeight, inWidth, 1], filterHeight, 1, strideHeight, pad, roundingMode);\r\n            outHeight = outShape[0];\r\n            outWidth = outShape[1];\r\n        }\r\n        else if (pad === 'same') {\r\n            outHeight = Math.ceil(inHeight / strideHeight);\r\n            outWidth = Math.ceil(inWidth / strideWidth);\r\n            var padAlongHeight = (outHeight - 1) * strideHeight + filterHeight - inHeight;\r\n            var padAlongWidth = (outWidth - 1) * strideWidth + filterWidth - inWidth;\r\n            var top_1 = Math.floor(padAlongHeight / 2);\r\n            var bottom = padAlongHeight - top_1;\r\n            var left = Math.floor(padAlongWidth / 2);\r\n            var right = padAlongWidth - left;\r\n            padInfo = { top: top_1, bottom: bottom, left: left, right: right, type: 'SAME' };\r\n        }\r\n        else if (pad === 'valid') {\r\n            padInfo = { top: 0, bottom: 0, left: 0, right: 0, type: 'VALID' };\r\n            outHeight = Math.ceil((inHeight - filterHeight + 1) / strideHeight);\r\n            outWidth = Math.ceil((inWidth - filterWidth + 1) / strideWidth);\r\n        }\r\n        else {\r\n            throw Error(\"Unknown padding parameter: \" + pad);\r\n        }\r\n        return { padInfo: padInfo, outHeight: outHeight, outWidth: outWidth };\r\n    }\r\n    function get3DPadAndOutInfo(pad, inDepth, inHeight, inWidth, strideDepth, strideHeight, strideWidth, filterDepth, filterHeight, filterWidth) {\r\n        var padInfo;\r\n        var outDepth;\r\n        var outHeight;\r\n        var outWidth;\r\n        if (pad === 'same') {\r\n            outDepth = Math.ceil(inDepth / strideDepth);\r\n            outHeight = Math.ceil(inHeight / strideHeight);\r\n            outWidth = Math.ceil(inWidth / strideWidth);\r\n            var padAlongDepth = (outDepth - 1) * strideDepth + filterDepth - inDepth;\r\n            var padAlongHeight = (outHeight - 1) * strideHeight + filterHeight - inHeight;\r\n            var padAlongWidth = (outWidth - 1) * strideWidth + filterWidth - inWidth;\r\n            var front = Math.floor(padAlongDepth / 2);\r\n            var back = padAlongDepth - front;\r\n            var top_2 = Math.floor(padAlongHeight / 2);\r\n            var bottom = padAlongHeight - top_2;\r\n            var left = Math.floor(padAlongWidth / 2);\r\n            var right = padAlongWidth - left;\r\n            padInfo = { top: top_2, bottom: bottom, left: left, right: right, front: front, back: back, type: 'SAME' };\r\n        }\r\n        else if (pad === 'valid') {\r\n            padInfo = {\r\n                top: 0,\r\n                bottom: 0,\r\n                left: 0,\r\n                right: 0,\r\n                front: 0,\r\n                back: 0,\r\n                type: 'VALID'\r\n            };\r\n            outDepth = Math.ceil((inDepth - filterDepth + 1) / strideDepth);\r\n            outHeight = Math.ceil((inHeight - filterHeight + 1) / strideHeight);\r\n            outWidth = Math.ceil((inWidth - filterWidth + 1) / strideWidth);\r\n        }\r\n        else {\r\n            throw Error(\"Unknown padding parameter: \" + pad);\r\n        }\r\n        return { padInfo: padInfo, outDepth: outDepth, outHeight: outHeight, outWidth: outWidth };\r\n    }\r\n    function conditionalRound(value, roundingMode) {\r\n        if (!roundingMode) {\r\n            return value;\r\n        }\r\n        switch (roundingMode) {\r\n            case 'round':\r\n                return Math.round(value);\r\n            case 'ceil':\r\n                return Math.ceil(value);\r\n            case 'floor':\r\n                return Math.floor(value);\r\n            default:\r\n                throw new Error(\"Unknown roundingMode \" + roundingMode);\r\n        }\r\n    }\r\n    function tupleValuesAreOne(param) {\r\n        var _a = parseTupleParam(param), dimA = _a[0], dimB = _a[1];\r\n        return dimA === 1 && dimB === 1;\r\n    }\r\n    function eitherStridesOrDilationsAreOne(strides, dilations) {\r\n        return tupleValuesAreOne(strides) || tupleValuesAreOne(dilations);\r\n    }\n\n    function conv1d_(x, filter, stride, pad, dataFormat, dilation, dimRoundingMode) {\r\n        if (dataFormat === void 0) { dataFormat = 'NWC'; }\r\n        if (dilation === void 0) { dilation = 1; }\r\n        var $x = convertToTensor(x, 'x', 'conv1d');\r\n        var $filter = convertToTensor(filter, 'filter', 'conv1d');\r\n        var x3D = $x;\r\n        var reshapedTo3D = false;\r\n        if ($x.rank === 2) {\r\n            reshapedTo3D = true;\r\n            x3D = $x.as3D(1, $x.shape[0], $x.shape[1]);\r\n        }\r\n        assert(x3D.rank === 3, \"Error in conv1d: input must be rank 3, but got rank \" + x3D.rank + \".\");\r\n        assert($filter.rank === 3, \"Error in conv1d: filter must be rank 3, but got rank \" +\r\n            ($filter.rank + \".\"));\r\n        if (dimRoundingMode != null) {\r\n            assert(isInt(pad), \"Error in conv1d: pad must be an integer when using, \" +\r\n                (\"dimRoundingMode \" + dimRoundingMode + \" but got pad \" + pad + \".\"));\r\n        }\r\n        assert(x3D.shape[2] === $filter.shape[1], \"Error in conv1d: depth of input (\" + x3D.shape[2] + \") must match \" +\r\n            (\"input depth for filter \" + $filter.shape[1] + \".\"));\r\n        assert(eitherStridesOrDilationsAreOne(stride, dilation), 'Error in conv1D: Either stride or dilation must be 1. ' +\r\n            (\"Got stride \" + stride + \" and dilation '\" + dilation + \"'\"));\r\n        assert(dataFormat === 'NWC', \"Error in conv1d: got dataFormat of \" + dataFormat + \" but only NWC is currently supported.\");\r\n        var filter4D = $filter.as4D(1, $filter.shape[0], $filter.shape[1], $filter.shape[2]);\r\n        var input4D = x3D.as4D(x3D.shape[0], 1, x3D.shape[1], x3D.shape[2]);\r\n        var strides = [1, stride];\r\n        var dilations = [1, dilation];\r\n        var conv2dDataFormat = 'NHWC';\r\n        var res = conv2d(input4D, filter4D, strides, pad, conv2dDataFormat, dilations, dimRoundingMode);\r\n        if (reshapedTo3D) {\r\n            return res.as2D(res.shape[2], res.shape[3]);\r\n        }\r\n        return res.as3D(res.shape[0], res.shape[2], res.shape[3]);\r\n    }\r\n    function conv2d_(x, filter, strides, pad, dataFormat, dilations, dimRoundingMode) {\r\n        if (dataFormat === void 0) { dataFormat = 'NHWC'; }\r\n        if (dilations === void 0) { dilations = [1, 1]; }\r\n        var $x = convertToTensor(x, 'x', 'conv2d');\r\n        var $filter = convertToTensor(filter, 'filter', 'conv2d');\r\n        var x4D = $x;\r\n        var reshapedTo4D = false;\r\n        if ($x.rank === 3) {\r\n            reshapedTo4D = true;\r\n            x4D = $x.as4D(1, $x.shape[0], $x.shape[1], $x.shape[2]);\r\n        }\r\n        assert(x4D.rank === 4, \"Error in conv2d: input must be rank 4, but got rank \" + x4D.rank + \".\");\r\n        assert($filter.rank === 4, \"Error in conv2d: filter must be rank 4, but got rank \" +\r\n            ($filter.rank + \".\"));\r\n        if (dimRoundingMode != null) {\r\n            assert(isInt(pad), \"Error in conv2d: pad must be an integer when using, \" +\r\n                (\"dimRoundingMode \" + dimRoundingMode + \" but got pad \" + pad + \".\"));\r\n        }\r\n        assert(x4D.shape[3] === $filter.shape[2], \"Error in conv2d: depth of input (\" + x4D.shape[3] + \") must match \" +\r\n            (\"input depth for filter \" + $filter.shape[2] + \".\"));\r\n        assert(eitherStridesOrDilationsAreOne(strides, dilations), 'Error in conv2D: Either strides or dilations must be 1. ' +\r\n            (\"Got strides \" + strides + \" and dilations '\" + dilations + \"'\"));\r\n        assert(dataFormat === 'NHWC', \"Error in conv2d: got dataFormat of \" + dataFormat + \" but only NHWC is currently supported.\");\r\n        var convInfo = computeConv2DInfo(x4D.shape, $filter.shape, strides, dilations, pad, dimRoundingMode);\r\n        var grad = function (dy) {\r\n            assert(tupleValuesAreOne(dilations), 'Error in gradient of conv2D: dilation rates greater than 1 are not' +\r\n                (\"yet supported in gradients. Got dilations '\" + dilations + \"'\"));\r\n            return {\r\n                x: function () { return conv2dDerInput_(x4D.shape, dy, $filter, strides, pad); },\r\n                $filter: function () { return conv2dDerFilter_(x4D, dy, $filter.shape, strides, pad); }\r\n            };\r\n        };\r\n        var res = ENV.engine.runKernel(function (backend) { return backend.conv2d(x4D, $filter, convInfo); }, { x: x4D, $filter: $filter }, grad);\r\n        if (reshapedTo4D) {\r\n            return res.as3D(res.shape[1], res.shape[2], res.shape[3]);\r\n        }\r\n        return res;\r\n    }\r\n    function conv2dDerInput_(xShape, dy, filter, strides, pad, dimRoundingMode) {\r\n        assert(xShape.length === dy.rank, \"Length of inShape \" +\r\n            (\"(\" + xShape.length + \") and rank of dy (\" + dy.rank + \") must match\"));\r\n        var xShape4D = xShape;\r\n        var dy4D = dy;\r\n        var reshapedTo4D = false;\r\n        if (dy.rank === 3) {\r\n            reshapedTo4D = true;\r\n            dy4D = dy.as4D(1, dy.shape[0], dy.shape[1], dy.shape[2]);\r\n            xShape4D = [1, xShape[0], xShape[1], xShape[2]];\r\n        }\r\n        var inDepth = xShape4D[3];\r\n        var outDepth = dy4D.shape[3];\r\n        assert(xShape4D.length === 4, \"Error in conv2dDerInput: inShape must be length 4, but got length \" +\r\n            (xShape4D.length + \".\"));\r\n        assert(dy4D.rank === 4, \"Error in conv2dDerInput: dy must be rank 4, but got \" +\r\n            (\"rank \" + dy4D.rank));\r\n        assert(filter.rank === 4, \"Error in conv2dDerInput: filter must be rank 4, but got \" +\r\n            (\"rank \" + filter.rank));\r\n        assert(inDepth === filter.shape[2], \"Error in conv2dDerInput: depth of input (\" + inDepth + \") must \" +\r\n            (\"match input depth for filter \" + filter.shape[2] + \".\"));\r\n        assert(outDepth === filter.shape[3], \"Error in conv2dDerInput: depth of output (\" + outDepth + \") must \" +\r\n            (\"match output depth for filter \" + filter.shape[3] + \".\"));\r\n        if (dimRoundingMode != null) {\r\n            assert(isInt(pad), \"Error in conv2dDerInput: pad must be an integer when using, \" +\r\n                (\"dimRoundingMode \" + dimRoundingMode + \" but got pad \" + pad + \".\"));\r\n        }\r\n        var dilations = 1;\r\n        var grad = function (ddx) {\r\n            var dataFormat = 'NHWC';\r\n            return {\r\n                dy4D: function () { return conv2d(ddx, filter, strides, pad, dataFormat, dilations, dimRoundingMode); },\r\n                filter: function () { return conv2dDerFilter(ddx, dy4D, filter.shape, strides, pad, dimRoundingMode); }\r\n            };\r\n        };\r\n        var convInfo = computeConv2DInfo(xShape4D, filter.shape, strides, dilations, pad, dimRoundingMode);\r\n        var res = ENV.engine.runKernel(function (backend) { return backend.conv2dDerInput(dy4D, filter, convInfo); }, { dy4D: dy4D, filter: filter }, grad);\r\n        if (reshapedTo4D) {\r\n            return res.as3D(res.shape[1], res.shape[2], res.shape[3]);\r\n        }\r\n        return res;\r\n    }\r\n    function conv2dDerFilter_(x, dy, filterShape, strides, pad, dimRoundingMode) {\r\n        var x4D = x;\r\n        if (x.rank === 3) {\r\n            x4D = x.as4D(1, x.shape[0], x.shape[1], x.shape[2]);\r\n        }\r\n        var dy4D = dy;\r\n        if (dy4D.rank === 3) {\r\n            dy4D = dy.as4D(1, dy.shape[0], dy.shape[1], dy.shape[2]);\r\n        }\r\n        assert(x4D.rank === 4, \"Error in conv2dDerFilter: input must be rank 4, but got shape \" +\r\n            (x4D.shape + \".\"));\r\n        assert(dy4D.rank === 4, \"Error in conv2dDerFilter: dy must be rank 4, but got shape \" +\r\n            (dy4D.shape + \".\"));\r\n        assert(filterShape.length === 4, \"Error in conv2dDerFilter: filterShape must be length 4, but got \" +\r\n            (filterShape + \".\"));\r\n        assert(x4D.shape[3] === filterShape[2], \"Error in conv2dDerFilter: depth of input \" + x4D.shape[3] + \") must \" +\r\n            (\"match input depth in filter (\" + filterShape[2] + \".\"));\r\n        assert(dy4D.shape[3] === filterShape[3], \"Error in conv2dDerFilter: depth of dy (\" + dy4D.shape[3] + \") must \" +\r\n            (\"match output depth for filter (\" + filterShape[3] + \").\"));\r\n        if (dimRoundingMode != null) {\r\n            assert(isInt(pad), \"Error in conv2dDerFilter: pad must be an integer when using, \" +\r\n                (\"dimRoundingMode \" + dimRoundingMode + \" but got pad \" + pad + \".\"));\r\n        }\r\n        var dilations = 1;\r\n        var convInfo = computeConv2DInfo(x4D.shape, filterShape, strides, dilations, pad, dimRoundingMode);\r\n        return ENV.engine.runKernel(function (backend) { return backend.conv2dDerFilter(x4D, dy4D, convInfo); }, { x4D: x4D, dy4D: dy4D });\r\n    }\r\n    function conv2dTranspose_(x, filter, outputShape, strides, pad, dimRoundingMode) {\r\n        var $x = convertToTensor(x, 'x', 'conv2dTranspose');\r\n        var $filter = convertToTensor(filter, 'filter', 'conv2dTranspose');\r\n        return conv2dDerInput_(outputShape, $x, $filter, strides, pad, dimRoundingMode);\r\n    }\r\n    function depthwiseConv2d_(x, filter, strides, pad, dataFormat, dilations, dimRoundingMode) {\r\n        if (dataFormat === void 0) { dataFormat = 'NHWC'; }\r\n        if (dilations === void 0) { dilations = [1, 1]; }\r\n        var $x = convertToTensor(x, 'x', 'depthwiseConv2d');\r\n        var $filter = convertToTensor(filter, 'filter', 'depthwiseConv2d');\r\n        var x4D = $x;\r\n        var reshapedTo4D = false;\r\n        if ($x.rank === 3) {\r\n            reshapedTo4D = true;\r\n            x4D = $x.as4D(1, $x.shape[0], $x.shape[1], $x.shape[2]);\r\n        }\r\n        assert(x4D.rank === 4, \"Error in depthwiseConv2d: input must be rank 4, but got \" +\r\n            (\"rank \" + x4D.rank + \".\"));\r\n        assert($filter.rank === 4, \"Error in depthwiseConv2d: filter must be rank 4, but got rank \" +\r\n            ($filter.rank + \".\"));\r\n        assert(x4D.shape[3] === $filter.shape[2], \"Error in depthwiseConv2d: number of input channels \" +\r\n            (\"(\" + x4D.shape[3] + \") must match the inChannels dimension in \") +\r\n            (\"filter \" + $filter.shape[2] + \".\"));\r\n        if (dilations == null) {\r\n            dilations = [1, 1];\r\n        }\r\n        assert(eitherStridesOrDilationsAreOne(strides, dilations), 'Error in depthwiseConv2d: Either strides or dilations must be 1. ' +\r\n            (\"Got strides \" + strides + \" and dilations '\" + dilations + \"'\"));\r\n        if (dimRoundingMode != null) {\r\n            assert(isInt(pad), \"Error in depthwiseConv2d: pad must be an integer when using, \" +\r\n                (\"dimRoundingMode \" + dimRoundingMode + \" but got pad \" + pad + \".\"));\r\n        }\r\n        var convInfo = computeConv2DInfo(x4D.shape, $filter.shape, strides, dilations, pad, dimRoundingMode, true);\r\n        var grad = function (dy) {\r\n            assert(tupleValuesAreOne(dilations), 'Error in gradient of depthwiseConv2d: dilation rates greater than ' +\r\n                (\"1 are not yet supported. Got dilations '\" + dilations + \"'\"));\r\n            return {\r\n                x: function () { return depthwiseConv2dDerInput(x4D.shape, dy, $filter, convInfo); },\r\n                $filter: function () { return depthwiseConv2dDerFilter(x4D, dy, $filter.shape, convInfo); },\r\n            };\r\n        };\r\n        var res = ENV.engine.runKernel(function (backend) { return backend.depthwiseConv2D(x4D, $filter, convInfo); }, { x: x4D, $filter: $filter }, grad);\r\n        if (reshapedTo4D) {\r\n            return res.as3D(res.shape[1], res.shape[2], res.shape[3]);\r\n        }\r\n        return res;\r\n    }\r\n    function separableConv2d_(x, depthwiseFilter, pointwiseFilter, strides, pad, dilation, dataFormat) {\r\n        if (dilation === void 0) { dilation = [1, 1]; }\r\n        if (dataFormat === void 0) { dataFormat = 'NHWC'; }\r\n        var $x = convertToTensor(x, 'x', 'separableConv2d');\r\n        var $depthwiseFilter = convertToTensor(depthwiseFilter, 'depthwiseFilter', 'separableConv2d');\r\n        var $pointwiseFilter = convertToTensor(pointwiseFilter, 'pointwiseFilter', 'separableConv2d');\r\n        var x4D = $x;\r\n        var reshapedTo4D = false;\r\n        if ($x.rank === 3) {\r\n            reshapedTo4D = true;\r\n            x4D = $x.as4D(1, $x.shape[0], $x.shape[1], $x.shape[2]);\r\n        }\r\n        if (dataFormat === 'NCHW') {\r\n            throw new Error('separableConv2d currently does not support dataFormat NCHW; only ' +\r\n                'NHWC is supported');\r\n        }\r\n        assert(x4D.rank === 4, \"Error in separableConv2d: input must be rank 4, but got \" +\r\n            (\"rank \" + x4D.rank + \".\"));\r\n        assert($depthwiseFilter.rank === 4, \"Error in separableConv2d: depthwise filter must be rank 4, but got \" +\r\n            (\"rank \" + $depthwiseFilter.rank + \".\"));\r\n        assert($pointwiseFilter.rank === 4, \"Error in separableConv2d: pointwise filter must be rank 4, but got \" +\r\n            (\"rank \" + $depthwiseFilter.rank + \".\"));\r\n        assert($pointwiseFilter.shape[0] === 1, \"Error in separableConv2d: the first dimension of pointwise filter \" +\r\n            (\" must be 1, but got \" + $pointwiseFilter.shape[0] + \".\"));\r\n        assert($pointwiseFilter.shape[1] === 1, \"Error in separableConv2d: the second dimension of pointwise filter \" +\r\n            (\" must be 1, but got \" + $pointwiseFilter.shape[1] + \".\"));\r\n        var inChannels = $depthwiseFilter.shape[2];\r\n        var channelMultiplier = $depthwiseFilter.shape[3];\r\n        assert($pointwiseFilter.shape[2] === inChannels * channelMultiplier, \"Error in separableConv2d: the third dimension of pointwise filter \" +\r\n            (\"must be \" + inChannels * channelMultiplier + \", \") +\r\n            (\"but got \" + $pointwiseFilter.shape[2] + \".\"));\r\n        var depthwise = depthwiseConv2d(x4D, $depthwiseFilter, strides, pad, dataFormat, dilation);\r\n        var pointwiseStride = 1;\r\n        var res = conv2d(depthwise, $pointwiseFilter, pointwiseStride, 'valid', dataFormat);\r\n        if (reshapedTo4D) {\r\n            return res.as3D(res.shape[1], res.shape[2], res.shape[3]);\r\n        }\r\n        return res;\r\n    }\r\n    function parseTupleParam$1(param) {\r\n        if (typeof param === 'number') {\r\n            return [param, param, param];\r\n        }\r\n        if (param.length === 2) {\r\n            return [param[0], param[1], 1];\r\n        }\r\n        return param;\r\n    }\r\n    function tupleValuesAreOne$1(param) {\r\n        var _a = parseTupleParam$1(param), dimA = _a[0], dimB = _a[1], dimC = _a[2];\r\n        return dimA === 1 && dimB === 1 && dimC === 1;\r\n    }\r\n    function eitherStridesOrDilationsAreOne$1(strides, dilations) {\r\n        return tupleValuesAreOne$1(strides) || tupleValuesAreOne$1(dilations);\r\n    }\r\n    function depthwiseConv2dDerInput(xShape, dy, filter, convInfo) {\r\n        var dy4D = dy;\r\n        var reshapedTo4D = false;\r\n        if (dy.rank === 3) {\r\n            reshapedTo4D = true;\r\n            dy4D = dy.as4D(1, dy.shape[0], dy.shape[1], dy.shape[2]);\r\n        }\r\n        var res = ENV.engine.runKernel(function (backend) { return backend.depthwiseConv2DDerInput(dy4D, filter, convInfo); }, { dy4D: dy4D });\r\n        if (reshapedTo4D) {\r\n            return res.as3D(res.shape[1], res.shape[2], res.shape[3]);\r\n        }\r\n        return res;\r\n    }\r\n    function depthwiseConv2dDerFilter(x, dy, filterShape, convInfo) {\r\n        var x4D = x;\r\n        if (x.rank === 3) {\r\n            x4D = x.as4D(1, x.shape[0], x.shape[1], x.shape[2]);\r\n        }\r\n        var dy4D = dy;\r\n        if (dy4D.rank === 3) {\r\n            dy4D = dy.as4D(1, dy.shape[0], dy.shape[1], dy.shape[2]);\r\n        }\r\n        return ENV.engine.runKernel(function (backend) { return backend.depthwiseConv2DDerFilter(x4D, dy4D, convInfo); }, { x4D: x4D, dy4D: dy4D });\r\n    }\r\n    function conv3d_(x, filter, strides, pad, dataFormat, dilations) {\r\n        if (dataFormat === void 0) { dataFormat = 'NHWC'; }\r\n        if (dilations === void 0) { dilations = [1, 1, 1]; }\r\n        var $x = convertToTensor(x, 'x', 'conv3d');\r\n        var $filter = convertToTensor(filter, 'filter', 'conv3d');\r\n        var x5D = $x;\r\n        var reshapedTo5D = false;\r\n        if ($x.rank === 4) {\r\n            reshapedTo5D = true;\r\n            x5D = $x.as5D(1, $x.shape[0], $x.shape[1], $x.shape[2], $x.shape[3]);\r\n        }\r\n        assert(x5D.rank === 5, \"Error in conv3d: input must be rank 5, but got rank \" + x5D.rank + \".\");\r\n        assert($filter.rank === 5, \"Error in conv3d: filter must be rank 5, but got rank \" +\r\n            ($filter.rank + \".\"));\r\n        assert(x5D.shape[4] === $filter.shape[3], \"Error in conv3d: depth of input (\" + x5D.shape[4] + \") must match \" +\r\n            (\"input depth for filter \" + $filter.shape[3] + \".\"));\r\n        assert(eitherStridesOrDilationsAreOne$1(strides, dilations), 'Error in conv3D: Either strides or dilations must be 1. ' +\r\n            (\"Got strides \" + strides + \" and dilations '\" + dilations + \"'\"));\r\n        assert(dataFormat === 'NHWC', \"Error in conv3d: got dataFormat of \" + dataFormat + \" but only NHWC is currently supported.\");\r\n        var convInfo = computeConv3DInfo(x5D.shape, $filter.shape, strides, dilations, pad);\r\n        var grad = function (dy) {\r\n            assert(tupleValuesAreOne$1(dilations), 'Error in gradient of conv3D: dilation rates greater than 1 are not' +\r\n                (\"yet supported in gradients. Got dilations '\" + dilations + \"'\"));\r\n            return {\r\n                x: function () { return conv3dDerInput_(x5D.shape, dy, $filter, strides, pad); },\r\n                $filter: function () { return conv3dDerFilter_(x5D, dy, $filter.shape, strides, pad); }\r\n            };\r\n        };\r\n        var res = ENV.engine.runKernel(function (backend) { return backend.conv3d(x5D, $filter, convInfo); }, { x: x5D, $filter: $filter }, grad);\r\n        if (reshapedTo5D) {\r\n            return res.as4D(res.shape[1], res.shape[2], res.shape[3], res.shape[4]);\r\n        }\r\n        return res;\r\n    }\r\n    function conv3dDerInput_(xShape, dy, filter, strides, pad) {\r\n        assert(xShape.length === dy.rank, \"Length of inShape \" +\r\n            (\"(\" + xShape.length + \") and rank of dy (\" + dy.rank + \") must match\"));\r\n        var xShape5D = xShape;\r\n        var dy5D = dy;\r\n        var reshapedTo5D = false;\r\n        if (dy.rank === 4) {\r\n            reshapedTo5D = true;\r\n            dy5D = dy.as5D(1, dy.shape[0], dy.shape[1], dy.shape[2], dy.shape[3]);\r\n            xShape5D = [1, xShape[0], xShape[1], xShape[2], xShape[3]];\r\n        }\r\n        var inDepth = xShape5D[4];\r\n        var outDepth = dy5D.shape[4];\r\n        assert(xShape5D.length === 5, \"Error in conv3dDerInput: inShape must be length 5, but got length \" +\r\n            (xShape5D.length + \".\"));\r\n        assert(dy5D.rank === 5, \"Error in conv3dDerInput: dy must be rank 5, but got \" +\r\n            (\"rank \" + dy5D.rank));\r\n        assert(filter.rank === 5, \"Error in conv3dDerInput: filter must be rank 5, but got \" +\r\n            (\"rank \" + filter.rank));\r\n        assert(inDepth === filter.shape[3], \"Error in conv3dDerInput: depth of input (\" + inDepth + \") must \" +\r\n            (\"match input depth for filter \" + filter.shape[3] + \".\"));\r\n        assert(outDepth === filter.shape[4], \"Error in conv3dDerInput: depth of output (\" + outDepth + \") must \" +\r\n            (\"match output depth for filter \" + filter.shape[4] + \".\"));\r\n        var dilations = 1;\r\n        var convInfo = computeConv3DInfo(xShape5D, filter.shape, strides, dilations, pad);\r\n        var res = ENV.engine.runKernel(function (backend) { return backend.conv3dDerInput(dy5D, filter, convInfo); }, { dy5D: dy5D });\r\n        if (reshapedTo5D) {\r\n            return res.as4D(res.shape[1], res.shape[2], res.shape[3], res.shape[4]);\r\n        }\r\n        return res;\r\n    }\r\n    function conv3dDerFilter_(x, dy, filterShape, strides, pad) {\r\n        var x5D = x;\r\n        if (x.rank === 4) {\r\n            x5D = x.as5D(1, x.shape[0], x.shape[1], x.shape[2], x.shape[3]);\r\n        }\r\n        var dy5D = dy;\r\n        if (dy5D.rank === 4) {\r\n            dy5D = dy.as5D(1, dy.shape[0], dy.shape[1], dy.shape[2], dy.shape[3]);\r\n        }\r\n        assert(x5D.rank === 5, \"Error in conv3dDerFilter: input must be rank 5, but got shape \" +\r\n            (x5D.shape + \".\"));\r\n        assert(dy5D.rank === 5, \"Error in conv3dDerFilter: dy must be rank 5, but got shape \" +\r\n            (dy5D.shape + \".\"));\r\n        assert(filterShape.length === 5, \"Error in conv3dDerFilter: filterShape must be length 5, but got \" +\r\n            (filterShape + \".\"));\r\n        assert(x5D.shape[4] === filterShape[3], \"Error in conv3dDerFilter: depth of input \" + x5D.shape[4] + \") must \" +\r\n            (\"match input depth in filter (\" + filterShape[3] + \".\"));\r\n        assert(dy5D.shape[4] === filterShape[4], \"Error in conv3dDerFilter: depth of dy (\" + dy5D.shape[4] + \") must \" +\r\n            (\"match output depth for filter (\" + filterShape[4] + \").\"));\r\n        var dilations = 1;\r\n        var convInfo = computeConv3DInfo(x5D.shape, filterShape, strides, dilations, pad);\r\n        return ENV.engine.runKernel(function (backend) { return backend.conv3dDerFilter(x5D, dy5D, convInfo); }, { x5D: x5D, dy5D: dy5D });\r\n    }\r\n    var conv1d = op({ conv1d_: conv1d_ });\r\n    var conv2d = op({ conv2d_: conv2d_ });\r\n    var conv3d = op({ conv3d_: conv3d_ });\r\n    var conv2dDerFilter = op({ conv2dDerFilter_: conv2dDerFilter_ });\r\n    var depthwiseConv2d = op({ depthwiseConv2d_: depthwiseConv2d_ });\r\n    var separableConv2d = op({ separableConv2d_: separableConv2d_ });\r\n    var conv2dTranspose = op({ conv2dTranspose_: conv2dTranspose_ });\n\n    function matMul_(a, b, transposeA, transposeB) {\r\n        if (transposeA === void 0) { transposeA = false; }\r\n        if (transposeB === void 0) { transposeB = false; }\r\n        var _a;\r\n        var $a = convertToTensor(a, 'a', 'matMul');\r\n        var $b = convertToTensor(b, 'b', 'matMul');\r\n        _a = makeTypesMatch($a, $b), $a = _a[0], $b = _a[1];\r\n        var innerShapeA = transposeA ? $a.shape[$a.rank - 2] : $a.shape[$a.rank - 1];\r\n        var innerShapeB = transposeB ? $b.shape[$b.rank - 1] : $b.shape[$b.rank - 2];\r\n        var outerShapeA = transposeA ? $a.shape[$a.rank - 1] : $a.shape[$a.rank - 2];\r\n        var outerShapeB = transposeB ? $b.shape[$b.rank - 2] : $b.shape[$b.rank - 1];\r\n        var outerDimsA = $a.shape.slice(0, -2);\r\n        var outerDimsB = $b.shape.slice(0, -2);\r\n        var batchDimA = sizeFromShape(outerDimsA);\r\n        var batchDimB = sizeFromShape(outerDimsB);\r\n        assert($a.rank >= 2 && $b.rank >= 2 && $a.rank === $b.rank, \"Error in matMul: inputs must have the same rank of at least 2, \" +\r\n            (\"got ranks \" + $a.rank + \" and \" + $b.rank + \".\"));\r\n        assert(arraysEqual(outerDimsA, outerDimsB), \"Error in matMul: outer dimensions (\" + outerDimsA + \") and (\" +\r\n            (outerDimsB + \") of Tensors with shapes \" + $a.shape + \" and \") +\r\n            ($b.shape + \" must match.\"));\r\n        assert(innerShapeA === innerShapeB, \"Error in matMul: inner shapes (\" + innerShapeA + \") and (\" +\r\n            (innerShapeB + \") of Tensors with shapes \" + $a.shape + \" and \") +\r\n            ($b.shape + \" and transposeA=\" + transposeA) +\r\n            (\" and transposeB=\" + transposeB + \" must match.\"));\r\n        var outShape = $a.shape.slice(0, -2).concat([outerShapeA, outerShapeB]);\r\n        var a3D = transposeA ? $a.as3D(batchDimA, innerShapeA, outerShapeA) :\r\n            $a.as3D(batchDimA, outerShapeA, innerShapeA);\r\n        var b3D = transposeB ? $b.as3D(batchDimB, outerShapeB, innerShapeB) :\r\n            $b.as3D(batchDimB, innerShapeB, outerShapeB);\r\n        var grad = function (dy) {\r\n            if (!transposeA && !transposeB) {\r\n                return {\r\n                    $a: function () { return dy.matMul(b3D, false, true); },\r\n                    $b: function () { return a3D.matMul(dy, true, false); }\r\n                };\r\n            }\r\n            else if (!transposeA && transposeB) {\r\n                return {\r\n                    $a: function () { return dy.matMul(b3D, false, false); },\r\n                    $b: function () { return dy.matMul(a3D, true, false); }\r\n                };\r\n            }\r\n            else if (transposeA && !transposeB) {\r\n                return {\r\n                    $a: function () { return b3D.matMul(dy, false, true); },\r\n                    $b: function () { return a3D.matMul(dy, false, false); }\r\n                };\r\n            }\r\n            else {\r\n                return {\r\n                    $a: function () { return b3D.matMul(dy, true, true); },\r\n                    $b: function () { return dy.matMul(a3D, true, true); }\r\n                };\r\n            }\r\n        };\r\n        var res = ENV.engine.runKernel(function (backend) { return backend.batchMatMul(a3D, b3D, transposeA, transposeB); }, { $a: a3D, $b: b3D }, grad);\r\n        return res.reshape(outShape);\r\n    }\r\n    function outerProduct_(v1, v2) {\r\n        var $v1 = convertToTensor(v1, 'v1', 'outerProduct');\r\n        var $v2 = convertToTensor(v2, 'v2', 'outerProduct');\r\n        assert($v1.rank === 1 && $v2.rank === 1, \"Error in outerProduct: inputs must be rank 1, but got ranks \" +\r\n            ($v1.rank + \" and \" + $v2.rank + \".\"));\r\n        return $v1.as2D(-1, 1).matMul($v2.as2D(1, -1));\r\n    }\r\n    function dot_(t1, t2) {\r\n        var $t1 = convertToTensor(t1, 't1', 'dot');\r\n        var $t2 = convertToTensor(t2, 't2', 'dot');\r\n        assert(($t1.rank === 1 || $t1.rank === 2) && ($t2.rank === 1 || $t2.rank === 2), \"Error in dot: inputs must all be rank 1 or 2, but got ranks \" +\r\n            ($t1.rank + \" and \" + $t2.rank + \".\"));\r\n        var t1Inner = ($t1.rank === 1 ? $t1.size : $t1.shape[1]);\r\n        var t2Inner = ($t2.rank === 1 ? $t2.size : $t2.shape[0]);\r\n        assert(t1Inner === t2Inner, \"Error in dot: inner dimensions of inputs must match, but got \" +\r\n            (t1Inner + \" and \" + t2Inner + \".\"));\r\n        if ($t1.rank === 1 && $t2.rank === 1) {\r\n            return $t1.as2D(1, -1).matMul($t2.as2D(-1, 1)).asScalar();\r\n        }\r\n        else if ($t1.rank === 1 && $t2.rank === 2) {\r\n            return $t1.as2D(1, -1).matMul($t2.as2D($t2.shape[0], $t2.shape[1])).as1D();\r\n        }\r\n        else if ($t1.rank === 2 && $t2.rank === 1) {\r\n            return $t1.matMul($t2.as2D(-1, 1)).as1D();\r\n        }\r\n        else {\r\n            return $t1.matMul($t2.as2D($t2.shape[0], $t2.shape[1]));\r\n        }\r\n    }\r\n    var matMul = op({ matMul_: matMul_ });\r\n    var dot = op({ dot_: dot_ });\r\n    var outerProduct = op({ outerProduct_: outerProduct_ });\n\n    function reverse1d_(x) {\r\n        var $x = convertToTensor(x, 'x', 'reverse');\r\n        assert($x.rank === 1, \"Error in reverse1D: x must be rank 1 but got\\n             rank \" + $x.rank + \".\");\r\n        return reverse($x, 0);\r\n    }\r\n    function reverse2d_(x, axis) {\r\n        var $x = convertToTensor(x, 'x', 'reverse');\r\n        assert($x.rank === 2, \"Error in reverse2D: x must be rank 2 but got\\n             rank \" + $x.rank + \".\");\r\n        return reverse($x, axis);\r\n    }\r\n    function reverse3d_(x, axis) {\r\n        var $x = convertToTensor(x, 'x', 'reverse');\r\n        assert($x.rank === 3, \"Error in reverse3D: x must be rank 3 but got\\n             rank \" + $x.rank + \".\");\r\n        return reverse($x, axis);\r\n    }\r\n    function reverse4d_(x, axis) {\r\n        var $x = convertToTensor(x, 'x', 'reverse');\r\n        assert($x.rank === 4, \"Error in reverse4D: x must be rank 4 but got\\n             rank \" + $x.rank + \".\");\r\n        return reverse($x, axis);\r\n    }\r\n    function reverse_(x, axis) {\r\n        var $x = convertToTensor(x, 'x', 'reverse');\r\n        if ($x.rank === 0) {\r\n            return $x.clone();\r\n        }\r\n        var axes = parseAxisParam(axis, $x.shape);\r\n        var grad = function (dy) {\r\n            return { $x: function () { return dy.reverse(axes); } };\r\n        };\r\n        var res = ENV.engine.runKernel(function (backend) { return backend.reverse($x, axes); }, { $x: $x }, grad);\r\n        return res.reshapeAs($x);\r\n    }\r\n    var reverse = op({ reverse_: reverse_ });\r\n    var reverse1d = op({ reverse1d_: reverse1d_ });\r\n    var reverse2d = op({ reverse2d_: reverse2d_ });\r\n    var reverse3d = op({ reverse3d_: reverse3d_ });\r\n    var reverse4d = op({ reverse4d_: reverse4d_ });\n\n    function maxPoolImpl_(x, filterSize, strides, dilations, pad$$1, dimRoundingMode) {\r\n        var $x = convertToTensor(x, 'x', 'maxPool');\r\n        var x4D = $x;\r\n        var reshapedTo4D = false;\r\n        if ($x.rank === 3) {\r\n            reshapedTo4D = true;\r\n            x4D = $x.as4D(1, $x.shape[0], $x.shape[1], $x.shape[2]);\r\n        }\r\n        if (dilations == null) {\r\n            dilations = [1, 1];\r\n        }\r\n        assert(x4D.rank === 4, \"Error in maxPool: input must be rank 4 but got rank \" + x4D.rank + \".\");\r\n        assert(eitherStridesOrDilationsAreOne(strides, dilations), 'Error in maxPool: Either strides or dilations must be 1. ' +\r\n            (\"Got strides \" + strides + \" and dilations '\" + dilations + \"'\"));\r\n        if (dimRoundingMode != null) {\r\n            assert(isInt(pad$$1), \"Error in maxPool: pad must be an integer when using, \" +\r\n                (\"dimRoundingMode \" + dimRoundingMode + \" but got pad \" + pad$$1 + \".\"));\r\n        }\r\n        var convInfo = computePool2DInfo(x4D.shape, filterSize, strides, dilations, pad$$1, dimRoundingMode);\r\n        var grad = function (dy, saved) {\r\n            var y4D = saved[0];\r\n            return {\r\n                x: function () { return maxPoolBackprop(dy, x4D, y4D, filterSize, strides, dilations, pad$$1); }\r\n            };\r\n        };\r\n        var res = ENV.engine.runKernel(function (backend, save) { return save(backend.maxPool(x4D, convInfo)); }, { x: x4D }, grad);\r\n        if (reshapedTo4D) {\r\n            return res.as3D(res.shape[1], res.shape[2], res.shape[3]);\r\n        }\r\n        return res;\r\n    }\r\n    function maxPool_(x, filterSize, strides, pad$$1, dimRoundingMode) {\r\n        return maxPoolImpl_(x, filterSize, strides, 1, pad$$1, dimRoundingMode);\r\n    }\r\n    function avgPoolImpl_(x, filterSize, strides, dilations, pad$$1, dimRoundingMode) {\r\n        var $x = convertToTensor(x, 'x', 'avgPool', 'float32');\r\n        if (dilations == null) {\r\n            dilations = [1, 1];\r\n        }\r\n        assert(eitherStridesOrDilationsAreOne(strides, dilations), 'Error in avgPool: Either strides or dilations must be 1. ' +\r\n            (\"Got strides \" + strides + \" and dilations '\" + dilations + \"'\"));\r\n        var x4D = $x;\r\n        var reshapedTo4D = false;\r\n        if ($x.rank === 3) {\r\n            reshapedTo4D = true;\r\n            x4D = $x.as4D(1, $x.shape[0], $x.shape[1], $x.shape[2]);\r\n        }\r\n        assert(x4D.rank === 4, \"Error in avgPool: x must be rank 4 but got rank \" + x4D.rank + \".\");\r\n        if (dimRoundingMode != null) {\r\n            assert(isInt(pad$$1), \"Error in avgPool: pad must be an integer when using, \" +\r\n                (\"dimRoundingMode \" + dimRoundingMode + \" but got pad \" + pad$$1 + \".\"));\r\n        }\r\n        var convInfo = computePool2DInfo(x4D.shape, filterSize, strides, dilations, pad$$1, dimRoundingMode);\r\n        var grad = function (dy) {\r\n            return {\r\n                x: function () { return avgPoolBackprop(dy, x4D, filterSize, strides, dilations, pad$$1); }\r\n            };\r\n        };\r\n        var res = ENV.engine.runKernel(function (backend) { return backend.avgPool(x4D, convInfo); }, { x: x4D }, grad);\r\n        res = res.cast($x.dtype);\r\n        if (reshapedTo4D) {\r\n            return res.as3D(res.shape[1], res.shape[2], res.shape[3]);\r\n        }\r\n        return res;\r\n    }\r\n    function avgPool_(x, filterSize, strides, pad$$1, dimRoundingMode) {\r\n        return avgPoolImpl_(x, filterSize, strides, 1, pad$$1, dimRoundingMode);\r\n    }\r\n    function pool_(input, windowShape, poolingType, pad$$1, dilations, strides) {\r\n        if (dilations == null) {\r\n            dilations = [1, 1];\r\n        }\r\n        if (strides == null) {\r\n            strides = 1;\r\n        }\r\n        if (pad$$1 === 0) {\r\n            pad$$1 = 'valid';\r\n        }\r\n        var $x = convertToTensor(input, 'x', 'maxPool');\r\n        var x4D = $x;\r\n        var reshapedTo4D = false;\r\n        if ($x.rank === 3) {\r\n            reshapedTo4D = true;\r\n            x4D = $x.as4D(1, $x.shape[0], $x.shape[1], $x.shape[2]);\r\n        }\r\n        assert(eitherStridesOrDilationsAreOne(strides, dilations), 'Error in pool: Either strides or dilations must be 1. ' +\r\n            (\"Got strides \" + strides + \" and dilations '\" + dilations + \"'\"));\r\n        var convInfo = computePool2DInfo(x4D.shape, windowShape, strides, dilations, pad$$1);\r\n        var dilation = [convInfo.dilationHeight, convInfo.dilationWidth];\r\n        var basePadding;\r\n        if (pad$$1 === 'same') {\r\n            basePadding = withSpaceToBatchBasePaddings([convInfo.filterHeight, convInfo.filterWidth], dilation);\r\n        }\r\n        else {\r\n            basePadding = [[0, 0], [0, 0]];\r\n        }\r\n        var isDilationOne = dilation[0] === 1 && dilation[1] === 1;\r\n        var _a = requiredSpaceToBatchPaddings([convInfo.inHeight, convInfo.inWidth], dilation, basePadding), adjustedPadding = _a[0], adjustedCrops = _a[1];\r\n        var convertedPad = isDilationOne ? pad$$1 : 'valid';\r\n        var convertedX = isDilationOne ? x4D : spaceToBatchND(x4D, dilation, adjustedPadding);\r\n        var forwardOp = poolingType === 'avg' ?\r\n            function () { return avgPoolImpl_(convertedX, windowShape, strides, 1, convertedPad); } :\r\n            function () { return maxPoolImpl_(convertedX, windowShape, strides, 1, convertedPad); };\r\n        var y = forwardOp();\r\n        var res = isDilationOne ? y : batchToSpaceND(y, dilation, adjustedCrops);\r\n        if (reshapedTo4D) {\r\n            return res.as3D(res.shape[1], res.shape[2], res.shape[3]);\r\n        }\r\n        return res;\r\n    }\r\n    function maxPoolBackprop(dy, input, output, filterSize, strides, dilations, pad$$1, dimRoundingMode) {\r\n        var $dy = convertToTensor(dy, 'dy', 'maxPoolBackprop');\r\n        var $input = convertToTensor(input, 'input', 'maxPoolBackprop');\r\n        var $output = convertToTensor(output, 'output', 'maxPoolBackprop');\r\n        assert($input.rank === $dy.rank, \"Rank of input (\" + $input.rank + \") does not match rank of dy (\" + $dy.rank + \")\");\r\n        if (dilations == null) {\r\n            dilations = [1, 1];\r\n        }\r\n        assert(eitherStridesOrDilationsAreOne(strides, dilations), 'Error in maxPoolBackProp: Either strides or dilations must be 1. ' +\r\n            (\"Got strides \" + strides + \" and dilations '\" + dilations + \"'\"));\r\n        assert($dy.rank === 4, \"Error in maxPoolBackprop: dy must be rank 4 but got rank \" +\r\n            ($dy.rank + \".\"));\r\n        assert($input.rank === 4, \"Error in maxPoolBackprop: input must be rank 4 but got rank \" +\r\n            ($input.rank + \".\"));\r\n        if (dimRoundingMode != null) {\r\n            assert(isInt(pad$$1), \"Error in maxPoolBackprop: pad must be an integer when using, \" +\r\n                (\"dimRoundingMode \" + dimRoundingMode + \" but got pad \" + pad$$1 + \".\"));\r\n        }\r\n        var convInfo = computePool2DInfo($input.shape, filterSize, strides, dilations, pad$$1, dimRoundingMode);\r\n        var res = ENV.engine.runKernel(function (backend) { return backend.maxPoolBackprop($dy, $input, $output, convInfo); }, { $dy: $dy, $input: $input });\r\n        return res;\r\n    }\r\n    function avgPoolBackprop(dy, input, filterSize, strides, dilations, pad$$1) {\r\n        var $dy = convertToTensor(dy, 'dy', 'avgPoolBackprop');\r\n        var $input = convertToTensor(input, 'input', 'avgPoolBackprop');\r\n        assert($input.rank === $dy.rank, \"Rank of input (\" + $input.rank + \") does not match rank of dy (\" + $dy.rank + \")\");\r\n        if (dilations == null) {\r\n            dilations = [1, 1];\r\n        }\r\n        assert(eitherStridesOrDilationsAreOne(strides, dilations), 'Error in avgPoolBackprop: Either strides or dilations must be 1. ' +\r\n            (\"Got strides \" + strides + \" and dilations '\" + dilations + \"'\"));\r\n        var input4D = $input;\r\n        var dy4D = $dy;\r\n        var reshapedTo4D = false;\r\n        if ($input.rank === 3) {\r\n            reshapedTo4D = true;\r\n            input4D = $input.as4D(1, $input.shape[0], $input.shape[1], $input.shape[2]);\r\n            dy4D = $dy.as4D(1, $dy.shape[0], $dy.shape[1], $dy.shape[2]);\r\n        }\r\n        assert(dy4D.rank === 4, \"Error in avgPoolBackprop: dy must be rank 4 but got rank \" +\r\n            (dy4D.rank + \".\"));\r\n        assert(input4D.rank === 4, \"Error in avgPoolBackprop: input must be rank 4 but got rank \" +\r\n            (input4D.rank + \".\"));\r\n        var convInfo = computePool2DInfo(input4D.shape, filterSize, strides, dilations, pad$$1);\r\n        var res = ENV.engine.runKernel(function (backend) { return backend.avgPoolBackprop(dy4D, input4D, convInfo); }, { dy4D: dy4D, input4D: input4D });\r\n        if (reshapedTo4D) {\r\n            return res.as3D(res.shape[1], res.shape[2], res.shape[3]);\r\n        }\r\n        return res;\r\n    }\r\n    function requiredSpaceToBatchPaddings(inputShape, blockShape, basePadding) {\r\n        var padStart = basePadding.map(function (b) { return b[0]; });\r\n        var origPadEnd = basePadding.map(function (b) { return b[1]; });\r\n        var fullInputShape = inputShape.concat(padStart, origPadEnd);\r\n        var padEndExtra = blockShape.map(function (b, i) { return (b - fullInputShape[i] % b) % b; });\r\n        var padEnd = origPadEnd.map(function (s, i) { return s + padEndExtra[i]; });\r\n        var paddings = blockShape.map(function (_, i) { return [padStart[i], padEnd[i]]; });\r\n        var crops = blockShape.map(function (_, i) { return [0, padEndExtra[i]]; });\r\n        return [paddings, crops];\r\n    }\r\n    function withSpaceToBatchBasePaddings(filterShape, dilation) {\r\n        var dilatedFilterShape = filterShape.map(function (s, i) {\r\n            return s + (s - 1) * (dilation[i] - 1);\r\n        });\r\n        var padExtraShape = dilatedFilterShape.map(function (s) { return s - 1; });\r\n        var padExtraStart = padExtraShape.map(function (s) { return Math.floor(s / 2); });\r\n        var padExtraEnd = padExtraShape.map(function (s, i) { return s - padExtraStart[i]; });\r\n        return padExtraShape.map(function (_, i) {\r\n            return [padExtraStart[i], padExtraEnd[i]];\r\n        });\r\n    }\r\n    var maxPool = op({ maxPool_: maxPool_ });\r\n    var avgPool = op({ avgPool_: avgPool_ });\r\n    var pool = op({ pool_: pool_ });\n\n    function slice1d_(x, begin, size) {\r\n        var $x = convertToTensor(x, 'x', 'slice1d');\r\n        assert($x.rank === 1, \"slice1d expects a rank-1 tensor, but got a rank-\" + $x.rank + \" tensor\");\r\n        return slice($x, [begin], [size]);\r\n    }\r\n    function slice2d_(x, begin, size) {\r\n        var $x = convertToTensor(x, 'x', 'slice2d');\r\n        assert($x.rank === 2, \"slice2d expects a rank-2 tensor, but got a rank-\" + $x.rank + \" tensor\");\r\n        return slice($x, begin, size);\r\n    }\r\n    function slice3d_(x, begin, size) {\r\n        var $x = convertToTensor(x, 'x', 'slice3d');\r\n        assert($x.rank === 3, \"slice3d expects a rank-3 tensor, but got a rank-\" + $x.rank + \" tensor\");\r\n        return slice($x, begin, size);\r\n    }\r\n    function slice4d_(x, begin, size) {\r\n        var $x = convertToTensor(x, 'x', 'slice4d');\r\n        assert($x.rank === 4, \"slice4d expects a rank-4 tensor, but got a rank-\" + $x.rank + \" tensor\");\r\n        return slice($x, begin, size);\r\n    }\r\n    function slice_(x, begin, size) {\r\n        var $x = convertToTensor(x, 'x', 'slice');\r\n        if ($x.rank === 0) {\r\n            throw new Error('Slicing scalar is not possible');\r\n        }\r\n        var begin_;\r\n        if (typeof begin === 'number') {\r\n            begin_ = [begin].concat(new Array($x.rank - 1).fill(0));\r\n        }\r\n        else if (begin.length < $x.rank) {\r\n            begin_ = begin.concat(new Array($x.rank - begin.length).fill(0));\r\n        }\r\n        else {\r\n            begin_ = begin.slice();\r\n        }\r\n        var size_;\r\n        if (size == null) {\r\n            size_ = new Array($x.rank).fill(-1);\r\n        }\r\n        else if (typeof size === 'number') {\r\n            size_ = [size].concat(new Array($x.rank - 1).fill(-1));\r\n        }\r\n        else if (size.length < $x.rank) {\r\n            size_ = size.concat(new Array($x.rank - size.length).fill(-1));\r\n        }\r\n        else {\r\n            size_ = size;\r\n        }\r\n        size_ = size_.map(function (d, i) {\r\n            if (d >= 0) {\r\n                return d;\r\n            }\r\n            else {\r\n                assert(d === -1, 'Bad value in size');\r\n                return $x.shape[i] - begin_[i];\r\n            }\r\n        });\r\n        assertParamsValid($x, begin_, size_);\r\n        var inputShape = $x.shape;\r\n        var grad = function (dy) {\r\n            var paddings = [];\r\n            for (var i = 0; i < dy.rank; i++) {\r\n                paddings.push([begin_[i], inputShape[i] - begin_[i] - size_[i]]);\r\n            }\r\n            return { $x: function () { return dy.pad(paddings); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.slice($x, begin_, size_); }, { $x: $x }, grad);\r\n    }\r\n    var slice = op({ slice_: slice_ });\r\n    var slice1d = op({ slice1d_: slice1d_ });\r\n    var slice2d = op({ slice2d_: slice2d_ });\r\n    var slice3d = op({ slice3d_: slice3d_ });\r\n    var slice4d = op({ slice4d_: slice4d_ });\n\n    function logSumExp_(x, axis, keepDims) {\r\n        if (axis === void 0) { axis = null; }\r\n        if (keepDims === void 0) { keepDims = false; }\r\n        var $x = convertToTensor(x, 'x', 'logSumExp');\r\n        var axes = parseAxisParam(axis, $x.shape);\r\n        var xMax = $x.max(axes, true);\r\n        var a = $x.sub(xMax);\r\n        var b = a.exp();\r\n        var c = b.sum(axes);\r\n        var d = c.log();\r\n        var res = xMax.reshape(d.shape).add(d);\r\n        if (keepDims) {\r\n            var newShape = expandShapeToKeepDim(res.shape, axes);\r\n            return res.reshape(newShape);\r\n        }\r\n        return res;\r\n    }\r\n    function sum_(x, axis, keepDims) {\r\n        if (axis === void 0) { axis = null; }\r\n        if (keepDims === void 0) { keepDims = false; }\r\n        var $x = convertToTensor(x, 'x', 'sum');\r\n        if ($x.dtype === 'bool') {\r\n            $x = $x.toInt();\r\n        }\r\n        var axes = parseAxisParam(axis, $x.shape);\r\n        var customOp = customGrad(function (x) {\r\n            var permutation = getAxesPermutation(axes, x.rank);\r\n            var reductionAxes = axes;\r\n            var permutedX = x;\r\n            if (permutation != null) {\r\n                permutedX = x.transpose(permutation);\r\n                reductionAxes = getInnerMostAxes(reductionAxes.length, x.rank);\r\n            }\r\n            var value = ENV.engine.runKernel(function (backend) { return backend.sum(permutedX, reductionAxes); }, { permutedX: permutedX });\r\n            if (keepDims) {\r\n                var newShape = expandShapeToKeepDim(value.shape, axes);\r\n                value = value.reshape(newShape);\r\n            }\r\n            var gradFunc = function (dy) {\r\n                var expandedDyShape = x.shape.slice();\r\n                axes.forEach(function (axis) {\r\n                    expandedDyShape[axis] = 1;\r\n                });\r\n                var expandedDy = dy.reshape(expandedDyShape);\r\n                var derX = expandedDy.mul(ones$1(x.shape, 'float32'));\r\n                return derX;\r\n            };\r\n            return { value: value, gradFunc: gradFunc };\r\n        });\r\n        return customOp($x);\r\n    }\r\n    function prod_(x, axis, keepDims) {\r\n        if (axis === void 0) { axis = null; }\r\n        if (keepDims === void 0) { keepDims = false; }\r\n        var $x = convertToTensor(x, 'x', 'prod');\r\n        if ($x.dtype === 'bool') {\r\n            $x = $x.toInt();\r\n        }\r\n        var axes = parseAxisParam(axis, $x.shape);\r\n        var permutation = getAxesPermutation(axes, $x.rank);\r\n        var reductionAxes = axes;\r\n        var permutedX = $x;\r\n        if (permutation != null) {\r\n            permutedX = $x.transpose(permutation);\r\n            reductionAxes = getInnerMostAxes(reductionAxes.length, $x.rank);\r\n        }\r\n        var value = ENV.engine.runKernel(function (backend) { return backend.prod(permutedX, reductionAxes); }, { permutedX: permutedX });\r\n        if (keepDims) {\r\n            var newShape = expandShapeToKeepDim(value.shape, axes);\r\n            value = value.reshape(newShape);\r\n        }\r\n        return value;\r\n    }\r\n    function mean_(x, axis, keepDims) {\r\n        if (axis === void 0) { axis = null; }\r\n        if (keepDims === void 0) { keepDims = false; }\r\n        var $x = convertToTensor(x, 'x', 'mean');\r\n        var axes = parseAxisParam(axis, $x.shape);\r\n        var shapes = computeOutAndReduceShapes($x.shape, axes);\r\n        var reduceShape = shapes[1];\r\n        var reduceSize = sizeFromShape(reduceShape);\r\n        var customOp = customGrad(function (x) {\r\n            var reduceSizeScalar = scalar(reduceSize);\r\n            var xReduce = reduceSizeScalar.dtype === x.dtype ? x : x.cast(reduceSizeScalar.dtype);\r\n            var res = xReduce.div(reduceSizeScalar);\r\n            var value = res.sum(axis, keepDims);\r\n            var gradFunc = function (dy) {\r\n                var expandedDyShape = x.shape.slice();\r\n                axes.forEach(function (axis) {\r\n                    expandedDyShape[axis] = 1;\r\n                });\r\n                var expandedDy = dy.reshape(expandedDyShape);\r\n                var derX = expandedDy.mul(ones$1(x.shape, 'float32')).div(reduceSizeScalar);\r\n                return derX;\r\n            };\r\n            return { value: value, gradFunc: gradFunc };\r\n        });\r\n        return customOp($x);\r\n    }\r\n    function gradForMinAndMax(dy, saved, xOrig, origAxes, permutedAxes) {\r\n        var y = saved[0];\r\n        if (y.rank < xOrig.rank) {\r\n            y = y.reshape(expandShapeToKeepDim(y.shape, origAxes));\r\n        }\r\n        if (dy.rank < xOrig.rank) {\r\n            dy = dy.reshape(expandShapeToKeepDim(dy.shape, origAxes));\r\n        }\r\n        return {\r\n            $x: function () {\r\n                var dx = dy.mul(xOrig.equal(y).cast(dy.dtype));\r\n                return permutedAxes == null ? dx : dx.transpose(permutedAxes);\r\n            }\r\n        };\r\n    }\r\n    function min_(x, axis, keepDims) {\r\n        if (axis === void 0) { axis = null; }\r\n        if (keepDims === void 0) { keepDims = false; }\r\n        var $x = convertToTensor(x, 'x', 'min');\r\n        var xOrig = $x;\r\n        var origAxes = parseAxisParam(axis, $x.shape);\r\n        var axes = origAxes;\r\n        var permutedAxes = getAxesPermutation(axes, $x.rank);\r\n        if (permutedAxes != null) {\r\n            $x = $x.transpose(permutedAxes);\r\n            axes = getInnerMostAxes(axes.length, $x.rank);\r\n        }\r\n        var grad$$1 = function (dy, saved) {\r\n            return gradForMinAndMax(dy, saved, xOrig, origAxes, permutedAxes);\r\n        };\r\n        var res = ENV.engine.runKernel(function (backend, save) { return save(backend.min($x, axes)); }, { $x: $x }, grad$$1);\r\n        if (keepDims) {\r\n            var newShape = expandShapeToKeepDim(res.shape, origAxes);\r\n            res = res.reshape(newShape);\r\n        }\r\n        return res;\r\n    }\r\n    function max_(x, axis, keepDims) {\r\n        if (axis === void 0) { axis = null; }\r\n        if (keepDims === void 0) { keepDims = false; }\r\n        var $x = convertToTensor(x, 'x', 'max');\r\n        var xOrig = $x;\r\n        var origAxes = parseAxisParam(axis, $x.shape);\r\n        var axes = origAxes;\r\n        var permutedAxes = getAxesPermutation(axes, $x.rank);\r\n        if (permutedAxes != null) {\r\n            $x = $x.transpose(permutedAxes);\r\n            axes = getInnerMostAxes(axes.length, $x.rank);\r\n        }\r\n        var grad$$1 = function (dy, saved) {\r\n            return gradForMinAndMax(dy, saved, xOrig, origAxes, permutedAxes);\r\n        };\r\n        var res = ENV.engine.runKernel(function (backend, save) { return save(backend.max($x, axes)); }, { $x: $x }, grad$$1);\r\n        if (keepDims) {\r\n            var newShape = expandShapeToKeepDim(res.shape, origAxes);\r\n            res = res.reshape(newShape);\r\n        }\r\n        return res;\r\n    }\r\n    function argMin_(x, axis) {\r\n        if (axis === void 0) { axis = 0; }\r\n        var $x = convertToTensor(x, 'x', 'argMin');\r\n        if (axis == null) {\r\n            axis = 0;\r\n        }\r\n        var axes = parseAxisParam(axis, $x.shape);\r\n        var permutedAxes = getAxesPermutation(axes, $x.rank);\r\n        if (permutedAxes != null) {\r\n            $x = $x.transpose(permutedAxes);\r\n            axes = getInnerMostAxes(axes.length, $x.rank);\r\n        }\r\n        var grad$$1 = function (dy) {\r\n            return { $x: function () { return zerosLike($x); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.argMin($x, axes[0]); }, { $x: $x }, grad$$1);\r\n    }\r\n    function argMax_(x, axis) {\r\n        if (axis === void 0) { axis = 0; }\r\n        var $x = convertToTensor(x, 'x', 'argMax');\r\n        if (axis == null) {\r\n            axis = 0;\r\n        }\r\n        var axes = parseAxisParam(axis, $x.shape);\r\n        var permutedAxes = getAxesPermutation(axes, $x.rank);\r\n        if (permutedAxes != null) {\r\n            $x = $x.transpose(permutedAxes);\r\n            axes = getInnerMostAxes(axes.length, $x.rank);\r\n        }\r\n        var grad$$1 = function (dy) {\r\n            return { $x: function () { return zerosLike($x); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.argMax($x, axes[0]); }, { $x: $x }, grad$$1);\r\n    }\r\n    function all_(x, axis, keepDims) {\r\n        if (axis === void 0) { axis = null; }\r\n        if (keepDims === void 0) { keepDims = false; }\r\n        var $x = convertToTensor(x, 'x', 'all', 'bool');\r\n        var origAxes = parseAxisParam(axis, $x.shape);\r\n        var axes = origAxes;\r\n        var permutedAxes = getAxesPermutation(axes, $x.rank);\r\n        if (permutedAxes != null) {\r\n            $x = $x.transpose(permutedAxes);\r\n            axes = getInnerMostAxes(axes.length, $x.rank);\r\n        }\r\n        var res = ENV.engine.runKernel(function (backend) { return backend.all($x, axes); }, { $x: $x });\r\n        if (keepDims) {\r\n            var newShape = expandShapeToKeepDim(res.shape, origAxes);\r\n            return res.reshape(newShape);\r\n        }\r\n        return res;\r\n    }\r\n    function any_(x, axis, keepDims) {\r\n        if (axis === void 0) { axis = null; }\r\n        if (keepDims === void 0) { keepDims = false; }\r\n        var $x = convertToTensor(x, 'x', 'any', 'bool');\r\n        var origAxes = parseAxisParam(axis, $x.shape);\r\n        var axes = origAxes;\r\n        var permutedAxes = getAxesPermutation(axes, $x.rank);\r\n        if (permutedAxes != null) {\r\n            $x = $x.transpose(permutedAxes);\r\n            axes = getInnerMostAxes(axes.length, $x.rank);\r\n        }\r\n        var res = ENV.engine.runKernel(function (backend) { return backend.any($x, axes); }, { $x: $x });\r\n        if (keepDims) {\r\n            var newShape = expandShapeToKeepDim(res.shape, origAxes);\r\n            return res.reshape(newShape);\r\n        }\r\n        return res;\r\n    }\r\n    function moments_(x, axis, keepDims) {\r\n        if (axis === void 0) { axis = null; }\r\n        if (keepDims === void 0) { keepDims = false; }\r\n        x = convertToTensor(x, 'x', 'moments');\r\n        var axes = parseAxisParam(axis, x.shape);\r\n        var mean = x.mean(axes, keepDims);\r\n        var keepDimsShape = mean.shape;\r\n        if (!keepDims) {\r\n            keepDimsShape = expandShapeToKeepDim(mean.shape, axes);\r\n        }\r\n        var devSquared = x.toFloat().sub(mean.reshape(keepDimsShape)).square();\r\n        var variance = devSquared.mean(axes, keepDims);\r\n        return { mean: mean, variance: variance };\r\n    }\r\n    var all = op({ all_: all_ });\r\n    var any = op({ any_: any_ });\r\n    var argMax = op({ argMax_: argMax_ });\r\n    var argMin = op({ argMin_: argMin_ });\r\n    var logSumExp = op({ logSumExp_: logSumExp_ });\r\n    var max = op({ max_: max_ });\r\n    var mean = op({ mean_: mean_ });\r\n    var min = op({ min_: min_ });\r\n    var moments = op({ moments_: moments_ });\r\n    var sum$1 = op({ sum_: sum_ });\r\n    var prod = op({ prod_: prod_ });\n\n    function notEqual_(a, b) {\r\n        var _a;\r\n        var $a = convertToTensor(a, 'a', 'notEqual');\r\n        var $b = convertToTensor(b, 'b', 'notEqual');\r\n        _a = makeTypesMatch($a, $b), $a = _a[0], $b = _a[1];\r\n        assertAndGetBroadcastShape($a.shape, $b.shape);\r\n        return ENV.engine.runKernel(function (backend) { return backend.notEqual($a, $b); }, { $a: $a, $b: $b });\r\n    }\r\n    function notEqualStrict_(a, b) {\r\n        var $a = convertToTensor(a, 'a', 'notEqualStrict');\r\n        var $b = convertToTensor(b, 'b', 'notEqualStrict');\r\n        assertShapesMatch($a.shape, $b.shape, 'Error in notEqualStrict: ');\r\n        return $a.notEqual($b);\r\n    }\r\n    function less_(a, b) {\r\n        var _a;\r\n        var $a = convertToTensor(a, 'a', 'less');\r\n        var $b = convertToTensor(b, 'b', 'less');\r\n        _a = makeTypesMatch($a, $b), $a = _a[0], $b = _a[1];\r\n        assertAndGetBroadcastShape($a.shape, $b.shape);\r\n        return ENV.engine.runKernel(function (backend) { return backend.less($a, $b); }, { $a: $a, $b: $b });\r\n    }\r\n    function lessStrict_(a, b) {\r\n        var $a = convertToTensor(a, 'a', 'lessStrict');\r\n        var $b = convertToTensor(b, 'b', 'lessStrict');\r\n        assertShapesMatch($a.shape, $b.shape, 'Error in lessStrict: ');\r\n        return $a.less($b);\r\n    }\r\n    function equal_(a, b) {\r\n        var _a;\r\n        var $a = convertToTensor(a, 'a', 'equal');\r\n        var $b = convertToTensor(b, 'b', 'equal');\r\n        _a = makeTypesMatch($a, $b), $a = _a[0], $b = _a[1];\r\n        assertAndGetBroadcastShape($a.shape, $b.shape);\r\n        return ENV.engine.runKernel(function (backend) { return backend.equal($a, $b); }, { $a: $a, $b: $b });\r\n    }\r\n    function equalStrict_(a, b) {\r\n        var $a = convertToTensor(a, 'a', 'equalStrict');\r\n        var $b = convertToTensor(b, 'b', 'equalStrict');\r\n        assertShapesMatch($a.shape, $b.shape, 'Error in equalStrict: ');\r\n        return $a.equal($b);\r\n    }\r\n    function lessEqual_(a, b) {\r\n        var _a;\r\n        var $a = convertToTensor(a, 'a', 'lessEqual');\r\n        var $b = convertToTensor(b, 'b', 'lessEqual');\r\n        _a = makeTypesMatch($a, $b), $a = _a[0], $b = _a[1];\r\n        assertAndGetBroadcastShape($a.shape, $b.shape);\r\n        return ENV.engine.runKernel(function (backend) { return backend.lessEqual($a, $b); }, { $a: $a, $b: $b });\r\n    }\r\n    function lessEqualStrict_(a, b) {\r\n        var $a = convertToTensor(a, 'a', 'lessEqualStrict');\r\n        var $b = convertToTensor(b, 'b', 'lessEqualStrict');\r\n        assertShapesMatch($a.shape, $b.shape, 'Error in lessEqualStrict: ');\r\n        return $a.lessEqual($b);\r\n    }\r\n    function greater_(a, b) {\r\n        var _a;\r\n        var $a = convertToTensor(a, 'a', 'greater');\r\n        var $b = convertToTensor(b, 'b', 'greater');\r\n        _a = makeTypesMatch($a, $b), $a = _a[0], $b = _a[1];\r\n        assertAndGetBroadcastShape($a.shape, $b.shape);\r\n        return ENV.engine.runKernel(function (backend) { return backend.greater($a, $b); }, { $a: $a, $b: $b });\r\n    }\r\n    function greaterStrict_(a, b) {\r\n        var $a = convertToTensor(a, 'a', 'greaterStrict');\r\n        var $b = convertToTensor(b, 'b', 'greaterStrict');\r\n        assertShapesMatch($a.shape, $b.shape, 'Error in greaterStrict: ');\r\n        return $a.greater($b);\r\n    }\r\n    function greaterEqual_(a, b) {\r\n        var _a;\r\n        var $a = convertToTensor(a, 'a', 'greaterEqual');\r\n        var $b = convertToTensor(b, 'b', 'greaterEqual');\r\n        _a = makeTypesMatch($a, $b), $a = _a[0], $b = _a[1];\r\n        assertAndGetBroadcastShape($a.shape, $b.shape);\r\n        var grad = function (dy) {\r\n            return { $a: function () { return zerosLike($a); }, $b: function () { return zerosLike($b); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.greaterEqual($a, $b); }, { $a: $a, $b: $b }, grad);\r\n    }\r\n    function greaterEqualStrict_(a, b) {\r\n        var $a = convertToTensor(a, 'a', 'greaterEqualStrict');\r\n        var $b = convertToTensor(b, 'b', 'greaterEqualStrict');\r\n        assertShapesMatch($a.shape, $b.shape, 'Error in greaterEqualStrict: ');\r\n        return $a.greaterEqual($b);\r\n    }\r\n    var equal = op({ equal_: equal_ });\r\n    var equalStrict = op({ equalStrict_: equalStrict_ });\r\n    var greater = op({ greater_: greater_ });\r\n    var greaterEqual = op({ greaterEqual_: greaterEqual_ });\r\n    var greaterEqualStrict = op({ greaterEqualStrict_: greaterEqualStrict_ });\r\n    var greaterStrict = op({ greaterStrict_: greaterStrict_ });\r\n    var less = op({ less_: less_ });\r\n    var lessEqual = op({ lessEqual_: lessEqual_ });\r\n    var lessEqualStrict = op({ lessEqualStrict_: lessEqualStrict_ });\r\n    var lessStrict = op({ lessStrict_: lessStrict_ });\r\n    var notEqual = op({ notEqual_: notEqual_ });\r\n    var notEqualStrict = op({ notEqualStrict_: notEqualStrict_ });\n\n    function add_(a, b) {\r\n        var _a;\r\n        var $a = convertToTensor(a, 'a', 'add');\r\n        var $b = convertToTensor(b, 'b', 'add');\r\n        _a = makeTypesMatch($a, $b), $a = _a[0], $b = _a[1];\r\n        var outShape = assertAndGetBroadcastShape($a.shape, $b.shape);\r\n        var der = function (dy) {\r\n            var derA = function () {\r\n                var res = dy;\r\n                var reduceAxes = getReductionAxes($a.shape, outShape);\r\n                if (reduceAxes.length > 0) {\r\n                    res = res.sum(reduceAxes);\r\n                }\r\n                return res.reshape($a.shape);\r\n            };\r\n            var derB = function () {\r\n                var res = dy;\r\n                var reduceAxes = getReductionAxes($b.shape, outShape);\r\n                if (reduceAxes.length > 0) {\r\n                    res = res.sum(reduceAxes);\r\n                }\r\n                return res.reshape($b.shape);\r\n            };\r\n            return { $a: derA, $b: derB };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.add($a, $b); }, { $a: $a, $b: $b }, der);\r\n    }\r\n    function addN_(tensors) {\r\n        assert(Array.isArray(tensors), function () { return 'The argument passed to tf.addN() must be a list of tensors'; });\r\n        assert(tensors.length >= 1, function () { return \"Must pass at least one tensor to tf.addN(), but got \" +\r\n            (\"\" + tensors.length); });\r\n        var $tensors = tensors.map(function (t, i) { return convertToTensor(t, \"tensors\" + i, 'addN'); });\r\n        var firstTensor = $tensors[0];\r\n        $tensors.forEach(function (t) {\r\n            if (t.dtype !== firstTensor.dtype) {\r\n                throw new Error('All tensors passed to tf.addN() must have the same dtype');\r\n            }\r\n        });\r\n        $tensors.forEach(function (t) {\r\n            if (!arraysEqual(t.shape, firstTensor.shape)) {\r\n                throw new Error('All tensors passed to tf.addN() must have the same shape');\r\n            }\r\n        });\r\n        var der = function (dy) {\r\n            var ders = {};\r\n            $tensors.forEach(function (t, i) {\r\n                ders[i] = function () { return dy.clone(); };\r\n            });\r\n            return ders;\r\n        };\r\n        var inputs = $tensors;\r\n        return ENV.engine.runKernel(function (backend) { return backend.addN($tensors); }, inputs, der);\r\n    }\r\n    function addStrict_(a, b) {\r\n        var $a = convertToTensor(a, 'a', 'addStrict');\r\n        var $b = convertToTensor(b, 'b', 'addStrict');\r\n        assertShapesMatch($a.shape, $b.shape, 'Error in addStrict: ');\r\n        return $a.add($b);\r\n    }\r\n    function sub_(a, b) {\r\n        var _a;\r\n        var $a = convertToTensor(a, 'a', 'sub');\r\n        var $b = convertToTensor(b, 'b', 'sub');\r\n        _a = makeTypesMatch($a, $b), $a = _a[0], $b = _a[1];\r\n        var outShape = assertAndGetBroadcastShape($a.shape, $b.shape);\r\n        var der = function (dy) {\r\n            var derA = function () {\r\n                var res = dy;\r\n                var reduceAxes = getReductionAxes($a.shape, outShape);\r\n                if (reduceAxes.length > 0) {\r\n                    res = res.sum(reduceAxes);\r\n                }\r\n                return res.reshape($a.shape);\r\n            };\r\n            var derB = function () {\r\n                var res = dy;\r\n                var reduceAxes = getReductionAxes($b.shape, outShape);\r\n                if (reduceAxes.length > 0) {\r\n                    res = res.sum(reduceAxes);\r\n                }\r\n                return res.neg().reshape($b.shape);\r\n            };\r\n            return { $a: derA, $b: derB };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.subtract($a, $b); }, { $a: $a, $b: $b }, der);\r\n    }\r\n    function subStrict_(a, b) {\r\n        var $a = convertToTensor(a, 'a', 'subStrict');\r\n        var $b = convertToTensor(b, 'b', 'subStrict');\r\n        assertShapesMatch($a.shape, $b.shape, 'Error in subStrict: ');\r\n        return $a.sub($b);\r\n    }\r\n    function pow_(base, exp$$1) {\r\n        var $base = convertToTensor(base, 'base', 'pow');\r\n        var $exp = convertToTensor(exp$$1, 'exp', 'pow');\r\n        var outShape = assertAndGetBroadcastShape($base.shape, $exp.shape);\r\n        base = $base.cast(upcastType($base.dtype, $exp.dtype));\r\n        exp$$1 = $exp.cast(upcastType($base.dtype, $exp.dtype));\r\n        var grad = function (dy, saved) {\r\n            var y = saved[0];\r\n            var derBase = function () {\r\n                var expFloat = $exp.toFloat();\r\n                var res = dy.mul(expFloat.mul($base.pow(expFloat.sub(scalar(1)))));\r\n                var reduceAxes = getReductionAxes($base.shape, outShape);\r\n                if (reduceAxes.length > 0) {\r\n                    res = res.sum(reduceAxes);\r\n                }\r\n                return res.reshape($base.shape);\r\n            };\r\n            var derExp = function () {\r\n                var condition = $base.greater(0);\r\n                var logBase = $base.log().where(condition, zerosLike($base));\r\n                var res = dy.mul(y.mul(logBase));\r\n                var reduceAxes = getReductionAxes($exp.shape, outShape);\r\n                if (reduceAxes.length > 0) {\r\n                    res = res.sum(reduceAxes);\r\n                }\r\n                return res.reshape($exp.shape);\r\n            };\r\n            return { $base: derBase, $exp: derExp };\r\n        };\r\n        return ENV.engine.runKernel(function (backend, save) { return save(backend.pow($base, $exp)); }, { $base: $base, $exp: $exp }, grad);\r\n    }\r\n    function powStrict_(base, exp$$1) {\r\n        assertShapesMatch(base.shape, exp$$1.shape, 'Error in powStrict: ');\r\n        return base.pow(exp$$1);\r\n    }\r\n    function mul_(a, b) {\r\n        var _a;\r\n        var $a = convertToTensor(a, 'a', 'mul');\r\n        var $b = convertToTensor(b, 'b', 'mul');\r\n        _a = makeTypesMatch($a, $b), $a = _a[0], $b = _a[1];\r\n        var outShape = assertAndGetBroadcastShape($a.shape, $b.shape);\r\n        var der = function (dy) {\r\n            var derA = function () {\r\n                var res = dy.mul($b.toFloat());\r\n                var reduceAxes = getReductionAxes($a.shape, outShape);\r\n                if (reduceAxes.length > 0) {\r\n                    return res.sum(reduceAxes).reshape($a.shape);\r\n                }\r\n                return res;\r\n            };\r\n            var derB = function () {\r\n                var res = dy.mul($a.toFloat());\r\n                var reduceAxes = getReductionAxes($b.shape, outShape);\r\n                if (reduceAxes.length > 0) {\r\n                    return res.sum(reduceAxes).reshape($b.shape);\r\n                }\r\n                return res;\r\n            };\r\n            return { $a: derA, $b: derB };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.multiply($a, $b); }, { $a: $a, $b: $b }, der);\r\n    }\r\n    function mulStrict_(a, b) {\r\n        var $a = convertToTensor(a, 'a', 'mul');\r\n        var $b = convertToTensor(b, 'b', 'mul');\r\n        assertShapesMatch($a.shape, $b.shape, 'Error in multiplyStrict: ');\r\n        return $a.mul($b);\r\n    }\r\n    function div_(a, b) {\r\n        var _a;\r\n        var $a = convertToTensor(a, 'a', 'div');\r\n        var $b = convertToTensor(b, 'b', 'div');\r\n        _a = makeTypesMatch($a, $b), $a = _a[0], $b = _a[1];\r\n        var forwardFunc;\r\n        if ($a.dtype === 'int32' && $b.dtype === 'int32') {\r\n            return floorDiv($a, $b);\r\n        }\r\n        else {\r\n            forwardFunc = function (backend) { return backend.realDivide($a, $b); };\r\n        }\r\n        var outShape = assertAndGetBroadcastShape($a.shape, $b.shape);\r\n        var der = function (dy) {\r\n            var derA = function () {\r\n                var res = dy.div($b.toFloat());\r\n                var reduceAxes = getReductionAxes($a.shape, outShape);\r\n                if (reduceAxes.length > 0) {\r\n                    return res.sum(reduceAxes).reshape($a.shape);\r\n                }\r\n                return res;\r\n            };\r\n            var derB = function () {\r\n                var res = dy.mul($a.toFloat());\r\n                var reduceAxes = getReductionAxes($b.shape, outShape);\r\n                if (reduceAxes.length > 0) {\r\n                    res = res.sum(reduceAxes).reshape($b.shape);\r\n                }\r\n                var tmp = $b.square();\r\n                return res.div(tmp.toFloat()).neg();\r\n            };\r\n            return { $a: derA, $b: derB };\r\n        };\r\n        return ENV.engine.runKernel(forwardFunc, { $a: $a, $b: $b }, der);\r\n    }\r\n    function floorDiv_(a, b) {\r\n        var _a;\r\n        var $a = convertToTensor(a, 'a', 'floorDiv');\r\n        var $b = convertToTensor(b, 'b', 'floorDiv');\r\n        _a = makeTypesMatch($a, $b), $a = _a[0], $b = _a[1];\r\n        var forwardFunc = function (backend) { return backend.floorDiv($a, $b); };\r\n        var outShape = assertAndGetBroadcastShape($a.shape, $b.shape);\r\n        var der = function (dy) {\r\n            var derA = function () {\r\n                var res = dy.div($b.toFloat());\r\n                var reduceAxes = getReductionAxes($a.shape, outShape);\r\n                if (reduceAxes.length > 0) {\r\n                    return res.sum(reduceAxes).reshape($a.shape);\r\n                }\r\n                return res;\r\n            };\r\n            var derB = function () {\r\n                var res = dy.mul($a.toFloat());\r\n                var reduceAxes = getReductionAxes($b.shape, outShape);\r\n                if (reduceAxes.length > 0) {\r\n                    res = res.sum(reduceAxes).reshape($b.shape);\r\n                }\r\n                var tmp = $b.square();\r\n                return res.div(tmp.toFloat()).neg();\r\n            };\r\n            return { $a: derA, $b: derB };\r\n        };\r\n        return ENV.engine.runKernel(forwardFunc, { $a: $a, $b: $b }, der);\r\n    }\r\n    function divStrict_(a, b) {\r\n        var $a = convertToTensor(a, 'a', 'div');\r\n        var $b = convertToTensor(b, 'b', 'div');\r\n        assertShapesMatch($a.shape, $b.shape, 'Error in divideStrict: ');\r\n        return $a.div($b);\r\n    }\r\n    function mod_(a, b) {\r\n        var _a;\r\n        var $a = convertToTensor(a, 'a', 'mod');\r\n        var $b = convertToTensor(b, 'b', 'mod');\r\n        _a = makeTypesMatch($a, $b), $a = _a[0], $b = _a[1];\r\n        var outShape = assertAndGetBroadcastShape($a.shape, $b.shape);\r\n        var der = function (dy) {\r\n            var derA = function () {\r\n                var reduceAxes = getReductionAxes($a.shape, outShape);\r\n                if (reduceAxes.length > 0) {\r\n                    return dy.sum(reduceAxes).reshape($a.shape);\r\n                }\r\n                return dy;\r\n            };\r\n            var derB = function () {\r\n                var res = dy.mul($a.div($b).floor().neg());\r\n                var reduceAxes = getReductionAxes($b.shape, outShape);\r\n                if (reduceAxes.length > 0) {\r\n                    return res.sum(reduceAxes).reshape($b.shape);\r\n                }\r\n                return res;\r\n            };\r\n            return { $a: derA, $b: derB };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.mod($a, $b); }, { $a: $a, $b: $b }, der);\r\n    }\r\n    function modStrict_(a, b) {\r\n        var $a = convertToTensor(a, 'a', 'modStrict');\r\n        var $b = convertToTensor(b, 'b', 'modStrict');\r\n        assertShapesMatch($a.shape, $b.shape, 'Error in modStrict: ');\r\n        return $a.mod($b);\r\n    }\r\n    function minimum_(a, b) {\r\n        var _a;\r\n        var $a = convertToTensor(a, 'a', 'minimum');\r\n        var $b = convertToTensor(b, 'b', 'minimum');\r\n        _a = makeTypesMatch($a, $b), $a = _a[0], $b = _a[1];\r\n        if ($a.dtype === 'bool') {\r\n            $a = $a.toInt();\r\n            $b = $b.toInt();\r\n        }\r\n        assertAndGetBroadcastShape($a.shape, $b.shape);\r\n        var der = function (dy) {\r\n            var derA = function () { return dy.mul($a.lessEqual($b).toFloat()); };\r\n            var derB = function () { return dy.mul($a.greater($b).toFloat()); };\r\n            return { $a: derA, $b: derB };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.minimum($a, $b); }, { $a: $a, $b: $b }, der);\r\n    }\r\n    function minimumStrict_(a, b) {\r\n        var $a = convertToTensor(a, 'a', 'minimumStrict');\r\n        var $b = convertToTensor(b, 'b', 'minimumStrict');\r\n        assertShapesMatch($a.shape, $b.shape, 'Error in minimumStrict: ');\r\n        return $a.minimum($b);\r\n    }\r\n    function maximum_(a, b) {\r\n        var _a;\r\n        var $a = convertToTensor(a, 'a', 'maximum');\r\n        var $b = convertToTensor(b, 'b', 'maximum');\r\n        _a = makeTypesMatch($a, $b), $a = _a[0], $b = _a[1];\r\n        if ($a.dtype === 'bool') {\r\n            $a = $a.toInt();\r\n            $b = $b.toInt();\r\n        }\r\n        assertAndGetBroadcastShape($a.shape, $b.shape);\r\n        var der = function (dy) {\r\n            var derA = function () { return dy.mul($a.greaterEqual($b).toFloat()); };\r\n            var derB = function () { return dy.mul($a.less($b).toFloat()); };\r\n            return { $a: derA, $b: derB };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.maximum($a, $b); }, { $a: $a, $b: $b }, der);\r\n    }\r\n    function maximumStrict_(a, b) {\r\n        var $a = convertToTensor(a, 'a', 'maximumStrict');\r\n        var $b = convertToTensor(b, 'b', 'maximumStrict');\r\n        assertShapesMatch($a.shape, $b.shape, 'Error in maximumStrict: ');\r\n        return $a.maximum($b);\r\n    }\r\n    function squaredDifference_(a, b) {\r\n        var _a;\r\n        var $a = convertToTensor(a, 'a', 'squaredDifference');\r\n        var $b = convertToTensor(b, 'b', 'squaredDifference');\r\n        _a = makeTypesMatch($a, $b), $a = _a[0], $b = _a[1];\r\n        assertAndGetBroadcastShape($a.shape, $b.shape);\r\n        var der = function (dy) {\r\n            var two = scalar(2);\r\n            var derA = function () { return dy.mul($a.sub($b).mul(two)); };\r\n            var derB = function () { return dy.mul($b.sub($a).mul(two)); };\r\n            return { $a: derA, $b: derB };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.squaredDifference($a, $b); }, { $a: $a, $b: $b }, der);\r\n    }\r\n    function squaredDifferenceStrict_(a, b) {\r\n        var $a = convertToTensor(a, 'a', 'squaredDifferenceStrict');\r\n        var $b = convertToTensor(b, 'b', 'squaredDifferenceStrict');\r\n        assertShapesMatch($a.shape, $b.shape, 'Error in squaredDifferenceStrict: ');\r\n        return $a.squaredDifference($b);\r\n    }\r\n    function atan2_(a, b) {\r\n        var _a;\r\n        var $a = convertToTensor(a, 'a', 'atan2');\r\n        var $b = convertToTensor(b, 'b', 'atan2');\r\n        _a = makeTypesMatch($a, $b), $a = _a[0], $b = _a[1];\r\n        var outShape = assertAndGetBroadcastShape($a.shape, $b.shape);\r\n        var der = function (dy) {\r\n            var derA = function () {\r\n                var d = add($a.square(), $b.square());\r\n                var res = dy.mul($b.div(d));\r\n                var reduceAxes = getReductionAxes($a.shape, outShape);\r\n                if (reduceAxes.length > 0) {\r\n                    res = res.sum(reduceAxes);\r\n                }\r\n                return res.reshape($a.shape);\r\n            };\r\n            var derB = function () {\r\n                var d = add($a.square(), $b.square());\r\n                var res = neg(dy.mul($a.div(d)));\r\n                var reduceAxes = getReductionAxes($b.shape, outShape);\r\n                if (reduceAxes.length > 0) {\r\n                    res = res.sum(reduceAxes);\r\n                }\r\n                return res.reshape($b.shape);\r\n            };\r\n            return { $a: derA, $b: derB };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.atan2($a, $b); }, { $a: $a, $b: $b }, der);\r\n    }\r\n    var add = op({ add_: add_ });\r\n    var addN = op({ addN_: addN_ });\r\n    var addStrict = op({ addStrict_: addStrict_ });\r\n    var atan2 = op({ atan2_: atan2_ });\r\n    var div = op({ div_: div_ });\r\n    var divStrict = op({ divStrict_: divStrict_ });\r\n    var floorDiv = op({ floorDiv_: floorDiv_ });\r\n    var maximum = op({ maximum_: maximum_ });\r\n    var maximumStrict = op({ maximumStrict_: maximumStrict_ });\r\n    var minimum = op({ minimum_: minimum_ });\r\n    var minimumStrict = op({ minimumStrict_: minimumStrict_ });\r\n    var mod = op({ mod_: mod_ });\r\n    var modStrict = op({ modStrict_: modStrict_ });\r\n    var mul = op({ mul_: mul_ });\r\n    var mulStrict = op({ mulStrict_: mulStrict_ });\r\n    var pow = op({ pow_: pow_ });\r\n    var powStrict = op({ powStrict_: powStrict_ });\r\n    var squaredDifference = op({ squaredDifference_: squaredDifference_ });\r\n    var squaredDifferenceStrict = op({ squaredDifferenceStrict_: squaredDifferenceStrict_ });\r\n    var sub = op({ sub_: sub_ });\r\n    var subStrict = op({ subStrict_: subStrict_ });\n\n    function logicalNot_(x) {\r\n        var $x = convertToTensor(x, 'x', 'logicalNot', 'bool');\r\n        return ENV.engine.runKernel(function (backend) { return backend.logicalNot($x); }, { $x: $x });\r\n    }\r\n    function logicalAnd_(a, b) {\r\n        var $a = convertToTensor(a, 'a', 'logicalAnd', 'bool');\r\n        var $b = convertToTensor(b, 'b', 'logicalAnd', 'bool');\r\n        assertAndGetBroadcastShape($a.shape, $b.shape);\r\n        return ENV.engine.runKernel(function (backend) { return backend.logicalAnd($a, $b); }, { $a: $a, $b: $b });\r\n    }\r\n    function logicalOr_(a, b) {\r\n        var $a = convertToTensor(a, 'a', 'logicalOr', 'bool');\r\n        var $b = convertToTensor(b, 'b', 'logicalOr', 'bool');\r\n        assertAndGetBroadcastShape($a.shape, $b.shape);\r\n        return ENV.engine.runKernel(function (backend) { return backend.logicalOr($a, $b); }, { $a: $a, $b: $b });\r\n    }\r\n    function logicalXor_(a, b) {\r\n        var $a = convertToTensor(a, 'a', 'logicalXor', 'bool');\r\n        var $b = convertToTensor(b, 'b', 'logicalXor', 'bool');\r\n        assertAndGetBroadcastShape($a.shape, $b.shape);\r\n        return logicalOr(a, b).logicalAnd(logicalAnd(a, b).logicalNot());\r\n    }\r\n    function where_(condition, a, b) {\r\n        var $a = convertToTensor(a, 'a', 'where');\r\n        var $b = convertToTensor(b, 'b', 'where');\r\n        var $condition = convertToTensor(condition, 'condition', 'where', 'bool');\r\n        assertShapesMatch($a.shape, $b.shape, 'Error in where: ');\r\n        if ($condition.rank === 1) {\r\n            assert($condition.shape[0] === $a.shape[0], 'The first dimension of `a` must match the size of `condition`.');\r\n        }\r\n        else {\r\n            assertShapesMatch($condition.shape, $b.shape, 'Error in where: ');\r\n        }\r\n        var grad = function (dy) { return ({\r\n            $condition: function () { return zerosLike($condition).toFloat(); },\r\n            $a: function () { return dy.mul($condition.cast(dy.dtype)); },\r\n            $b: function () { return dy.mul($condition.logicalNot().cast(dy.dtype)); }\r\n        }); };\r\n        return ENV.engine.runKernel(function (backend) { return backend.select($condition, $a, $b); }, { $condition: $condition, $a: $a, $b: $b }, grad);\r\n    }\r\n    function whereAsync_(condition) {\r\n        return __awaiter(this, void 0, void 0, function () {\r\n            var $condition, vals, res;\r\n            return __generator(this, function (_a) {\r\n                switch (_a.label) {\r\n                    case 0:\r\n                        $condition = convertToTensor(condition, 'condition', 'whereAsync', 'bool');\r\n                        return [4, $condition.data()];\r\n                    case 1:\r\n                        vals = _a.sent();\r\n                        res = whereImpl($condition.shape, vals);\r\n                        if (condition !== $condition) {\r\n                            $condition.dispose();\r\n                        }\r\n                        return [2, res];\r\n                }\r\n            });\r\n        });\r\n    }\r\n    var logicalAnd = op({ logicalAnd_: logicalAnd_ });\r\n    var logicalNot = op({ logicalNot_: logicalNot_ });\r\n    var logicalOr = op({ logicalOr_: logicalOr_ });\r\n    var logicalXor = op({ logicalXor_: logicalXor_ });\r\n    var where = op({ where_: where_ });\r\n    var whereAsync = whereAsync_;\n\n    function relu_(x) {\r\n        var $x = convertToTensor(x, 'x', 'relu');\r\n        if ($x.dtype === 'bool') {\r\n            return $x.toInt();\r\n        }\r\n        var grad = function (dy) {\r\n            var stepRes = $x.step();\r\n            return { $x: function () { return dy.mulStrict(stepRes.toFloat()); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.relu($x); }, { $x: $x }, grad);\r\n    }\r\n    function elu_(x) {\r\n        var $x = convertToTensor(x, 'x', 'elu');\r\n        var grad = function (dy, saved) {\r\n            var y = saved[0];\r\n            return {\r\n                $x: function () {\r\n                    return ENV.engine.runKernel(function (backend) { return backend.eluDer(dy, y); }, { dy: dy, y: y });\r\n                }\r\n            };\r\n        };\r\n        return ENV.engine.runKernel(function (backend, save) { return save(backend.elu($x)); }, { $x: $x }, grad);\r\n    }\r\n    function selu_(x) {\r\n        var $x = convertToTensor(x, 'x', 'selu');\r\n        var grad = function (dy) {\r\n            return {\r\n                $x: function () {\r\n                    var mask = $x.greater(scalar(0));\r\n                    var scaleAlpha = scalar(SELU_SCALEALPHA);\r\n                    var scale = scalar(SELU_SCALE);\r\n                    var greaterThanZeroDer = dy.mul(scale);\r\n                    var lessEqualZeroDer = dy.mul(scaleAlpha).mul($x.toFloat().exp());\r\n                    return where(mask, greaterThanZeroDer, lessEqualZeroDer);\r\n                }\r\n            };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.selu($x); }, { $x: $x }, grad);\r\n    }\r\n    function leakyRelu_(x, alpha) {\r\n        if (alpha === void 0) { alpha = 0.2; }\r\n        var $x = convertToTensor(x, 'x', 'leakyRelu');\r\n        return maximum(scalar(alpha).mul($x), $x);\r\n    }\r\n    function prelu_(x, alpha) {\r\n        var $x = convertToTensor(x, 'x', 'prelu');\r\n        var $alpha = convertToTensor(alpha, 'alpha', 'prelu');\r\n        var grad = function (dy) {\r\n            var mask = $x.greater(0);\r\n            return {\r\n                $x: function () { return where(mask, dy, dy.mul($alpha)); },\r\n                $alpha: function () {\r\n                    var res = where(mask, zerosLike(dy), dy.mul($x));\r\n                    var reduceAxes = getReductionAxes($alpha.shape, dy.shape);\r\n                    if (reduceAxes.length > 0) {\r\n                        res = res.sum(reduceAxes);\r\n                    }\r\n                    return res.reshape($alpha.shape);\r\n                }\r\n            };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.prelu($x, $alpha); }, { $x: $x, $alpha: $alpha }, grad);\r\n    }\r\n    var elu = op({ elu_: elu_ });\r\n    var leakyRelu = op({ leakyRelu_: leakyRelu_ });\r\n    var prelu = op({ prelu_: prelu_ });\r\n    var relu = op({ relu_: relu_ });\r\n    var selu = op({ selu_: selu_ });\n\n    function transpose_(x, perm) {\r\n        var $x = convertToTensor(x, 'x', 'transpose');\r\n        if (perm == null) {\r\n            perm = $x.shape.map(function (s, i) { return i; }).reverse();\r\n        }\r\n        assert($x.rank === perm.length, \"Error in transpose: rank of input \" + $x.rank + \" \" +\r\n            (\"must match length of perm \" + perm + \".\"));\r\n        perm.forEach(function (axis) {\r\n            assert(axis >= 0 && axis < $x.rank, \"All entries in 'perm' must be between 0 and \" + ($x.rank - 1) +\r\n                (\" but got \" + perm));\r\n        });\r\n        if ($x.rank <= 1) {\r\n            return $x.clone();\r\n        }\r\n        var der = function (dy) {\r\n            var undoPerm = getUndoAxesPermutation(perm);\r\n            return { $x: function () { return dy.transpose(undoPerm); } };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) { return backend.transpose($x, perm); }, { $x: $x }, der);\r\n    }\r\n    var transpose = op({ transpose_: transpose_ });\n\n    function localResponseNormalization_(x, depthRadius, bias, alpha, beta) {\r\n        if (depthRadius === void 0) { depthRadius = 5; }\r\n        if (bias === void 0) { bias = 1; }\r\n        if (alpha === void 0) { alpha = 1; }\r\n        if (beta === void 0) { beta = 0.5; }\r\n        var $x = convertToTensor(x, 'x', 'localResponseNormalization');\r\n        assert($x.rank === 4 || $x.rank === 3, \"Error in localResponseNormalization: x must be rank 3 or 4 but got\\n               rank \" + $x.rank + \".\");\r\n        assert(isInt(depthRadius), \"Error in localResponseNormalization: depthRadius must be an integer\\n                     but got depthRadius \" + depthRadius + \".\");\r\n        var x4D = $x;\r\n        var reshapedTo4D = false;\r\n        if ($x.rank === 3) {\r\n            reshapedTo4D = true;\r\n            x4D = $x.as4D(1, $x.shape[0], $x.shape[1], $x.shape[2]);\r\n        }\r\n        var backward = function (dy, saved) {\r\n            var outputImage = saved[0];\r\n            return {\r\n                x4D: function () { return ENV.engine.runKernel(function (backend) { return backend.LRNGrad(dy, x4D, outputImage, depthRadius, bias, alpha, beta); }, {}); }\r\n            };\r\n        };\r\n        var res = ENV.engine.runKernel(function (backend, save) { return save(backend.localResponseNormalization4D(x4D, depthRadius, bias, alpha, beta)); }, { x4D: x4D }, backward);\r\n        if (reshapedTo4D) {\r\n            return res.as3D(res.shape[1], res.shape[2], res.shape[3]);\r\n        }\r\n        else {\r\n            return res;\r\n        }\r\n    }\r\n    var localResponseNormalization = op({ localResponseNormalization_: localResponseNormalization_ });\n\n    function norm_(x, ord, axis, keepDims) {\r\n        if (ord === void 0) { ord = 'euclidean'; }\r\n        if (axis === void 0) { axis = null; }\r\n        if (keepDims === void 0) { keepDims = false; }\r\n        x = convertToTensor(x, 'x', 'norm');\r\n        var norm = normImpl(x, ord, axis);\r\n        var keepDimsShape = norm.shape;\r\n        if (keepDims) {\r\n            var axes = parseAxisParam(axis, x.shape);\r\n            keepDimsShape = expandShapeToKeepDim(norm.shape, axes);\r\n        }\r\n        return norm.reshape(keepDimsShape);\r\n    }\r\n    function normImpl(x, p, axis) {\r\n        if (axis === void 0) { axis = null; }\r\n        if (x.rank === 0) {\r\n            return x.abs();\r\n        }\r\n        if (x.rank !== 1 && axis === null) {\r\n            return normImpl(x.reshape([-1]), p, axis);\r\n        }\r\n        if (x.rank === 1 || typeof axis === 'number' ||\r\n            Array.isArray(axis) && axis.length === 1) {\r\n            if (p === 1) {\r\n                return x.abs().sum(axis);\r\n            }\r\n            if (p === Infinity) {\r\n                return x.abs().max(axis);\r\n            }\r\n            if (p === -Infinity) {\r\n                return x.abs().min(axis);\r\n            }\r\n            if (p === 'euclidean' || p === 2) {\r\n                return x.abs().pow(scalar(2, 'int32')).sum(axis).sqrt();\r\n            }\r\n            throw new Error(\"Error in norm: invalid ord value: \" + p);\r\n        }\r\n        if (Array.isArray(axis) && axis.length === 2) {\r\n            if (p === 1) {\r\n                return x.abs().sum(axis[0]).max(axis[1] - 1);\r\n            }\r\n            if (p === Infinity) {\r\n                return x.abs().sum(axis[1]).max(axis[0]);\r\n            }\r\n            if (p === -Infinity) {\r\n                return x.abs().sum(axis[1]).min(axis[0]);\r\n            }\r\n            if (p === 'fro' || p === 'euclidean') {\r\n                return x.square().sum(axis).sqrt();\r\n            }\r\n            throw new Error(\"Error in norm: invalid ord value: \" + p);\r\n        }\r\n        throw new Error(\"Error in norm: invalid axis: \" + axis);\r\n    }\r\n    var norm = op({ norm_: norm_ });\n\n    function unsortedSegmentSum_(x, segmentIds, numSegments) {\r\n        var $x = convertToTensor(x, 'x', 'unsortedSegmentSum');\r\n        var $segmentIds = convertToTensor(segmentIds, 'segmentIds', 'unsortedSegmentSum', 'int32');\r\n        assert(isInt(numSegments), 'numSegments must be of dtype int');\r\n        var gradFunc = function (dy) {\r\n            var derX = function () {\r\n                return gatherDropNegatives(dy, $segmentIds);\r\n            };\r\n            return { $x: derX };\r\n        };\r\n        return ENV.engine.runKernel(function (backend) {\r\n            return backend.unsortedSegmentSum($x, $segmentIds, numSegments);\r\n        }, { $x: $x }, gradFunc);\r\n    }\r\n    function gather_(x, indices, axis) {\r\n        if (axis === void 0) { axis = 0; }\r\n        var $x = convertToTensor(x, 'x', 'gather');\r\n        var $indices = convertToTensor(indices, 'indices', 'gather', 'int32');\r\n        axis = parseAxisParam(axis, $x.shape)[0];\r\n        var shapeInfo = collectGatherOpShapeInfo($x, $indices, axis);\r\n        var grad = function (dy) {\r\n            var derX = function () {\r\n                var paramsShape = $x.shape;\r\n                var indicesSize = $indices.size;\r\n                var outerShape = paramsShape.slice(0, axis);\r\n                var outerDims = outerShape.length;\r\n                var innerShape = paramsShape.slice(axis, paramsShape.length).slice(1);\r\n                var innerDims = innerShape.length;\r\n                var outerAxesIndices = arrayRange(0, outerDims);\r\n                var innerAxesIndices = arrayRange(outerDims + 1, outerDims + 1 + innerDims);\r\n                var valuesShape = arrayConcat([outerShape, [indicesSize], innerShape]);\r\n                var values = dy.reshape(valuesShape);\r\n                var reshapedIndices = $indices.reshape([indicesSize]);\r\n                var transposeDims = arrayConcat([[outerDims], outerAxesIndices, innerAxesIndices]);\r\n                var valuesTranspose = values.transpose(transposeDims);\r\n                var paramsGrad = unsortedSegmentSum(valuesTranspose, reshapedIndices, $x.shape[axis]);\r\n                var invertTransposeDims = getUndoAxesPermutation(transposeDims);\r\n                paramsGrad = paramsGrad.transpose(invertTransposeDims);\r\n                return paramsGrad;\r\n            };\r\n            return { $x: derX };\r\n        };\r\n        return (ENV.engine.runKernel(function (backend) { return backend.gather($x, $indices.flatten(), axis); }, { $x: $x }, grad))\r\n            .reshape(shapeInfo.outputShape);\r\n    }\r\n    function arrayRange(start, stop) {\r\n        var result = [];\r\n        for (var i = start; i < stop; ++i) {\r\n            result.push(i);\r\n        }\r\n        return result;\r\n    }\r\n    function arrayConcat(arrays) {\r\n        var result = [];\r\n        for (var i = 0; i < arrays.length; ++i) {\r\n            for (var j = 0; j < arrays[i].length; ++j) {\r\n                result.push(arrays[i][j]);\r\n            }\r\n        }\r\n        return result;\r\n    }\r\n    function gatherDropNegatives(x, indices) {\r\n        var zeroClippedIndices = maximum(indices, zerosLike(indices));\r\n        var gathered = gather(x, zeroClippedIndices);\r\n        var isPositive = greaterEqual(indices, scalar(0, 'int32'));\r\n        var numIters = gathered.rank - isPositive.rank;\r\n        for (var i = 0; i < numIters; ++i) {\r\n            isPositive = expandDims(isPositive, i + 1);\r\n        }\r\n        isPositive = logicalAnd(isPositive, ones$1(gathered.shape, 'bool'));\r\n        var zeroSlice = zerosLike(gathered);\r\n        return where(isPositive, gathered, zeroSlice);\r\n    }\r\n    var gather = op({ gather_: gather_ });\r\n    var unsortedSegmentSum = op({ unsortedSegmentSum_: unsortedSegmentSum_ });\n\n    function multiRNNCell_(lstmCells, data, c, h) {\r\n        var $data = convertToTensor(data, 'data', 'multiRNNCell');\r\n        var $c = convertToTensorArray(c, 'c', 'multiRNNCell');\r\n        var $h = convertToTensorArray(h, 'h', 'multiRNNCell');\r\n        var input = $data;\r\n        var newStates = [];\r\n        for (var i = 0; i < lstmCells.length; i++) {\r\n            var output = lstmCells[i](input, $c[i], $h[i]);\r\n            newStates.push(output[0]);\r\n            newStates.push(output[1]);\r\n            input = output[1];\r\n        }\r\n        var newC = [];\r\n        var newH = [];\r\n        for (var i = 0; i < newStates.length; i += 2) {\r\n            newC.push(newStates[i]);\r\n            newH.push(newStates[i + 1]);\r\n        }\r\n        return [newC, newH];\r\n    }\r\n    function basicLSTMCell_(forgetBias, lstmKernel, lstmBias, data, c, h) {\r\n        var $forgetBias = convertToTensor(forgetBias, 'forgetBias', 'basicLSTMCell');\r\n        var $lstmKernel = convertToTensor(lstmKernel, 'lstmKernel', 'basicLSTMCell');\r\n        var $lstmBias = convertToTensor(lstmBias, 'lstmBias', 'basicLSTMCell');\r\n        var $data = convertToTensor(data, 'data', 'basicLSTMCell');\r\n        var $c = convertToTensor(c, 'c', 'basicLSTMCell');\r\n        var $h = convertToTensor(h, 'h', 'basicLSTMCell');\r\n        var combined = $data.concat($h, 1);\r\n        var weighted = combined.matMul($lstmKernel);\r\n        var res = weighted.add($lstmBias);\r\n        var batchSize = res.shape[0];\r\n        var sliceCols = res.shape[1] / 4;\r\n        var sliceSize = [batchSize, sliceCols];\r\n        var i = res.slice([0, 0], sliceSize);\r\n        var j = res.slice([0, sliceCols], sliceSize);\r\n        var f = res.slice([0, sliceCols * 2], sliceSize);\r\n        var o = res.slice([0, sliceCols * 3], sliceSize);\r\n        var newC = i.sigmoid().mulStrict(j.tanh()).addStrict($c.mulStrict($forgetBias.add(f).sigmoid()));\r\n        var newH = newC.tanh().mulStrict(o.sigmoid());\r\n        return [newC, newH];\r\n    }\r\n    var basicLSTMCell = op({ basicLSTMCell_: basicLSTMCell_ });\r\n    var multiRNNCell = op({ multiRNNCell_: multiRNNCell_ });\n\n    function movingAverage_(v, x, decay, step, zeroDebias) {\r\n        if (zeroDebias === void 0) { zeroDebias = true; }\r\n        var $v = convertToTensor(v, 'v', 'movingAverage');\r\n        var $x = convertToTensor(x, 'x', 'movingAverage');\r\n        var $decay = convertToTensor(decay, 'decay', 'movingAverage');\r\n        assertTypesMatch($v, $x);\r\n        assert(arraysEqual($v.shape, $x.shape), 'Shape mismatch in v and x');\r\n        var one = scalar(1);\r\n        var oneMinusDecay = one.sub($decay);\r\n        var update = $x.sub($v).mul(oneMinusDecay);\r\n        if (zeroDebias) {\r\n            assert(step != null, 'When using zeroDebias: true, step is required.');\r\n            var $step = convertToTensor(step, 'step', 'movingAverage');\r\n            update = update.div(one.sub(pow($decay, $step)));\r\n        }\r\n        return $v.add(update);\r\n    }\r\n    var movingAverage = op({ movingAverage_: movingAverage_ });\n\n    function stridedSlice_(x, begin, end, strides, beginMask, endMask, ellipsisMask, newAxisMask, shrinkAxisMask) {\r\n        if (beginMask === void 0) { beginMask = 0; }\r\n        if (endMask === void 0) { endMask = 0; }\r\n        if (ellipsisMask === void 0) { ellipsisMask = 0; }\r\n        if (newAxisMask === void 0) { newAxisMask = 0; }\r\n        if (shrinkAxisMask === void 0) { shrinkAxisMask = 0; }\r\n        if (ellipsisMask !== 0) {\r\n            throw new Error('ellipsis mask is not yet supported');\r\n        }\r\n        if (newAxisMask !== 0) {\r\n            throw new Error('new axis mask is not yet supported');\r\n        }\r\n        var $x = convertToTensor(x, 'x', 'stridedSlice');\r\n        var nonStrided = strides.every(function (v) { return v === 1; });\r\n        if (nonStrided) {\r\n            var _a = getStridedSlicedInfo($x.shape, begin, end, strides, beginMask, endMask, ellipsisMask, newAxisMask, shrinkAxisMask), beginIndex = _a[0], size = _a[1], shrinkAxis_1 = _a[2];\r\n            var outShape = size.filter(function (_, index) { return shrinkAxis_1.indexOf(index) === -1; });\r\n            return slice($x, beginIndex, size).reshape(outShape);\r\n        }\r\n        return ENV.engine.runKernel(function (backend) { return backend.stridedSlice($x, begin, end, strides, beginMask, endMask, ellipsisMask, newAxisMask, shrinkAxisMask); }, { $x: $x });\r\n    }\r\n    var stridedSlice = op({ stridedSlice_: stridedSlice_ });\n\n    function topk_(x, k, sorted) {\r\n        if (k === void 0) { k = 1; }\r\n        if (sorted === void 0) { sorted = true; }\r\n        var $x = convertToTensor(x, 'x', 'topk');\r\n        if ($x.rank === 0) {\r\n            throw new Error('topk() expects the input to be of rank 1 or higher');\r\n        }\r\n        var lastDim = $x.shape[$x.shape.length - 1];\r\n        if (k > lastDim) {\r\n            throw new Error(\"'k' passed to topk() must be <= the last dimension (\" + lastDim + \") \" +\r\n                (\"but got \" + k));\r\n        }\r\n        var _a = ENV.engine.runKernel(function (b) { return b.topk($x, k, sorted); }, { $x: $x }), values = _a[0], indices = _a[1];\r\n        return { values: values, indices: indices };\r\n    }\r\n    var topk = op({ topk_: topk_ });\n\n    function scatterND_(indices, updates, shape) {\r\n        var $indices = convertToTensor(indices, 'indices', 'scatterND', 'int32');\r\n        var $updates = convertToTensor(updates, 'updates', 'scatterND');\r\n        validateInput($updates, $indices, shape);\r\n        return ENV.engine.runKernel(function (backend) { return backend.scatterND($indices, $updates, shape); }, { $indices: $indices, $updates: $updates });\r\n    }\r\n    var scatterND = op({ scatterND_: scatterND_ });\n\n    function fft_(input) {\r\n        assert(input.dtype === 'complex64', \"The dtype for tf.spectral.fft() must be complex64 \" +\r\n            (\"but got \" + input.dtype + \".\"));\r\n        var innerDimensionSize = input.shape[input.shape.length - 1];\r\n        var batch = input.size / innerDimensionSize;\r\n        var input2D = input.as2D(batch, innerDimensionSize);\r\n        var ret = ENV.engine.runKernel(function (backend) { return backend.fft(input2D); }, { input: input });\r\n        return ret.reshape(input.shape);\r\n    }\r\n    function ifft_(input) {\r\n        assert(input.dtype === 'complex64', \"The dtype for tf.spectral.ifft() must be complex64 \" +\r\n            (\"but got \" + input.dtype + \".\"));\r\n        var innerDimensionSize = input.shape[input.shape.length - 1];\r\n        var batch = input.size / innerDimensionSize;\r\n        var input2D = input.as2D(batch, innerDimensionSize);\r\n        var ret = ENV.engine.runKernel(function (backend) { return backend.ifft(input2D); }, { input: input });\r\n        return ret.reshape(input.shape);\r\n    }\r\n    function rfft_(input) {\r\n        assert(input.dtype === 'float32', \"The dtype for rfft() must be real value but\\n    got \" + input.dtype);\r\n        var innerDimensionSize = input.shape[input.shape.length - 1];\r\n        var batch = input.size / innerDimensionSize;\r\n        var zeros$$1 = input.zerosLike();\r\n        var complexInput = complex(input, zeros$$1).as2D(batch, innerDimensionSize);\r\n        var ret = fft(complexInput);\r\n        var half = Math.floor(innerDimensionSize / 2) + 1;\r\n        var realValues = real(ret);\r\n        var imagValues = imag(ret);\r\n        var realComplexConjugate = realValues.split([half, innerDimensionSize - half], realValues.shape.length - 1);\r\n        var imagComplexConjugate = imagValues.split([half, innerDimensionSize - half], imagValues.shape.length - 1);\r\n        var outputShape = input.shape.slice();\r\n        outputShape[input.shape.length - 1] = half;\r\n        return complex(realComplexConjugate[0], imagComplexConjugate[0])\r\n            .reshape(outputShape);\r\n    }\r\n    function irfft_(input) {\r\n        var innerDimensionSize = input.shape[input.shape.length - 1];\r\n        var batch = input.size / innerDimensionSize;\r\n        if (innerDimensionSize <= 2) {\r\n            var complexInput = input.as2D(batch, innerDimensionSize);\r\n            var ret = ifft(complexInput);\r\n            return real(ret);\r\n        }\r\n        else {\r\n            var outputShape = [batch, 2 * (innerDimensionSize - 1)];\r\n            var realInput = real(input).as2D(batch, innerDimensionSize);\r\n            var imagInput = imag(input).as2D(batch, innerDimensionSize);\r\n            var realConjugate = realInput.slice([0, 1], [batch, innerDimensionSize - 2]).reverse(1);\r\n            var imagConjugate = imagInput.slice([0, 1], [batch, innerDimensionSize - 2])\r\n                .reverse(1)\r\n                .mul(scalar(-1));\r\n            var r = realInput.concat(realConjugate, 1);\r\n            var i = imagInput.concat(imagConjugate, 1);\r\n            var complexInput = complex(r, i).as2D(outputShape[0], outputShape[1]);\r\n            var ret = ifft(complexInput);\r\n            return real(ret);\r\n        }\r\n    }\r\n    var fft = op({ fft_: fft_ });\r\n    var ifft = op({ ifft_: ifft_ });\r\n    var rfft = op({ rfft_: rfft_ });\r\n    var irfft = op({ irfft_: irfft_ });\n\n    var spectral_ops = /*#__PURE__*/Object.freeze({\n        fft: fft,\n        ifft: ifft,\n        rfft: rfft,\n        irfft: irfft\n    });\n\n    function validateInput$1(sparseIndices, sparseValues, outputShape, defaultValues) {\r\n        if (sparseIndices.dtype !== 'int32') {\r\n            throw new Error('tf.sparseToDense() expects the indices to be int32 type,' +\r\n                (\" but the dtype was \" + sparseIndices.dtype + \".\"));\r\n        }\r\n        if (sparseIndices.rank > 2) {\r\n            throw new Error('sparseIndices should be a scalar, vector, or matrix,' +\r\n                (\" but got shape \" + sparseIndices.shape + \".\"));\r\n        }\r\n        var numElems = sparseIndices.rank > 0 ? sparseIndices.shape[0] : 1;\r\n        var numDims = sparseIndices.rank > 1 ? sparseIndices.shape[1] : 1;\r\n        if (outputShape.length !== numDims) {\r\n            throw new Error('outputShape has incorrect number of elements:,' +\r\n                (\" \" + outputShape.length + \", should be: \" + numDims + \".\"));\r\n        }\r\n        var numValues = sparseValues.size;\r\n        if (!(sparseValues.rank === 0 ||\r\n            sparseValues.rank === 1 && numValues === numElems)) {\r\n            throw new Error('sparseValues has incorrect shape ' +\r\n                (sparseValues.shape + \", should be [] or [\" + numElems + \"]\"));\r\n        }\r\n        if (sparseValues.dtype !== defaultValues.dtype) {\r\n            throw new Error('sparseValues.dtype must match defaultValues.dtype');\r\n        }\r\n    }\n\n    function sparseToDense_(sparseIndices, sparseValues, outputShape, defaultValue) {\r\n        var $sparseIndices = convertToTensor(sparseIndices, 'sparseIndices', 'sparseToDense', 'int32');\r\n        var $sparseValues = convertToTensor(sparseValues, 'sparseValues', 'sparseToDense');\r\n        var $defaultValue = convertToTensor(defaultValue, 'defaultValue', 'sparseToDense', $sparseValues.dtype);\r\n        validateInput$1($sparseIndices, $sparseValues, outputShape, $defaultValue);\r\n        return ENV.engine.runKernel(function (backend) { return backend.sparseToDense($sparseIndices, $sparseValues, outputShape, $defaultValue); }, { $sparseIndices: $sparseIndices, $sparseValues: $sparseValues, $defaultValue: $defaultValue });\r\n    }\r\n    var sparseToDense = op({ sparseToDense_: sparseToDense_ });\n\n    function gatherND_(x, indices) {\r\n        var $indices = convertToTensor(indices, 'indices', 'gatherND', 'int32');\r\n        var $x = convertToTensor(x, 'x', 'gatherND');\r\n        return ENV.engine.runKernel(function (backend) { return backend.gatherND($x, $indices); }, { $x: $x, $indices: $indices });\r\n    }\r\n    var gatherND = op({ gatherND_: gatherND_ });\n\n    (function (Reduction) {\r\n        Reduction[Reduction[\"NONE\"] = 0] = \"NONE\";\r\n        Reduction[Reduction[\"MEAN\"] = 1] = \"MEAN\";\r\n        Reduction[Reduction[\"SUM\"] = 2] = \"SUM\";\r\n        Reduction[Reduction[\"SUM_BY_NONZERO_WEIGHTS\"] = 3] = \"SUM_BY_NONZERO_WEIGHTS\";\r\n    })(exports.Reduction || (exports.Reduction = {}));\r\n    function computeWeightedLoss_(losses, weights, reduction) {\r\n        if (reduction === void 0) { reduction = exports.Reduction.SUM_BY_NONZERO_WEIGHTS; }\r\n        var $losses = convertToTensor(losses, 'losses', 'computeWeightedLoss');\r\n        var $weights = null;\r\n        if (weights != null) {\r\n            $weights = convertToTensor(weights, 'weights', 'computeWeightedLoss');\r\n        }\r\n        var weightedLoss = ($weights == null) ? $losses : $losses.mul($weights);\r\n        if (reduction === exports.Reduction.NONE) {\r\n            return weightedLoss;\r\n        }\r\n        if (reduction === exports.Reduction.SUM) {\r\n            return weightedLoss.sum();\r\n        }\r\n        if (reduction === exports.Reduction.MEAN) {\r\n            if ($weights == null) {\r\n                return weightedLoss.mean();\r\n            }\r\n            else {\r\n                var broadcastFactor = sizeFromShape($losses.shape) / sizeFromShape($weights.shape);\r\n                var result = weightedLoss.sum().div($weights.sum());\r\n                return broadcastFactor > 1 ? result.div(scalar(broadcastFactor)) :\r\n                    result;\r\n            }\r\n        }\r\n        if (reduction === exports.Reduction.SUM_BY_NONZERO_WEIGHTS) {\r\n            if ($weights == null) {\r\n                return weightedLoss.sum().div(scalar($losses.size));\r\n            }\r\n            else {\r\n                var broadcastedWeights = $weights.mul(ones$1($losses.shape));\r\n                var numNonZeros = broadcastedWeights.notEqual(scalar(0)).sum().toFloat();\r\n                return weightedLoss.sum().div(numNonZeros);\r\n            }\r\n        }\r\n        throw Error(\"Unknown reduction: \" + reduction);\r\n    }\r\n    function absoluteDifference_(labels, predictions, weights, reduction) {\r\n        if (reduction === void 0) { reduction = exports.Reduction.SUM_BY_NONZERO_WEIGHTS; }\r\n        var $labels = convertToTensor(labels, 'labels', 'absoluteDifference');\r\n        var $predictions = convertToTensor(predictions, 'predictions', 'absoluteDifference');\r\n        var $weights = null;\r\n        if (weights != null) {\r\n            $weights = convertToTensor(weights, 'weights', 'absoluteDifference');\r\n        }\r\n        assertShapesMatch($labels.shape, $predictions.shape, 'Error in absoluteDifference: ');\r\n        var losses = $labels.sub($predictions).abs();\r\n        return computeWeightedLoss(losses, $weights, reduction);\r\n    }\r\n    function meanSquaredError_(labels, predictions, weights, reduction) {\r\n        if (reduction === void 0) { reduction = exports.Reduction.SUM_BY_NONZERO_WEIGHTS; }\r\n        var $labels = convertToTensor(labels, 'labels', 'meanSquaredError');\r\n        var $predictions = convertToTensor(predictions, 'predictions', 'meanSquaredError');\r\n        var $weights = null;\r\n        if (weights != null) {\r\n            $weights = convertToTensor(weights, 'weights', 'meanSquaredError');\r\n        }\r\n        assertShapesMatch($labels.shape, $predictions.shape, 'Error in meanSquaredError: ');\r\n        var losses = $labels.squaredDifference($predictions);\r\n        return computeWeightedLoss(losses, $weights, reduction);\r\n    }\r\n    function cosineDistance_(labels, predictions, axis, weights, reduction) {\r\n        if (reduction === void 0) { reduction = exports.Reduction.SUM_BY_NONZERO_WEIGHTS; }\r\n        var $labels = convertToTensor(labels, 'labels', 'cosineDistance');\r\n        var $predictions = convertToTensor(predictions, 'predictions', 'cosineDistance');\r\n        var $weights = null;\r\n        if (weights != null) {\r\n            $weights = convertToTensor(weights, 'weights', 'cosineDistance');\r\n        }\r\n        assertShapesMatch($labels.shape, $predictions.shape, 'Error in cosineDistance: ');\r\n        var one = scalar(1);\r\n        var losses = one.sub($labels.mul($predictions).sum(axis, true));\r\n        return computeWeightedLoss(losses, $weights, reduction);\r\n    }\r\n    function hingeLoss_(labels, predictions, weights, reduction) {\r\n        if (reduction === void 0) { reduction = exports.Reduction.SUM_BY_NONZERO_WEIGHTS; }\r\n        var $labels = convertToTensor(labels, 'labels', 'hingeLoss');\r\n        var $predictions = convertToTensor(predictions, 'predictions', 'hingeLoss');\r\n        var $weights = null;\r\n        if (weights != null) {\r\n            $weights = convertToTensor(weights, 'weights', 'hingeLoss');\r\n        }\r\n        assertShapesMatch($labels.shape, $predictions.shape, 'Error in hingeLoss: ');\r\n        var one = scalar(1);\r\n        $labels = scalar(2).mul($labels).sub(one);\r\n        var losses = one.sub($labels.mul($predictions)).relu();\r\n        return computeWeightedLoss(losses, $weights, reduction);\r\n    }\r\n    function logLoss_(labels, predictions, weights, epsilon, reduction) {\r\n        if (epsilon === void 0) { epsilon = 1e-7; }\r\n        if (reduction === void 0) { reduction = exports.Reduction.SUM_BY_NONZERO_WEIGHTS; }\r\n        var $labels = convertToTensor(labels, 'labels', 'logLoss');\r\n        var $predictions = convertToTensor(predictions, 'predictions', 'logLoss');\r\n        var $weights = null;\r\n        if (weights != null) {\r\n            $weights = convertToTensor(weights, 'weights', 'logLoss');\r\n        }\r\n        assertShapesMatch($labels.shape, $predictions.shape, 'Error in logLoss: ');\r\n        var one = scalar(1);\r\n        var epsilonScalar = scalar(epsilon);\r\n        var losses = $labels.mul($predictions.add(epsilonScalar).log())\r\n            .neg()\r\n            .sub(one.sub($labels).mul(one.sub($predictions).add(epsilonScalar).log()));\r\n        return computeWeightedLoss(losses, $weights, reduction);\r\n    }\r\n    function sigmoidCrossEntropyWithLogits_(labels, logits) {\r\n        var $labels = convertToTensor(labels, 'labels', 'sigmoidCrossEntropyWithLogits');\r\n        var $logits = convertToTensor(logits, 'logits', 'sigmoidCrossEntropyWithLogits');\r\n        assertShapesMatch($labels.shape, $logits.shape, 'Error in sigmoidCrossEntropyWithLogits: ');\r\n        var maxOutput = $logits.relu();\r\n        var outputXTarget = $logits.mul($labels);\r\n        var sigmoidOutput = $logits.abs().neg().exp().log1p();\r\n        return maxOutput.sub(outputXTarget).add(sigmoidOutput);\r\n    }\r\n    function sigmoidCrossEntropy_(multiClassLabels, logits, weights, labelSmoothing, reduction) {\r\n        if (labelSmoothing === void 0) { labelSmoothing = 0; }\r\n        if (reduction === void 0) { reduction = exports.Reduction.SUM_BY_NONZERO_WEIGHTS; }\r\n        var $multiClassLabels = convertToTensor(multiClassLabels, 'multiClassLabels', 'sigmoidCrossEntropy');\r\n        var $logits = convertToTensor(logits, 'logits', 'sigmoidCrossEntropy');\r\n        var $weights = null;\r\n        if (weights != null) {\r\n            $weights = convertToTensor(weights, 'weights', 'sigmoidCrossEntropy');\r\n        }\r\n        assertShapesMatch($multiClassLabels.shape, $logits.shape, 'Error in sigmoidCrossEntropy: ');\r\n        if (labelSmoothing > 0) {\r\n            var labelSmoothingScalar = scalar(labelSmoothing);\r\n            var one = scalar(1);\r\n            var half = scalar(0.5);\r\n            $multiClassLabels = $multiClassLabels.mul(one.sub(labelSmoothingScalar))\r\n                .add(half.mul(labelSmoothingScalar));\r\n        }\r\n        var losses = sigmoidCrossEntropyWithLogits_($multiClassLabels, $logits);\r\n        return computeWeightedLoss(losses, $weights, reduction);\r\n    }\r\n    function huberLoss_(labels, predictions, weights, delta, reduction) {\r\n        if (delta === void 0) { delta = 1.0; }\r\n        if (reduction === void 0) { reduction = exports.Reduction.SUM_BY_NONZERO_WEIGHTS; }\r\n        var $labels = convertToTensor(labels, 'labels', 'huberLoss');\r\n        var $predictions = convertToTensor(predictions, 'predictions', 'huberLoss');\r\n        var $weights = null;\r\n        if (weights != null) {\r\n            $weights = convertToTensor(weights, 'weights', 'huberLoss');\r\n        }\r\n        assertShapesMatch($labels.shape, $predictions.shape, 'Error in huberLoss: ');\r\n        var deltaScalar = scalar(delta);\r\n        var error = $predictions.sub($labels).abs();\r\n        var quadratic = minimum(error, deltaScalar);\r\n        var linear = error.sub(quadratic);\r\n        var losses = scalar(0.5).mul(quadratic.square()).add(deltaScalar.mul(linear));\r\n        return computeWeightedLoss(losses, $weights, reduction);\r\n    }\r\n    function softmaxCrossEntropyWithLogits_(labels, logits, dim) {\r\n        if (dim === void 0) { dim = -1; }\r\n        if (dim === -1) {\r\n            dim = logits.rank - 1;\r\n        }\r\n        if (dim !== logits.rank - 1) {\r\n            throw Error(\"Softmax cross entropy along a non-last dimension is not yet \" +\r\n                (\"supported. Labels / logits was rank \" + logits.rank + \" \") +\r\n                (\"and dim was \" + dim));\r\n        }\r\n        var customOp = customGrad(function (labels, logits) {\r\n            var keepDims = true;\r\n            var lse = logits.logSumExp([dim], keepDims);\r\n            var logResult = logits.toFloat().sub(lse);\r\n            var costVector = logResult.mul(labels).neg();\r\n            var value = costVector.sum([dim]);\r\n            var gradFunc = function (dy) {\r\n                var dyShape = expandShapeToKeepDim(dy.shape, [dim]);\r\n                return [\r\n                    dy.reshape(dyShape).mul(labels.toFloat().sub(logResult.exp())),\r\n                    dy.reshape(dyShape).mul(logResult.exp().sub(labels.toFloat())),\r\n                ];\r\n            };\r\n            return { value: value, gradFunc: gradFunc };\r\n        });\r\n        return customOp(labels, logits);\r\n    }\r\n    function softmaxCrossEntropy_(onehotLabels, logits, weights, labelSmoothing, reduction) {\r\n        if (labelSmoothing === void 0) { labelSmoothing = 0; }\r\n        if (reduction === void 0) { reduction = exports.Reduction.SUM_BY_NONZERO_WEIGHTS; }\r\n        var $onehotLabels = convertToTensor(onehotLabels, 'onehotLabels', 'softmaxCrossEntropy');\r\n        var $logits = convertToTensor(logits, 'logits', 'softmaxCrossEntropy');\r\n        var $weights = null;\r\n        if (weights != null) {\r\n            $weights = convertToTensor(weights, 'weights', 'softmaxCrossEntropy');\r\n        }\r\n        assertShapesMatch($onehotLabels.shape, $logits.shape, 'Error in softmaxCrossEntropy: ');\r\n        if (labelSmoothing > 0) {\r\n            var labelSmoothingScalar = scalar(labelSmoothing);\r\n            var one = scalar(1);\r\n            var numClasses = scalar($onehotLabels.shape[1]);\r\n            $onehotLabels = $onehotLabels.mul(one.sub(labelSmoothingScalar))\r\n                .add(labelSmoothingScalar.div(numClasses));\r\n        }\r\n        var losses = softmaxCrossEntropyWithLogits_($onehotLabels, $logits);\r\n        return computeWeightedLoss(losses, $weights, reduction);\r\n    }\r\n    var absoluteDifference = op({ absoluteDifference_: absoluteDifference_ });\r\n    var computeWeightedLoss = op({ computeWeightedLoss_: computeWeightedLoss_ });\r\n    var cosineDistance = op({ cosineDistance_: cosineDistance_ });\r\n    var hingeLoss = op({ hingeLoss_: hingeLoss_ });\r\n    var huberLoss = op({ huberLoss_: huberLoss_ });\r\n    var logLoss = op({ logLoss_: logLoss_ });\r\n    var meanSquaredError = op({ meanSquaredError_: meanSquaredError_ });\r\n    var sigmoidCrossEntropy = op({ sigmoidCrossEntropy_: sigmoidCrossEntropy_ });\r\n    var softmaxCrossEntropy = op({ softmaxCrossEntropy_: softmaxCrossEntropy_ });\n\n    var loss_ops = /*#__PURE__*/Object.freeze({\n        get Reduction () { return exports.Reduction; },\n        absoluteDifference: absoluteDifference,\n        computeWeightedLoss: computeWeightedLoss,\n        cosineDistance: cosineDistance,\n        hingeLoss: hingeLoss,\n        huberLoss: huberLoss,\n        logLoss: logLoss,\n        meanSquaredError: meanSquaredError,\n        sigmoidCrossEntropy: sigmoidCrossEntropy,\n        softmaxCrossEntropy: softmaxCrossEntropy\n    });\n\n    function gramSchmidt_(xs) {\r\n        var inputIsTensor2D;\r\n        if (Array.isArray(xs)) {\r\n            inputIsTensor2D = false;\r\n            assert(xs != null && xs.length > 0, 'Gram-Schmidt process: input must not be null, undefined, or empty');\r\n            var dim = xs[0].shape[0];\r\n            for (var i = 1; i < xs.length; ++i) {\r\n                assert(xs[i].shape[0] === dim, 'Gram-Schmidt: Non-unique lengths found in the input vectors: ' +\r\n                    (\"(\" + xs[i].shape[0] + \" vs. \" + dim + \")\"));\r\n            }\r\n        }\r\n        else {\r\n            inputIsTensor2D = true;\r\n            xs = split$1(xs, xs.shape[0], 0).map(function (x) { return squeeze(x, [0]); });\r\n        }\r\n        assert(xs.length <= xs[0].shape[0], \"Gram-Schmidt: Number of vectors (\" + xs.length + \") exceeds \" +\r\n            (\"number of dimensions (\" + xs[0].shape[0] + \").\"));\r\n        var ys = [];\r\n        var xs1d = xs;\r\n        var _loop_1 = function (i) {\r\n            ys.push(ENV.engine.tidy(function () {\r\n                var x = xs1d[i];\r\n                if (i > 0) {\r\n                    for (var j = 0; j < i; ++j) {\r\n                        var proj = sum$1(ys[j].mulStrict(x)).mul(ys[j]);\r\n                        x = x.sub(proj);\r\n                    }\r\n                }\r\n                return x.div(norm(x, 'euclidean'));\r\n            }));\r\n        };\r\n        for (var i = 0; i < xs.length; ++i) {\r\n            _loop_1(i);\r\n        }\r\n        if (inputIsTensor2D) {\r\n            return stack(ys, 0);\r\n        }\r\n        else {\r\n            return ys;\r\n        }\r\n    }\r\n    function qr_(x, fullMatrices) {\r\n        if (fullMatrices === void 0) { fullMatrices = false; }\r\n        if (x.rank < 2) {\r\n            throw new Error(\"qr() requires input tensor to have a rank >= 2, but got rank \" + x.rank);\r\n        }\r\n        else if (x.rank === 2) {\r\n            return qr2d(x, fullMatrices);\r\n        }\r\n        else {\r\n            var outerDimsProd = x.shape.slice(0, x.shape.length - 2)\r\n                .reduce(function (value, prev) { return value * prev; });\r\n            var x2ds = unstack(x.reshape([\r\n                outerDimsProd, x.shape[x.shape.length - 2],\r\n                x.shape[x.shape.length - 1]\r\n            ]), 0);\r\n            var q2ds_1 = [];\r\n            var r2ds_1 = [];\r\n            x2ds.forEach(function (x2d) {\r\n                var _a = qr2d(x2d, fullMatrices), q2d = _a[0], r2d = _a[1];\r\n                q2ds_1.push(q2d);\r\n                r2ds_1.push(r2d);\r\n            });\r\n            var q = stack(q2ds_1, 0).reshape(x.shape);\r\n            var r = stack(r2ds_1, 0).reshape(x.shape);\r\n            return [q, r];\r\n        }\r\n    }\r\n    function qr2d(x, fullMatrices) {\r\n        if (fullMatrices === void 0) { fullMatrices = false; }\r\n        return ENV.engine.tidy(function () {\r\n            if (x.shape.length !== 2) {\r\n                throw new Error(\"qr2d() requires a 2D Tensor, but got a \" + x.shape.length + \"D Tensor.\");\r\n            }\r\n            var m = x.shape[0];\r\n            var n = x.shape[1];\r\n            var q = eye(m);\r\n            var r = x.clone();\r\n            var one2D = tensor2d([[1]], [1, 1]);\r\n            var w = one2D.clone();\r\n            var iters = m >= n ? n : m;\r\n            var _loop_2 = function (j) {\r\n                var _a;\r\n                var rTemp = r;\r\n                var wTemp = w;\r\n                var qTemp = q;\r\n                _a = ENV.engine.tidy(function () {\r\n                    var rjEnd1 = r.slice([j, j], [m - j, 1]);\r\n                    var normX = rjEnd1.norm();\r\n                    var rjj = r.slice([j, j], [1, 1]);\r\n                    var s = rjj.sign().neg();\r\n                    var u1 = rjj.sub(s.mul(normX));\r\n                    var wPre = rjEnd1.div(u1);\r\n                    if (wPre.shape[0] === 1) {\r\n                        w = one2D.clone();\r\n                    }\r\n                    else {\r\n                        w = one2D.concat(wPre.slice([1, 0], [wPre.shape[0] - 1, wPre.shape[1]]), 0);\r\n                    }\r\n                    var tau = s.matMul(u1).div(normX).neg();\r\n                    var rjEndAll = r.slice([j, 0], [m - j, n]);\r\n                    var tauTimesW = tau.mul(w);\r\n                    if (j === 0) {\r\n                        r = rjEndAll.sub(tauTimesW.matMul(w.transpose().matMul(rjEndAll)));\r\n                    }\r\n                    else {\r\n                        r = r.slice([0, 0], [j, n])\r\n                            .concat(rjEndAll.sub(tauTimesW.matMul(w.transpose().matMul(rjEndAll))), 0);\r\n                    }\r\n                    var qAllJEnd = q.slice([0, j], [m, q.shape[1] - j]);\r\n                    if (j === 0) {\r\n                        q = qAllJEnd.sub(qAllJEnd.matMul(w).matMul(tauTimesW.transpose()));\r\n                    }\r\n                    else {\r\n                        q = q.slice([0, 0], [m, j])\r\n                            .concat(qAllJEnd.sub(qAllJEnd.matMul(w).matMul(tauTimesW.transpose())), 1);\r\n                    }\r\n                    return [w, r, q];\r\n                }), w = _a[0], r = _a[1], q = _a[2];\r\n                dispose([rTemp, wTemp, qTemp]);\r\n            };\r\n            for (var j = 0; j < iters; ++j) {\r\n                _loop_2(j);\r\n            }\r\n            if (!fullMatrices && m > n) {\r\n                q = q.slice([0, 0], [m, n]);\r\n                r = r.slice([0, 0], [n, n]);\r\n            }\r\n            return [q, r];\r\n        });\r\n    }\r\n    var gramSchmidt = op({ gramSchmidt_: gramSchmidt_ });\r\n    var qr = op({ qr_: qr_ });\n\n    var linalg_ops = /*#__PURE__*/Object.freeze({\n        gramSchmidt: gramSchmidt,\n        qr: qr\n    });\n\n    function resizeBilinear_(images, size, alignCorners) {\r\n        if (alignCorners === void 0) { alignCorners = false; }\r\n        var $images = convertToTensor(images, 'images', 'resizeBilinear');\r\n        assert($images.rank === 3 || $images.rank === 4, \"Error in resizeBilinear: x must be rank 3 or 4, but got \" +\r\n            (\"rank \" + $images.rank + \".\"));\r\n        assert(size.length === 2, \"Error in resizeBilinear: new shape must 2D, but got shape \" +\r\n            (size + \".\"));\r\n        var batchImages = $images;\r\n        var reshapedTo4D = false;\r\n        if ($images.rank === 3) {\r\n            reshapedTo4D = true;\r\n            batchImages =\r\n                $images.as4D(1, $images.shape[0], $images.shape[1], $images.shape[2]);\r\n        }\r\n        var newHeight = size[0], newWidth = size[1];\r\n        var forward = function (backend, save) {\r\n            return backend.resizeBilinear(batchImages, newHeight, newWidth, alignCorners);\r\n        };\r\n        var backward = function (dy, saved) {\r\n            return {\r\n                batchImages: function () { return ENV.engine.runKernel(function (backend) {\r\n                    return backend.resizeBilinearBackprop(dy, batchImages, alignCorners);\r\n                }, {}); }\r\n            };\r\n        };\r\n        var res = ENV.engine.runKernel(forward, { batchImages: batchImages }, backward);\r\n        if (reshapedTo4D) {\r\n            return res.as3D(res.shape[1], res.shape[2], res.shape[3]);\r\n        }\r\n        return res;\r\n    }\r\n    function resizeNearestNeighbor_(images, size, alignCorners) {\r\n        if (alignCorners === void 0) { alignCorners = false; }\r\n        var $images = convertToTensor(images, 'images', 'resizeNearestNeighbor');\r\n        assert($images.rank === 3 || $images.rank === 4, \"Error in resizeNearestNeighbor: x must be rank 3 or 4, but got \" +\r\n            (\"rank \" + $images.rank + \".\"));\r\n        assert(size.length === 2, \"Error in resizeNearestNeighbor: new shape must 2D, but got shape \" +\r\n            (size + \".\"));\r\n        assert($images.dtype === 'float32' || $images.dtype === 'int32', '`images` must have `int32` or `float32` as dtype');\r\n        var batchImages = $images;\r\n        var reshapedTo4D = false;\r\n        if ($images.rank === 3) {\r\n            reshapedTo4D = true;\r\n            batchImages =\r\n                $images.as4D(1, $images.shape[0], $images.shape[1], $images.shape[2]);\r\n        }\r\n        var newHeight = size[0], newWidth = size[1];\r\n        var forward = function (backend, save) {\r\n            return backend.resizeNearestNeighbor(batchImages, newHeight, newWidth, alignCorners);\r\n        };\r\n        var backward = function (dy, saved) {\r\n            return {\r\n                batchImages: function () { return ENV.engine.runKernel(function (backend) { return backend.resizeNearestNeighborBackprop(dy, batchImages, alignCorners); }, {}); }\r\n            };\r\n        };\r\n        var res = ENV.engine.runKernel(forward, { batchImages: batchImages }, backward);\r\n        if (reshapedTo4D) {\r\n            return res.as3D(res.shape[1], res.shape[2], res.shape[3]);\r\n        }\r\n        return res;\r\n    }\r\n    function nonMaxSuppression_(boxes, scores, maxOutputSize, iouThreshold, scoreThreshold) {\r\n        if (iouThreshold === void 0) { iouThreshold = 0.5; }\r\n        if (scoreThreshold === void 0) { scoreThreshold = Number.NEGATIVE_INFINITY; }\r\n        var $boxes = convertToTensor(boxes, 'boxes', 'nonMaxSuppression');\r\n        var $scores = convertToTensor(scores, 'scores', 'nonMaxSuppression');\r\n        var inputs = nonMaxSuppSanityCheck($boxes, $scores, maxOutputSize, iouThreshold, scoreThreshold);\r\n        maxOutputSize = inputs.maxOutputSize;\r\n        iouThreshold = inputs.iouThreshold;\r\n        scoreThreshold = inputs.scoreThreshold;\r\n        return ENV.engine.runKernel(function (b) { return b.nonMaxSuppression($boxes, $scores, maxOutputSize, iouThreshold, scoreThreshold); }, { $boxes: $boxes });\r\n    }\r\n    function nonMaxSuppressionAsync_(boxes, scores, maxOutputSize, iouThreshold, scoreThreshold) {\r\n        if (iouThreshold === void 0) { iouThreshold = 0.5; }\r\n        if (scoreThreshold === void 0) { scoreThreshold = Number.NEGATIVE_INFINITY; }\r\n        return __awaiter(this, void 0, void 0, function () {\r\n            var $boxes, $scores, inputs, boxesVals, scoresVals, res;\r\n            return __generator(this, function (_a) {\r\n                switch (_a.label) {\r\n                    case 0:\r\n                        $boxes = convertToTensor(boxes, 'boxes', 'nonMaxSuppressionAsync');\r\n                        $scores = convertToTensor(scores, 'scores', 'nonMaxSuppressionAsync');\r\n                        inputs = nonMaxSuppSanityCheck($boxes, $scores, maxOutputSize, iouThreshold, scoreThreshold);\r\n                        maxOutputSize = inputs.maxOutputSize;\r\n                        iouThreshold = inputs.iouThreshold;\r\n                        scoreThreshold = inputs.scoreThreshold;\r\n                        return [4, $boxes.data()];\r\n                    case 1:\r\n                        boxesVals = _a.sent();\r\n                        return [4, $scores.data()];\r\n                    case 2:\r\n                        scoresVals = _a.sent();\r\n                        res = nonMaxSuppressionImpl(boxesVals, scoresVals, maxOutputSize, iouThreshold, scoreThreshold);\r\n                        if ($boxes !== boxes) {\r\n                            $boxes.dispose();\r\n                        }\r\n                        if ($scores !== scores) {\r\n                            $scores.dispose();\r\n                        }\r\n                        return [2, res];\r\n                }\r\n            });\r\n        });\r\n    }\r\n    function nonMaxSuppSanityCheck(boxes, scores, maxOutputSize, iouThreshold, scoreThreshold) {\r\n        if (iouThreshold == null) {\r\n            iouThreshold = 0.5;\r\n        }\r\n        if (scoreThreshold == null) {\r\n            scoreThreshold = Number.NEGATIVE_INFINITY;\r\n        }\r\n        var numBoxes = boxes.shape[0];\r\n        maxOutputSize = Math.min(maxOutputSize, numBoxes);\r\n        assert(0 <= iouThreshold && iouThreshold <= 1, \"iouThreshold must be in [0, 1], but was '\" + iouThreshold + \"'\");\r\n        assert(boxes.rank === 2, \"boxes must be a 2D tensor, but was of rank '\" + boxes.rank + \"'\");\r\n        assert(boxes.shape[1] === 4, \"boxes must have 4 columns, but 2nd dimension was \" + boxes.shape[1]);\r\n        assert(scores.rank === 1, 'scores must be a 1D tensor');\r\n        assert(scores.shape[0] === numBoxes, \"scores has incompatible shape with boxes. Expected \" + numBoxes + \", \" +\r\n            (\"but was \" + scores.shape[0]));\r\n        return { maxOutputSize: maxOutputSize, iouThreshold: iouThreshold, scoreThreshold: scoreThreshold };\r\n    }\r\n    function cropAndResize_(image, boxes, boxInd, cropSize, method, extrapolationValue) {\r\n        var $image = convertToTensor(image, 'image', 'cropAndResize', 'float32');\r\n        var $boxes = convertToTensor(boxes, 'boxes', 'cropAndResize', 'float32');\r\n        var $boxInd = convertToTensor(boxInd, 'boxInd', 'cropAndResize', 'int32');\r\n        method = method || 'bilinear';\r\n        extrapolationValue = extrapolationValue || 0;\r\n        var numBoxes = $boxes.shape[0];\r\n        assert($image.rank === 4, 'Error in cropAndResize: image must be rank 4,' +\r\n            (\"but got rank \" + $image.rank + \".\"));\r\n        assert($boxes.rank === 2 && $boxes.shape[1] === 4, \"Error in cropAndResize: boxes must be have size [\" + numBoxes + \",4] \" +\r\n            (\"but had shape \" + $boxes.shape + \".\"));\r\n        assert($boxInd.rank === 1 && $boxInd.shape[0] === numBoxes, \"Error in cropAndResize: boxInd must be have size [\" + numBoxes + \"] \" +\r\n            (\"but had shape \" + $boxes.shape + \".\"));\r\n        assert(cropSize.length === 2, \"Error in cropAndResize: cropSize must be of length 2, but got length \" +\r\n            (cropSize.length + \".\"));\r\n        assert(cropSize[0] >= 1 && cropSize[1] >= 1, \"cropSize must be atleast [1,1], but was \" + cropSize);\r\n        assert(method === 'bilinear' || method === 'nearest', \"method must be bilinear or nearest, but was \" + method);\r\n        var forward = function (backend, save) {\r\n            return backend.cropAndResize($image, $boxes, $boxInd, cropSize, method, extrapolationValue);\r\n        };\r\n        var res = ENV.engine.runKernel(forward, { $image: $image, $boxes: $boxes });\r\n        return res;\r\n    }\r\n    var resizeBilinear = op({ resizeBilinear_: resizeBilinear_ });\r\n    var resizeNearestNeighbor = op({ resizeNearestNeighbor_: resizeNearestNeighbor_ });\r\n    var nonMaxSuppression = op({ nonMaxSuppression_: nonMaxSuppression_ });\r\n    var nonMaxSuppressionAsync = nonMaxSuppressionAsync_;\r\n    var cropAndResize = op({ cropAndResize_: cropAndResize_ });\n\n    var image_ops = /*#__PURE__*/Object.freeze({\n        resizeBilinear: resizeBilinear,\n        resizeNearestNeighbor: resizeNearestNeighbor,\n        nonMaxSuppression: nonMaxSuppression,\n        nonMaxSuppressionAsync: nonMaxSuppressionAsync,\n        cropAndResize: cropAndResize\n    });\n\n    function matMul_$1(a, b, transposeA, transposeB, bias, activation) {\r\n        if (transposeA === void 0) { transposeA = false; }\r\n        if (transposeB === void 0) { transposeB = false; }\r\n        if (activation === void 0) { activation = 'linear'; }\r\n        var _a;\r\n        var $a = convertToTensor(a, 'a', 'fused matMul');\r\n        var $b = convertToTensor(b, 'b', 'fused matMul');\r\n        _a = makeTypesMatch($a, $b), $a = _a[0], $b = _a[1];\r\n        var innerShapeA = transposeA ? $a.shape[$a.rank - 2] : $a.shape[$a.rank - 1];\r\n        var innerShapeB = transposeB ? $b.shape[$b.rank - 1] : $b.shape[$b.rank - 2];\r\n        var outerShapeA = transposeA ? $a.shape[$a.rank - 1] : $a.shape[$a.rank - 2];\r\n        var outerShapeB = transposeB ? $b.shape[$b.rank - 2] : $b.shape[$b.rank - 1];\r\n        var outerDimsA = $a.shape.slice(0, -2);\r\n        var outerDimsB = $b.shape.slice(0, -2);\r\n        var batchDimA = sizeFromShape(outerDimsA);\r\n        var batchDimB = sizeFromShape(outerDimsB);\r\n        assert($a.rank >= 2 && $b.rank >= 2 && $a.rank === $b.rank, \"Error in fused matMul: inputs must have the same rank of at least 2, \" +\r\n            (\"got ranks \" + $a.rank + \" and \" + $b.rank + \".\"));\r\n        assert(arraysEqual(outerDimsA, outerDimsB), \"Error in fused matMul: outer dimensions (\" + outerDimsA + \") and (\" +\r\n            (outerDimsB + \") of Tensors with shapes \" + $a.shape + \" and \") +\r\n            ($b.shape + \" must match.\"));\r\n        assert(innerShapeA === innerShapeB, \"Error in fused matMul: inner shapes (\" + innerShapeA + \") and (\" +\r\n            (innerShapeB + \") of Tensors with shapes \" + $a.shape + \" and \") +\r\n            ($b.shape + \" and transposeA=\" + transposeA) +\r\n            (\" and transposeB=\" + transposeB + \" must match.\"));\r\n        var outShape = $a.shape.slice(0, -2).concat([outerShapeA, outerShapeB]);\r\n        var a3D = transposeA ? $a.as3D(batchDimA, innerShapeA, outerShapeA) :\r\n            $a.as3D(batchDimA, outerShapeA, innerShapeA);\r\n        var b3D = transposeB ? $b.as3D(batchDimB, outerShapeB, innerShapeB) :\r\n            $b.as3D(batchDimB, innerShapeB, outerShapeB);\r\n        var $bias;\r\n        if (bias != null) {\r\n            $bias = convertToTensor(bias, 'bias', 'fused matMul');\r\n            $bias = makeTypesMatch($bias, $a)[0];\r\n            assert(getBroadcastDims(outShape, $bias.shape).length === 0, \"Error in fused matMul: broadcasting is not supported for bias add.\");\r\n        }\r\n        var grad = function (dy, saved) {\r\n            var y = saved[0];\r\n            var dyActivation;\r\n            if (activation == null || activation === 'linear') {\r\n                dyActivation = dy;\r\n            }\r\n            else if (activation === 'relu') {\r\n                dyActivation = dy.mul(y.step());\r\n            }\r\n            else {\r\n                throw new Error(\"Gradient for activation \" + activation + \" has not been \" +\r\n                    \"implemented yet.\");\r\n            }\r\n            var biasGradient = {};\r\n            if (bias != null) {\r\n                biasGradient = {\r\n                    $bias: function () {\r\n                        var res = dyActivation;\r\n                        var reduceAxes = getReductionAxes($bias.shape, outShape);\r\n                        if (reduceAxes.length > 0) {\r\n                            res = res.sum(reduceAxes);\r\n                        }\r\n                        return res.reshape($bias.shape);\r\n                    }\r\n                };\r\n            }\r\n            if (!transposeA && !transposeB) {\r\n                return Object.assign({\r\n                    $a: function () { return dyActivation.matMul(b3D, false, true); },\r\n                    $b: function () { return a3D.matMul(dyActivation, true, false); }\r\n                }, biasGradient);\r\n            }\r\n            else if (!transposeA && transposeB) {\r\n                return Object.assign({\r\n                    $a: function () { return dyActivation.matMul(b3D, false, false); },\r\n                    $b: function () { return dyActivation.matMul(a3D, true, false); }\r\n                }, biasGradient);\r\n            }\r\n            else if (transposeA && !transposeB) {\r\n                return Object.assign({\r\n                    $a: function () { return b3D.matMul(dyActivation, false, true); },\r\n                    $b: function () { return a3D.matMul(dyActivation, false, false); }\r\n                }, biasGradient);\r\n            }\r\n            else {\r\n                return Object.assign({\r\n                    $a: function () { return b3D.matMul(dyActivation, true, true); },\r\n                    $b: function () { return dyActivation.matMul(a3D, true, true); }\r\n                }, biasGradient);\r\n            }\r\n        };\r\n        var inputs = { $a: a3D, $b: b3D };\r\n        if (bias != null) {\r\n            inputs.$bias = $bias;\r\n        }\r\n        var res = ENV.engine.runKernel(function (backend, save) { return save(backend.fusedBatchMatMul(a3D, b3D, transposeA, transposeB, $bias, activation)); }, inputs, grad);\r\n        return res.reshape(outShape);\r\n    }\r\n    var matMul$1 = op({ matMul_: matMul_$1 });\n\n    var fused_ops = /*#__PURE__*/Object.freeze({\n        matMul: matMul$1\n    });\n\n\n\n    var ops = /*#__PURE__*/Object.freeze({\n        image: image_ops,\n        linalg: linalg_ops,\n        losses: loss_ops,\n        spectral: spectral_ops,\n        fused: fused_ops,\n        op: op,\n        batchNormalization2d: batchNormalization2d,\n        batchNormalization3d: batchNormalization3d,\n        batchNormalization4d: batchNormalization4d,\n        batchNormalization: batchNormalization,\n        complex: complex,\n        real: real,\n        imag: imag,\n        concat: concat,\n        concat1d: concat1d,\n        concat2d: concat2d,\n        concat3d: concat3d,\n        concat4d: concat4d,\n        split: split$1,\n        conv1d: conv1d,\n        conv2d: conv2d,\n        conv3d: conv3d,\n        conv2dDerFilter: conv2dDerFilter,\n        depthwiseConv2d: depthwiseConv2d,\n        separableConv2d: separableConv2d,\n        conv2dTranspose: conv2dTranspose,\n        matMul: matMul,\n        dot: dot,\n        outerProduct: outerProduct,\n        reverse: reverse,\n        reverse1d: reverse1d,\n        reverse2d: reverse2d,\n        reverse3d: reverse3d,\n        reverse4d: reverse4d,\n        maxPool: maxPool,\n        avgPool: avgPool,\n        pool: pool,\n        slice: slice,\n        slice1d: slice1d,\n        slice2d: slice2d,\n        slice3d: slice3d,\n        slice4d: slice4d,\n        abs: abs,\n        acos: acos,\n        acosh: acosh,\n        asin: asin,\n        asinh: asinh,\n        atan: atan,\n        atanh: atanh,\n        ceil: ceil,\n        clipByValue: clipByValue,\n        cos: cos,\n        cosh: cosh,\n        erf: erf,\n        exp: exp,\n        expm1: expm1,\n        floor: floor,\n        log: log$1,\n        log1p: log1p,\n        logSigmoid: logSigmoid,\n        neg: neg,\n        reciprocal: reciprocal,\n        round: round,\n        rsqrt: rsqrt,\n        sigmoid: sigmoid,\n        sign: sign,\n        sin: sin,\n        sinh: sinh,\n        softplus: softplus,\n        sqrt: sqrt,\n        square: square,\n        step: step,\n        tan: tan,\n        tanh: tanh$1,\n        all: all,\n        any: any,\n        argMax: argMax,\n        argMin: argMin,\n        logSumExp: logSumExp,\n        max: max,\n        mean: mean,\n        min: min,\n        moments: moments,\n        sum: sum$1,\n        prod: prod,\n        equal: equal,\n        equalStrict: equalStrict,\n        greater: greater,\n        greaterEqual: greaterEqual,\n        greaterEqualStrict: greaterEqualStrict,\n        greaterStrict: greaterStrict,\n        less: less,\n        lessEqual: lessEqual,\n        lessEqualStrict: lessEqualStrict,\n        lessStrict: lessStrict,\n        notEqual: notEqual,\n        notEqualStrict: notEqualStrict,\n        add: add,\n        addN: addN,\n        addStrict: addStrict,\n        atan2: atan2,\n        div: div,\n        divStrict: divStrict,\n        floorDiv: floorDiv,\n        maximum: maximum,\n        maximumStrict: maximumStrict,\n        minimum: minimum,\n        minimumStrict: minimumStrict,\n        mod: mod,\n        modStrict: modStrict,\n        mul: mul,\n        mulStrict: mulStrict,\n        pow: pow,\n        powStrict: powStrict,\n        squaredDifference: squaredDifference,\n        squaredDifferenceStrict: squaredDifferenceStrict,\n        sub: sub,\n        subStrict: subStrict,\n        elu: elu,\n        leakyRelu: leakyRelu,\n        prelu: prelu,\n        relu: relu,\n        selu: selu,\n        logicalAnd: logicalAnd,\n        logicalNot: logicalNot,\n        logicalOr: logicalOr,\n        logicalXor: logicalXor,\n        where: where,\n        whereAsync: whereAsync,\n        buffer: buffer,\n        toPixels: toPixels,\n        print: print,\n        batchToSpaceND: batchToSpaceND,\n        cast: cast,\n        clone: clone,\n        cumsum: cumsum,\n        depthToSpace: depthToSpace,\n        expandDims: expandDims,\n        eye: eye,\n        fromPixels: fromPixels,\n        multinomial: multinomial,\n        oneHot: oneHot,\n        pad: pad,\n        pad1d: pad1d,\n        pad2d: pad2d,\n        pad3d: pad3d,\n        pad4d: pad4d,\n        rand: rand,\n        randomNormal: randomNormal,\n        randomUniform: randomUniform,\n        reshape: reshape,\n        spaceToBatchND: spaceToBatchND,\n        squeeze: squeeze,\n        stack: stack,\n        tile: tile,\n        truncatedNormal: truncatedNormal,\n        unstack: unstack,\n        setdiff1dAsync: setdiff1dAsync,\n        fill: fill,\n        linspace: linspace,\n        ones: ones$1,\n        range: range,\n        scalar: scalar,\n        tensor: tensor,\n        tensor1d: tensor1d,\n        tensor2d: tensor2d,\n        tensor3d: tensor3d,\n        tensor4d: tensor4d,\n        tensor5d: tensor5d,\n        tensor6d: tensor6d,\n        zeros: zeros,\n        onesLike: onesLike,\n        zerosLike: zerosLike,\n        transpose: transpose,\n        softmax: softmax,\n        logSoftmax: logSoftmax,\n        localResponseNormalization: localResponseNormalization,\n        norm: norm,\n        gather: gather,\n        unsortedSegmentSum: unsortedSegmentSum,\n        basicLSTMCell: basicLSTMCell,\n        multiRNNCell: multiRNNCell,\n        movingAverage: movingAverage,\n        stridedSlice: stridedSlice,\n        topk: topk,\n        scatterND: scatterND,\n        fft: fft,\n        ifft: ifft,\n        rfft: rfft,\n        irfft: irfft,\n        sparseToDense: sparseToDense,\n        gatherND: gatherND\n    });\n\n    function mapActivation(backend, activation, x) {\r\n        if (activation === 'linear') {\r\n            return backend.linear(x);\r\n        }\r\n        else if (activation === 'relu') {\r\n            return backend.relu(x);\r\n        }\r\n        throw new Error(\"Activation \" + activation + \" has not been implemented for the CPU backend.\");\r\n    }\r\n    var MathBackendCPU = (function () {\r\n        function MathBackendCPU() {\r\n            this.blockSize = 48;\r\n            this.firstUse = true;\r\n            if (ENV.get('IS_BROWSER')) {\r\n                this.fromPixels2DContext =\r\n                    document.createElement('canvas').getContext('2d');\r\n            }\r\n        }\r\n        MathBackendCPU.prototype.setDataMover = function (dataMover) {\r\n            this.data = new DataStorage(dataMover);\r\n        };\r\n        MathBackendCPU.prototype.register = function (dataId, shape, dtype) {\r\n            if (this.firstUse) {\r\n                this.firstUse = false;\r\n                if (ENV.get('IS_NODE')) {\r\n                    warn('\\n============================\\n' +\r\n                        'Hi there 👋. Looks like you are running TensorFlow.js in ' +\r\n                        'Node.js. To speed things up dramatically, install our node ' +\r\n                        'backend, which binds to TensorFlow C++, by running ' +\r\n                        'npm i @tensorflow/tfjs-node, ' +\r\n                        'or npm i @tensorflow/tfjs-node-gpu if you have CUDA. ' +\r\n                        'Then call require(\\'@tensorflow/tfjs-node\\'); (-gpu ' +\r\n                        'suffix for CUDA) at the start of your program. ' +\r\n                        'Visit https://github.com/tensorflow/tfjs-node for more details.' +\r\n                        '\\n============================\\n');\r\n                }\r\n            }\r\n            if (this.data.has(dataId)) {\r\n                throw new Error(\"Data buffer is already registered\");\r\n            }\r\n            this.data.set(dataId, { dtype: dtype });\r\n        };\r\n        MathBackendCPU.prototype.write = function (dataId, values) {\r\n            if (values == null) {\r\n                throw new Error('MathBackendCPU.write(): values can not be null');\r\n            }\r\n            this.data.get(dataId).values = values;\r\n        };\r\n        MathBackendCPU.prototype.fromPixels = function (pixels, numChannels) {\r\n            if (pixels == null) {\r\n                throw new Error('pixels passed to tf.fromPixels() can not be null');\r\n            }\r\n            var vals;\r\n            if (ENV.get('IS_NODE') && pixels.getContext == null) {\r\n                throw new Error('When running in node, pixels must be an HTMLCanvasElement ' +\r\n                    'like the one returned by the `canvas` npm package');\r\n            }\r\n            if (pixels.getContext != null) {\r\n                vals = pixels\r\n                    .getContext('2d')\r\n                    .getImageData(0, 0, pixels.width, pixels.height)\r\n                    .data;\r\n            }\r\n            else if (pixels instanceof ImageData) {\r\n                vals = pixels.data;\r\n            }\r\n            else if (pixels instanceof HTMLImageElement ||\r\n                pixels instanceof HTMLVideoElement) {\r\n                if (this.fromPixels2DContext == null) {\r\n                    throw new Error('Can\\'t read pixels from HTMLImageElement outside ' +\r\n                        'the browser.');\r\n                }\r\n                this.fromPixels2DContext.canvas.width = pixels.width;\r\n                this.fromPixels2DContext.canvas.height = pixels.height;\r\n                this.fromPixels2DContext.drawImage(pixels, 0, 0, pixels.width, pixels.height);\r\n                vals = this.fromPixels2DContext\r\n                    .getImageData(0, 0, pixels.width, pixels.height)\r\n                    .data;\r\n            }\r\n            else {\r\n                throw new Error('pixels passed to tf.fromPixels() must be either an ' +\r\n                    \"HTMLVideoElement, HTMLImageElement, HTMLCanvasElement or \" +\r\n                    (\"ImageData, but was \" + pixels.constructor.name));\r\n            }\r\n            var values;\r\n            if (numChannels === 4) {\r\n                values = new Int32Array(vals);\r\n            }\r\n            else {\r\n                var numPixels = pixels.width * pixels.height;\r\n                values = new Int32Array(numPixels * numChannels);\r\n                for (var i = 0; i < numPixels; i++) {\r\n                    for (var channel = 0; channel < numChannels; ++channel) {\r\n                        values[i * numChannels + channel] = vals[i * 4 + channel];\r\n                    }\r\n                }\r\n            }\r\n            var outShape = [pixels.height, pixels.width, numChannels];\r\n            return tensor3d(values, outShape, 'int32');\r\n        };\r\n        MathBackendCPU.prototype.read = function (dataId) {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                return __generator(this, function (_a) {\r\n                    return [2, this.readSync(dataId)];\r\n                });\r\n            });\r\n        };\r\n        MathBackendCPU.prototype.readSync = function (dataId) {\r\n            var _a = this.data.get(dataId), dtype = _a.dtype, complexTensors = _a.complexTensors;\r\n            if (dtype === 'complex64') {\r\n                var realValues = complexTensors.real.dataSync();\r\n                var imagValues = complexTensors.imag.dataSync();\r\n                return mergeRealAndImagArrays(realValues, imagValues);\r\n            }\r\n            return this.data.get(dataId).values;\r\n        };\r\n        MathBackendCPU.prototype.disposeData = function (dataId) {\r\n            if (this.data.has(dataId)) {\r\n                var complexTensors = this.data.get(dataId).complexTensors;\r\n                if (complexTensors != null) {\r\n                    complexTensors.real.dispose();\r\n                    complexTensors.imag.dispose();\r\n                }\r\n                this.data.delete(dataId);\r\n            }\r\n        };\r\n        MathBackendCPU.prototype.time = function (f) {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var start, kernelMs;\r\n                return __generator(this, function (_a) {\r\n                    start = now();\r\n                    f();\r\n                    kernelMs = now() - start;\r\n                    return [2, { kernelMs: kernelMs }];\r\n                });\r\n            });\r\n        };\r\n        MathBackendCPU.prototype.memory = function () {\r\n            return {\r\n                unreliable: true,\r\n                reasons: ['The reported memory is an upper bound. Due to automatic garbage ' +\r\n                        'collection, the true allocated memory may be less.']\r\n            };\r\n        };\r\n        MathBackendCPU.prototype.complex = function (real$$1, imag$$1) {\r\n            var result = Tensor.make(real$$1.shape, {}, 'complex64');\r\n            var resultData = this.data.get(result.dataId);\r\n            resultData.complexTensors = {\r\n                real: ENV.engine.keep(real$$1.clone()),\r\n                imag: ENV.engine.keep(imag$$1.clone())\r\n            };\r\n            return result;\r\n        };\r\n        MathBackendCPU.prototype.real = function (input) {\r\n            var resultData = this.data.get(input.dataId);\r\n            return resultData.complexTensors.real.clone();\r\n        };\r\n        MathBackendCPU.prototype.imag = function (input) {\r\n            var resultData = this.data.get(input.dataId);\r\n            return resultData.complexTensors.imag.clone();\r\n        };\r\n        MathBackendCPU.prototype.assertNotComplex = function (tensor$$1, opName) {\r\n            if (!Array.isArray(tensor$$1)) {\r\n                tensor$$1 = [tensor$$1];\r\n            }\r\n            tensor$$1.forEach(function (t) {\r\n                if (t != null) {\r\n                    assert(t.dtype !== 'complex64', opName + \" does not support complex64 tensors.\");\r\n                }\r\n            });\r\n        };\r\n        MathBackendCPU.prototype.slice = function (x, begin, size) {\r\n            this.assertNotComplex(x, 'slice');\r\n            var isContinous = isSliceContinous(x.shape, begin, size);\r\n            if (isContinous) {\r\n                var flatOffset = computeFlatOffset(begin, x.strides);\r\n                var length_1 = sizeFromShape(size);\r\n                var vals = x.dataSync();\r\n                return tensor(vals.subarray(flatOffset, flatOffset + length_1), size, x.dtype);\r\n            }\r\n            var buffer$$1 = buffer(size, x.dtype);\r\n            for (var i = 0; i < buffer$$1.size; ++i) {\r\n                var loc = buffer$$1.indexToLoc(i);\r\n                var xLoc = loc.map(function (idx, j) { return idx + begin[j]; });\r\n                buffer$$1.values[i] = x.get.apply(x, xLoc);\r\n            }\r\n            return buffer$$1.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.stridedSlice = function (x, begin, end, strides, beginMask, endMask, ellipsisMask, newAxisMask, shrinkAxisMask) {\r\n            this.assertNotComplex(x, 'stridedSlice');\r\n            var _a = getStridedSlicedInfo(x.shape, begin, end, strides, beginMask, endMask, ellipsisMask, newAxisMask, shrinkAxisMask), beginIndex = _a[0], size = _a[1], shrinkAxis = _a[2];\r\n            var shape = size.filter(function (v, index) { return shrinkAxis.indexOf(index) === -1; });\r\n            if (shape.some(function (axis) { return axis === 0; })) {\r\n                return tensor([], shape);\r\n            }\r\n            var buffer$$1 = buffer(size, x.dtype);\r\n            for (var i = 0; i < buffer$$1.size; i++) {\r\n                var loc = buffer$$1.indexToLoc(i);\r\n                var newLoc = new Array(loc.length);\r\n                for (var j = 0; j < newLoc.length; j++) {\r\n                    newLoc[j] = loc[j] * strides[j] + beginIndex[j];\r\n                }\r\n                buffer$$1.set.apply(buffer$$1, [x.get.apply(x, newLoc)].concat(loc));\r\n            }\r\n            return buffer$$1.toTensor().reshape(shape);\r\n        };\r\n        MathBackendCPU.prototype.unstack = function (x, axis) {\r\n            var num = x.shape[axis];\r\n            var outShape = new Array(x.rank - 1);\r\n            var outIndex = 0;\r\n            for (var i = 0; i < x.rank; i++) {\r\n                if (i !== axis) {\r\n                    outShape[outIndex++] = x.shape[i];\r\n                }\r\n            }\r\n            var begin = new Array(x.rank).fill(0);\r\n            var size = x.shape.slice();\r\n            size[axis] = 1;\r\n            var res = new Array(num);\r\n            for (var i = 0; i < res.length; i++) {\r\n                begin[axis] = i;\r\n                res[i] = this.slice(x, begin, size).reshape(outShape);\r\n            }\r\n            return res;\r\n        };\r\n        MathBackendCPU.prototype.reverse = function (x, axis) {\r\n            this.assertNotComplex(x, 'reverse');\r\n            var buffer$$1 = buffer(x.shape, x.dtype);\r\n            var xBuffer = x.buffer();\r\n            var _loop_1 = function (i) {\r\n                var outLoc = buffer$$1.indexToLoc(i);\r\n                var inLoc = outLoc.slice();\r\n                axis.forEach(function (ax) { return inLoc[ax] = x.shape[ax] - 1 - inLoc[ax]; });\r\n                buffer$$1.set.apply(buffer$$1, [xBuffer.get.apply(xBuffer, inLoc)].concat(outLoc));\r\n            };\r\n            for (var i = 0; i < buffer$$1.size; i++) {\r\n                _loop_1(i);\r\n            }\r\n            return buffer$$1.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.concat = function (tensors, axis) {\r\n            this.assertNotComplex(tensors, 'concat');\r\n            var tensors2D = tensors.map(function (t) {\r\n                var innerSize = sizeFromShape(t.shape.slice(axis));\r\n                return t.as2D(-1, innerSize);\r\n            });\r\n            var outShape = computeOutShape(tensors2D.map(function (t) { return t.shape; }), 1);\r\n            var values = buffer(outShape, tensors[0].dtype)\r\n                .values;\r\n            if (tensors2D[0].shape[0] === 1) {\r\n                var offset_1 = 0;\r\n                tensors2D.forEach(function (t) {\r\n                    values.set(t.dataSync(), offset_1);\r\n                    offset_1 += t.size;\r\n                });\r\n            }\r\n            else {\r\n                var colOffset_1 = 0;\r\n                tensors2D.forEach(function (t) {\r\n                    var tVals = t.dataSync();\r\n                    var tIdx = 0;\r\n                    for (var row = 0; row < t.shape[0]; ++row) {\r\n                        var resIdx = row * outShape[1] + colOffset_1;\r\n                        for (var col = 0; col < t.shape[1]; ++col) {\r\n                            values[resIdx + col] = tVals[tIdx++];\r\n                        }\r\n                    }\r\n                    colOffset_1 += t.shape[1];\r\n                });\r\n            }\r\n            var finalOutShape = computeOutShape(tensors.map(function (t) { return t.shape; }), axis);\r\n            return tensor(values, finalOutShape, tensors[0].dtype);\r\n        };\r\n        MathBackendCPU.prototype.neg = function (x) {\r\n            this.assertNotComplex(x, 'neg');\r\n            return this.multiply(scalar(-1), x);\r\n        };\r\n        MathBackendCPU.prototype.add = function (a, b) {\r\n            if (a.dtype === 'complex64' || b.dtype === 'complex64') {\r\n                return this.broadcastedBinaryComplexOp(a.cast('complex64'), b.cast('complex64'), function (aReal, aImag, bReal, bImag) {\r\n                    return { real: aReal + bReal, imag: aImag + bImag };\r\n                });\r\n            }\r\n            return this.broadcastedBinaryOp(a, b, upcastType(a.dtype, b.dtype), function (aValue, bValue) { return aValue + bValue; });\r\n        };\r\n        MathBackendCPU.prototype.addN = function (tensors) {\r\n            this.assertNotComplex(tensors, 'addN');\r\n            var vals = tensors.map(function (t) { return t.dataSync(); });\r\n            var result = buffer(tensors[0].shape, tensors[0].dtype);\r\n            var resultVals = result.values;\r\n            for (var i = 0; i < tensors.length; i++) {\r\n                var currVals = vals[i];\r\n                for (var j = 0; j < resultVals.length; j++) {\r\n                    resultVals[j] += currVals[j];\r\n                }\r\n            }\r\n            return result.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.subtract = function (a, b) {\r\n            if (a.dtype === 'complex64' || b.dtype === 'complex64') {\r\n                return this.broadcastedBinaryComplexOp(a.cast('complex64'), b.cast('complex64'), function (aReal, aImag, bReal, bImag) {\r\n                    return { real: aReal - bReal, imag: aImag - bImag };\r\n                });\r\n            }\r\n            return this.broadcastedBinaryOp(a, b, upcastType(a.dtype, b.dtype), function (aValue, bValue) { return aValue - bValue; });\r\n        };\r\n        MathBackendCPU.prototype.pow = function (a, b) {\r\n            this.assertNotComplex([a, b], 'pow');\r\n            return this.broadcastedBinaryOp(a, b, a.dtype, function (aValue, bValue) { return Math.pow(aValue, bValue); });\r\n        };\r\n        MathBackendCPU.prototype.batchMatMul = function (a, b, transposeA, transposeB) {\r\n            this.assertNotComplex([a, b], 'matMul');\r\n            var sharedDim = transposeA ? a.shape[1] : a.shape[2];\r\n            var leftDim = transposeA ? a.shape[2] : a.shape[1];\r\n            var rightDim = transposeB ? b.shape[1] : b.shape[2];\r\n            var batchDim = a.shape[0];\r\n            var aValues = a.dataSync();\r\n            var bValues = b.dataSync();\r\n            var _a = transposeA ?\r\n                [a.strides[0], 1, a.strides[1]] :\r\n                [a.strides[0], a.strides[1], 1], aBatch = _a[0], aOuterStep = _a[1], aInnerStep = _a[2];\r\n            var _b = transposeB ?\r\n                [1, b.strides[1], b.strides[0]] :\r\n                [b.strides[1], 1, b.strides[0]], bInnerStep = _b[0], bOuterStep = _b[1], bBatch = _b[2];\r\n            var size = leftDim * rightDim;\r\n            var result = buffer([batchDim, leftDim, rightDim], a.dtype);\r\n            var resVals = result.values;\r\n            var blockSize = this.blockSize;\r\n            for (var b_1 = 0; b_1 < batchDim; b_1++) {\r\n                for (var i0 = 0; i0 < leftDim; i0 += blockSize) {\r\n                    for (var j0 = 0; j0 < rightDim; j0 += blockSize) {\r\n                        for (var k0 = 0; k0 < sharedDim; k0 += blockSize) {\r\n                            var iBlock = Math.min(i0 + blockSize, leftDim);\r\n                            var jBlock = Math.min(j0 + blockSize, rightDim);\r\n                            var kBlock = Math.min(k0 + blockSize, sharedDim);\r\n                            for (var i = i0; i < iBlock; i++) {\r\n                                for (var j = j0; j < jBlock; j++) {\r\n                                    var sum$$1 = 0.0;\r\n                                    for (var k = k0; k < kBlock; k++) {\r\n                                        sum$$1 += aValues[b_1 * aBatch + i * aOuterStep + k * aInnerStep] *\r\n                                            bValues[k * bInnerStep + j * bOuterStep + b_1 * bBatch];\r\n                                    }\r\n                                    resVals[b_1 * size + (i * rightDim + j)] += sum$$1;\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return result.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.fusedBatchMatMul = function (a, b, transposeA, transposeB, bias, activation) {\r\n            var result = this.batchMatMul(a, b, transposeA, transposeB);\r\n            if (bias) {\r\n                result = this.add(result, bias);\r\n            }\r\n            if (activation) {\r\n                result = mapActivation(this, activation, result);\r\n            }\r\n            return result;\r\n        };\r\n        MathBackendCPU.prototype.multiply = function (a, b) {\r\n            if (a.dtype === 'complex64' || b.dtype === 'complex64') {\r\n                return this.broadcastedBinaryComplexOp(a.cast('complex64'), b.cast('complex64'), function (aReal, aImag, bReal, bImag) {\r\n                    return {\r\n                        real: aReal * bReal - aImag * bImag,\r\n                        imag: aReal * bImag + aImag * bReal\r\n                    };\r\n                });\r\n            }\r\n            return this.broadcastedBinaryOp(a, b, upcastType(a.dtype, b.dtype), function (aValue, bValue) { return aValue * bValue; });\r\n        };\r\n        MathBackendCPU.prototype.realDivide = function (a, b) {\r\n            this.assertNotComplex([a, b], 'realDivide');\r\n            var op$$1 = function (a, b) { return a / b; };\r\n            var outputDtype = 'float32';\r\n            return this.broadcastedBinaryOp(a, b, outputDtype, op$$1);\r\n        };\r\n        MathBackendCPU.prototype.floorDiv = function (a, b) {\r\n            this.assertNotComplex([a, b], 'floorDiv');\r\n            var op$$1 = function (a, b) { return Math.floor(a / b); };\r\n            var outputDtype = 'int32';\r\n            return this.broadcastedBinaryOp(a, b, outputDtype, op$$1);\r\n        };\r\n        MathBackendCPU.prototype.sum = function (x, axes) {\r\n            this.assertNotComplex(x, 'sum');\r\n            assertAxesAreInnerMostDims('sum', axes, x.rank);\r\n            var _a = computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1];\r\n            var resultDtype = upcastType(x.dtype, 'int32');\r\n            var result = zeros(outShape, resultDtype);\r\n            var reduceSize = sizeFromShape(reduceShape);\r\n            var vals = result.dataSync();\r\n            var aVals = x.dataSync();\r\n            for (var i = 0; i < vals.length; ++i) {\r\n                var offset = i * reduceSize;\r\n                var sum$$1 = 0;\r\n                for (var j = 0; j < reduceSize; ++j) {\r\n                    sum$$1 += aVals[offset + j];\r\n                }\r\n                vals[i] = sum$$1;\r\n            }\r\n            return result;\r\n        };\r\n        MathBackendCPU.prototype.prod = function (x, axes) {\r\n            this.assertNotComplex(x, 'sum');\r\n            var _a = computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1];\r\n            var resultDtype = upcastType(x.dtype, 'int32');\r\n            var result = zeros(outShape, resultDtype);\r\n            var reduceSize = sizeFromShape(reduceShape);\r\n            var vals = result.dataSync();\r\n            var aVals = x.dataSync();\r\n            for (var i = 0; i < vals.length; ++i) {\r\n                var offset = i * reduceSize;\r\n                var prod$$1 = 1;\r\n                for (var j = 0; j < reduceSize; ++j) {\r\n                    prod$$1 *= aVals[offset + j];\r\n                }\r\n                vals[i] = prod$$1;\r\n            }\r\n            return result;\r\n        };\r\n        MathBackendCPU.prototype.unsortedSegmentSum = function (x, segmentIds, numSegments) {\r\n            this.assertNotComplex(x, 'unsortedSegmentSum');\r\n            var res = [];\r\n            var numIters = x.rank - segmentIds.rank;\r\n            for (var i = 0; i < numIters; ++i) {\r\n                segmentIds = segmentIds.expandDims(i + 1);\r\n            }\r\n            for (var i = 0; i < numSegments; ++i) {\r\n                var segmentId = scalar(i, 'int32');\r\n                var mask = equal(segmentId, segmentIds).asType('float32');\r\n                var sum$$1 = mask.mul(x).sum(0);\r\n                res.push(sum$$1);\r\n            }\r\n            return stack(res);\r\n        };\r\n        MathBackendCPU.prototype.argMin = function (x, axis) {\r\n            this.assertNotComplex(x, 'argMin');\r\n            var axes = [axis];\r\n            assertAxesAreInnerMostDims('argMin', axes, x.rank);\r\n            var _a = computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1];\r\n            var result = zeros(outShape, 'int32');\r\n            var reduceSize = sizeFromShape(reduceShape);\r\n            var vals = result.dataSync();\r\n            var aVals = x.dataSync();\r\n            for (var i = 0; i < vals.length; ++i) {\r\n                var offset = i * reduceSize;\r\n                var min$$1 = aVals[offset];\r\n                var minIndex = 0;\r\n                for (var j = 0; j < reduceSize; ++j) {\r\n                    var value = aVals[offset + j];\r\n                    if (value < min$$1) {\r\n                        min$$1 = value;\r\n                        minIndex = j;\r\n                    }\r\n                }\r\n                vals[i] = minIndex;\r\n            }\r\n            return result;\r\n        };\r\n        MathBackendCPU.prototype.argMax = function (x, axis) {\r\n            this.assertNotComplex(x, 'argMax');\r\n            var axes = [axis];\r\n            assertAxesAreInnerMostDims('argMax', axes, x.rank);\r\n            var _a = computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1];\r\n            var result = zeros(outShape, 'int32');\r\n            var reduceSize = sizeFromShape(reduceShape);\r\n            var vals = result.dataSync();\r\n            var aVals = x.dataSync();\r\n            for (var i = 0; i < vals.length; ++i) {\r\n                var offset = i * reduceSize;\r\n                var max$$1 = aVals[offset];\r\n                var maxIndex = 0;\r\n                for (var j = 0; j < reduceSize; ++j) {\r\n                    var value = aVals[offset + j];\r\n                    if (value > max$$1) {\r\n                        max$$1 = value;\r\n                        maxIndex = j;\r\n                    }\r\n                }\r\n                vals[i] = maxIndex;\r\n            }\r\n            return result;\r\n        };\r\n        MathBackendCPU.prototype.cumsum = function (x, axis, exclusive, reverse$$1) {\r\n            this.assertNotComplex(x, 'cumsum');\r\n            if (axis !== x.rank - 1) {\r\n                throw new Error(\"backend.cumsum in CPU expects an inner-most axis=\" + (x.rank - 1) + \" \" +\r\n                    (\"but got axis=\" + axis));\r\n            }\r\n            var resultDtype = upcastType(x.dtype, 'int32');\r\n            var result = zeros(x.shape, resultDtype);\r\n            var vals = result.dataSync();\r\n            var aVals = x.dataSync();\r\n            var finalDim = x.shape[x.rank - 1];\r\n            var indexAdjuster = reverse$$1 ?\r\n                function (i, j) { return i + finalDim - j - 1; } :\r\n                function (i, j) { return i + j; };\r\n            for (var i = 0; i < aVals.length; i += finalDim) {\r\n                for (var j = 0; j < finalDim; j++) {\r\n                    var idx = indexAdjuster(i, j);\r\n                    if (j === 0) {\r\n                        vals[idx] = exclusive ? 0 : aVals[idx];\r\n                    }\r\n                    else {\r\n                        var prevIdx = indexAdjuster(i, j - 1);\r\n                        vals[idx] = exclusive ? aVals[prevIdx] + vals[prevIdx] :\r\n                            aVals[idx] + vals[prevIdx];\r\n                    }\r\n                }\r\n            }\r\n            return result;\r\n        };\r\n        MathBackendCPU.prototype.equal = function (a, b) {\r\n            this.assertNotComplex([a, b], 'equal');\r\n            return this.broadcastedBinaryOp(a, b, 'bool', function (aVal, bVal) {\r\n                return (aVal === bVal) ? 1 : 0;\r\n            });\r\n        };\r\n        MathBackendCPU.prototype.notEqual = function (a, b) {\r\n            this.assertNotComplex([a, b], 'notEqual');\r\n            return this.broadcastedBinaryOp(a, b, 'bool', function (aVal, bVal) {\r\n                return (aVal !== bVal) ? 1 : 0;\r\n            });\r\n        };\r\n        MathBackendCPU.prototype.less = function (a, b) {\r\n            this.assertNotComplex([a, b], 'less');\r\n            return this.broadcastedBinaryOp(a, b, 'bool', function (aVal, bVal) {\r\n                return (aVal < bVal) ? 1 : 0;\r\n            });\r\n        };\r\n        MathBackendCPU.prototype.lessEqual = function (a, b) {\r\n            this.assertNotComplex([a, b], 'lessEqual');\r\n            return this.broadcastedBinaryOp(a, b, 'bool', function (aVal, bVal) {\r\n                return (aVal <= bVal) ? 1 : 0;\r\n            });\r\n        };\r\n        MathBackendCPU.prototype.greater = function (a, b) {\r\n            this.assertNotComplex([a, b], 'greater');\r\n            return this.broadcastedBinaryOp(a, b, 'bool', function (aVal, bVal) {\r\n                return (aVal > bVal) ? 1 : 0;\r\n            });\r\n        };\r\n        MathBackendCPU.prototype.greaterEqual = function (a, b) {\r\n            this.assertNotComplex([a, b], 'greaterEqual');\r\n            return this.broadcastedBinaryOp(a, b, 'bool', function (aVal, bVal) {\r\n                return (aVal >= bVal) ? 1 : 0;\r\n            });\r\n        };\r\n        MathBackendCPU.prototype.logicalNot = function (x) {\r\n            this.assertNotComplex(x, 'logicalNot');\r\n            var values = x.dataSync();\r\n            var newValues = new Uint8Array(values.length);\r\n            for (var i = 0; i < values.length; ++i) {\r\n                newValues[i] = values[i] ? 0 : 1;\r\n            }\r\n            return Tensor.make(x.shape, { values: newValues }, 'bool');\r\n        };\r\n        MathBackendCPU.prototype.logicalAnd = function (a, b) {\r\n            this.assertNotComplex([a, b], 'logicalAnd');\r\n            return this.broadcastedBinaryOp(a, b, 'bool', function (aVal, bVal) {\r\n                return aVal && bVal;\r\n            });\r\n        };\r\n        MathBackendCPU.prototype.logicalOr = function (a, b) {\r\n            this.assertNotComplex([a, b], 'logicalOr');\r\n            return this.broadcastedBinaryOp(a, b, 'bool', function (aVal, bVal) {\r\n                return aVal || bVal;\r\n            });\r\n        };\r\n        MathBackendCPU.prototype.select = function (condition, a, b) {\r\n            this.assertNotComplex([condition, a, b], 'select');\r\n            var values = condition.dataSync();\r\n            var aValues = a.dataSync();\r\n            var bValues = b.dataSync();\r\n            var result = zeros(a.shape, upcastType(a.dtype, b.dtype));\r\n            var newValues = result.dataSync();\r\n            var index = 0;\r\n            var offset = condition.rank === 0 || condition.rank > 1 || a.rank === 1 ?\r\n                1 :\r\n                a.shape[1];\r\n            for (var i = 0; i < values.length; i++) {\r\n                for (var j = 0; j < offset; j++) {\r\n                    if (values[i] === 1) {\r\n                        newValues[index++] = aValues[i];\r\n                    }\r\n                    else {\r\n                        newValues[index++] = bValues[i];\r\n                    }\r\n                }\r\n            }\r\n            return result;\r\n        };\r\n        MathBackendCPU.prototype.where = function (condition) {\r\n            this.assertNotComplex([condition], 'where');\r\n            var condVals = condition.dataSync();\r\n            return whereImpl(condition.shape, condVals);\r\n        };\r\n        MathBackendCPU.prototype.topk = function (x, k, sorted) {\r\n            this.assertNotComplex(x, 'topk');\r\n            var xVals = x.dataSync();\r\n            return topkImpl(xVals, x.shape, x.dtype, k, sorted);\r\n        };\r\n        MathBackendCPU.prototype.min = function (x, axes) {\r\n            this.assertNotComplex(x, 'min');\r\n            assertAxesAreInnerMostDims('min', axes, x.rank);\r\n            var _a = computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1];\r\n            var result = zeros(outShape, x.dtype);\r\n            var reduceSize = sizeFromShape(reduceShape);\r\n            var vals = result.dataSync();\r\n            var aVals = x.dataSync();\r\n            for (var i = 0; i < vals.length; ++i) {\r\n                var offset = i * reduceSize;\r\n                var min$$1 = aVals[offset];\r\n                for (var j = 0; j < reduceSize; ++j) {\r\n                    var value = aVals[offset + j];\r\n                    if (value < min$$1) {\r\n                        min$$1 = value;\r\n                    }\r\n                }\r\n                vals[i] = min$$1;\r\n            }\r\n            return result;\r\n        };\r\n        MathBackendCPU.prototype.minimum = function (a, b) {\r\n            this.assertNotComplex([a, b], 'minimum');\r\n            return this.broadcastedBinaryOp(a, b, a.dtype, function (aVal, bVal) { return Math.min(aVal, bVal); });\r\n        };\r\n        MathBackendCPU.prototype.mod = function (a, b) {\r\n            this.assertNotComplex([a, b], 'mod');\r\n            return this.broadcastedBinaryOp(a, b, a.dtype, function (aVal, bVal) {\r\n                var rem = aVal % bVal;\r\n                if ((aVal < 0 && bVal < 0) || (aVal >= 0 && bVal >= 0)) {\r\n                    return rem;\r\n                }\r\n                else {\r\n                    return (rem + bVal) % bVal;\r\n                }\r\n            });\r\n        };\r\n        MathBackendCPU.prototype.max = function (x, axes) {\r\n            this.assertNotComplex(x, 'max');\r\n            assertAxesAreInnerMostDims('max', axes, x.rank);\r\n            var _a = computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1];\r\n            var result = zeros(outShape, x.dtype);\r\n            var reduceSize = sizeFromShape(reduceShape);\r\n            var vals = result.dataSync();\r\n            var aVals = x.dataSync();\r\n            for (var i = 0; i < vals.length; ++i) {\r\n                var offset = i * reduceSize;\r\n                var max$$1 = aVals[offset];\r\n                for (var j = 0; j < reduceSize; ++j) {\r\n                    var value = aVals[offset + j];\r\n                    if (value > max$$1) {\r\n                        max$$1 = value;\r\n                    }\r\n                }\r\n                vals[i] = max$$1;\r\n            }\r\n            return result;\r\n        };\r\n        MathBackendCPU.prototype.maximum = function (a, b) {\r\n            this.assertNotComplex([a, b], 'maximum');\r\n            return this.broadcastedBinaryOp(a, b, a.dtype, function (aVal, bVal) { return Math.max(aVal, bVal); });\r\n        };\r\n        MathBackendCPU.prototype.all = function (x, axes) {\r\n            this.assertNotComplex(x, 'all');\r\n            assertAxesAreInnerMostDims('all', axes, x.rank);\r\n            var _a = computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1];\r\n            var result = zeros(outShape, x.dtype);\r\n            var reduceSize = sizeFromShape(reduceShape);\r\n            var vals = result.dataSync();\r\n            var aVals = x.dataSync();\r\n            for (var i = 0; i < vals.length; ++i) {\r\n                var offset = i * reduceSize;\r\n                var all$$1 = aVals[offset];\r\n                for (var j = 0; j < reduceSize; ++j) {\r\n                    var value = aVals[offset + j];\r\n                    all$$1 = all$$1 && value;\r\n                }\r\n                vals[i] = all$$1;\r\n            }\r\n            return result;\r\n        };\r\n        MathBackendCPU.prototype.any = function (x, axes) {\r\n            this.assertNotComplex(x, 'any');\r\n            assertAxesAreInnerMostDims('any', axes, x.rank);\r\n            var _a = computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1];\r\n            var result = zeros(outShape, x.dtype);\r\n            var reduceSize = sizeFromShape(reduceShape);\r\n            var vals = result.dataSync();\r\n            var aVals = x.dataSync();\r\n            for (var i = 0; i < vals.length; ++i) {\r\n                var offset = i * reduceSize;\r\n                var anyVal = aVals[offset];\r\n                for (var j = 0; j < reduceSize; ++j) {\r\n                    var value = aVals[offset + j];\r\n                    anyVal = anyVal || value;\r\n                }\r\n                vals[i] = anyVal;\r\n            }\r\n            return result;\r\n        };\r\n        MathBackendCPU.prototype.squaredDifference = function (a, b) {\r\n            this.assertNotComplex([a, b], 'squaredDifference');\r\n            return this.broadcastedBinaryOp(a, b, a.dtype, function (aVal, bVal) {\r\n                var diff = aVal - bVal;\r\n                return diff * diff;\r\n            });\r\n        };\r\n        MathBackendCPU.prototype.ceil = function (x) {\r\n            this.assertNotComplex(x, 'ceil');\r\n            var values = x.dataSync();\r\n            var newValues = new Float32Array(values.length);\r\n            for (var i = 0; i < values.length; ++i) {\r\n                newValues[i] = Math.ceil(values[i]);\r\n            }\r\n            return Tensor.make(x.shape, { values: newValues });\r\n        };\r\n        MathBackendCPU.prototype.floor = function (x) {\r\n            this.assertNotComplex(x, 'floor');\r\n            var values = x.dataSync();\r\n            var newValues = new Float32Array(values.length);\r\n            for (var i = 0; i < values.length; ++i) {\r\n                newValues[i] = Math.floor(values[i]);\r\n            }\r\n            return Tensor.make(x.shape, { values: newValues });\r\n        };\r\n        MathBackendCPU.prototype.sign = function (x) {\r\n            this.assertNotComplex(x, 'x');\r\n            var values = x.dataSync();\r\n            var newValues = new Float32Array(values.length);\r\n            for (var i = 0; i < values.length; ++i) {\r\n                if (values[i] < 0) {\r\n                    newValues[i] = -1;\r\n                }\r\n                else if (values[i] > 0) {\r\n                    newValues[i] = 1;\r\n                }\r\n                else {\r\n                    newValues[i] = 0;\r\n                }\r\n            }\r\n            return Tensor.make(x.shape, { values: newValues });\r\n        };\r\n        MathBackendCPU.prototype.round = function (x) {\r\n            this.assertNotComplex(x, 'round');\r\n            var values = x.dataSync();\r\n            var newValues = new Float32Array(values.length);\r\n            for (var i = 0; i < values.length; ++i) {\r\n                var base = Math.floor(values[i]);\r\n                if (values[i] - base < 0.5) {\r\n                    newValues[i] = Math.floor(values[i]);\r\n                }\r\n                else if (values[i] - base > 0.5) {\r\n                    newValues[i] = Math.ceil(values[i]);\r\n                }\r\n                else {\r\n                    if (base % 2.0 === 0.0) {\r\n                        newValues[i] = base;\r\n                    }\r\n                    else {\r\n                        newValues[i] = base + 1.0;\r\n                    }\r\n                }\r\n            }\r\n            return Tensor.make(x.shape, { values: newValues });\r\n        };\r\n        MathBackendCPU.prototype.exp = function (x) {\r\n            this.assertNotComplex(x, 'exp');\r\n            var values = x.dataSync();\r\n            var newValues = new Float32Array(values.length);\r\n            for (var i = 0; i < values.length; ++i) {\r\n                newValues[i] = Math.exp(values[i]);\r\n            }\r\n            return Tensor.make(x.shape, { values: newValues });\r\n        };\r\n        MathBackendCPU.prototype.expm1 = function (x) {\r\n            this.assertNotComplex(x, 'expm1');\r\n            var values = x.dataSync();\r\n            var newValues = new Float32Array(values.length);\r\n            for (var i = 0; i < values.length; ++i) {\r\n                newValues[i] = Math.expm1(values[i]);\r\n            }\r\n            return Tensor.make(x.shape, { values: newValues });\r\n        };\r\n        MathBackendCPU.prototype.log = function (x) {\r\n            this.assertNotComplex(x, 'log');\r\n            var values = x.dataSync();\r\n            var newValues = new Float32Array(values.length);\r\n            for (var i = 0; i < values.length; ++i) {\r\n                var value = values[i];\r\n                newValues[i] = Math.log(value);\r\n            }\r\n            return Tensor.make(x.shape, { values: newValues });\r\n        };\r\n        MathBackendCPU.prototype.log1p = function (x) {\r\n            this.assertNotComplex(x, 'log1p');\r\n            var values = x.dataSync();\r\n            var newValues = new Float32Array(values.length);\r\n            for (var i = 0; i < values.length; ++i) {\r\n                var value = values[i];\r\n                newValues[i] = Math.log1p(value);\r\n            }\r\n            return Tensor.make(x.shape, { values: newValues });\r\n        };\r\n        MathBackendCPU.prototype.sqrt = function (x) {\r\n            this.assertNotComplex(x, 'sqrt');\r\n            var values = x.dataSync();\r\n            var newValues = new Float32Array(values.length);\r\n            for (var i = 0; i < values.length; ++i) {\r\n                var value = values[i];\r\n                newValues[i] = Math.sqrt(value);\r\n            }\r\n            return Tensor.make(x.shape, { values: newValues });\r\n        };\r\n        MathBackendCPU.prototype.rsqrt = function (x) {\r\n            this.assertNotComplex(x, 'rsqrt');\r\n            var values = x.dataSync();\r\n            var newValues = new Float32Array(values.length);\r\n            for (var i = 0; i < values.length; ++i) {\r\n                var value = values[i];\r\n                newValues[i] = 1 / Math.sqrt(value);\r\n            }\r\n            return Tensor.make(x.shape, { values: newValues });\r\n        };\r\n        MathBackendCPU.prototype.square = function (x) {\r\n            this.assertNotComplex(x, 'square');\r\n            var values = x.dataSync();\r\n            var newValues = new Float32Array(values.length);\r\n            for (var i = 0; i < values.length; ++i) {\r\n                var value = values[i];\r\n                newValues[i] = value * value;\r\n            }\r\n            return Tensor.make(x.shape, { values: newValues });\r\n        };\r\n        MathBackendCPU.prototype.reciprocal = function (x) {\r\n            this.assertNotComplex(x, 'reciprocal');\r\n            var values = x.dataSync();\r\n            var newValues = new Float32Array(values.length);\r\n            for (var i = 0; i < values.length; ++i) {\r\n                newValues[i] = 1 / values[i];\r\n            }\r\n            return Tensor.make(x.shape, { values: newValues });\r\n        };\r\n        MathBackendCPU.prototype.linear = function (x) {\r\n            return x;\r\n        };\r\n        MathBackendCPU.prototype.relu = function (x) {\r\n            this.assertNotComplex(x, 'relu');\r\n            var res = zeros(x.shape, x.dtype);\r\n            var resVals = res.dataSync();\r\n            var inVals = x.dataSync();\r\n            for (var i = 0; i < inVals.length; ++i) {\r\n                resVals[i] = Math.max(0, inVals[i]);\r\n            }\r\n            return res;\r\n        };\r\n        MathBackendCPU.prototype.prelu = function (x, a) {\r\n            this.assertNotComplex([x, a], 'prelu');\r\n            return this.broadcastedBinaryOp(x, a, x.dtype, function (xValue, aValue) { return xValue < 0 ? aValue * xValue : xValue; });\r\n        };\r\n        MathBackendCPU.prototype.elu = function (x) {\r\n            this.assertNotComplex(x, 'elu');\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                var v = values[i];\r\n                if (v >= 0) {\r\n                    resultValues[i] = v;\r\n                }\r\n                else {\r\n                    resultValues[i] = (Math.exp(v) - 1);\r\n                }\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.eluDer = function (dy, y) {\r\n            this.assertNotComplex([dy, y], 'eluDer');\r\n            var resultValues = new Float32Array(y.size);\r\n            var values = y.dataSync();\r\n            var dyValues = dy.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                var v = values[i];\r\n                if (v >= 1) {\r\n                    resultValues[i] = dyValues[i];\r\n                }\r\n                else {\r\n                    resultValues[i] = dyValues[i] * (v + 1);\r\n                }\r\n            }\r\n            return Tensor.make(y.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.selu = function (x) {\r\n            this.assertNotComplex(x, 'selu');\r\n            var scaleAlpha = SELU_SCALEALPHA;\r\n            var scale = SELU_SCALE;\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                var v = values[i];\r\n                if (v >= 0) {\r\n                    resultValues[i] = scale * v;\r\n                }\r\n                else {\r\n                    resultValues[i] = scaleAlpha * (Math.exp(v) - 1);\r\n                }\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.clip = function (x, min$$1, max$$1) {\r\n            this.assertNotComplex(x, 'clip');\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                var v = values[i];\r\n                resultValues[i] = v > max$$1 ? max$$1 : (v < min$$1 ? min$$1 : v);\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.abs = function (x) {\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                resultValues[i] = Math.abs(values[i]);\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.complexAbs = function (x) {\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < x.size; ++i) {\r\n                var real$$1 = values[i * 2];\r\n                var imag$$1 = values[i * 2 + 1];\r\n                resultValues[i] = Math.hypot(real$$1, imag$$1);\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.int = function (x) {\r\n            this.assertNotComplex(x, 'int');\r\n            var resultValues = new Int32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                resultValues[i] = values[i];\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues }, 'int32');\r\n        };\r\n        MathBackendCPU.prototype.sigmoid = function (x) {\r\n            this.assertNotComplex(x, 'sigmoid');\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                resultValues[i] = 1 / (1 + Math.exp(-values[i]));\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.softplus = function (x) {\r\n            this.assertNotComplex(x, 'softplus');\r\n            var epsilon = 1.1920928955078125e-7;\r\n            var threshold = Math.log(epsilon) + 2.0;\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                var tooLarge = values[i] > -threshold;\r\n                var tooSmall = values[i] < threshold;\r\n                var expX = Math.exp(values[i]);\r\n                var result = void 0;\r\n                if (tooSmall) {\r\n                    result = expX;\r\n                }\r\n                else if (tooLarge) {\r\n                    result = values[i];\r\n                }\r\n                else {\r\n                    result = Math.log(1.0 + expX);\r\n                }\r\n                resultValues[i] = result;\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.sin = function (x) {\r\n            this.assertNotComplex(x, 'sin');\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                resultValues[i] = Math.sin(values[i]);\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.cos = function (x) {\r\n            this.assertNotComplex(x, 'cos');\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                resultValues[i] = Math.cos(values[i]);\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.tan = function (x) {\r\n            this.assertNotComplex(x, 'tan');\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                resultValues[i] = Math.tan(values[i]);\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.asin = function (x) {\r\n            this.assertNotComplex(x, 'asin');\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                resultValues[i] = Math.asin(values[i]);\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.acos = function (x) {\r\n            this.assertNotComplex(x, 'acos');\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                resultValues[i] = Math.acos(values[i]);\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.atan = function (x) {\r\n            this.assertNotComplex(x, 'atan');\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                resultValues[i] = Math.atan(values[i]);\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.atan2 = function (a, b) {\r\n            this.assertNotComplex([a, b], 'atan2');\r\n            return this.broadcastedBinaryOp(a, b, a.dtype, function (aValue, bValue) { return Math.atan2(aValue, bValue); });\r\n        };\r\n        MathBackendCPU.prototype.sinh = function (x) {\r\n            this.assertNotComplex(x, 'sinh');\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                resultValues[i] = Math.sinh(values[i]);\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.cosh = function (x) {\r\n            this.assertNotComplex(x, 'cosh');\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                resultValues[i] = Math.cosh(values[i]);\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.tanh = function (x) {\r\n            this.assertNotComplex(x, 'tanh');\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                resultValues[i] = tanh(values[i]);\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.asinh = function (x) {\r\n            this.assertNotComplex(x, 'asinh');\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                resultValues[i] = Math.asinh(values[i]);\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.acosh = function (x) {\r\n            this.assertNotComplex(x, 'acosh');\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                resultValues[i] = Math.acosh(values[i]);\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.atanh = function (x) {\r\n            this.assertNotComplex(x, 'atanh');\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                resultValues[i] = Math.atanh(values[i]);\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.erf = function (x) {\r\n            this.assertNotComplex(x, 'erf');\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            var p = ERF_P;\r\n            var a1 = ERF_A1;\r\n            var a2 = ERF_A2;\r\n            var a3 = ERF_A3;\r\n            var a4 = ERF_A4;\r\n            var a5 = ERF_A5;\r\n            for (var i = 0; i < values.length; ++i) {\r\n                var v = values[i];\r\n                var t = 1.0 / (1.0 + p * v);\r\n                resultValues[i] = 1.0 -\r\n                    (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t *\r\n                        Math.exp(-v * v);\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.step = function (x, alpha) {\r\n            if (alpha === void 0) { alpha = 0; }\r\n            this.assertNotComplex(x, 'step');\r\n            var resultValues = new Float32Array(x.size);\r\n            var values = x.dataSync();\r\n            for (var i = 0; i < values.length; ++i) {\r\n                var value = values[i];\r\n                if (isNaN(value)) {\r\n                    resultValues[i] = NaN;\r\n                }\r\n                else {\r\n                    resultValues[i] = value > 0 ? 1 : alpha;\r\n                }\r\n            }\r\n            return Tensor.make(x.shape, { values: resultValues });\r\n        };\r\n        MathBackendCPU.prototype.conv2d = function (x, filter, convInfo) {\r\n            this.assertNotComplex([x, filter], 'conv2d');\r\n            var filterHeight = convInfo.filterHeight;\r\n            var filterWidth = convInfo.filterWidth;\r\n            var dilationHeight = convInfo.dilationHeight;\r\n            var dilationWidth = convInfo.dilationWidth;\r\n            var padLeft = convInfo.padInfo.left;\r\n            var padTop = convInfo.padInfo.top;\r\n            var y = buffer(convInfo.outShape, x.dtype);\r\n            var xVals = x.dataSync();\r\n            var wVals = filter.dataSync();\r\n            var yVals = y.values;\r\n            for (var b = 0; b < convInfo.batchSize; ++b) {\r\n                var xOffset1 = b * x.strides[0];\r\n                var yOffset1 = b * y.strides[0];\r\n                for (var yR = 0; yR < convInfo.outHeight; ++yR) {\r\n                    var yOffset2 = yOffset1 + yR * y.strides[1];\r\n                    var xRCorner = yR * convInfo.strideHeight - padLeft;\r\n                    for (var wR = 0; wR < filterHeight; wR++) {\r\n                        var xR = xRCorner + wR * dilationHeight;\r\n                        if (xR < 0 || xR >= convInfo.inHeight) {\r\n                            continue;\r\n                        }\r\n                        var wOffset1 = wR * filter.strides[0];\r\n                        var xOffset2 = xOffset1 + xR * x.strides[1];\r\n                        for (var yC = 0; yC < convInfo.outWidth; ++yC) {\r\n                            var yOffset3 = yOffset2 + yC * convInfo.outChannels;\r\n                            var xCCorner = yC * convInfo.strideWidth - padTop;\r\n                            for (var wC = 0; wC < filterWidth; wC++) {\r\n                                var xC = xCCorner + wC * dilationWidth;\r\n                                if (xC < 0 || xC >= convInfo.inWidth) {\r\n                                    continue;\r\n                                }\r\n                                var wOffset2 = wOffset1 + wC * filter.strides[1];\r\n                                var xOffset3 = xOffset2 + xC * convInfo.inChannels;\r\n                                var wOffset3 = wOffset2;\r\n                                for (var d1 = 0; d1 < convInfo.inChannels; ++d1) {\r\n                                    var xVal = xVals[xOffset3 + d1];\r\n                                    for (var d2 = 0; d2 < convInfo.outChannels; ++d2) {\r\n                                        yVals[yOffset3 + d2] += xVal * wVals[wOffset3 + d2];\r\n                                    }\r\n                                    wOffset3 += convInfo.outChannels;\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return y.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.conv3d = function (x, filter, convInfo) {\r\n            var filterDepth = convInfo.filterDepth;\r\n            var filterHeight = convInfo.filterHeight;\r\n            var filterWidth = convInfo.filterWidth;\r\n            var dilationDepth = convInfo.dilationDepth;\r\n            var dilationHeight = convInfo.dilationHeight;\r\n            var dilationWidth = convInfo.dilationWidth;\r\n            var padFront = convInfo.padInfo.front;\r\n            var padLeft = convInfo.padInfo.left;\r\n            var padTop = convInfo.padInfo.top;\r\n            var y = buffer(convInfo.outShape, x.dtype);\r\n            var xVals = x.dataSync();\r\n            var wVals = filter.dataSync();\r\n            var yVals = y.values;\r\n            for (var b = 0; b < convInfo.batchSize; ++b) {\r\n                var xOffset1 = b * x.strides[0];\r\n                var yOffset1 = b * y.strides[0];\r\n                for (var yF = 0; yF < convInfo.outDepth; ++yF) {\r\n                    var yOffset2 = yOffset1 + yF * y.strides[1];\r\n                    var xFCorner = yF * convInfo.strideDepth - padFront;\r\n                    for (var wF = 0; wF < filterDepth; wF++) {\r\n                        var xF = xFCorner + wF * dilationDepth;\r\n                        if (xF < 0 || xF >= convInfo.inDepth) {\r\n                            continue;\r\n                        }\r\n                        var wOffset1 = wF * filter.strides[0];\r\n                        var xOffset2 = xOffset1 + xF * x.strides[1];\r\n                        for (var yR = 0; yR < convInfo.outHeight; ++yR) {\r\n                            var yOffset3 = yOffset2 + yR * y.strides[2];\r\n                            var xRCorner = yR * convInfo.strideHeight - padTop;\r\n                            for (var wR = 0; wR < filterHeight; wR++) {\r\n                                var xR = xRCorner + wR * dilationHeight;\r\n                                if (xR < 0 || xR >= convInfo.inHeight) {\r\n                                    continue;\r\n                                }\r\n                                var wOffset2 = wOffset1 + wR * filter.strides[1];\r\n                                var xOffset3 = xOffset2 + xR * x.strides[2];\r\n                                for (var yC = 0; yC < convInfo.outWidth; ++yC) {\r\n                                    var yOffset4 = yOffset3 + yC * convInfo.outChannels;\r\n                                    var xCCorner = yC * convInfo.strideWidth - padLeft;\r\n                                    for (var wC = 0; wC < filterWidth; wC++) {\r\n                                        var xC = xCCorner + wC * dilationWidth;\r\n                                        if (xC < 0 || xC >= convInfo.inWidth) {\r\n                                            continue;\r\n                                        }\r\n                                        var wOffset3 = wOffset2 + wC * filter.strides[2];\r\n                                        var xOffset4 = xOffset3 + xC * convInfo.inChannels;\r\n                                        var wOffset4 = wOffset3;\r\n                                        for (var d1 = 0; d1 < convInfo.inChannels; ++d1) {\r\n                                            var xVal = xVals[xOffset4 + d1];\r\n                                            for (var d2 = 0; d2 < convInfo.outChannels; ++d2) {\r\n                                                yVals[yOffset4 + d2] += xVal * wVals[wOffset4 + d2];\r\n                                            }\r\n                                            wOffset4 += convInfo.outChannels;\r\n                                        }\r\n                                    }\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return y.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.conv2dDerInput = function (dy, filter, convInfo) {\r\n            this.assertNotComplex([dy, filter], 'conv2dDerInput');\r\n            var dx = buffer(convInfo.inShape, 'float32');\r\n            var dxValues = dx.values;\r\n            var _a = dx.strides, dxS0 = _a[0], dxS1 = _a[1], dxS2 = _a[2];\r\n            var dyValues = dy.dataSync();\r\n            var _b = dy.strides, dyS0 = _b[0], dyS1 = _b[1], dyS2 = _b[2];\r\n            var fltValues = filter.dataSync();\r\n            var _c = filter.strides, fltS0 = _c[0], fltS1 = _c[1], fltS2 = _c[2];\r\n            var batchSize = convInfo.batchSize, filterHeight = convInfo.filterHeight, filterWidth = convInfo.filterWidth, inChannels = convInfo.inChannels, inHeight = convInfo.inHeight, inWidth = convInfo.inWidth, outChannels = convInfo.outChannels, outHeight = convInfo.outHeight, outWidth = convInfo.outWidth, strideHeight = convInfo.strideHeight, strideWidth = convInfo.strideWidth;\r\n            var topPad = filterHeight - 1 - convInfo.padInfo.top;\r\n            var leftPad = filterWidth - 1 - convInfo.padInfo.left;\r\n            for (var b = 0; b < batchSize; ++b) {\r\n                for (var d1 = 0; d1 < inChannels; ++d1) {\r\n                    for (var xR = 0; xR < inHeight; ++xR) {\r\n                        var xRCorner = xR - topPad;\r\n                        var xRMin = Math.max(0, Math.ceil(xRCorner / strideHeight));\r\n                        var yRMax = Math.min(outHeight, (filterHeight + xRCorner) / strideHeight);\r\n                        for (var xC = 0; xC < inWidth; ++xC) {\r\n                            var xCCorner = xC - leftPad;\r\n                            var xCMin = Math.max(0, Math.ceil(xCCorner / strideWidth));\r\n                            var yCMax = Math.min(outWidth, (filterWidth + xCCorner) / strideWidth);\r\n                            var dotProd = 0;\r\n                            for (var yR = xRMin; yR < yRMax; ++yR) {\r\n                                var wR = yR * strideHeight - xRCorner;\r\n                                for (var yC = xCMin; yC < yCMax; ++yC) {\r\n                                    var wC = yC * strideWidth - xCCorner;\r\n                                    var dyOffset = dyS0 * b + dyS1 * yR + dyS2 * yC;\r\n                                    var fltOffset = fltS0 * (filterHeight - 1 - wR) +\r\n                                        fltS1 * (filterWidth - 1 - wC) + fltS2 * d1;\r\n                                    for (var d2 = 0; d2 < outChannels; ++d2) {\r\n                                        var pixel = dyValues[dyOffset + d2];\r\n                                        var weight = fltValues[fltOffset + d2];\r\n                                        dotProd += pixel * weight;\r\n                                    }\r\n                                }\r\n                            }\r\n                            dxValues[dxS0 * b + dxS1 * xR + dxS2 * xC + d1] = dotProd;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return dx.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.conv3dDerInput = function (dy, filter, convInfo) {\r\n            var dx = buffer(convInfo.inShape, 'float32');\r\n            var dxValues = dx.values;\r\n            var _a = dx.strides, dxS0 = _a[0], dxS1 = _a[1], dxS2 = _a[2], dxS3 = _a[3];\r\n            var dyValues = dy.dataSync();\r\n            var _b = dy.strides, dyS0 = _b[0], dyS1 = _b[1], dyS2 = _b[2], dyS3 = _b[3];\r\n            var fltValues = filter.dataSync();\r\n            var _c = filter.strides, fltS0 = _c[0], fltS1 = _c[1], fltS2 = _c[2], fltS3 = _c[3];\r\n            var batchSize = convInfo.batchSize, filterDepth = convInfo.filterDepth, filterHeight = convInfo.filterHeight, filterWidth = convInfo.filterWidth, inChannels = convInfo.inChannels, inDepth = convInfo.inDepth, inHeight = convInfo.inHeight, inWidth = convInfo.inWidth, outChannels = convInfo.outChannels, outDepth = convInfo.outDepth, outHeight = convInfo.outHeight, outWidth = convInfo.outWidth, strideDepth = convInfo.strideDepth, strideHeight = convInfo.strideHeight, strideWidth = convInfo.strideWidth;\r\n            var frontPad = filterDepth - 1 - convInfo.padInfo.front;\r\n            var topPad = filterHeight - 1 - convInfo.padInfo.top;\r\n            var leftPad = filterWidth - 1 - convInfo.padInfo.left;\r\n            for (var b = 0; b < batchSize; ++b) {\r\n                for (var d1 = 0; d1 < inChannels; ++d1) {\r\n                    for (var xF = 0; xF < inDepth; ++xF) {\r\n                        var xFCorner = xF - frontPad;\r\n                        var xFMin = Math.max(0, Math.ceil(xFCorner / strideDepth));\r\n                        var yFMax = Math.min(outDepth, (filterDepth + xFCorner) / strideDepth);\r\n                        for (var xR = 0; xR < inHeight; ++xR) {\r\n                            var xRCorner = xR - topPad;\r\n                            var xRMin = Math.max(0, Math.ceil(xRCorner / strideHeight));\r\n                            var yRMax = Math.min(outHeight, (filterHeight + xRCorner) / strideHeight);\r\n                            for (var xC = 0; xC < inWidth; ++xC) {\r\n                                var xCCorner = xC - leftPad;\r\n                                var xCMin = Math.max(0, Math.ceil(xCCorner / strideWidth));\r\n                                var yCMax = Math.min(outWidth, (filterWidth + xCCorner) / strideWidth);\r\n                                var dotProd = 0;\r\n                                for (var yF = xFMin; yF < yFMax; ++yF) {\r\n                                    var wF = yF * strideDepth - xFCorner;\r\n                                    for (var yR = xRMin; yR < yRMax; ++yR) {\r\n                                        var wR = yR * strideHeight - xRCorner;\r\n                                        for (var yC = xCMin; yC < yCMax; ++yC) {\r\n                                            var wC = yC * strideWidth - xCCorner;\r\n                                            var dyOffset = dyS0 * b + dyS1 * yF + dyS2 * yR + dyS3 * yC;\r\n                                            var fltOffset = fltS0 * (filterDepth - 1 - wF) +\r\n                                                fltS1 * (filterHeight - 1 - wR) +\r\n                                                fltS2 * (filterWidth - 1 - wC) + fltS3 * d1;\r\n                                            for (var d2 = 0; d2 < outChannels; ++d2) {\r\n                                                var pixel = dyValues[dyOffset + d2];\r\n                                                var weight = fltValues[fltOffset + d2];\r\n                                                dotProd += pixel * weight;\r\n                                            }\r\n                                        }\r\n                                    }\r\n                                }\r\n                                dxValues[dxS0 * b + dxS1 * xF + dxS2 * xR + dxS3 * xC + d1] =\r\n                                    dotProd;\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return dx.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.conv2dDerFilter = function (x, dy, convInfo) {\r\n            this.assertNotComplex([x, dy], 'conv2dDerFilter');\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var filterHeight = convInfo.filterHeight;\r\n            var filterWidth = convInfo.filterWidth;\r\n            var dW = buffer(convInfo.filterShape, 'float32');\r\n            var leftPad = convInfo.padInfo.left;\r\n            var topPad = convInfo.padInfo.top;\r\n            for (var wR = 0; wR < filterHeight; ++wR) {\r\n                var yRMin = Math.max(0, Math.ceil((topPad - wR) / strideHeight));\r\n                var yRMax = Math.min(convInfo.outHeight, (convInfo.inHeight + topPad - wR) / strideHeight);\r\n                for (var wC = 0; wC < filterWidth; ++wC) {\r\n                    var yCMin = Math.max(0, Math.ceil((leftPad - wC) / strideWidth));\r\n                    var yCMax = Math.min(convInfo.outWidth, (convInfo.inWidth + leftPad - wC) / strideWidth);\r\n                    for (var d1 = 0; d1 < convInfo.inChannels; ++d1) {\r\n                        for (var d2 = 0; d2 < convInfo.outChannels; ++d2) {\r\n                            var dotProd = 0;\r\n                            for (var b = 0; b < convInfo.batchSize; ++b) {\r\n                                for (var yR = yRMin; yR < yRMax; ++yR) {\r\n                                    var xR = wR + yR * strideHeight - topPad;\r\n                                    for (var yC = yCMin; yC < yCMax; ++yC) {\r\n                                        var xC = wC + yC * strideWidth - leftPad;\r\n                                        dotProd += x.get(b, xR, xC, d1) * dy.get(b, yR, yC, d2);\r\n                                    }\r\n                                }\r\n                            }\r\n                            dW.set(dotProd, wR, wC, d1, d2);\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return dW.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.conv3dDerFilter = function (x, dy, convInfo) {\r\n            var strideDepth = convInfo.strideDepth;\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var filterDepth = convInfo.filterDepth;\r\n            var filterHeight = convInfo.filterHeight;\r\n            var filterWidth = convInfo.filterWidth;\r\n            var dw = buffer(convInfo.filterShape, 'float32');\r\n            var dwValues = dw.values;\r\n            var _a = dw.strides, dwS0 = _a[0], dwS1 = _a[1], dwS2 = _a[2], dwS3 = _a[3];\r\n            var dyValues = dy.dataSync();\r\n            var _b = dy.strides, dyS0 = _b[0], dyS1 = _b[1], dyS2 = _b[2], dyS3 = _b[3];\r\n            var xValues = x.dataSync();\r\n            var _c = x.strides, xS0 = _c[0], xS1 = _c[1], xS2 = _c[2], xS3 = _c[3];\r\n            var frontPad = convInfo.padInfo.front;\r\n            var leftPad = convInfo.padInfo.left;\r\n            var topPad = convInfo.padInfo.top;\r\n            for (var wF = 0; wF < filterDepth; ++wF) {\r\n                var yFMin = Math.max(0, Math.ceil((frontPad - wF) / strideDepth));\r\n                var yFMax = Math.min(convInfo.outDepth, (convInfo.inDepth + frontPad - wF) / strideDepth);\r\n                var wOffset1 = wF * dwS0;\r\n                for (var wR = 0; wR < filterHeight; ++wR) {\r\n                    var yRMin = Math.max(0, Math.ceil((topPad - wR) / strideHeight));\r\n                    var yRMax = Math.min(convInfo.outHeight, (convInfo.inHeight + topPad - wR) / strideHeight);\r\n                    var wOffset2 = wR * dwS1 + wOffset1;\r\n                    for (var wC = 0; wC < filterWidth; ++wC) {\r\n                        var yCMin = Math.max(0, Math.ceil((leftPad - wC) / strideWidth));\r\n                        var yCMax = Math.min(convInfo.outWidth, (convInfo.inWidth + leftPad - wC) / strideWidth);\r\n                        var wOffset3 = wC * dwS2 + wOffset2;\r\n                        for (var d1 = 0; d1 < convInfo.inChannels; ++d1) {\r\n                            var wOffset4 = d1 * dwS3 + wOffset3;\r\n                            for (var d2 = 0; d2 < convInfo.outChannels; ++d2) {\r\n                                var dotProd = 0;\r\n                                for (var b = 0; b < convInfo.batchSize; ++b) {\r\n                                    var xOffset1 = b * xS0;\r\n                                    var yOffset1 = b * dyS0;\r\n                                    for (var yF = yFMin; yF < yFMax; ++yF) {\r\n                                        var xF = wF + yF * strideDepth - frontPad;\r\n                                        var xOffset2 = xF * xS1 + xOffset1;\r\n                                        var yOffset2 = yF * dyS1 + yOffset1;\r\n                                        for (var yR = yRMin; yR < yRMax; ++yR) {\r\n                                            var xR = wR + yR * strideHeight - topPad;\r\n                                            var xOffset3 = xR * xS2 + xOffset2;\r\n                                            var yOffset3 = yR * dyS2 + yOffset2;\r\n                                            for (var yC = yCMin; yC < yCMax; ++yC) {\r\n                                                var xC = wC + yC * strideWidth - leftPad;\r\n                                                var xOffset4 = xC * xS3 + xOffset3;\r\n                                                var yOffset4 = yC * dyS3 + yOffset3;\r\n                                                dotProd +=\r\n                                                    xValues[xOffset4 + d1] * dyValues[yOffset4 + d2];\r\n                                            }\r\n                                        }\r\n                                    }\r\n                                }\r\n                                dwValues[wOffset4 + d2] = dotProd;\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return dw.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.depthwiseConv2D = function (x, filter, convInfo) {\r\n            this.assertNotComplex([x, filter], 'depthwiseConv2D');\r\n            var filterHeight = convInfo.filterHeight;\r\n            var filterWidth = convInfo.filterWidth;\r\n            var dilationHeight = convInfo.dilationHeight;\r\n            var dilationWidth = convInfo.dilationWidth;\r\n            var padLeft = convInfo.padInfo.left;\r\n            var padTop = convInfo.padInfo.top;\r\n            var chMul = convInfo.outChannels / convInfo.inChannels;\r\n            var y = buffer(convInfo.outShape, x.dtype);\r\n            var xVals = x.dataSync();\r\n            var wVals = filter.dataSync();\r\n            var yVals = y.values;\r\n            for (var b = 0; b < convInfo.batchSize; ++b) {\r\n                var xOffset1 = b * x.strides[0];\r\n                var yOffset1 = b * y.strides[0];\r\n                for (var yR = 0; yR < convInfo.outHeight; ++yR) {\r\n                    var yOffset2 = yOffset1 + yR * y.strides[1];\r\n                    var xRCorner = yR * convInfo.strideHeight - padLeft;\r\n                    for (var wR = 0; wR < filterHeight; ++wR) {\r\n                        var xR = xRCorner + wR * dilationHeight;\r\n                        if (xR < 0 || xR >= convInfo.inHeight) {\r\n                            continue;\r\n                        }\r\n                        var wOffset1 = wR * filter.strides[0];\r\n                        var xOffset2 = xOffset1 + xR * x.strides[1];\r\n                        for (var yC = 0; yC < convInfo.outWidth; ++yC) {\r\n                            var yOffset3 = yOffset2 + yC * y.strides[2];\r\n                            var xCCorner = yC * convInfo.strideWidth - padTop;\r\n                            for (var wC = 0; wC < filterWidth; ++wC) {\r\n                                var xC = xCCorner + wC * dilationWidth;\r\n                                if (xC < 0 || xC >= convInfo.inWidth) {\r\n                                    continue;\r\n                                }\r\n                                var wOffset2 = wOffset1 + wC * filter.strides[1];\r\n                                var xOffset3 = xOffset2 + xC * convInfo.inChannels;\r\n                                var yOffset4 = yOffset3;\r\n                                var wOffset3 = wOffset2;\r\n                                for (var d1 = 0; d1 < convInfo.inChannels; ++d1) {\r\n                                    var xVal = xVals[xOffset3 + d1];\r\n                                    for (var q = 0; q < chMul; ++q) {\r\n                                        yVals[yOffset4 + q] += xVal * wVals[wOffset3 + q];\r\n                                    }\r\n                                    yOffset4 += chMul;\r\n                                    wOffset3 += chMul;\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return y.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.depthwiseConv2DDerInput = function (dy, filter, convInfo) {\r\n            this.assertNotComplex([dy, filter], 'depthwiseConv2DDerInput');\r\n            var dx = buffer(convInfo.inShape, 'float32');\r\n            var dxValues = dx.values;\r\n            var _a = dx.strides, dxS0 = _a[0], dxS1 = _a[1], dxS2 = _a[2];\r\n            var dyValues = dy.dataSync();\r\n            var _b = dy.strides, dyS0 = _b[0], dyS1 = _b[1], dyS2 = _b[2];\r\n            var fltValues = filter.dataSync();\r\n            var _c = filter.strides, fltS0 = _c[0], fltS1 = _c[1], fltS2 = _c[2];\r\n            var batchSize = convInfo.batchSize, filterHeight = convInfo.filterHeight, filterWidth = convInfo.filterWidth, inChannels = convInfo.inChannels, inHeight = convInfo.inHeight, inWidth = convInfo.inWidth, outChannels = convInfo.outChannels, outHeight = convInfo.outHeight, outWidth = convInfo.outWidth, strideHeight = convInfo.strideHeight, strideWidth = convInfo.strideWidth;\r\n            var topPad = filterHeight - 1 - convInfo.padInfo.top;\r\n            var leftPad = filterWidth - 1 - convInfo.padInfo.left;\r\n            var chMul = outChannels / inChannels;\r\n            for (var b = 0; b < batchSize; ++b) {\r\n                for (var d1 = 0; d1 < inChannels; ++d1) {\r\n                    for (var xR = 0; xR < inHeight; ++xR) {\r\n                        var xRCorner = xR - topPad;\r\n                        var xRMin = Math.max(0, Math.ceil(xRCorner / strideHeight));\r\n                        var yRMax = Math.min(outHeight, (filterHeight + xRCorner) / strideHeight);\r\n                        for (var xC = 0; xC < inWidth; ++xC) {\r\n                            var xCCorner = xC - leftPad;\r\n                            var xCMin = Math.max(0, Math.ceil(xCCorner / strideWidth));\r\n                            var yCMax = Math.min(outWidth, (filterWidth + xCCorner) / strideWidth);\r\n                            var dotProd = 0;\r\n                            for (var yR = xRMin; yR < yRMax; ++yR) {\r\n                                var wR = yR * strideHeight - xRCorner;\r\n                                for (var yC = xCMin; yC < yCMax; ++yC) {\r\n                                    var wC = yC * strideWidth - xCCorner;\r\n                                    var dyOffset = dyS0 * b + dyS1 * yR + dyS2 * yC;\r\n                                    var fltOffset = fltS0 * (filterHeight - 1 - wR) +\r\n                                        fltS1 * (filterWidth - 1 - wC) + fltS2 * d1;\r\n                                    for (var dm = 0; dm < chMul; ++dm) {\r\n                                        var d2 = d1 * chMul + dm;\r\n                                        var pixel = dyValues[dyOffset + d2];\r\n                                        var weight = fltValues[fltOffset + dm];\r\n                                        dotProd += pixel * weight;\r\n                                    }\r\n                                }\r\n                            }\r\n                            dxValues[dxS0 * b + dxS1 * xR + dxS2 * xC + d1] = dotProd;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return dx.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.depthwiseConv2DDerFilter = function (x, dy, convInfo) {\r\n            this.assertNotComplex([x, dy], 'depthwiseConv2DDerFilter');\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var filterHeight = convInfo.filterHeight;\r\n            var filterWidth = convInfo.filterWidth;\r\n            var dW = buffer(convInfo.filterShape, 'float32');\r\n            var leftPad = convInfo.padInfo.left;\r\n            var topPad = convInfo.padInfo.top;\r\n            var chMul = convInfo.outChannels / convInfo.inChannels;\r\n            for (var wR = 0; wR < filterHeight; ++wR) {\r\n                var yRMin = Math.max(0, Math.ceil((topPad - wR) / strideHeight));\r\n                var yRMax = Math.min(convInfo.outHeight, (convInfo.inHeight + topPad - wR) / strideHeight);\r\n                for (var wC = 0; wC < filterWidth; ++wC) {\r\n                    var yCMin = Math.max(0, Math.ceil((leftPad - wC) / strideWidth));\r\n                    var yCMax = Math.min(convInfo.outWidth, (convInfo.inWidth + leftPad - wC) / strideWidth);\r\n                    for (var d2 = 0; d2 < convInfo.outChannels; ++d2) {\r\n                        var d1 = Math.trunc(d2 / chMul);\r\n                        var dm = d2 % chMul;\r\n                        var dotProd = 0;\r\n                        for (var b = 0; b < convInfo.batchSize; ++b) {\r\n                            for (var yR = yRMin; yR < yRMax; ++yR) {\r\n                                var xR = wR + yR * strideHeight - topPad;\r\n                                for (var yC = yCMin; yC < yCMax; ++yC) {\r\n                                    var xC = wC + yC * strideWidth - leftPad;\r\n                                    dotProd += x.get(b, xR, xC, d1) * dy.get(b, yR, yC, d2);\r\n                                }\r\n                            }\r\n                        }\r\n                        dW.set(dotProd, wR, wC, d1, dm);\r\n                    }\r\n                }\r\n            }\r\n            return dW.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.tile = function (x, reps) {\r\n            this.assertNotComplex(x, 'tile');\r\n            var newShape = new Array(x.rank);\r\n            for (var i = 0; i < newShape.length; i++) {\r\n                newShape[i] = x.shape[i] * reps[i];\r\n            }\r\n            var result = buffer(newShape, x.dtype);\r\n            var xBuf = x.buffer();\r\n            for (var i = 0; i < result.values.length; ++i) {\r\n                var newLoc = result.indexToLoc(i);\r\n                var originalLoc = new Array(x.rank);\r\n                for (var i_1 = 0; i_1 < originalLoc.length; i_1++) {\r\n                    originalLoc[i_1] = newLoc[i_1] % x.shape[i_1];\r\n                }\r\n                var originalIndex = xBuf.locToIndex(originalLoc);\r\n                result.values[i] = xBuf.values[originalIndex];\r\n            }\r\n            return result.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.pad = function (x, paddings, constantValue) {\r\n            this.assertNotComplex(x, 'pad');\r\n            var outShape = paddings.map(function (p, i) { return p[0] + x.shape[i] + p[1]; });\r\n            var start = paddings.map(function (p) { return p[0]; });\r\n            var xBuffer = x.buffer();\r\n            var buffer$$1 = buffer(outShape, x.dtype);\r\n            if (constantValue !== 0) {\r\n                buffer$$1.values.fill(constantValue);\r\n            }\r\n            for (var i = 0; i < x.size; i++) {\r\n                var coords = xBuffer.indexToLoc(i);\r\n                var outCoords = coords.map(function (c, i) { return c + start[i]; });\r\n                buffer$$1.set.apply(buffer$$1, [x.get.apply(x, coords)].concat(outCoords));\r\n            }\r\n            return buffer$$1.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.transpose = function (x, perm) {\r\n            this.assertNotComplex(x, 'transpose');\r\n            var newShape = new Array(x.rank);\r\n            for (var i = 0; i < newShape.length; i++) {\r\n                newShape[i] = x.shape[perm[i]];\r\n            }\r\n            var values = x.dataSync();\r\n            var result = buffer(newShape, x.dtype);\r\n            var xBuf = x.buffer();\r\n            for (var i = 0; i < x.size; ++i) {\r\n                var loc = xBuf.indexToLoc(i);\r\n                var newLoc = new Array(loc.length);\r\n                for (var i_2 = 0; i_2 < newLoc.length; i_2++) {\r\n                    newLoc[i_2] = loc[perm[i_2]];\r\n                }\r\n                var newIndex = result.locToIndex(newLoc);\r\n                result.values[newIndex] = values[i];\r\n            }\r\n            return result.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.gather = function (x, indices, axis) {\r\n            this.assertNotComplex([x, indices], 'gather');\r\n            var newShape = x.shape.slice();\r\n            var indicesValues = indices.dataSync();\r\n            newShape[axis] = indicesValues.length;\r\n            var result = buffer(newShape, x.dtype);\r\n            var xBuf = x.buffer();\r\n            for (var i = 0; i < result.size; ++i) {\r\n                var newLoc = result.indexToLoc(i);\r\n                var originalLoc = newLoc.slice();\r\n                originalLoc[axis] = indicesValues[newLoc[axis]];\r\n                var originalIndex = xBuf.locToIndex(originalLoc);\r\n                result.values[i] = xBuf.values[originalIndex];\r\n            }\r\n            return result.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.batchToSpaceND = function (x, blockShape, crops) {\r\n            this.assertNotComplex([x], 'batchToSpaceND');\r\n            var prod$$1 = blockShape.reduce(function (a, b) { return a * b; });\r\n            var reshaped = getReshaped(x.shape, blockShape, prod$$1);\r\n            var permuted = getPermuted(reshaped.length, blockShape.length);\r\n            var reshapedPermuted = getReshapedPermuted(x.shape, blockShape, prod$$1);\r\n            var sliceBeginCoords = getSliceBeginCoords(crops, blockShape.length);\r\n            var sliceSize = getSliceSize(reshapedPermuted, crops, blockShape.length);\r\n            return x.reshape(reshaped)\r\n                .transpose(permuted)\r\n                .reshape(reshapedPermuted)\r\n                .slice(sliceBeginCoords, sliceSize);\r\n        };\r\n        MathBackendCPU.prototype.spaceToBatchND = function (x, blockShape, paddings) {\r\n            this.assertNotComplex([x], 'spaceToBatchND');\r\n            var prod$$1 = blockShape.reduce(function (a, b) { return a * b; });\r\n            var completePaddings = [[0, 0]];\r\n            completePaddings.push.apply(completePaddings, paddings);\r\n            for (var i = 1 + blockShape.length; i < x.shape.length; ++i) {\r\n                completePaddings.push([0, 0]);\r\n            }\r\n            var paddedX = x.pad(completePaddings);\r\n            var reshapedPaddedShape = getReshaped(paddedX.shape, blockShape, prod$$1, false);\r\n            var permutedReshapedPaddedPermutation = getPermuted(reshapedPaddedShape.length, blockShape.length, false);\r\n            var flattenShape = getReshapedPermuted(paddedX.shape, blockShape, prod$$1, false);\r\n            return paddedX.reshape(reshapedPaddedShape)\r\n                .transpose(permutedReshapedPaddedPermutation)\r\n                .reshape(flattenShape);\r\n        };\r\n        MathBackendCPU.prototype.pool = function (x, convInfo, poolType) {\r\n            this.assertNotComplex(x, 'pool');\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var dilationHeight = convInfo.dilationHeight;\r\n            var dilationWidth = convInfo.dilationWidth;\r\n            var effectiveFilterHeight = convInfo.effectiveFilterHeight;\r\n            var effectiveFilterWidth = convInfo.effectiveFilterWidth;\r\n            var padTop = convInfo.padInfo.top;\r\n            var padLeft = convInfo.padInfo.left;\r\n            var initialValue = (poolType === 'max' ? Number.NEGATIVE_INFINITY :\r\n                Number.POSITIVE_INFINITY);\r\n            var xValues = x.dataSync();\r\n            var output = buffer(convInfo.outShape, x.dtype);\r\n            var outputVals = output.values;\r\n            var outputBatchStrides = convInfo.outShape[1] * convInfo.outShape[2] * convInfo.outShape[3];\r\n            var outputRowStrides = convInfo.outShape[2] * convInfo.outShape[3];\r\n            var outputColStrides = convInfo.outShape[3];\r\n            for (var b = 0; b < convInfo.batchSize; ++b) {\r\n                var outputBatchOffset = b * outputBatchStrides;\r\n                var inputBatchOffset = b * x.strides[0];\r\n                for (var d = 0; d < convInfo.inChannels; ++d) {\r\n                    for (var yR = 0; yR < convInfo.outHeight; ++yR) {\r\n                        var xRCorner = yR * strideHeight - padTop;\r\n                        var xRMin = Math.max(0, xRCorner);\r\n                        var xRMax = Math.min(convInfo.inHeight, effectiveFilterHeight + xRCorner);\r\n                        var outputRowOffset = outputBatchOffset + yR * outputRowStrides;\r\n                        for (var yC = 0; yC < convInfo.outWidth; ++yC) {\r\n                            var xCCorner = yC * strideWidth - padLeft;\r\n                            var xCMin = Math.max(0, xCCorner);\r\n                            var xCMax = Math.min(convInfo.inWidth, effectiveFilterWidth + xCCorner);\r\n                            var minMaxValue = initialValue;\r\n                            var avgValue = 0;\r\n                            var count = 0;\r\n                            for (var xR = xRMin; xR < xRMax; xR += dilationHeight) {\r\n                                var xROffset = inputBatchOffset + xR * x.strides[1];\r\n                                for (var xC = xCMin; xC < xCMax; xC += dilationWidth) {\r\n                                    var xCOffset = xROffset + xC * x.strides[2];\r\n                                    var pixel = xValues[xCOffset + d];\r\n                                    if ((poolType === 'max' && pixel > minMaxValue)) {\r\n                                        minMaxValue = pixel;\r\n                                    }\r\n                                    else if (poolType === 'avg') {\r\n                                        avgValue += pixel;\r\n                                        count++;\r\n                                    }\r\n                                }\r\n                                if (isNaN(minMaxValue)) {\r\n                                    break;\r\n                                }\r\n                            }\r\n                            var outputOffset = outputRowOffset + yC * outputColStrides + d;\r\n                            outputVals[outputOffset] =\r\n                                poolType === 'avg' ? avgValue / count : minMaxValue;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return output.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.maxPool = function (x, convInfo) {\r\n            return this.pool(x, convInfo, 'max');\r\n        };\r\n        MathBackendCPU.prototype.maxPoolPositions = function (x, convInfo) {\r\n            var maxPositions = buffer(convInfo.outShape, 'int32');\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var dilationHeight = convInfo.dilationHeight;\r\n            var dilationWidth = convInfo.dilationWidth;\r\n            var effectiveFilterHeight = convInfo.effectiveFilterHeight;\r\n            var effectiveFilterWidth = convInfo.effectiveFilterWidth;\r\n            var padTop = convInfo.padInfo.top;\r\n            var padLeft = convInfo.padInfo.left;\r\n            for (var b = 0; b < convInfo.batchSize; ++b) {\r\n                for (var d = 0; d < convInfo.inChannels; ++d) {\r\n                    for (var yR = 0; yR < convInfo.outHeight; ++yR) {\r\n                        var xRCorner = yR * strideHeight - padTop;\r\n                        var xRMin = xRCorner;\r\n                        while (xRMin < 0) {\r\n                            xRMin += dilationHeight;\r\n                        }\r\n                        var xRMax = Math.min(convInfo.inHeight, effectiveFilterHeight + xRCorner);\r\n                        for (var yC = 0; yC < convInfo.outWidth; ++yC) {\r\n                            var xCCorner = yC * strideWidth - padLeft;\r\n                            var xCMin = xCCorner;\r\n                            while (xCMin < 0) {\r\n                                xCMin += dilationWidth;\r\n                            }\r\n                            var xCMax = Math.min(convInfo.inWidth, effectiveFilterWidth + xCCorner);\r\n                            var maxValue = Number.NEGATIVE_INFINITY;\r\n                            var maxPosition = -1;\r\n                            for (var xR = xRMin; xR < xRMax; xR += dilationHeight) {\r\n                                var wR = xR - xRCorner;\r\n                                for (var xC = xCMin; xC < xCMax; xC += dilationWidth) {\r\n                                    var wC = xC - xCCorner;\r\n                                    var pixel = x.get(b, xR, xC, d);\r\n                                    if (pixel > maxValue) {\r\n                                        maxValue = pixel;\r\n                                        maxPosition = wR * effectiveFilterWidth + wC;\r\n                                    }\r\n                                }\r\n                            }\r\n                            maxPositions.set(maxPosition, b, yR, yC, d);\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return maxPositions.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.maxPoolBackprop = function (dy, x, y, convInfo) {\r\n            this.assertNotComplex([x, y], 'maxPoolBackprop');\r\n            var maxPositions = this.maxPoolPositions(x, convInfo);\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var dilationHeight = convInfo.dilationHeight;\r\n            var dilationWidth = convInfo.dilationWidth;\r\n            var effectiveFilterHeight = convInfo.effectiveFilterHeight;\r\n            var effectiveFilterWidth = convInfo.effectiveFilterWidth;\r\n            var padLeft = effectiveFilterWidth - 1 - convInfo.padInfo.left;\r\n            var padTop = effectiveFilterHeight - 1 - convInfo.padInfo.top;\r\n            var dx = buffer(x.shape, 'float32');\r\n            for (var b = 0; b < convInfo.batchSize; ++b) {\r\n                for (var d = 0; d < convInfo.inChannels; ++d) {\r\n                    for (var dxR = 0; dxR < convInfo.inHeight; ++dxR) {\r\n                        for (var dxC = 0; dxC < convInfo.inWidth; ++dxC) {\r\n                            var dyRCorner = dxR - padTop;\r\n                            var dyCCorner = dxC - padLeft;\r\n                            var dotProd = 0;\r\n                            for (var wR = 0; wR < effectiveFilterHeight; wR += dilationHeight) {\r\n                                var dyR = (dyRCorner + wR) / strideHeight;\r\n                                if (dyR < 0 || dyR >= convInfo.outHeight ||\r\n                                    Math.floor(dyR) !== dyR) {\r\n                                    continue;\r\n                                }\r\n                                for (var wC = 0; wC < effectiveFilterWidth; wC += dilationWidth) {\r\n                                    var dyC = (dyCCorner + wC) / strideWidth;\r\n                                    if (dyC < 0 || dyC >= convInfo.outWidth ||\r\n                                        Math.floor(dyC) !== dyC) {\r\n                                        continue;\r\n                                    }\r\n                                    var maxPos = effectiveFilterHeight * effectiveFilterWidth -\r\n                                        1 - maxPositions.get(b, dyR, dyC, d);\r\n                                    var curPos = wR * effectiveFilterWidth + wC;\r\n                                    var mask = maxPos === curPos ? 1 : 0;\r\n                                    if (mask === 0) {\r\n                                        continue;\r\n                                    }\r\n                                    var pixel = dy.get(b, dyR, dyC, d);\r\n                                    dotProd += pixel * mask;\r\n                                }\r\n                            }\r\n                            dx.set(dotProd, b, dxR, dxC, d);\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return dx.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.avgPoolBackprop = function (dy, x, convInfo) {\r\n            this.assertNotComplex([dy, x], 'avgPoolBackprop');\r\n            var strideHeight = convInfo.strideHeight;\r\n            var strideWidth = convInfo.strideWidth;\r\n            var filterHeight = convInfo.filterHeight;\r\n            var filterWidth = convInfo.filterWidth;\r\n            var dilationHeight = convInfo.dilationHeight;\r\n            var dilationWidth = convInfo.dilationWidth;\r\n            var effectiveFilterHeight = convInfo.effectiveFilterHeight;\r\n            var effectiveFilterWidth = convInfo.effectiveFilterWidth;\r\n            var padLeft = effectiveFilterWidth - 1 - convInfo.padInfo.left;\r\n            var padTop = effectiveFilterHeight - 1 - convInfo.padInfo.top;\r\n            var dx = buffer(x.shape, 'float32');\r\n            var avgMultiplier = 1 / (filterHeight * filterWidth);\r\n            for (var b = 0; b < convInfo.batchSize; ++b) {\r\n                for (var d = 0; d < convInfo.inChannels; ++d) {\r\n                    for (var dxR = 0; dxR < convInfo.inHeight; ++dxR) {\r\n                        for (var dxC = 0; dxC < convInfo.inWidth; ++dxC) {\r\n                            var dyRCorner = dxR - padTop;\r\n                            var dyCCorner = dxC - padLeft;\r\n                            var dotProd = 0;\r\n                            for (var wR = 0; wR < effectiveFilterHeight; wR += dilationHeight) {\r\n                                var dyR = (dyRCorner + wR) / strideHeight;\r\n                                if (dyR < 0 || dyR >= convInfo.outHeight ||\r\n                                    Math.floor(dyR) !== dyR) {\r\n                                    continue;\r\n                                }\r\n                                for (var wC = 0; wC < effectiveFilterWidth; wC += dilationWidth) {\r\n                                    var dyC = (dyCCorner + wC) / strideWidth;\r\n                                    if (dyC < 0 || dyC >= convInfo.outWidth ||\r\n                                        Math.floor(dyC) !== dyC) {\r\n                                        continue;\r\n                                    }\r\n                                    var pixel = dy.get(b, dyR, dyC, d);\r\n                                    dotProd += pixel;\r\n                                }\r\n                            }\r\n                            dx.set(dotProd * avgMultiplier, b, dxR, dxC, d);\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return dx.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.cast = function (x, dtype) {\r\n            return castTensor(x, dtype, this);\r\n        };\r\n        MathBackendCPU.prototype.reshape = function (x, shape) {\r\n            return reshapeTensor(x, shape);\r\n        };\r\n        MathBackendCPU.prototype.avgPool = function (x, convInfo) {\r\n            this.assertNotComplex(x, 'avgPool');\r\n            return this.pool(x, convInfo, 'avg').toFloat();\r\n        };\r\n        MathBackendCPU.prototype.resizeBilinear = function (x, newHeight, newWidth, alignCorners) {\r\n            this.assertNotComplex(x, 'resizeBilinear');\r\n            var _a = x.shape, batch = _a[0], oldHeight = _a[1], oldWidth = _a[2], numChannels = _a[3];\r\n            var xValues = x.dataSync();\r\n            var result = new Float32Array(sizeFromShape([batch, newHeight, newWidth, numChannels]));\r\n            var effectiveInputSize = [\r\n                (alignCorners && newHeight > 1) ? oldHeight - 1 : oldHeight,\r\n                (alignCorners && newWidth > 1) ? oldWidth - 1 : oldWidth\r\n            ];\r\n            var effectiveOutputSize = [\r\n                (alignCorners && newHeight > 1) ? newHeight - 1 : newHeight,\r\n                (alignCorners && newWidth > 1) ? newWidth - 1 : newWidth\r\n            ];\r\n            var outputIdx = 0;\r\n            var effectiveRowSizeRatio = effectiveInputSize[0] / effectiveOutputSize[0];\r\n            var effectiveColSizeRatio = effectiveInputSize[1] / effectiveOutputSize[1];\r\n            for (var b = 0; b < batch; b++) {\r\n                for (var r = 0; r < newHeight; r++) {\r\n                    var sourceFracRow = effectiveRowSizeRatio * r;\r\n                    var sourceRowFloor = Math.floor(sourceFracRow);\r\n                    var rowFrac = sourceFracRow - sourceRowFloor;\r\n                    var sourceRowCeil = Math.min(oldHeight - 1, Math.ceil(sourceFracRow));\r\n                    var topRowOffset = b * x.strides[0] + sourceRowFloor * x.strides[1];\r\n                    var botRowOffset = b * x.strides[0] + sourceRowCeil * x.strides[1];\r\n                    for (var c = 0; c < newWidth; c++) {\r\n                        var sourceFracCol = effectiveColSizeRatio * c;\r\n                        var sourceColFloor = Math.floor(sourceFracCol);\r\n                        var colFrac = sourceFracCol - sourceColFloor;\r\n                        var sourceColCeil = Math.min(oldWidth - 1, Math.ceil(sourceFracCol));\r\n                        var topLeftOffest = topRowOffset + sourceColFloor * x.strides[2];\r\n                        var botLeftOffset = botRowOffset + sourceColFloor * x.strides[2];\r\n                        var topRightOffset = topRowOffset + +sourceColCeil * x.strides[2];\r\n                        var botRightOffest = botRowOffset + sourceColCeil * x.strides[2];\r\n                        for (var d = 0; d < numChannels; d++) {\r\n                            var topLeft = xValues[topLeftOffest + d];\r\n                            var bottomLeft = xValues[botLeftOffset + d];\r\n                            var topRight = xValues[topRightOffset + d];\r\n                            var bottomRight = xValues[botRightOffest + d];\r\n                            var top_1 = topLeft + (topRight - topLeft) * colFrac;\r\n                            var bottom = bottomLeft + (bottomRight - bottomLeft) * colFrac;\r\n                            var newValue = top_1 + (bottom - top_1) * rowFrac;\r\n                            result[outputIdx++] = newValue;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return tensor(result, [batch, newHeight, newWidth, numChannels]);\r\n        };\r\n        MathBackendCPU.prototype.resizeBilinearBackprop = function (dy, x, alignCorners) {\r\n            this.assertNotComplex([dy, x], 'resizeBilinearBackprop');\r\n            var _a = x.shape, batch = _a[0], xHeight = _a[1], xWidth = _a[2], depth = _a[3];\r\n            var _b = dy.shape, yHeight = _b[1], yWidth = _b[2];\r\n            var output = new Float32Array(batch * xHeight * xWidth * depth);\r\n            var effectiveXSize = [\r\n                (alignCorners && yHeight > 1) ? xHeight - 1 : xHeight,\r\n                (alignCorners && yWidth > 1) ? xWidth - 1 : xWidth\r\n            ];\r\n            var effectiveYSize = [\r\n                (alignCorners && yHeight > 1) ? yHeight - 1 : yHeight,\r\n                (alignCorners && yWidth > 1) ? yWidth - 1 : yWidth\r\n            ];\r\n            var heightScale = effectiveXSize[0] / effectiveYSize[0];\r\n            var widthScale = effectiveXSize[1] / effectiveYSize[1];\r\n            var dyValues = dy.dataSync();\r\n            var offset = 0;\r\n            for (var b = 0; b < batch; b++) {\r\n                var bOffset = b * x.strides[0];\r\n                for (var r = 0; r < yHeight; r++) {\r\n                    var dxR = r * heightScale;\r\n                    var topDxRIndex = Math.floor(dxR);\r\n                    var bottomDxRIndex = Math.min(Math.ceil(dxR), xHeight - 1);\r\n                    var topDxROffset = bOffset + topDxRIndex * x.strides[1];\r\n                    var bottomDxROffset = bOffset + bottomDxRIndex * x.strides[1];\r\n                    var dxRLerp = dxR - topDxRIndex;\r\n                    var inverseDxRLerp = 1.0 - dxRLerp;\r\n                    for (var c = 0; c < yWidth; c++) {\r\n                        var dxC = c * widthScale;\r\n                        var leftDxCIndex = Math.floor(dxC);\r\n                        var rightDxCIndex = Math.min(Math.ceil(dxC), xWidth - 1);\r\n                        var dxCLerp = dxC - leftDxCIndex;\r\n                        var inverseDxCLerp = 1.0 - dxCLerp;\r\n                        var topLeftRCOffset = topDxROffset + leftDxCIndex * x.strides[2];\r\n                        var topRightRCOffset = topDxROffset + rightDxCIndex * x.strides[2];\r\n                        var bottomLeftRCOffset = bottomDxROffset + leftDxCIndex * x.strides[2];\r\n                        var bottomRightRCOffset = bottomDxROffset + rightDxCIndex * x.strides[2];\r\n                        var inverseDxRLerpTimesInverseDxCLerp = inverseDxRLerp * inverseDxCLerp;\r\n                        var inverseDxRLerpTimesDxCLerp = inverseDxRLerp * dxCLerp;\r\n                        var dxRLerpTimesInverseDxCLerp = dxRLerp * inverseDxCLerp;\r\n                        var dxRLerpTimesDxCLerp = dxRLerp * dxCLerp;\r\n                        for (var d = 0; d < depth; d++) {\r\n                            var dyVal = dyValues[offset++];\r\n                            output[topLeftRCOffset + d] +=\r\n                                dyVal * inverseDxRLerpTimesInverseDxCLerp;\r\n                            output[topRightRCOffset + d] += dyVal * inverseDxRLerpTimesDxCLerp;\r\n                            output[bottomLeftRCOffset + d] +=\r\n                                dyVal * dxRLerpTimesInverseDxCLerp;\r\n                            output[bottomRightRCOffset + d] += dyVal * dxRLerpTimesDxCLerp;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return tensor4d(output, [batch, xWidth, xHeight, depth], x.dtype);\r\n        };\r\n        MathBackendCPU.prototype.resizeNearestNeighbor = function (x, newHeight, newWidth, alignCorners) {\r\n            this.assertNotComplex(x, 'resizeNearestNeighbor');\r\n            var _a = x.shape, batch = _a[0], oldHeight = _a[1], oldWidth = _a[2], numChannels = _a[3];\r\n            var xValues = x.dataSync();\r\n            var output = new Float32Array(batch * newHeight * newWidth * numChannels);\r\n            var effectiveInputSize = [\r\n                (alignCorners && newHeight > 1) ? oldHeight - 1 : oldHeight,\r\n                (alignCorners && newWidth > 1) ? oldWidth - 1 : oldWidth\r\n            ];\r\n            var effectiveOutputSize = [\r\n                (alignCorners && newHeight > 1) ? newHeight - 1 : newHeight,\r\n                (alignCorners && newWidth > 1) ? newWidth - 1 : newWidth\r\n            ];\r\n            var effectiveRowSizeRatio = effectiveInputSize[0] / effectiveOutputSize[0];\r\n            var effectiveColSizeRatio = effectiveInputSize[1] / effectiveOutputSize[1];\r\n            var outputOffset = 0;\r\n            for (var b = 0; b < batch; b++) {\r\n                var batchOffset = b * x.strides[0];\r\n                for (var r = 0; r < newHeight; r++) {\r\n                    var sourceFracRow = effectiveRowSizeRatio * r;\r\n                    var sourceNearestRow = Math.min(oldHeight - 1, alignCorners ? Math.round(sourceFracRow) :\r\n                        Math.floor(sourceFracRow));\r\n                    var rowOffset = batchOffset + sourceNearestRow * x.strides[1];\r\n                    for (var c = 0; c < newWidth; c++) {\r\n                        var sourceFracCol = effectiveColSizeRatio * c;\r\n                        var sourceNearestCol = Math.min(oldWidth - 1, alignCorners ? Math.round(sourceFracCol) :\r\n                            Math.floor(sourceFracCol));\r\n                        var colOffset = rowOffset + sourceNearestCol * x.strides[2];\r\n                        for (var d = 0; d < numChannels; d++) {\r\n                            var newVal = xValues[colOffset + d];\r\n                            output[outputOffset++] = newVal;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return tensor(output, [batch, newHeight, newWidth, numChannels], x.dtype);\r\n        };\r\n        MathBackendCPU.prototype.resizeNearestNeighborBackprop = function (dy, x, alignCorners) {\r\n            this.assertNotComplex([dy, x], 'resizeNearestNeighborBackprop');\r\n            var _a = x.shape, batch = _a[0], xHeight = _a[1], xWidth = _a[2], depth = _a[3];\r\n            var _b = dy.shape, yHeight = _b[1], yWidth = _b[2];\r\n            var output = new Float32Array(batch * xHeight * xWidth * depth);\r\n            var dyValues = dy.dataSync();\r\n            var effectiveXSize = [\r\n                (alignCorners && yHeight > 1) ? xHeight - 1 : xHeight,\r\n                (alignCorners && yWidth > 1) ? xWidth - 1 : xWidth\r\n            ];\r\n            var effectiveYSize = [\r\n                (alignCorners && yHeight > 1) ? yHeight - 1 : yHeight,\r\n                (alignCorners && yWidth > 1) ? yWidth - 1 : yWidth\r\n            ];\r\n            var heightScale = effectiveXSize[0] / effectiveYSize[0];\r\n            var widthScale = effectiveXSize[1] / effectiveYSize[1];\r\n            var invHeightScale = 1 / heightScale;\r\n            var invWidthScale = 1 / widthScale;\r\n            var winHeight = (Math.ceil(invHeightScale) * 2) + 2;\r\n            var winWidth = (Math.ceil(invWidthScale) * 2) + 2;\r\n            for (var b = 0; b < batch; b++) {\r\n                var batchOffset = b * x.strides[0];\r\n                for (var r = 0; r < xHeight; r++) {\r\n                    var rowOffset = batchOffset + r * x.strides[1];\r\n                    var startRLerp = Math.floor(r * invHeightScale);\r\n                    var startDyR = Math.floor(startRLerp - (winHeight / 2));\r\n                    for (var c = 0; c < xWidth; c++) {\r\n                        var colOffset = rowOffset + c * x.strides[2];\r\n                        var startCLerp = Math.floor(c * invWidthScale);\r\n                        var startDyC = Math.floor(startCLerp - (winWidth / 2));\r\n                        for (var d = 0; d < depth; d++) {\r\n                            var accum = 0;\r\n                            for (var dyRIndex = 0; dyRIndex < winHeight; dyRIndex++) {\r\n                                var dyR = dyRIndex + startDyR;\r\n                                if (dyR < 0 || dyR >= yHeight) {\r\n                                    continue;\r\n                                }\r\n                                var dyROffset = batchOffset + dyR * dy.strides[1];\r\n                                var sourceFracRow = dyR * heightScale;\r\n                                var sourceNearestRow = Math.min(xHeight - 1, alignCorners ? Math.round(sourceFracRow) :\r\n                                    Math.floor(sourceFracRow));\r\n                                if (r !== sourceNearestRow) {\r\n                                    continue;\r\n                                }\r\n                                for (var dyCIndex = 0; dyCIndex < winWidth; dyCIndex++) {\r\n                                    var dyC = dyCIndex + startDyC;\r\n                                    if (dyC < 0 || dyC >= yWidth) {\r\n                                        continue;\r\n                                    }\r\n                                    var dyCOffset = dyROffset + dyC * dy.strides[2];\r\n                                    var sourceFracCol = dyC * widthScale;\r\n                                    var sourceNearestCol = Math.min(xWidth - 1, alignCorners ? Math.round(sourceFracCol) :\r\n                                        Math.floor(sourceFracCol));\r\n                                    if (c === sourceNearestCol) {\r\n                                        accum += dyValues[dyCOffset + d];\r\n                                    }\r\n                                }\r\n                            }\r\n                            output[colOffset + d] = accum;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return tensor4d(output, x.shape, x.dtype);\r\n        };\r\n        MathBackendCPU.prototype.batchNormalization = function (x, mean$$1, variance, varianceEpsilon, scale, offset) {\r\n            this.assertNotComplex([x, mean$$1, variance, scale, offset], 'batchNormalization');\r\n            var xVals = x.dataSync();\r\n            var mVals = mean$$1.dataSync();\r\n            var varVals = variance.dataSync();\r\n            var sVals = scale ? scale.dataSync() : new Float32Array([1]);\r\n            var offVals = offset ? offset.dataSync() : new Float32Array([0]);\r\n            var outVals = new Float32Array(xVals.length);\r\n            var offValsLength = offVals.length;\r\n            var sValsLength = sVals.length;\r\n            var varValsLength = varVals.length;\r\n            var mValsLength = mVals.length;\r\n            var offi = 0;\r\n            var mi = 0;\r\n            var si = 0;\r\n            var vi = 0;\r\n            for (var i = 0; i < xVals.length; ++i) {\r\n                outVals[i] = offVals[offi++] +\r\n                    (xVals[i] - mVals[mi++]) * sVals[si++] /\r\n                        Math.sqrt(varVals[vi++] + varianceEpsilon);\r\n                if (offi >= offValsLength) {\r\n                    offi = 0;\r\n                }\r\n                if (mi >= mValsLength) {\r\n                    mi = 0;\r\n                }\r\n                if (si >= sValsLength) {\r\n                    si = 0;\r\n                }\r\n                if (vi >= varValsLength) {\r\n                    vi = 0;\r\n                }\r\n            }\r\n            return tensor4d(outVals, x.shape);\r\n        };\r\n        MathBackendCPU.prototype.localResponseNormalization4D = function (x, depthRadius, bias, alpha, beta) {\r\n            this.assertNotComplex(x, 'localResponseNormalization4D');\r\n            var channels = x.shape[3];\r\n            var maxD = channels - 1;\r\n            var xValues = x.dataSync();\r\n            var size = sizeFromShape(x.shape);\r\n            var result = new Float32Array(size);\r\n            function sumAcrossChannels(offset) {\r\n                var currentChannel = offset % channels;\r\n                var beginSumOffset = offset - currentChannel + Math.max(0, currentChannel - depthRadius);\r\n                var endSumOffset = offset - currentChannel +\r\n                    Math.min(currentChannel + depthRadius, maxD);\r\n                var sum$$1 = 0.0;\r\n                for (; beginSumOffset <= endSumOffset; beginSumOffset++) {\r\n                    var z = xValues[beginSumOffset];\r\n                    sum$$1 += z * z;\r\n                }\r\n                return sum$$1;\r\n            }\r\n            for (var offset = 0; offset < size; offset++) {\r\n                var sum$$1 = sumAcrossChannels(offset);\r\n                var val = xValues[offset] * Math.pow(bias + alpha * sum$$1, -beta);\r\n                result[offset] = val;\r\n            }\r\n            return tensor4d(result, x.shape);\r\n        };\r\n        MathBackendCPU.prototype.LRNGrad = function (dy, inputImage, outputImage, depthRadius, bias, alpha, beta) {\r\n            this.assertNotComplex(dy, 'LRNGrad');\r\n            var channels = dy.shape[3];\r\n            var dyValues = dy.dataSync();\r\n            var inputImageValues = inputImage.dataSync();\r\n            var outputImageValues = outputImage.dataSync();\r\n            var result = new Float32Array(sizeFromShape(dy.shape));\r\n            var size = sizeFromShape(dy.shape);\r\n            for (var offset = 0; offset < size; offset++) {\r\n                var currentChannel = offset % channels;\r\n                var depthBegin = (offset - currentChannel) + Math.max(0, currentChannel - depthRadius);\r\n                var depthEnd = (offset - currentChannel) +\r\n                    Math.min(channels, currentChannel + depthRadius + 1);\r\n                var norm$$1 = 0;\r\n                for (var k = depthBegin; k < depthEnd; k++) {\r\n                    norm$$1 += Math.pow(inputImageValues[k], 2);\r\n                }\r\n                norm$$1 = alpha * norm$$1 + bias;\r\n                for (var k = depthBegin; k < depthEnd; k++) {\r\n                    var dyi = -2 * alpha * beta * inputImageValues[k] *\r\n                        outputImageValues[offset] / norm$$1;\r\n                    if (offset === k) {\r\n                        dyi += Math.pow(norm$$1, -beta);\r\n                    }\r\n                    dyi *= dyValues[offset];\r\n                    result[k] += dyi;\r\n                }\r\n            }\r\n            return tensor4d(result, dy.shape);\r\n        };\r\n        MathBackendCPU.prototype.multinomial = function (logits, normalized, numSamples, seed) {\r\n            this.assertNotComplex(logits, 'multinomial');\r\n            var probabilities = normalized ? logits : softmax(logits);\r\n            var batchSize = probabilities.shape[0];\r\n            var numEvents = probabilities.shape[1];\r\n            var res = zeros([batchSize, numSamples], 'int32');\r\n            var resVals = res.dataSync();\r\n            var probVals = probabilities.dataSync();\r\n            for (var b = 0; b < batchSize; ++b) {\r\n                var offset = b * numEvents;\r\n                var cdf = new Float32Array(numEvents - 1);\r\n                cdf[0] = probVals[offset];\r\n                for (var event_1 = 1; event_1 < cdf.length; ++event_1) {\r\n                    cdf[event_1] = cdf[event_1 - 1] + probVals[offset + event_1];\r\n                }\r\n                var random = seedrandom_1(seed.toString());\r\n                var outOffset = b * numSamples;\r\n                for (var sampleId = 0; sampleId < numSamples; ++sampleId) {\r\n                    var r = random();\r\n                    resVals[outOffset + sampleId] = cdf.length;\r\n                    for (var event_2 = 0; event_2 < cdf.length; event_2++) {\r\n                        if (r < cdf[event_2]) {\r\n                            resVals[outOffset + sampleId] = event_2;\r\n                            break;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return res;\r\n        };\r\n        MathBackendCPU.prototype.oneHot = function (indices, depth, onValue, offValue) {\r\n            this.assertNotComplex(indices, 'oneHot');\r\n            var res = new Float32Array(indices.size * depth);\r\n            res.fill(offValue);\r\n            for (var event_3 = 0; event_3 < indices.size; ++event_3) {\r\n                if (indices.get(event_3) >= 0 && indices.get(event_3) < depth) {\r\n                    res[event_3 * depth + indices.get(event_3)] = onValue;\r\n                }\r\n            }\r\n            return tensor2d(res, [indices.size, depth], 'int32');\r\n        };\r\n        MathBackendCPU.prototype.nonMaxSuppression = function (boxes, scores, maxOutputSize, iouThreshold, scoreThreshold) {\r\n            this.assertNotComplex(boxes, 'nonMaxSuppression');\r\n            var boxesVals = boxes.dataSync();\r\n            var scoresVals = scores.dataSync();\r\n            return nonMaxSuppressionImpl(boxesVals, scoresVals, maxOutputSize, iouThreshold, scoreThreshold);\r\n        };\r\n        MathBackendCPU.prototype.fft = function (x) {\r\n            return this.fftBatch(x, false);\r\n        };\r\n        MathBackendCPU.prototype.ifft = function (x) {\r\n            return this.fftBatch(x, true);\r\n        };\r\n        MathBackendCPU.prototype.fftBatch = function (x, inverse) {\r\n            var batch = x.shape[0];\r\n            var innerDim = x.shape[1];\r\n            var realResult = buffer(x.shape, 'float32');\r\n            var imagResult = buffer(x.shape, 'float32');\r\n            var real$$1 = real(x).as2D(batch, innerDim);\r\n            var imag$$1 = imag(x).as2D(batch, innerDim);\r\n            for (var b = 0; b < batch; b++) {\r\n                var r = real$$1.slice([b, 0], [1, innerDim]);\r\n                var i = imag$$1.slice([b, 0], [1, innerDim]);\r\n                var input = complex(r, i);\r\n                var res = this.fftImpl(input, inverse).dataSync();\r\n                for (var d = 0; d < innerDim; d++) {\r\n                    var c = getComplexWithIndex(res, d);\r\n                    realResult.values[b * innerDim + d] = c.real;\r\n                    imagResult.values[b * innerDim + d] = c.imag;\r\n                }\r\n            }\r\n            var t = complex(realResult.toTensor(), imagResult.toTensor());\r\n            return t.as2D(batch, innerDim);\r\n        };\r\n        MathBackendCPU.prototype.fftImpl = function (x, inverse) {\r\n            var x1D = x.as1D();\r\n            var n = x1D.size;\r\n            if (this.isExponentOf2(n)) {\r\n                var result = this.fftRadix2(x1D, n, inverse).as2D(x.shape[0], x.shape[1]);\r\n                if (inverse) {\r\n                    result = complex(real(result).div(scalar(n)), imag(result).div(scalar(n)));\r\n                }\r\n                return result;\r\n            }\r\n            else {\r\n                var data = x.dataSync();\r\n                var rawOutput = this.fourierTransformByMatmul(data, n, inverse);\r\n                var output = splitRealAndImagArrays(rawOutput);\r\n                return complex(output.real, output.imag).as2D(x.shape[0], x.shape[1]);\r\n            }\r\n        };\r\n        MathBackendCPU.prototype.isExponentOf2 = function (size) {\r\n            return (size & size - 1) === 0;\r\n        };\r\n        MathBackendCPU.prototype.fftRadix2 = function (input, size, inverse) {\r\n            if (size === 1) {\r\n                return input;\r\n            }\r\n            var data = input.dataSync();\r\n            var half = size / 2;\r\n            var evenComplex = complexWithEvenIndex(data);\r\n            var evenTensor = complex(evenComplex.real, evenComplex.imag).as1D();\r\n            var oddComplex = complexWithOddIndex(data);\r\n            var oddTensor = complex(oddComplex.real, oddComplex.imag).as1D();\r\n            evenTensor = this.fftRadix2(evenTensor, half, inverse);\r\n            oddTensor = this.fftRadix2(oddTensor, half, inverse);\r\n            var e = exponents(size, inverse);\r\n            var exponent$$1 = complex(e.real, e.imag).mul(oddTensor);\r\n            var addPart = evenTensor.add(exponent$$1);\r\n            var subPart = evenTensor.sub(exponent$$1);\r\n            var realTensor = real(addPart).concat(real(subPart));\r\n            var imagTensor = imag(addPart).concat(imag(subPart));\r\n            return complex(realTensor, imagTensor).as1D();\r\n        };\r\n        MathBackendCPU.prototype.fourierTransformByMatmul = function (data, size, inverse) {\r\n            var ret = new Float32Array(size * 2);\r\n            for (var r = 0; r < size; r++) {\r\n                var real$$1 = 0.0;\r\n                var imag$$1 = 0.0;\r\n                for (var c = 0; c < size; c++) {\r\n                    var e = exponent(r * c, size, inverse);\r\n                    var term = getComplexWithIndex(data, c);\r\n                    real$$1 += term.real * e.real - term.imag * e.imag;\r\n                    imag$$1 += term.real * e.imag + term.imag * e.real;\r\n                }\r\n                if (inverse) {\r\n                    real$$1 /= size;\r\n                    imag$$1 /= size;\r\n                }\r\n                assignToTypedArray(ret, real$$1, imag$$1, r);\r\n            }\r\n            return ret;\r\n        };\r\n        MathBackendCPU.prototype.depthToSpace = function (x, blockSize, dataFormat) {\r\n            assert(dataFormat === 'NHWC', \"Only NHWC dataFormat supported on CPU for depthToSpace. Got \" + dataFormat);\r\n            assert(blockSize > 1, \"blockSize should be > 1 for depthToSpace, but was: \" + blockSize);\r\n            var batchSize = x.shape[0];\r\n            var inputHeight = x.shape[1];\r\n            var inputWidth = x.shape[2];\r\n            var inputDepth = x.shape[3];\r\n            var outputHeight = inputHeight * blockSize;\r\n            var outputWidth = inputWidth * blockSize;\r\n            var outputDepth = inputDepth / (blockSize * blockSize);\r\n            var xValues = x.dataSync();\r\n            var result = new Float32Array(batchSize * outputHeight * outputWidth * outputDepth);\r\n            var outputIdx = 0;\r\n            for (var b = 0; b < batchSize; ++b) {\r\n                for (var h = 0; h < outputHeight; ++h) {\r\n                    var inH = Math.floor(h / blockSize);\r\n                    var offsetH = (h % blockSize);\r\n                    for (var w = 0; w < outputWidth; ++w) {\r\n                        var inW = Math.floor(w / blockSize);\r\n                        var offsetW = (w % blockSize);\r\n                        var offsetD = (offsetH * blockSize + offsetW) * outputDepth;\r\n                        for (var d = 0; d < outputDepth; ++d) {\r\n                            var inD = d + offsetD;\r\n                            var inputIdx = inD + inputDepth * (inW + inputWidth * (inH + inputHeight * b));\r\n                            result[outputIdx++] = xValues[inputIdx];\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return tensor4d(result, [batchSize, outputHeight, outputWidth, outputDepth]);\r\n        };\r\n        MathBackendCPU.prototype.broadcastedBinaryOp = function (a, b, dtype, op$$1) {\r\n            var newShape = assertAndGetBroadcastShape(a.shape, b.shape);\r\n            var result = buffer(newShape, dtype);\r\n            var aVals = a.dataSync();\r\n            var bVals = b.dataSync();\r\n            var aBroadcastDims = getBroadcastDims(a.shape, newShape);\r\n            var bBroadcastDims = getBroadcastDims(b.shape, newShape);\r\n            var resVals = result.values;\r\n            if (aBroadcastDims.length + bBroadcastDims.length === 0) {\r\n                for (var i = 0; i < resVals.length; ++i) {\r\n                    resVals[i] = op$$1(aVals[i % aVals.length], bVals[i % bVals.length]);\r\n                }\r\n            }\r\n            else {\r\n                var aBuf = a.buffer();\r\n                var bBuf = b.buffer();\r\n                var _loop_2 = function (i) {\r\n                    var loc = result.indexToLoc(i);\r\n                    var aLoc = loc.slice(-a.rank);\r\n                    aBroadcastDims.forEach(function (d) { return aLoc[d] = 0; });\r\n                    var aIndex = aBuf.locToIndex(aLoc);\r\n                    var bLoc = loc.slice(-b.rank);\r\n                    bBroadcastDims.forEach(function (d) { return bLoc[d] = 0; });\r\n                    var bIndex = bBuf.locToIndex(bLoc);\r\n                    resVals[i] = op$$1(aVals[aIndex], bVals[bIndex]);\r\n                };\r\n                for (var i = 0; i < resVals.length; ++i) {\r\n                    _loop_2(i);\r\n                }\r\n            }\r\n            return result.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.broadcastedBinaryComplexOp = function (a, b, op$$1) {\r\n            var newShape = assertAndGetBroadcastShape(a.shape, b.shape);\r\n            var realResult = buffer(newShape, 'float32');\r\n            var imagResult = buffer(newShape, 'float32');\r\n            var aVals = a.dataSync();\r\n            var bVals = b.dataSync();\r\n            var aBroadcastDims = getBroadcastDims(a.shape, newShape);\r\n            var bBroadcastDims = getBroadcastDims(b.shape, newShape);\r\n            var realVals = realResult.values;\r\n            var imagVals = imagResult.values;\r\n            if (aBroadcastDims.length + bBroadcastDims.length === 0) {\r\n                for (var i = 0; i < realVals.length; i++) {\r\n                    var aIdx = i % aVals.length;\r\n                    var bIdx = i % bVals.length;\r\n                    var result = op$$1(aVals[aIdx * 2], aVals[aIdx * 2 + 1], bVals[bIdx * 2], bVals[bIdx * 2 + 1]);\r\n                    realVals[i] = result.real;\r\n                    imagVals[i] = result.imag;\r\n                }\r\n            }\r\n            else {\r\n                var aRealBuf = this.data.get(a.dataId).complexTensors.real.buffer();\r\n                var bRealBuf = this.data.get(b.dataId).complexTensors.real.buffer();\r\n                var _loop_3 = function (i) {\r\n                    var loc = realResult.indexToLoc(i);\r\n                    var aLoc = loc.slice(-a.rank);\r\n                    aBroadcastDims.forEach(function (d) { return aLoc[d] = 0; });\r\n                    var aIndex = aRealBuf.locToIndex(aLoc);\r\n                    var bLoc = loc.slice(-b.rank);\r\n                    bBroadcastDims.forEach(function (d) { return bLoc[d] = 0; });\r\n                    var bIndex = bRealBuf.locToIndex(bLoc);\r\n                    var opResult = op$$1(aVals[aIndex * 2], aVals[aIndex * 2 + 1], bVals[bIndex * 2], bVals[bIndex * 2 + 1]);\r\n                    realVals[i] = opResult.real;\r\n                    imagVals[i] = opResult.imag;\r\n                };\r\n                for (var i = 0; i < realVals.length; i++) {\r\n                    _loop_3(i);\r\n                }\r\n            }\r\n            return this.complex(realResult.toTensor(), imagResult.toTensor());\r\n        };\r\n        MathBackendCPU.prototype.split = function (x, sizeSplits, axis) {\r\n            return split(x, sizeSplits, axis);\r\n        };\r\n        MathBackendCPU.prototype.dispose = function () { };\r\n        MathBackendCPU.prototype.floatPrecision = function () {\r\n            return 32;\r\n        };\r\n        MathBackendCPU.prototype.cropAndResize = function (images, boxes, boxIndex, cropSize, method, extrapolationValue) {\r\n            var _a = images.shape, batch = _a[0], imageHeight = _a[1], imageWidth = _a[2], numChannels = _a[3];\r\n            var numBoxes = boxes.shape[0];\r\n            var cropHeight = cropSize[0], cropWidth = cropSize[1];\r\n            var output = buffer([numBoxes, cropHeight, cropWidth, numChannels], images.dtype);\r\n            var boxVals = boxes.dataSync();\r\n            var boxIndVals = boxIndex.dataSync();\r\n            var imageVals = images.dataSync();\r\n            var inStride = images.strides;\r\n            var outStride = output.strides;\r\n            for (var b = 0; b < numBoxes; b++) {\r\n                var startInd = b * 4;\r\n                var y1 = boxVals[startInd];\r\n                var x1 = boxVals[startInd + 1];\r\n                var y2 = boxVals[startInd + 2];\r\n                var x2 = boxVals[startInd + 3];\r\n                var bInd = boxIndVals[b];\r\n                if (bInd >= batch) {\r\n                    continue;\r\n                }\r\n                var heightScale = (cropHeight > 1) ?\r\n                    (y2 - y1) * (imageHeight - 1) / (cropHeight - 1) :\r\n                    0;\r\n                var widthScale = (cropWidth > 1) ? (x2 - x1) * (imageWidth - 1) / (cropWidth - 1) : 0;\r\n                for (var y = 0; y < cropHeight; y++) {\r\n                    var yInd = (cropHeight > 1) ?\r\n                        y1 * (imageHeight - 1) + y * (heightScale) :\r\n                        0.5 * (y1 + y2) * (imageHeight - 1);\r\n                    if (yInd < 0 || yInd > imageHeight - 1) {\r\n                        for (var x = 0; x < cropWidth; x++) {\r\n                            for (var c = 0; c < numChannels; c++) {\r\n                                var ind = c + x * outStride[2] + y * outStride[1] + b * outStride[0];\r\n                                output.values[ind] = extrapolationValue;\r\n                            }\r\n                        }\r\n                        continue;\r\n                    }\r\n                    if (method === 'bilinear') {\r\n                        var topInd = Math.floor(yInd);\r\n                        var bottomInd = Math.ceil(yInd);\r\n                        var yLerp = yInd - topInd;\r\n                        for (var x = 0; x < cropWidth; x++) {\r\n                            var xInd = (cropWidth > 1) ?\r\n                                x1 * (imageWidth - 1) + x * widthScale :\r\n                                0.5 * (x1 + x2) * (imageWidth - 1);\r\n                            if (xInd < 0 || xInd > imageWidth - 1) {\r\n                                for (var c = 0; c < numChannels; c++) {\r\n                                    var ind = c + x * outStride[2] + y * outStride[1] + b * outStride[0];\r\n                                    output.values[ind] = extrapolationValue;\r\n                                }\r\n                                continue;\r\n                            }\r\n                            var leftInd = Math.floor(xInd);\r\n                            var rightInd = Math.ceil(xInd);\r\n                            var xLerp = xInd - leftInd;\r\n                            for (var c = 0; c < numChannels; c++) {\r\n                                var ind = c + leftInd * inStride[2] + topInd * inStride[1] +\r\n                                    bInd * inStride[0];\r\n                                var topLeft = imageVals[ind];\r\n                                ind = c + rightInd * inStride[2] + topInd * inStride[1] +\r\n                                    bInd * inStride[0];\r\n                                var topRight = imageVals[ind];\r\n                                ind = c + leftInd * inStride[2] + bottomInd * inStride[1] +\r\n                                    bInd * inStride[0];\r\n                                var bottomLeft = imageVals[ind];\r\n                                ind = c + rightInd * inStride[2] + bottomInd * inStride[1] +\r\n                                    bInd * inStride[0];\r\n                                var bottomRight = imageVals[ind];\r\n                                var top_2 = topLeft + (topRight - topLeft) * xLerp;\r\n                                var bottom = bottomLeft + (bottomRight - bottomLeft) * xLerp;\r\n                                ind = c + x * outStride[2] + y * outStride[1] + b * outStride[0];\r\n                                output.values[ind] = top_2 + ((bottom - top_2) * yLerp);\r\n                            }\r\n                        }\r\n                    }\r\n                    else {\r\n                        for (var x = 0; x < cropWidth; ++x) {\r\n                            var xInd = (cropWidth > 1) ?\r\n                                x1 * (imageWidth - 1) + x * widthScale :\r\n                                0.5 * (x1 + x2) * (imageWidth - 1);\r\n                            if (xInd < 0 || xInd > imageWidth - 1) {\r\n                                for (var c = 0; c < numChannels; c++) {\r\n                                    var ind = c + x * outStride[2] + y * outStride[1] + b * outStride[0];\r\n                                    output.values[ind] = extrapolationValue;\r\n                                }\r\n                                continue;\r\n                            }\r\n                            var closestX = Math.round(xInd);\r\n                            var closestY = Math.round(yInd);\r\n                            for (var c = 0; c < numChannels; c++) {\r\n                                var inInd = c + closestX * inStride[2] +\r\n                                    closestY * inStride[1] + bInd * inStride[0];\r\n                                var outInd = c + x * outStride[2] + y * outStride[1] + b * outStride[0];\r\n                                output.values[outInd] = imageVals[inInd];\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            return output.toTensor();\r\n        };\r\n        MathBackendCPU.prototype.sparseToDense = function (sparseIndices, sparseValues, outputShape, defaultValue) {\r\n            var _a = calculateShapes(sparseValues, sparseIndices, outputShape), sliceRank = _a.sliceRank, numUpdates = _a.numUpdates, sliceSize = _a.sliceSize, strides = _a.strides, outputSize = _a.outputSize;\r\n            var sumDupeIndices = false;\r\n            return this.scatter(sparseIndices, sparseValues, outputShape, outputSize, sliceSize, numUpdates, sliceRank, strides, defaultValue, sumDupeIndices);\r\n        };\r\n        MathBackendCPU.prototype.gatherND = function (x, indices) {\r\n            var indicesShape = indices.shape;\r\n            var sliceRank = indicesShape[indicesShape.length - 1];\r\n            var _a = prepareAndValidate(x, indices), resultShape = _a[0], numSlices = _a[1], sliceSize = _a[2], strides = _a[3];\r\n            if (numSlices === 0) {\r\n                return tensor([], resultShape, x.dtype);\r\n            }\r\n            var buffer$$1 = new TensorBuffer([numSlices, sliceSize], x.dtype);\r\n            var indicesData = indices.dataSync();\r\n            var xData = x.dataSync();\r\n            for (var i = 0; i < numSlices; i++) {\r\n                var index = [];\r\n                var flattenIndex = 0;\r\n                for (var j = 0; j < sliceRank; j++) {\r\n                    var dim = indicesData[i * sliceRank + j];\r\n                    flattenIndex += dim * strides[j];\r\n                    index.push(dim);\r\n                }\r\n                if (flattenIndex < 0 || flattenIndex >= x.size / sliceSize) {\r\n                    throw new Error(\"Invalid indices: \" + index + \" does not index into \" + x.shape);\r\n                }\r\n                for (var k = 0; k < sliceSize; k++) {\r\n                    buffer$$1.values[i * sliceSize + k] = xData[flattenIndex * sliceSize + k];\r\n                }\r\n            }\r\n            return buffer$$1.toTensor().reshape(resultShape);\r\n        };\r\n        MathBackendCPU.prototype.scatterND = function (indices, updates, shape) {\r\n            var _a = calculateShapes(updates, indices, shape), sliceRank = _a.sliceRank, numUpdates = _a.numUpdates, sliceSize = _a.sliceSize, strides = _a.strides, outputSize = _a.outputSize;\r\n            var defaultValue = scalar(0);\r\n            var sumDupeIndices = true;\r\n            return this.scatter(indices, updates, shape, outputSize, sliceSize, numUpdates, sliceRank, strides, defaultValue, sumDupeIndices);\r\n        };\r\n        MathBackendCPU.prototype.scatter = function (indices, updates, shape, outputSize, sliceSize, numUpdates, sliceRank, strides, defaultValue, sumDupeIndices) {\r\n            var flattenShape = [outputSize / sliceSize, sliceSize];\r\n            var indicesData = indices.dataSync();\r\n            var updatesData = updates.dataSync();\r\n            if (outputSize === 0) {\r\n                return tensor([], shape, updates.dtype);\r\n            }\r\n            var buffer$$1 = new TensorBuffer(flattenShape, updates.dtype);\r\n            buffer$$1.values.fill(defaultValue.dataSync()[0]);\r\n            for (var i = 0; i < numUpdates; i++) {\r\n                var index = [];\r\n                var flattenIndex = 0;\r\n                for (var j = 0; j < sliceRank; j++) {\r\n                    var dim = indicesData[i * sliceRank + j];\r\n                    index.push(dim);\r\n                    flattenIndex += dim * strides[j];\r\n                }\r\n                if (flattenIndex < 0 || flattenIndex >= outputSize / sliceSize) {\r\n                    throw new Error(\"Invalid indices: \" + index + \" does not index into \" + shape);\r\n                }\r\n                for (var k = 0; k < sliceSize; k++) {\r\n                    if (sumDupeIndices) {\r\n                        buffer$$1.values[flattenIndex * sliceSize + k] +=\r\n                            updatesData[i * sliceSize + k];\r\n                    }\r\n                    else {\r\n                        buffer$$1.values[flattenIndex * sliceSize + k] = updates.rank === 0 ?\r\n                            updatesData[0] :\r\n                            updatesData[i * sliceSize + k];\r\n                    }\r\n                }\r\n            }\r\n            return buffer$$1.toTensor().reshape(shape);\r\n        };\r\n        return MathBackendCPU;\r\n    }());\r\n    ENV.registerBackend('cpu', function () { return new MathBackendCPU(); }, 1, setTensorTracker);\n\n    var delayCallback = typeof requestAnimationFrame !== 'undefined' ?\r\n        requestAnimationFrame :\r\n        setImmediate;\r\n    function nextFrame() {\r\n        return new Promise(function (resolve) { return delayCallback(function () { return resolve(); }); });\r\n    }\n\n    var DTYPE_VALUE_SIZE_MAP = {\r\n        'float32': 4,\r\n        'int32': 4,\r\n        'uint16': 2,\r\n        'uint8': 1,\r\n        'bool': 1,\r\n    };\n\n    function encodeWeights(tensors) {\r\n        return __awaiter(this, void 0, void 0, function () {\r\n            var specs, dataPromises, name_1, t, tensorValues;\r\n            return __generator(this, function (_a) {\r\n                switch (_a.label) {\r\n                    case 0:\r\n                        specs = [];\r\n                        dataPromises = [];\r\n                        for (name_1 in tensors) {\r\n                            t = tensors[name_1];\r\n                            if (t.dtype !== 'float32' && t.dtype !== 'int32' && t.dtype !== 'bool') {\r\n                                throw new Error(\"Unsupported dtype in weight '\" + name_1 + \"': \" + t.dtype);\r\n                            }\r\n                            specs.push({ name: name_1, shape: t.shape, dtype: t.dtype });\r\n                            dataPromises.push(t.data());\r\n                        }\r\n                        return [4, Promise.all(dataPromises)];\r\n                    case 1:\r\n                        tensorValues = _a.sent();\r\n                        return [2, { data: concatenateTypedArrays(tensorValues), specs: specs }];\r\n                }\r\n            });\r\n        });\r\n    }\r\n    function decodeWeights(buffer, specs) {\r\n        var out = {};\r\n        var offset = 0;\r\n        var _loop_1 = function (spec) {\r\n            var name_2 = spec.name;\r\n            var dtype = spec.dtype;\r\n            var shape = spec.shape;\r\n            var size = sizeFromShape(shape);\r\n            var typedArray = void 0;\r\n            if ('quantization' in spec) {\r\n                var quantization_1 = spec.quantization;\r\n                if (quantization_1.dtype !== 'uint8' && quantization_1.dtype !== 'uint16') {\r\n                    throw new Error(\"Weight \" + spec.name + \" has unknown \" +\r\n                        (\"quantization dtype \" + quantization_1.dtype + \". \") +\r\n                        \"Supported quantization dtypes are: 'uint8' and 'uint16'.\");\r\n                }\r\n                var quantizationSizeFactor = DTYPE_VALUE_SIZE_MAP[quantization_1.dtype];\r\n                var byteBuffer = buffer.slice(offset, offset + size * quantizationSizeFactor);\r\n                var quantizedArray = (quantization_1.dtype === 'uint8') ?\r\n                    new Uint8Array(byteBuffer) :\r\n                    new Uint16Array(byteBuffer);\r\n                if (dtype === 'float32') {\r\n                    typedArray = Float32Array.from(quantizedArray, function (v) { return v * quantization_1.scale + quantization_1.min; });\r\n                }\r\n                else if (dtype === 'int32') {\r\n                    typedArray = Int32Array.from(quantizedArray, function (v) { return Math.round(v * quantization_1.scale + quantization_1.min); });\r\n                }\r\n                else {\r\n                    throw new Error(\"Unsupported dtype in weight '\" + name_2 + \"': \" + dtype);\r\n                }\r\n                offset += size * quantizationSizeFactor;\r\n            }\r\n            else {\r\n                var dtypeFactor = DTYPE_VALUE_SIZE_MAP[dtype];\r\n                var byteBuffer = buffer.slice(offset, offset + size * dtypeFactor);\r\n                if (dtype === 'float32') {\r\n                    typedArray = new Float32Array(byteBuffer);\r\n                }\r\n                else if (dtype === 'int32') {\r\n                    typedArray = new Int32Array(byteBuffer);\r\n                }\r\n                else if (dtype === 'bool') {\r\n                    typedArray = new Uint8Array(byteBuffer);\r\n                }\r\n                else {\r\n                    throw new Error(\"Unsupported dtype in weight '\" + name_2 + \"': \" + dtype);\r\n                }\r\n                offset += size * dtypeFactor;\r\n            }\r\n            var value = void 0;\r\n            if (dtype === 'float32') {\r\n                value = tensor(typedArray, shape, 'float32');\r\n            }\r\n            else if (dtype === 'int32') {\r\n                value = tensor(typedArray, shape, 'int32');\r\n            }\r\n            else if (dtype === 'bool') {\r\n                value = tensor(typedArray, shape, 'bool');\r\n            }\r\n            else {\r\n                throw new Error(\"Unsupported dtype in weight '\" + name_2 + \"': \" + dtype);\r\n            }\r\n            out[name_2] = value;\r\n        };\r\n        for (var _i = 0, specs_1 = specs; _i < specs_1.length; _i++) {\r\n            var spec = specs_1[_i];\r\n            _loop_1(spec);\r\n        }\r\n        return out;\r\n    }\r\n    function concatenateTypedArrays(xs) {\r\n        if (xs === null) {\r\n            throw new Error(\"Invalid input value: \" + JSON.stringify(xs));\r\n        }\r\n        var totalByteLength = 0;\r\n        var normalizedXs = [];\r\n        xs.forEach(function (x) {\r\n            totalByteLength += x.byteLength;\r\n            normalizedXs.push(x.byteLength === x.buffer.byteLength ? x :\r\n                new x.constructor(x));\r\n            if (!(x instanceof Float32Array || x instanceof Int32Array ||\r\n                x instanceof Uint8Array)) {\r\n                throw new Error(\"Unsupported TypedArray subtype: \" + x.constructor.name);\r\n            }\r\n        });\r\n        var y = new Uint8Array(totalByteLength);\r\n        var offset = 0;\r\n        normalizedXs.forEach(function (x) {\r\n            y.set(new Uint8Array(x.buffer), offset);\r\n            offset += x.byteLength;\r\n        });\r\n        return y.buffer;\r\n    }\r\n    var useNodeBuffer = typeof Buffer !== 'undefined' &&\r\n        (typeof Blob === 'undefined' || typeof atob === 'undefined' ||\r\n            typeof btoa === 'undefined');\r\n    function stringByteLength(str) {\r\n        if (useNodeBuffer) {\r\n            return Buffer.byteLength(str);\r\n        }\r\n        return new Blob([str]).size;\r\n    }\r\n    function arrayBufferToBase64String(buffer) {\r\n        if (useNodeBuffer) {\r\n            return Buffer.from(buffer).toString('base64');\r\n        }\r\n        return btoa(String.fromCharCode.apply(null, new Uint8Array(buffer)));\r\n    }\r\n    function base64StringToArrayBuffer(str) {\r\n        if (useNodeBuffer) {\r\n            var buf = Buffer.from(str, 'base64');\r\n            return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);\r\n        }\r\n        var s = atob(str);\r\n        var buffer = new Uint8Array(s.length);\r\n        for (var i = 0; i < s.length; ++i) {\r\n            buffer.set([s.charCodeAt(i)], i);\r\n        }\r\n        return buffer.buffer;\r\n    }\r\n    function concatenateArrayBuffers(buffers) {\r\n        var totalByteLength = 0;\r\n        buffers.forEach(function (buffer) {\r\n            totalByteLength += buffer.byteLength;\r\n        });\r\n        var temp = new Uint8Array(totalByteLength);\r\n        var offset = 0;\r\n        buffers.forEach(function (buffer) {\r\n            temp.set(new Uint8Array(buffer), offset);\r\n            offset += buffer.byteLength;\r\n        });\r\n        return temp.buffer;\r\n    }\r\n    function basename(path) {\r\n        var SEPARATOR = '/';\r\n        path = path.trim();\r\n        while (path.endsWith(SEPARATOR)) {\r\n            path = path.slice(0, path.length - 1);\r\n        }\r\n        var items = path.split(SEPARATOR);\r\n        return items[items.length - 1];\r\n    }\r\n    function getModelArtifactsInfoForJSON(modelArtifacts) {\r\n        if (modelArtifacts.modelTopology instanceof ArrayBuffer) {\r\n            throw new Error('Expected JSON model topology, received ArrayBuffer.');\r\n        }\r\n        return {\r\n            dateSaved: new Date(),\r\n            modelTopologyType: 'JSON',\r\n            modelTopologyBytes: modelArtifacts.modelTopology == null ?\r\n                0 :\r\n                stringByteLength(JSON.stringify(modelArtifacts.modelTopology)),\r\n            weightSpecsBytes: modelArtifacts.weightSpecs == null ?\r\n                0 :\r\n                stringByteLength(JSON.stringify(modelArtifacts.weightSpecs)),\r\n            weightDataBytes: modelArtifacts.weightData == null ?\r\n                0 :\r\n                modelArtifacts.weightData.byteLength,\r\n        };\r\n    }\n\n    var IORouterRegistry = (function () {\r\n        function IORouterRegistry() {\r\n            this.saveRouters = [];\r\n            this.loadRouters = [];\r\n        }\r\n        IORouterRegistry.getInstance = function () {\r\n            if (IORouterRegistry.instance == null) {\r\n                IORouterRegistry.instance = new IORouterRegistry();\r\n            }\r\n            return IORouterRegistry.instance;\r\n        };\r\n        IORouterRegistry.registerSaveRouter = function (saveRouter) {\r\n            IORouterRegistry.getInstance().saveRouters.push(saveRouter);\r\n        };\r\n        IORouterRegistry.registerLoadRouter = function (loadRouter) {\r\n            IORouterRegistry.getInstance().loadRouters.push(loadRouter);\r\n        };\r\n        IORouterRegistry.getSaveHandlers = function (url) {\r\n            return IORouterRegistry.getHandlers(url, 'save');\r\n        };\r\n        IORouterRegistry.getLoadHandlers = function (url, onProgress) {\r\n            return IORouterRegistry.getHandlers(url, 'load', onProgress);\r\n        };\r\n        IORouterRegistry.getHandlers = function (url, handlerType, onProgress) {\r\n            var validHandlers = [];\r\n            var routers = handlerType === 'load' ? this.getInstance().loadRouters :\r\n                this.getInstance().saveRouters;\r\n            routers.forEach(function (router) {\r\n                var handler = router(url, onProgress);\r\n                if (handler !== null) {\r\n                    validHandlers.push(handler);\r\n                }\r\n            });\r\n            return validHandlers;\r\n        };\r\n        return IORouterRegistry;\r\n    }());\r\n    var registerSaveRouter = function (loudRouter) {\r\n        return IORouterRegistry.registerSaveRouter(loudRouter);\r\n    };\r\n    var registerLoadRouter = function (loudRouter) {\r\n        return IORouterRegistry.registerLoadRouter(loudRouter);\r\n    };\r\n    var getSaveHandlers = function (url) {\r\n        return IORouterRegistry.getSaveHandlers(url);\r\n    };\r\n    var getLoadHandlers = function (url, onProgress) {\r\n        return IORouterRegistry.getLoadHandlers(url);\r\n    };\n\n    var URL_SCHEME_SUFFIX = '://';\r\n    var ModelStoreManagerRegistry = (function () {\r\n        function ModelStoreManagerRegistry() {\r\n            this.managers = {};\r\n        }\r\n        ModelStoreManagerRegistry.getInstance = function () {\r\n            if (ModelStoreManagerRegistry.instance == null) {\r\n                ModelStoreManagerRegistry.instance = new ModelStoreManagerRegistry();\r\n            }\r\n            return ModelStoreManagerRegistry.instance;\r\n        };\r\n        ModelStoreManagerRegistry.registerManager = function (scheme, manager) {\r\n            assert(scheme != null, 'scheme must not be undefined or null.');\r\n            if (scheme.endsWith(URL_SCHEME_SUFFIX)) {\r\n                scheme = scheme.slice(0, scheme.indexOf(URL_SCHEME_SUFFIX));\r\n            }\r\n            assert(scheme.length > 0, 'scheme must not be an empty string.');\r\n            var registry = ModelStoreManagerRegistry.getInstance();\r\n            assert(registry.managers[scheme] == null, \"A model store manager is already registered for scheme '\" + scheme + \"'.\");\r\n            registry.managers[scheme] = manager;\r\n        };\r\n        ModelStoreManagerRegistry.getManager = function (scheme) {\r\n            var manager = this.getInstance().managers[scheme];\r\n            if (manager == null) {\r\n                throw new Error(\"Cannot find model manager for scheme '\" + scheme + \"'\");\r\n            }\r\n            return manager;\r\n        };\r\n        ModelStoreManagerRegistry.getSchemes = function () {\r\n            return Object.keys(this.getInstance().managers);\r\n        };\r\n        return ModelStoreManagerRegistry;\r\n    }());\r\n    function parseURL(url) {\r\n        if (url.indexOf(URL_SCHEME_SUFFIX) === -1) {\r\n            throw new Error(\"The url string provided does not contain a scheme. \" +\r\n                \"Supported schemes are: \" +\r\n                (\"\" + ModelStoreManagerRegistry.getSchemes().join(',')));\r\n        }\r\n        return {\r\n            scheme: url.split(URL_SCHEME_SUFFIX)[0],\r\n            path: url.split(URL_SCHEME_SUFFIX)[1],\r\n        };\r\n    }\r\n    function cloneModelInternal(sourceURL, destURL, deleteSource) {\r\n        if (deleteSource === void 0) { deleteSource = false; }\r\n        return __awaiter(this, void 0, void 0, function () {\r\n            var loadHandlers, loadHandler, saveHandlers, saveHandler, sourceScheme, sourcePath, sameMedium, modelArtifacts, saveResult;\r\n            return __generator(this, function (_a) {\r\n                switch (_a.label) {\r\n                    case 0:\r\n                        assert(sourceURL !== destURL, \"Old path and new path are the same: '\" + sourceURL + \"'\");\r\n                        loadHandlers = IORouterRegistry.getLoadHandlers(sourceURL);\r\n                        assert(loadHandlers.length > 0, \"Copying failed because no load handler is found for source URL \" + sourceURL + \".\");\r\n                        assert(loadHandlers.length < 2, \"Copying failed because more than one (\" + loadHandlers.length + \") \" +\r\n                            (\"load handlers for source URL \" + sourceURL + \".\"));\r\n                        loadHandler = loadHandlers[0];\r\n                        saveHandlers = IORouterRegistry.getSaveHandlers(destURL);\r\n                        assert(saveHandlers.length > 0, \"Copying failed because no save handler is found for destination URL \" +\r\n                            (destURL + \".\"));\r\n                        assert(saveHandlers.length < 2, \"Copying failed because more than one (\" + loadHandlers.length + \") \" +\r\n                            (\"save handlers for destination URL \" + destURL + \".\"));\r\n                        saveHandler = saveHandlers[0];\r\n                        sourceScheme = parseURL(sourceURL).scheme;\r\n                        sourcePath = parseURL(sourceURL).path;\r\n                        sameMedium = sourceScheme === parseURL(sourceURL).scheme;\r\n                        return [4, loadHandler.load()];\r\n                    case 1:\r\n                        modelArtifacts = _a.sent();\r\n                        if (!(deleteSource && sameMedium)) return [3, 3];\r\n                        return [4, ModelStoreManagerRegistry.getManager(sourceScheme)\r\n                                .removeModel(sourcePath)];\r\n                    case 2:\r\n                        _a.sent();\r\n                        _a.label = 3;\r\n                    case 3: return [4, saveHandler.save(modelArtifacts)];\r\n                    case 4:\r\n                        saveResult = _a.sent();\r\n                        if (!(deleteSource && !sameMedium)) return [3, 6];\r\n                        return [4, ModelStoreManagerRegistry.getManager(sourceScheme)\r\n                                .removeModel(sourcePath)];\r\n                    case 5:\r\n                        _a.sent();\r\n                        _a.label = 6;\r\n                    case 6: return [2, saveResult.modelArtifactsInfo];\r\n                }\r\n            });\r\n        });\r\n    }\r\n    function listModels() {\r\n        return __awaiter(this, void 0, void 0, function () {\r\n            var schemes, out, _i, schemes_1, scheme, schemeOut, path, url;\r\n            return __generator(this, function (_a) {\r\n                switch (_a.label) {\r\n                    case 0:\r\n                        schemes = ModelStoreManagerRegistry.getSchemes();\r\n                        out = {};\r\n                        _i = 0, schemes_1 = schemes;\r\n                        _a.label = 1;\r\n                    case 1:\r\n                        if (!(_i < schemes_1.length)) return [3, 4];\r\n                        scheme = schemes_1[_i];\r\n                        return [4, ModelStoreManagerRegistry.getManager(scheme).listModels()];\r\n                    case 2:\r\n                        schemeOut = _a.sent();\r\n                        for (path in schemeOut) {\r\n                            url = scheme + URL_SCHEME_SUFFIX + path;\r\n                            out[url] = schemeOut[path];\r\n                        }\r\n                        _a.label = 3;\r\n                    case 3:\r\n                        _i++;\r\n                        return [3, 1];\r\n                    case 4: return [2, out];\r\n                }\r\n            });\r\n        });\r\n    }\r\n    function removeModel(url) {\r\n        return __awaiter(this, void 0, void 0, function () {\r\n            var schemeAndPath, manager;\r\n            return __generator(this, function (_a) {\r\n                switch (_a.label) {\r\n                    case 0:\r\n                        schemeAndPath = parseURL(url);\r\n                        manager = ModelStoreManagerRegistry.getManager(schemeAndPath.scheme);\r\n                        return [4, manager.removeModel(schemeAndPath.path)];\r\n                    case 1: return [2, _a.sent()];\r\n                }\r\n            });\r\n        });\r\n    }\r\n    function copyModel(sourceURL, destURL) {\r\n        return __awaiter(this, void 0, void 0, function () {\r\n            var deleteSource;\r\n            return __generator(this, function (_a) {\r\n                switch (_a.label) {\r\n                    case 0:\r\n                        deleteSource = false;\r\n                        return [4, cloneModelInternal(sourceURL, destURL, deleteSource)];\r\n                    case 1: return [2, _a.sent()];\r\n                }\r\n            });\r\n        });\r\n    }\r\n    function moveModel(sourceURL, destURL) {\r\n        return __awaiter(this, void 0, void 0, function () {\r\n            var deleteSource;\r\n            return __generator(this, function (_a) {\r\n                switch (_a.label) {\r\n                    case 0:\r\n                        deleteSource = true;\r\n                        return [4, cloneModelInternal(sourceURL, destURL, deleteSource)];\r\n                    case 1: return [2, _a.sent()];\r\n                }\r\n            });\r\n        });\r\n    }\n\n    var DATABASE_NAME = 'tensorflowjs';\r\n    var DATABASE_VERSION = 1;\r\n    var MODEL_STORE_NAME = 'models_store';\r\n    var INFO_STORE_NAME = 'model_info_store';\r\n    function getIndexedDBFactory() {\r\n        if (!ENV.get('IS_BROWSER')) {\r\n            throw new Error('Failed to obtain IndexedDB factory because the current environment' +\r\n                'is not a web browser.');\r\n        }\r\n        var theWindow = window;\r\n        var factory = theWindow.indexedDB || theWindow.mozIndexedDB ||\r\n            theWindow.webkitIndexedDB || theWindow.msIndexedDB ||\r\n            theWindow.shimIndexedDB;\r\n        if (factory == null) {\r\n            throw new Error('The current browser does not appear to support IndexedDB.');\r\n        }\r\n        return factory;\r\n    }\r\n    function setUpDatabase(openRequest) {\r\n        var db = openRequest.result;\r\n        db.createObjectStore(MODEL_STORE_NAME, { keyPath: 'modelPath' });\r\n        db.createObjectStore(INFO_STORE_NAME, { keyPath: 'modelPath' });\r\n    }\r\n    var BrowserIndexedDB = (function () {\r\n        function BrowserIndexedDB(modelPath) {\r\n            this.indexedDB = getIndexedDBFactory();\r\n            if (modelPath == null || !modelPath) {\r\n                throw new Error('For IndexedDB, modelPath must not be null, undefined or empty.');\r\n            }\r\n            this.modelPath = modelPath;\r\n        }\r\n        BrowserIndexedDB.prototype.save = function (modelArtifacts) {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                return __generator(this, function (_a) {\r\n                    if (modelArtifacts.modelTopology instanceof ArrayBuffer) {\r\n                        throw new Error('BrowserLocalStorage.save() does not support saving model topology ' +\r\n                            'in binary formats yet.');\r\n                    }\r\n                    return [2, this.databaseAction(this.modelPath, modelArtifacts)];\r\n                });\r\n            });\r\n        };\r\n        BrowserIndexedDB.prototype.load = function () {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                return __generator(this, function (_a) {\r\n                    return [2, this.databaseAction(this.modelPath)];\r\n                });\r\n            });\r\n        };\r\n        BrowserIndexedDB.prototype.databaseAction = function (modelPath, modelArtifacts) {\r\n            var _this = this;\r\n            return new Promise(function (resolve, reject) {\r\n                var openRequest = _this.indexedDB.open(DATABASE_NAME, DATABASE_VERSION);\r\n                openRequest.onupgradeneeded = function () { return setUpDatabase(openRequest); };\r\n                openRequest.onsuccess = function () {\r\n                    var db = openRequest.result;\r\n                    if (modelArtifacts == null) {\r\n                        var modelTx = db.transaction(MODEL_STORE_NAME, 'readonly');\r\n                        var modelStore = modelTx.objectStore(MODEL_STORE_NAME);\r\n                        var getRequest_1 = modelStore.get(_this.modelPath);\r\n                        getRequest_1.onsuccess = function () {\r\n                            if (getRequest_1.result == null) {\r\n                                db.close();\r\n                                return reject(new Error(\"Cannot find model with path '\" + _this.modelPath + \"' \" +\r\n                                    \"in IndexedDB.\"));\r\n                            }\r\n                            else {\r\n                                resolve(getRequest_1.result.modelArtifacts);\r\n                            }\r\n                        };\r\n                        getRequest_1.onerror = function (error) {\r\n                            db.close();\r\n                            return reject(getRequest_1.error);\r\n                        };\r\n                        modelTx.oncomplete = function () { return db.close(); };\r\n                    }\r\n                    else {\r\n                        var modelArtifactsInfo_1 = getModelArtifactsInfoForJSON(modelArtifacts);\r\n                        var infoTx_1 = db.transaction(INFO_STORE_NAME, 'readwrite');\r\n                        var infoStore_1 = infoTx_1.objectStore(INFO_STORE_NAME);\r\n                        var putInfoRequest_1 = infoStore_1.put({ modelPath: _this.modelPath, modelArtifactsInfo: modelArtifactsInfo_1 });\r\n                        var modelTx_1;\r\n                        putInfoRequest_1.onsuccess = function () {\r\n                            modelTx_1 = db.transaction(MODEL_STORE_NAME, 'readwrite');\r\n                            var modelStore = modelTx_1.objectStore(MODEL_STORE_NAME);\r\n                            var putModelRequest = modelStore.put({\r\n                                modelPath: _this.modelPath,\r\n                                modelArtifacts: modelArtifacts,\r\n                                modelArtifactsInfo: modelArtifactsInfo_1\r\n                            });\r\n                            putModelRequest.onsuccess = function () { return resolve({ modelArtifactsInfo: modelArtifactsInfo_1 }); };\r\n                            putModelRequest.onerror = function (error) {\r\n                                infoStore_1 = infoTx_1.objectStore(INFO_STORE_NAME);\r\n                                var deleteInfoRequest = infoStore_1.delete(_this.modelPath);\r\n                                deleteInfoRequest.onsuccess = function () {\r\n                                    db.close();\r\n                                    return reject(putModelRequest.error);\r\n                                };\r\n                                deleteInfoRequest.onerror = function (error) {\r\n                                    db.close();\r\n                                    return reject(putModelRequest.error);\r\n                                };\r\n                            };\r\n                        };\r\n                        putInfoRequest_1.onerror = function (error) {\r\n                            db.close();\r\n                            return reject(putInfoRequest_1.error);\r\n                        };\r\n                        infoTx_1.oncomplete = function () {\r\n                            if (modelTx_1 == null) {\r\n                                db.close();\r\n                            }\r\n                            else {\r\n                                modelTx_1.oncomplete = function () { return db.close(); };\r\n                            }\r\n                        };\r\n                    }\r\n                };\r\n                openRequest.onerror = function (error) { return reject(openRequest.error); };\r\n            });\r\n        };\r\n        BrowserIndexedDB.URL_SCHEME = 'indexeddb://';\r\n        return BrowserIndexedDB;\r\n    }());\r\n    var indexedDBRouter = function (url) {\r\n        if (!ENV.get('IS_BROWSER')) {\r\n            return null;\r\n        }\r\n        else {\r\n            if (!Array.isArray(url) && url.startsWith(BrowserIndexedDB.URL_SCHEME)) {\r\n                return browserIndexedDB(url.slice(BrowserIndexedDB.URL_SCHEME.length));\r\n            }\r\n            else {\r\n                return null;\r\n            }\r\n        }\r\n    };\r\n    IORouterRegistry.registerSaveRouter(indexedDBRouter);\r\n    IORouterRegistry.registerLoadRouter(indexedDBRouter);\r\n    function browserIndexedDB(modelPath) {\r\n        return new BrowserIndexedDB(modelPath);\r\n    }\r\n    function maybeStripScheme(key) {\r\n        return key.startsWith(BrowserIndexedDB.URL_SCHEME) ?\r\n            key.slice(BrowserIndexedDB.URL_SCHEME.length) :\r\n            key;\r\n    }\r\n    var BrowserIndexedDBManager = (function () {\r\n        function BrowserIndexedDBManager() {\r\n            this.indexedDB = getIndexedDBFactory();\r\n        }\r\n        BrowserIndexedDBManager.prototype.listModels = function () {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var _this = this;\r\n                return __generator(this, function (_a) {\r\n                    return [2, new Promise(function (resolve, reject) {\r\n                            var openRequest = _this.indexedDB.open(DATABASE_NAME, DATABASE_VERSION);\r\n                            openRequest.onupgradeneeded = function () { return setUpDatabase(openRequest); };\r\n                            openRequest.onsuccess = function () {\r\n                                var db = openRequest.result;\r\n                                var tx = db.transaction(INFO_STORE_NAME, 'readonly');\r\n                                var store = tx.objectStore(INFO_STORE_NAME);\r\n                                var getAllInfoRequest = store.getAll();\r\n                                getAllInfoRequest.onsuccess = function () {\r\n                                    var out = {};\r\n                                    for (var _i = 0, _a = getAllInfoRequest.result; _i < _a.length; _i++) {\r\n                                        var item = _a[_i];\r\n                                        out[item.modelPath] = item.modelArtifactsInfo;\r\n                                    }\r\n                                    resolve(out);\r\n                                };\r\n                                getAllInfoRequest.onerror = function (error) {\r\n                                    db.close();\r\n                                    return reject(getAllInfoRequest.error);\r\n                                };\r\n                                tx.oncomplete = function () { return db.close(); };\r\n                            };\r\n                            openRequest.onerror = function (error) { return reject(openRequest.error); };\r\n                        })];\r\n                });\r\n            });\r\n        };\r\n        BrowserIndexedDBManager.prototype.removeModel = function (path) {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var _this = this;\r\n                return __generator(this, function (_a) {\r\n                    path = maybeStripScheme(path);\r\n                    return [2, new Promise(function (resolve, reject) {\r\n                            var openRequest = _this.indexedDB.open(DATABASE_NAME, DATABASE_VERSION);\r\n                            openRequest.onupgradeneeded = function () { return setUpDatabase(openRequest); };\r\n                            openRequest.onsuccess = function () {\r\n                                var db = openRequest.result;\r\n                                var infoTx = db.transaction(INFO_STORE_NAME, 'readwrite');\r\n                                var infoStore = infoTx.objectStore(INFO_STORE_NAME);\r\n                                var getInfoRequest = infoStore.get(path);\r\n                                var modelTx;\r\n                                getInfoRequest.onsuccess = function () {\r\n                                    if (getInfoRequest.result == null) {\r\n                                        db.close();\r\n                                        return reject(new Error(\"Cannot find model with path '\" + path + \"' \" +\r\n                                            \"in IndexedDB.\"));\r\n                                    }\r\n                                    else {\r\n                                        var deleteInfoRequest = infoStore.delete(path);\r\n                                        var deleteModelData_1 = function () {\r\n                                            modelTx = db.transaction(MODEL_STORE_NAME, 'readwrite');\r\n                                            var modelStore = modelTx.objectStore(MODEL_STORE_NAME);\r\n                                            var deleteModelRequest = modelStore.delete(path);\r\n                                            deleteModelRequest.onsuccess = function () {\r\n                                                return resolve(getInfoRequest.result.modelArtifactsInfo);\r\n                                            };\r\n                                            deleteModelRequest.onerror = function (error) {\r\n                                                return reject(getInfoRequest.error);\r\n                                            };\r\n                                        };\r\n                                        deleteInfoRequest.onsuccess = deleteModelData_1;\r\n                                        deleteInfoRequest.onerror = function (error) {\r\n                                            deleteModelData_1();\r\n                                            db.close();\r\n                                            return reject(getInfoRequest.error);\r\n                                        };\r\n                                    }\r\n                                };\r\n                                getInfoRequest.onerror = function (error) {\r\n                                    db.close();\r\n                                    return reject(getInfoRequest.error);\r\n                                };\r\n                                infoTx.oncomplete = function () {\r\n                                    if (modelTx == null) {\r\n                                        db.close();\r\n                                    }\r\n                                    else {\r\n                                        modelTx.oncomplete = function () { return db.close(); };\r\n                                    }\r\n                                };\r\n                            };\r\n                            openRequest.onerror = function (error) { return reject(openRequest.error); };\r\n                        })];\r\n                });\r\n            });\r\n        };\r\n        return BrowserIndexedDBManager;\r\n    }());\r\n    if (ENV.get('IS_BROWSER')) {\r\n        try {\r\n            ModelStoreManagerRegistry.registerManager(BrowserIndexedDB.URL_SCHEME, new BrowserIndexedDBManager());\r\n        }\r\n        catch (err) {\r\n        }\r\n    }\n\n    var PATH_SEPARATOR = '/';\r\n    var PATH_PREFIX = 'tensorflowjs_models';\r\n    var INFO_SUFFIX = 'info';\r\n    var MODEL_TOPOLOGY_SUFFIX = 'model_topology';\r\n    var WEIGHT_SPECS_SUFFIX = 'weight_specs';\r\n    var WEIGHT_DATA_SUFFIX = 'weight_data';\r\n    function getModelKeys(path) {\r\n        return {\r\n            info: [PATH_PREFIX, path, INFO_SUFFIX].join(PATH_SEPARATOR),\r\n            topology: [PATH_PREFIX, path, MODEL_TOPOLOGY_SUFFIX].join(PATH_SEPARATOR),\r\n            weightSpecs: [PATH_PREFIX, path, WEIGHT_SPECS_SUFFIX].join(PATH_SEPARATOR),\r\n            weightData: [PATH_PREFIX, path, WEIGHT_DATA_SUFFIX].join(PATH_SEPARATOR)\r\n        };\r\n    }\r\n    function getModelPathFromKey(key) {\r\n        var items = key.split(PATH_SEPARATOR);\r\n        if (items.length < 3) {\r\n            throw new Error(\"Invalid key format: \" + key);\r\n        }\r\n        return items.slice(1, items.length - 1).join(PATH_SEPARATOR);\r\n    }\r\n    function maybeStripScheme$1(key) {\r\n        return key.startsWith(BrowserLocalStorage.URL_SCHEME) ?\r\n            key.slice(BrowserLocalStorage.URL_SCHEME.length) :\r\n            key;\r\n    }\r\n    var BrowserLocalStorage = (function () {\r\n        function BrowserLocalStorage(modelPath) {\r\n            if (!ENV.get('IS_BROWSER') || typeof window.localStorage === 'undefined') {\r\n                throw new Error('The current environment does not support local storage.');\r\n            }\r\n            this.LS = window.localStorage;\r\n            if (modelPath == null || !modelPath) {\r\n                throw new Error('For local storage, modelPath must not be null, undefined or empty.');\r\n            }\r\n            this.modelPath = modelPath;\r\n            this.keys = getModelKeys(this.modelPath);\r\n        }\r\n        BrowserLocalStorage.prototype.save = function (modelArtifacts) {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var topology, weightSpecs, modelArtifactsInfo, key;\r\n                return __generator(this, function (_a) {\r\n                    if (modelArtifacts.modelTopology instanceof ArrayBuffer) {\r\n                        throw new Error('BrowserLocalStorage.save() does not support saving model topology ' +\r\n                            'in binary formats yet.');\r\n                    }\r\n                    else {\r\n                        topology = JSON.stringify(modelArtifacts.modelTopology);\r\n                        weightSpecs = JSON.stringify(modelArtifacts.weightSpecs);\r\n                        modelArtifactsInfo = getModelArtifactsInfoForJSON(modelArtifacts);\r\n                        try {\r\n                            this.LS.setItem(this.keys.info, JSON.stringify(modelArtifactsInfo));\r\n                            this.LS.setItem(this.keys.topology, topology);\r\n                            this.LS.setItem(this.keys.weightSpecs, weightSpecs);\r\n                            this.LS.setItem(this.keys.weightData, arrayBufferToBase64String(modelArtifacts.weightData));\r\n                            return [2, { modelArtifactsInfo: modelArtifactsInfo }];\r\n                        }\r\n                        catch (err) {\r\n                            for (key in this.keys) {\r\n                                this.LS.removeItem(this.keys[key]);\r\n                            }\r\n                            throw new Error(\"Failed to save model '\" + this.modelPath + \"' to local storage: \" +\r\n                                \"size quota being exceeded is a possible cause of this failure: \" +\r\n                                (\"modelTopologyBytes=\" + modelArtifactsInfo.modelTopologyBytes + \", \") +\r\n                                (\"weightSpecsBytes=\" + modelArtifactsInfo.weightSpecsBytes + \", \") +\r\n                                (\"weightDataBytes=\" + modelArtifactsInfo.weightDataBytes + \".\"));\r\n                        }\r\n                    }\r\n                    return [2];\r\n                });\r\n            });\r\n        };\r\n        BrowserLocalStorage.prototype.load = function () {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var info, out, topology, weightSpecs, weightDataBase64;\r\n                return __generator(this, function (_a) {\r\n                    info = JSON.parse(this.LS.getItem(this.keys.info));\r\n                    if (info == null) {\r\n                        throw new Error(\"In local storage, there is no model with name '\" + this.modelPath + \"'\");\r\n                    }\r\n                    if (info.modelTopologyType !== 'JSON') {\r\n                        throw new Error('BrowserLocalStorage does not support loading non-JSON model ' +\r\n                            'topology yet.');\r\n                    }\r\n                    out = {};\r\n                    topology = JSON.parse(this.LS.getItem(this.keys.topology));\r\n                    if (topology == null) {\r\n                        throw new Error(\"In local storage, the topology of model '\" + this.modelPath + \"' \" +\r\n                            \"is missing.\");\r\n                    }\r\n                    out.modelTopology = topology;\r\n                    weightSpecs = JSON.parse(this.LS.getItem(this.keys.weightSpecs));\r\n                    if (weightSpecs == null) {\r\n                        throw new Error(\"In local storage, the weight specs of model '\" + this.modelPath + \"' \" +\r\n                            \"are missing.\");\r\n                    }\r\n                    out.weightSpecs = weightSpecs;\r\n                    weightDataBase64 = this.LS.getItem(this.keys.weightData);\r\n                    if (weightDataBase64 == null) {\r\n                        throw new Error(\"In local storage, the binary weight values of model \" +\r\n                            (\"'\" + this.modelPath + \"' are missing.\"));\r\n                    }\r\n                    out.weightData = base64StringToArrayBuffer(weightDataBase64);\r\n                    return [2, out];\r\n                });\r\n            });\r\n        };\r\n        BrowserLocalStorage.URL_SCHEME = 'localstorage://';\r\n        return BrowserLocalStorage;\r\n    }());\r\n    var localStorageRouter = function (url) {\r\n        if (!ENV.get('IS_BROWSER')) {\r\n            return null;\r\n        }\r\n        else {\r\n            if (!Array.isArray(url) &&\r\n                url.startsWith(BrowserLocalStorage.URL_SCHEME)) {\r\n                return browserLocalStorage(url.slice(BrowserLocalStorage.URL_SCHEME.length));\r\n            }\r\n            else {\r\n                return null;\r\n            }\r\n        }\r\n    };\r\n    IORouterRegistry.registerSaveRouter(localStorageRouter);\r\n    IORouterRegistry.registerLoadRouter(localStorageRouter);\r\n    function browserLocalStorage(modelPath) {\r\n        return new BrowserLocalStorage(modelPath);\r\n    }\r\n    var BrowserLocalStorageManager = (function () {\r\n        function BrowserLocalStorageManager() {\r\n            assert(ENV.get('IS_BROWSER'), 'Current environment is not a web browser');\r\n            assert(typeof window.localStorage !== 'undefined', 'Current browser does not appear to support localStorage');\r\n            this.LS = window.localStorage;\r\n        }\r\n        BrowserLocalStorageManager.prototype.listModels = function () {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var out, prefix, suffix, i, key, modelPath;\r\n                return __generator(this, function (_a) {\r\n                    out = {};\r\n                    prefix = PATH_PREFIX + PATH_SEPARATOR;\r\n                    suffix = PATH_SEPARATOR + INFO_SUFFIX;\r\n                    for (i = 0; i < this.LS.length; ++i) {\r\n                        key = this.LS.key(i);\r\n                        if (key.startsWith(prefix) && key.endsWith(suffix)) {\r\n                            modelPath = getModelPathFromKey(key);\r\n                            out[modelPath] = JSON.parse(this.LS.getItem(key));\r\n                        }\r\n                    }\r\n                    return [2, out];\r\n                });\r\n            });\r\n        };\r\n        BrowserLocalStorageManager.prototype.removeModel = function (path) {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var keys, info;\r\n                return __generator(this, function (_a) {\r\n                    path = maybeStripScheme$1(path);\r\n                    keys = getModelKeys(path);\r\n                    if (this.LS.getItem(keys.info) == null) {\r\n                        throw new Error(\"Cannot find model at path '\" + path + \"'\");\r\n                    }\r\n                    info = JSON.parse(this.LS.getItem(keys.info));\r\n                    this.LS.removeItem(keys.info);\r\n                    this.LS.removeItem(keys.topology);\r\n                    this.LS.removeItem(keys.weightSpecs);\r\n                    this.LS.removeItem(keys.weightData);\r\n                    return [2, info];\r\n                });\r\n            });\r\n        };\r\n        return BrowserLocalStorageManager;\r\n    }());\r\n    if (ENV.get('IS_BROWSER')) {\r\n        try {\r\n            ModelStoreManagerRegistry.registerManager(BrowserLocalStorage.URL_SCHEME, new BrowserLocalStorageManager());\r\n        }\r\n        catch (err) {\r\n        }\r\n    }\n\n    var DEFAULT_FILE_NAME_PREFIX = 'model';\r\n    var DEFAULT_JSON_EXTENSION_NAME = '.json';\r\n    var DEFAULT_WEIGHT_DATA_EXTENSION_NAME = '.weights.bin';\r\n    var BrowserDownloads = (function () {\r\n        function BrowserDownloads(fileNamePrefix) {\r\n            if (!ENV.get('IS_BROWSER')) {\r\n                throw new Error('browserDownloads() cannot proceed because the current environment ' +\r\n                    'is not a browser.');\r\n            }\r\n            if (fileNamePrefix.startsWith(BrowserDownloads.URL_SCHEME)) {\r\n                fileNamePrefix = fileNamePrefix.slice(BrowserDownloads.URL_SCHEME.length);\r\n            }\r\n            if (fileNamePrefix == null || fileNamePrefix.length === 0) {\r\n                fileNamePrefix = DEFAULT_FILE_NAME_PREFIX;\r\n            }\r\n            this.modelTopologyFileName = fileNamePrefix + DEFAULT_JSON_EXTENSION_NAME;\r\n            this.weightDataFileName =\r\n                fileNamePrefix + DEFAULT_WEIGHT_DATA_EXTENSION_NAME;\r\n        }\r\n        BrowserDownloads.prototype.save = function (modelArtifacts) {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var weightsURL, weightsManifest, modelTopologyAndWeightManifest, modelTopologyAndWeightManifestURL, jsonAnchor, weightDataAnchor;\r\n                return __generator(this, function (_a) {\r\n                    weightsURL = window.URL.createObjectURL(new Blob([modelArtifacts.weightData], { type: 'application/octet-stream' }));\r\n                    if (modelArtifacts.modelTopology instanceof ArrayBuffer) {\r\n                        throw new Error('BrowserDownloads.save() does not support saving model topology ' +\r\n                            'in binary formats yet.');\r\n                    }\r\n                    else {\r\n                        weightsManifest = [{\r\n                                paths: ['./' + this.weightDataFileName],\r\n                                weights: modelArtifacts.weightSpecs\r\n                            }];\r\n                        modelTopologyAndWeightManifest = {\r\n                            modelTopology: modelArtifacts.modelTopology,\r\n                            weightsManifest: weightsManifest\r\n                        };\r\n                        modelTopologyAndWeightManifestURL = window.URL.createObjectURL(new Blob([JSON.stringify(modelTopologyAndWeightManifest)], { type: 'application/json' }));\r\n                        jsonAnchor = this.jsonAnchor == null ? document.createElement('a') :\r\n                            this.jsonAnchor;\r\n                        jsonAnchor.download = this.modelTopologyFileName;\r\n                        jsonAnchor.href = modelTopologyAndWeightManifestURL;\r\n                        jsonAnchor.click();\r\n                        if (modelArtifacts.weightData != null) {\r\n                            weightDataAnchor = this.weightDataAnchor == null ?\r\n                                document.createElement('a') :\r\n                                this.weightDataAnchor;\r\n                            weightDataAnchor.download = this.weightDataFileName;\r\n                            weightDataAnchor.href = weightsURL;\r\n                            weightDataAnchor.click();\r\n                        }\r\n                        return [2, { modelArtifactsInfo: getModelArtifactsInfoForJSON(modelArtifacts) }];\r\n                    }\r\n                    return [2];\r\n                });\r\n            });\r\n        };\r\n        BrowserDownloads.URL_SCHEME = 'downloads://';\r\n        return BrowserDownloads;\r\n    }());\r\n    var BrowserFiles = (function () {\r\n        function BrowserFiles(files) {\r\n            if (files == null || files.length < 1) {\r\n                throw new Error(\"When calling browserFiles, at least 1 file is required, \" +\r\n                    (\"but received \" + files));\r\n            }\r\n            this.files = files;\r\n        }\r\n        BrowserFiles.prototype.load = function () {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var jsonFile, weightFiles;\r\n                var _this = this;\r\n                return __generator(this, function (_a) {\r\n                    jsonFile = this.files[0];\r\n                    weightFiles = this.files.slice(1);\r\n                    return [2, new Promise(function (resolve, reject) {\r\n                            var jsonReader = new FileReader();\r\n                            jsonReader.onload = function (event) {\r\n                                var modelJSON = JSON.parse(event.target.result);\r\n                                var modelTopology = modelJSON.modelTopology;\r\n                                if (modelTopology == null) {\r\n                                    reject(new Error(\"modelTopology field is missing from file \" + jsonFile.name));\r\n                                    return;\r\n                                }\r\n                                if (weightFiles.length === 0) {\r\n                                    resolve({ modelTopology: modelTopology });\r\n                                }\r\n                                var weightsManifest = modelJSON.weightsManifest;\r\n                                if (weightsManifest == null) {\r\n                                    reject(new Error(\"weightManifest field is missing from file \" + jsonFile.name));\r\n                                    return;\r\n                                }\r\n                                var pathToFile;\r\n                                try {\r\n                                    pathToFile =\r\n                                        _this.checkManifestAndWeightFiles(weightsManifest, weightFiles);\r\n                                }\r\n                                catch (err) {\r\n                                    reject(err);\r\n                                    return;\r\n                                }\r\n                                var weightSpecs = [];\r\n                                var paths = [];\r\n                                var perFileBuffers = [];\r\n                                weightsManifest.forEach(function (weightsGroup) {\r\n                                    weightsGroup.paths.forEach(function (path) {\r\n                                        paths.push(path);\r\n                                        perFileBuffers.push(null);\r\n                                    });\r\n                                    weightSpecs.push.apply(weightSpecs, weightsGroup.weights);\r\n                                });\r\n                                weightsManifest.forEach(function (weightsGroup) {\r\n                                    weightsGroup.paths.forEach(function (path) {\r\n                                        var weightFileReader = new FileReader();\r\n                                        weightFileReader.onload = function (event) {\r\n                                            var weightData = event.target.result;\r\n                                            var index = paths.indexOf(path);\r\n                                            perFileBuffers[index] = weightData;\r\n                                            if (perFileBuffers.indexOf(null) === -1) {\r\n                                                resolve({\r\n                                                    modelTopology: modelTopology,\r\n                                                    weightSpecs: weightSpecs,\r\n                                                    weightData: concatenateArrayBuffers(perFileBuffers),\r\n                                                });\r\n                                            }\r\n                                        };\r\n                                        weightFileReader.onerror = function (error) {\r\n                                            return reject(\"Failed to weights data from file of path '\" + path + \"'.\");\r\n                                        };\r\n                                        weightFileReader.readAsArrayBuffer(pathToFile[path]);\r\n                                    });\r\n                                });\r\n                            };\r\n                            jsonReader.onerror = function (error) { return reject(\"Failed to read model topology and weights manifest JSON \" +\r\n                                (\"from file '\" + jsonFile.name + \"'. BrowserFiles supports loading \") +\r\n                                \"Keras-style tf.Model artifacts only.\"); };\r\n                            jsonReader.readAsText(jsonFile);\r\n                        })];\r\n                });\r\n            });\r\n        };\r\n        BrowserFiles.prototype.checkManifestAndWeightFiles = function (manifest, files) {\r\n            var basenames = [];\r\n            var fileNames = files.map(function (file) { return basename(file.name); });\r\n            var pathToFile = {};\r\n            for (var _i = 0, manifest_1 = manifest; _i < manifest_1.length; _i++) {\r\n                var group = manifest_1[_i];\r\n                group.paths.forEach(function (path) {\r\n                    var pathBasename = basename(path);\r\n                    if (basenames.indexOf(pathBasename) !== -1) {\r\n                        throw new Error(\"Duplicate file basename found in weights manifest: \" +\r\n                            (\"'\" + pathBasename + \"'\"));\r\n                    }\r\n                    basenames.push(pathBasename);\r\n                    if (fileNames.indexOf(pathBasename) === -1) {\r\n                        throw new Error(\"Weight file with basename '\" + pathBasename + \"' is not provided.\");\r\n                    }\r\n                    else {\r\n                        pathToFile[path] = files[fileNames.indexOf(pathBasename)];\r\n                    }\r\n                });\r\n            }\r\n            if (basenames.length !== files.length) {\r\n                throw new Error(\"Mismatch in the number of files in weights manifest \" +\r\n                    (\"(\" + basenames.length + \") and the number of weight files provided \") +\r\n                    (\"(\" + files.length + \").\"));\r\n            }\r\n            return pathToFile;\r\n        };\r\n        return BrowserFiles;\r\n    }());\r\n    var browserDownloadsRouter = function (url) {\r\n        if (!ENV.get('IS_BROWSER')) {\r\n            return null;\r\n        }\r\n        else {\r\n            if (!Array.isArray(url) && url.startsWith(BrowserDownloads.URL_SCHEME)) {\r\n                return browserDownloads(url.slice(BrowserDownloads.URL_SCHEME.length));\r\n            }\r\n            else {\r\n                return null;\r\n            }\r\n        }\r\n    };\r\n    IORouterRegistry.registerSaveRouter(browserDownloadsRouter);\r\n    function browserDownloads(fileNamePrefix) {\r\n        if (fileNamePrefix === void 0) { fileNamePrefix = 'model'; }\r\n        return new BrowserDownloads(fileNamePrefix);\r\n    }\r\n    function browserFiles(files) {\r\n        return new BrowserFiles(files);\r\n    }\n\n    var OCTET_STREAM_TYPE = 'application/octet-stream';\r\n    var CONTENT_TYPE = 'Content-type';\r\n    function loadWeightsAsArrayBuffer(fetchURLs, requestOptions, fetchFunc, onProgress) {\r\n        return __awaiter(this, void 0, void 0, function () {\r\n            var headers, requests, fetchStartFraction, fetchEndFraction, responses, badContentType, bufferPromises, bufferStartFraction, bufferEndFraction, buffers;\r\n            return __generator(this, function (_a) {\r\n                switch (_a.label) {\r\n                    case 0:\r\n                        if (fetchFunc == null) {\r\n                            fetchFunc = fetch;\r\n                        }\r\n                        requestOptions = requestOptions || {};\r\n                        headers = (requestOptions.headers || {});\r\n                        headers['Accept'] = OCTET_STREAM_TYPE;\r\n                        requestOptions.headers = headers;\r\n                        requests = fetchURLs.map(function (fetchURL) { return fetchFunc(fetchURL, requestOptions); });\r\n                        fetchStartFraction = 0;\r\n                        fetchEndFraction = 0.5;\r\n                        if (onProgress != null) {\r\n                            monitorPromisesProgress(requests, onProgress, fetchStartFraction, fetchEndFraction);\r\n                        }\r\n                        return [4, Promise.all(requests)];\r\n                    case 1:\r\n                        responses = _a.sent();\r\n                        badContentType = responses.filter(function (response) {\r\n                            var contentType = response.headers.get(CONTENT_TYPE);\r\n                            return !contentType || contentType.indexOf(OCTET_STREAM_TYPE) === -1;\r\n                        });\r\n                        if (badContentType.length > 0) {\r\n                            throw new Error(badContentType\r\n                                .map(function (resp) { return \"Request to \" + resp.url + \" for weight file failed.\" +\r\n                                (\" Expected content type \" + OCTET_STREAM_TYPE + \" but got \" + resp.headers.get(CONTENT_TYPE) + \".\"); })\r\n                                .join('\\n'));\r\n                        }\r\n                        bufferPromises = responses.map(function (response) { return response.arrayBuffer(); });\r\n                        bufferStartFraction = 0.5;\r\n                        bufferEndFraction = 1;\r\n                        if (onProgress != null) {\r\n                            monitorPromisesProgress(bufferPromises, onProgress, bufferStartFraction, bufferEndFraction);\r\n                        }\r\n                        return [4, Promise.all(bufferPromises)];\r\n                    case 2:\r\n                        buffers = _a.sent();\r\n                        return [2, buffers];\r\n                }\r\n            });\r\n        });\r\n    }\r\n    function loadWeights(manifest, filePathPrefix, weightNames, requestOptions) {\r\n        if (filePathPrefix === void 0) { filePathPrefix = ''; }\r\n        return __awaiter(this, void 0, void 0, function () {\r\n            var fetchWeights, loadWeights;\r\n            return __generator(this, function (_a) {\r\n                fetchWeights = function (fetchUrls) {\r\n                    return loadWeightsAsArrayBuffer(fetchUrls, requestOptions);\r\n                };\r\n                loadWeights = weightsLoaderFactory(fetchWeights);\r\n                return [2, loadWeights(manifest, filePathPrefix, weightNames)];\r\n            });\r\n        });\r\n    }\r\n    function weightsLoaderFactory(fetchWeightsFunction) {\r\n        var _this = this;\r\n        return function (manifest, filePathPrefix, weightNames) {\r\n            if (filePathPrefix === void 0) { filePathPrefix = ''; }\r\n            return __awaiter(_this, void 0, void 0, function () {\r\n                var groupIndicesToFetchMap, groupWeightsToFetch, weightsFound, allManifestWeightNames, weightsNotFound, groupIndicesToFetch, fetchUrls, buffers, weightsTensorMap, bufferIndexOffset;\r\n                return __generator(this, function (_a) {\r\n                    switch (_a.label) {\r\n                        case 0:\r\n                            groupIndicesToFetchMap = manifest.map(function () { return false; });\r\n                            groupWeightsToFetch = {};\r\n                            weightsFound = weightNames != null ? weightNames.map(function () { return false; }) : [];\r\n                            allManifestWeightNames = [];\r\n                            manifest.forEach(function (manifestGroupConfig, groupIndex) {\r\n                                var groupOffset = 0;\r\n                                manifestGroupConfig.weights.forEach(function (weightsEntry) {\r\n                                    var rawDtype = ('quantization' in weightsEntry) ?\r\n                                        weightsEntry.quantization.dtype :\r\n                                        weightsEntry.dtype;\r\n                                    var weightsBytes = DTYPE_VALUE_SIZE_MAP[rawDtype] *\r\n                                        sizeFromShape(weightsEntry.shape);\r\n                                    var enqueueWeightsForFetchingFn = function () {\r\n                                        groupIndicesToFetchMap[groupIndex] = true;\r\n                                        if (groupWeightsToFetch[groupIndex] == null) {\r\n                                            groupWeightsToFetch[groupIndex] = [];\r\n                                        }\r\n                                        groupWeightsToFetch[groupIndex].push({\r\n                                            manifestEntry: weightsEntry,\r\n                                            groupOffset: groupOffset,\r\n                                            sizeBytes: weightsBytes\r\n                                        });\r\n                                    };\r\n                                    if (weightNames != null) {\r\n                                        weightNames.forEach(function (weightName, weightIndex) {\r\n                                            if (weightName === weightsEntry.name) {\r\n                                                enqueueWeightsForFetchingFn();\r\n                                                weightsFound[weightIndex] = true;\r\n                                            }\r\n                                        });\r\n                                    }\r\n                                    else {\r\n                                        enqueueWeightsForFetchingFn();\r\n                                    }\r\n                                    allManifestWeightNames.push(weightsEntry.name);\r\n                                    groupOffset += weightsBytes;\r\n                                });\r\n                            });\r\n                            if (!weightsFound.every(function (found) { return found; })) {\r\n                                weightsNotFound = weightNames.filter(function (_, i) { return !weightsFound[i]; });\r\n                                throw new Error(\"Could not find weights in manifest with names: \" +\r\n                                    (weightsNotFound.join(', ') + \". \\n\") +\r\n                                    \"Manifest JSON has weights with names: \" +\r\n                                    (allManifestWeightNames.join(', ') + \".\"));\r\n                            }\r\n                            groupIndicesToFetch = groupIndicesToFetchMap.reduce(function (accumulator, shouldFetch, i) {\r\n                                if (shouldFetch) {\r\n                                    accumulator.push(i);\r\n                                }\r\n                                return accumulator;\r\n                            }, []);\r\n                            fetchUrls = [];\r\n                            groupIndicesToFetch.forEach(function (i) {\r\n                                manifest[i].paths.forEach(function (filepath) {\r\n                                    var fetchUrl = filePathPrefix +\r\n                                        (!filePathPrefix.endsWith('/') ? '/' : '') + filepath;\r\n                                    fetchUrls.push(fetchUrl);\r\n                                });\r\n                            });\r\n                            return [4, fetchWeightsFunction(fetchUrls)];\r\n                        case 1:\r\n                            buffers = _a.sent();\r\n                            weightsTensorMap = {};\r\n                            bufferIndexOffset = 0;\r\n                            groupIndicesToFetch.forEach(function (i) {\r\n                                var numBuffers = manifest[i].paths.length;\r\n                                var groupBytes = 0;\r\n                                for (var i_1 = 0; i_1 < numBuffers; i_1++) {\r\n                                    groupBytes += buffers[bufferIndexOffset + i_1].byteLength;\r\n                                }\r\n                                var groupBuffer = new ArrayBuffer(groupBytes);\r\n                                var groupByteBuffer = new Uint8Array(groupBuffer);\r\n                                var groupBufferOffset = 0;\r\n                                for (var i_2 = 0; i_2 < numBuffers; i_2++) {\r\n                                    var buffer = new Uint8Array(buffers[bufferIndexOffset + i_2]);\r\n                                    groupByteBuffer.set(buffer, groupBufferOffset);\r\n                                    groupBufferOffset += buffer.byteLength;\r\n                                }\r\n                                var weightsEntries = groupWeightsToFetch[i];\r\n                                weightsEntries.forEach(function (weightsEntry) {\r\n                                    var byteBuffer = groupBuffer.slice(weightsEntry.groupOffset, weightsEntry.groupOffset + weightsEntry.sizeBytes);\r\n                                    var nameToTensorMap = decodeWeights(byteBuffer, [weightsEntry.manifestEntry]);\r\n                                    for (var name_1 in nameToTensorMap) {\r\n                                        weightsTensorMap[name_1] = nameToTensorMap[name_1];\r\n                                    }\r\n                                });\r\n                                bufferIndexOffset += numBuffers;\r\n                            });\r\n                            return [2, weightsTensorMap];\r\n                    }\r\n                });\r\n            });\r\n        };\r\n    }\n\n    var BrowserHTTPRequest = (function () {\r\n        function BrowserHTTPRequest(path, requestInit, weightPathPrefix, fetchFunc, onProgress) {\r\n            this.weightPathPrefix = weightPathPrefix;\r\n            this.onProgress = onProgress;\r\n            this.DEFAULT_METHOD = 'POST';\r\n            if (fetchFunc == null) {\r\n                if (typeof fetch === 'undefined') {\r\n                    throw new Error('browserHTTPRequest is not supported outside the web browser ' +\r\n                        'without a fetch polyfill.');\r\n                }\r\n                fetchFunc = fetch.bind(typeof window === 'undefined' ? null : window);\r\n            }\r\n            else {\r\n                assert(typeof fetchFunc === 'function', 'Must pass a function that matches the signature of ' +\r\n                    '`fetch` (see ' +\r\n                    'https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)');\r\n            }\r\n            this.fetchFunc = function (path, requestInits) {\r\n                return fetchFunc(path, requestInits).catch(function (error) {\r\n                    throw new Error(\"Request for \" + path + \" failed due to error: \" + error);\r\n                });\r\n            };\r\n            assert(path != null && path.length > 0, 'URL path for browserHTTPRequest must not be null, undefined or ' +\r\n                'empty.');\r\n            if (Array.isArray(path)) {\r\n                assert(path.length === 2, 'URL paths for browserHTTPRequest must have a length of 2, ' +\r\n                    (\"(actual length is \" + path.length + \").\"));\r\n            }\r\n            this.path = path;\r\n            if (requestInit != null && requestInit.body != null) {\r\n                throw new Error('requestInit is expected to have no pre-existing body, but has one.');\r\n            }\r\n            this.requestInit = requestInit || {};\r\n        }\r\n        BrowserHTTPRequest.prototype.save = function (modelArtifacts) {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var init, weightsManifest, modelTopologyAndWeightManifest, response;\r\n                return __generator(this, function (_a) {\r\n                    switch (_a.label) {\r\n                        case 0:\r\n                            if (modelArtifacts.modelTopology instanceof ArrayBuffer) {\r\n                                throw new Error('BrowserHTTPRequest.save() does not support saving model topology ' +\r\n                                    'in binary formats yet.');\r\n                            }\r\n                            init = Object.assign({ method: this.DEFAULT_METHOD }, this.requestInit);\r\n                            init.body = new FormData();\r\n                            weightsManifest = [{\r\n                                    paths: ['./model.weights.bin'],\r\n                                    weights: modelArtifacts.weightSpecs,\r\n                                }];\r\n                            modelTopologyAndWeightManifest = {\r\n                                modelTopology: modelArtifacts.modelTopology,\r\n                                weightsManifest: weightsManifest\r\n                            };\r\n                            init.body.append('model.json', new Blob([JSON.stringify(modelTopologyAndWeightManifest)], { type: 'application/json' }), 'model.json');\r\n                            if (modelArtifacts.weightData != null) {\r\n                                init.body.append('model.weights.bin', new Blob([modelArtifacts.weightData], { type: 'application/octet-stream' }), 'model.weights.bin');\r\n                            }\r\n                            return [4, this.getFetchFunc()(this.path, init)];\r\n                        case 1:\r\n                            response = _a.sent();\r\n                            if (response.ok) {\r\n                                return [2, {\r\n                                        modelArtifactsInfo: getModelArtifactsInfoForJSON(modelArtifacts),\r\n                                        responses: [response],\r\n                                    }];\r\n                            }\r\n                            else {\r\n                                throw new Error(\"BrowserHTTPRequest.save() failed due to HTTP response status \" +\r\n                                    (response.status + \".\"));\r\n                            }\r\n                            return [2];\r\n                    }\r\n                });\r\n            });\r\n        };\r\n        BrowserHTTPRequest.prototype.load = function () {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                return __generator(this, function (_a) {\r\n                    return [2, Array.isArray(this.path) ? this.loadBinaryModel() :\r\n                            this.loadJSONModel()];\r\n                });\r\n            });\r\n        };\r\n        BrowserHTTPRequest.prototype.loadBinaryTopology = function () {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var response;\r\n                return __generator(this, function (_a) {\r\n                    switch (_a.label) {\r\n                        case 0: return [4, this.getFetchFunc()(this.path[0], this.addAcceptHeader('application/octet-stream'))];\r\n                        case 1:\r\n                            response = _a.sent();\r\n                            this.verifyContentType(response, 'model topology', 'application/octet-stream');\r\n                            if (!response.ok) {\r\n                                throw new Error(\"Request to \" + this.path[0] + \" failed with error: \" + response.statusText);\r\n                            }\r\n                            return [4, response.arrayBuffer()];\r\n                        case 2: return [2, _a.sent()];\r\n                    }\r\n                });\r\n            });\r\n        };\r\n        BrowserHTTPRequest.prototype.addAcceptHeader = function (mimeType) {\r\n            var requestOptions = Object.assign({}, this.requestInit || {});\r\n            var headers = Object.assign({}, requestOptions.headers || {});\r\n            headers['Accept'] = mimeType;\r\n            requestOptions.headers = headers;\r\n            return requestOptions;\r\n        };\r\n        BrowserHTTPRequest.prototype.verifyContentType = function (response, target, type) {\r\n            var contentType = response.headers.get('content-type');\r\n            if (!contentType || contentType.indexOf(type) === -1) {\r\n                throw new Error(\"Request to \" + response.url + \" for \" + target + \" failed. Expected content type \" + type + \" but got \" + contentType + \".\");\r\n            }\r\n        };\r\n        BrowserHTTPRequest.prototype.loadBinaryModel = function () {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var graphPromise, manifestPromise, results, modelTopology, weightsManifestResponse, weightsManifest, weightSpecs, weightData, results_1;\r\n                return __generator(this, function (_a) {\r\n                    switch (_a.label) {\r\n                        case 0:\r\n                            graphPromise = this.loadBinaryTopology();\r\n                            return [4, this.getFetchFunc()(this.path[1], this.addAcceptHeader('application/json'))];\r\n                        case 1:\r\n                            manifestPromise = _a.sent();\r\n                            this.verifyContentType(manifestPromise, 'weights manifest', 'application/json');\r\n                            if (!manifestPromise.ok) {\r\n                                throw new Error(\"Request to \" + this.path[1] + \" failed with error: \" + manifestPromise.statusText);\r\n                            }\r\n                            return [4, Promise.all([graphPromise, manifestPromise])];\r\n                        case 2:\r\n                            results = _a.sent();\r\n                            modelTopology = results[0], weightsManifestResponse = results[1];\r\n                            return [4, weightsManifestResponse.json()];\r\n                        case 3:\r\n                            weightsManifest = _a.sent();\r\n                            if (!(weightsManifest != null)) return [3, 5];\r\n                            return [4, this.loadWeights(weightsManifest)];\r\n                        case 4:\r\n                            results_1 = _a.sent();\r\n                            weightSpecs = results_1[0], weightData = results_1[1];\r\n                            _a.label = 5;\r\n                        case 5: return [2, { modelTopology: modelTopology, weightSpecs: weightSpecs, weightData: weightData }];\r\n                    }\r\n                });\r\n            });\r\n        };\r\n        BrowserHTTPRequest.prototype.loadJSONModel = function () {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var modelConfigRequest, modelConfig, modelTopology, weightsManifest, weightSpecs, weightData, weightsManifest_1, results;\r\n                return __generator(this, function (_a) {\r\n                    switch (_a.label) {\r\n                        case 0: return [4, this.getFetchFunc()(this.path, this.addAcceptHeader('application/json'))];\r\n                        case 1:\r\n                            modelConfigRequest = _a.sent();\r\n                            this.verifyContentType(modelConfigRequest, 'model topology', 'application/json');\r\n                            if (!modelConfigRequest.ok) {\r\n                                throw new Error(\"Request to \" + this.path + \" failed with error: \" + modelConfigRequest.statusText);\r\n                            }\r\n                            return [4, modelConfigRequest.json()];\r\n                        case 2:\r\n                            modelConfig = _a.sent();\r\n                            modelTopology = modelConfig['modelTopology'];\r\n                            weightsManifest = modelConfig['weightsManifest'];\r\n                            if (modelTopology == null && weightsManifest == null) {\r\n                                throw new Error(\"The JSON from HTTP path \" + this.path + \" contains neither model \" +\r\n                                    \"topology or manifest for weights.\");\r\n                            }\r\n                            if (!(weightsManifest != null)) return [3, 4];\r\n                            weightsManifest_1 = modelConfig['weightsManifest'];\r\n                            return [4, this.loadWeights(weightsManifest_1)];\r\n                        case 3:\r\n                            results = _a.sent();\r\n                            weightSpecs = results[0], weightData = results[1];\r\n                            _a.label = 4;\r\n                        case 4: return [2, { modelTopology: modelTopology, weightSpecs: weightSpecs, weightData: weightData }];\r\n                    }\r\n                });\r\n            });\r\n        };\r\n        BrowserHTTPRequest.prototype.loadWeights = function (weightsManifest) {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var weightPath, _a, prefix, suffix, pathPrefix, weightSpecs, _i, weightsManifest_2, entry, fetchURLs, _b, _c;\r\n                return __generator(this, function (_d) {\r\n                    switch (_d.label) {\r\n                        case 0:\r\n                            weightPath = Array.isArray(this.path) ? this.path[1] : this.path;\r\n                            _a = parseUrl(weightPath), prefix = _a[0], suffix = _a[1];\r\n                            pathPrefix = this.weightPathPrefix || prefix;\r\n                            weightSpecs = [];\r\n                            for (_i = 0, weightsManifest_2 = weightsManifest; _i < weightsManifest_2.length; _i++) {\r\n                                entry = weightsManifest_2[_i];\r\n                                weightSpecs.push.apply(weightSpecs, entry.weights);\r\n                            }\r\n                            fetchURLs = [];\r\n                            weightsManifest.forEach(function (weightsGroup) {\r\n                                weightsGroup.paths.forEach(function (path) {\r\n                                    fetchURLs.push(pathPrefix + path + suffix);\r\n                                });\r\n                            });\r\n                            _b = [weightSpecs];\r\n                            _c = concatenateArrayBuffers;\r\n                            return [4, loadWeightsAsArrayBuffer(fetchURLs, this.requestInit, this.getFetchFunc(), this.onProgress)];\r\n                        case 1: return [2, _b.concat([\r\n                                _c.apply(void 0, [_d.sent()])\r\n                            ])];\r\n                    }\r\n                });\r\n            });\r\n        };\r\n        BrowserHTTPRequest.prototype.getFetchFunc = function () {\r\n            return this.fetchFunc;\r\n        };\r\n        BrowserHTTPRequest.URL_SCHEME_REGEX = /^https?:\\/\\//;\r\n        return BrowserHTTPRequest;\r\n    }());\r\n    function parseUrl(url) {\r\n        var lastSlash = url.lastIndexOf('/');\r\n        var lastSearchParam = url.lastIndexOf('?');\r\n        var prefix = url.substring(0, lastSlash);\r\n        var suffix = lastSearchParam > lastSlash ? url.substring(lastSearchParam) : '';\r\n        return [prefix + '/', suffix];\r\n    }\r\n    function isHTTPScheme(url) {\r\n        return url.match(BrowserHTTPRequest.URL_SCHEME_REGEX) != null;\r\n    }\r\n    var httpRequestRouter = function (url, onProgress) {\r\n        if (typeof fetch === 'undefined') {\r\n            return null;\r\n        }\r\n        else {\r\n            var isHTTP = true;\r\n            if (Array.isArray(url)) {\r\n                isHTTP = url.every(function (urlItem) { return isHTTPScheme(urlItem); });\r\n            }\r\n            else {\r\n                isHTTP = isHTTPScheme(url);\r\n            }\r\n            if (isHTTP) {\r\n                return browserHTTPRequest(url, null, null, null, onProgress);\r\n            }\r\n        }\r\n        return null;\r\n    };\r\n    IORouterRegistry.registerSaveRouter(httpRequestRouter);\r\n    IORouterRegistry.registerLoadRouter(httpRequestRouter);\r\n    function browserHTTPRequest(path, requestInit, weightPathPrefix, fetchFunc, onProgress) {\r\n        return new BrowserHTTPRequest(path, requestInit, weightPathPrefix, fetchFunc, onProgress);\r\n    }\n\n    var PassthroughLoader = (function () {\r\n        function PassthroughLoader(modelTopology, weightSpecs, weightData) {\r\n            this.modelTopology = modelTopology;\r\n            this.weightSpecs = weightSpecs;\r\n            this.weightData = weightData;\r\n        }\r\n        PassthroughLoader.prototype.load = function () {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                var result;\r\n                return __generator(this, function (_a) {\r\n                    result = {};\r\n                    if (this.modelTopology != null) {\r\n                        result = __assign({ modelTopology: this.modelTopology }, result);\r\n                    }\r\n                    if (this.weightSpecs != null && this.weightSpecs.length > 0) {\r\n                        result = __assign({ weightSpecs: this.weightSpecs }, result);\r\n                    }\r\n                    if (this.weightData != null && this.weightData.byteLength > 0) {\r\n                        result = __assign({ weightData: this.weightData }, result);\r\n                    }\r\n                    return [2, result];\r\n                });\r\n            });\r\n        };\r\n        return PassthroughLoader;\r\n    }());\r\n    var PassthroughSaver = (function () {\r\n        function PassthroughSaver(saveHandler) {\r\n            this.saveHandler = saveHandler;\r\n        }\r\n        PassthroughSaver.prototype.save = function (modelArtifacts) {\r\n            return __awaiter(this, void 0, void 0, function () {\r\n                return __generator(this, function (_a) {\r\n                    return [2, this.saveHandler(modelArtifacts)];\r\n                });\r\n            });\r\n        };\r\n        return PassthroughSaver;\r\n    }());\r\n    function fromMemory(modelTopology, weightSpecs, weightData) {\r\n        return new PassthroughLoader(modelTopology, weightSpecs, weightData);\r\n    }\r\n    function withSaveHandler(saveHandler) {\r\n        return new PassthroughSaver(saveHandler);\r\n    }\n\n\n\n    var io = /*#__PURE__*/Object.freeze({\n        browserFiles: browserFiles,\n        browserHTTPRequest: browserHTTPRequest,\n        concatenateArrayBuffers: concatenateArrayBuffers,\n        decodeWeights: decodeWeights,\n        encodeWeights: encodeWeights,\n        fromMemory: fromMemory,\n        getLoadHandlers: getLoadHandlers,\n        getModelArtifactsInfoForJSON: getModelArtifactsInfoForJSON,\n        getSaveHandlers: getSaveHandlers,\n        isHTTPScheme: isHTTPScheme,\n        loadWeights: loadWeights,\n        registerLoadRouter: registerLoadRouter,\n        registerSaveRouter: registerSaveRouter,\n        weightsLoaderFactory: weightsLoaderFactory,\n        withSaveHandler: withSaveHandler,\n        copyModel: copyModel,\n        listModels: listModels,\n        moveModel: moveModel,\n        removeModel: removeModel\n    });\n\n    function confusionMatrix_(labels, predictions, numClasses) {\r\n        var $labels = convertToTensor(labels, 'labels', 'confusionMatrix');\r\n        var $predictions = convertToTensor(predictions, 'predictions', 'confusionMatrix');\r\n        assert(numClasses == null || numClasses > 0 && Number.isInteger(numClasses), \"If provided, numClasses must be a positive integer, \" +\r\n            (\"but got \" + numClasses));\r\n        assert($labels.rank === 1, \"Expected the rank of labels to be 1, but got \" + $labels.rank);\r\n        assert($predictions.rank === 1, \"Expected the rank of predictions to be 1, \" +\r\n            (\"but got \" + $predictions.rank));\r\n        assert($labels.shape[0] === $predictions.shape[0], \"Mismatch in the number of examples: \" +\r\n            ($labels.shape[0] + \" vs. \" + $predictions.shape[0] + \". \") +\r\n            \"Labels and predictions should have the same number of elements.\");\r\n        assert(numClasses > 0 && Number.isInteger(numClasses), \"numClasses is required to be a positive integer, but got \" + numClasses);\r\n        var oneHotLabels = oneHot($labels.asType('int32'), numClasses);\r\n        var oneHotPredictions = oneHot($predictions.asType('int32'), numClasses);\r\n        return oneHotLabels.transpose().matMul(oneHotPredictions).asType('int32');\r\n    }\r\n    var confusionMatrix = op({ confusionMatrix_: confusionMatrix_ });\n\n\n\n    var math = /*#__PURE__*/Object.freeze({\n        confusionMatrix: confusionMatrix\n    });\n\n    var Serializable = (function () {\r\n        function Serializable() {\r\n        }\r\n        Serializable.prototype.getClassName = function () {\r\n            return this.constructor\r\n                .className;\r\n        };\r\n        Serializable.fromConfig = function (cls, config) {\r\n            return new cls(config);\r\n        };\r\n        return Serializable;\r\n    }());\r\n    var SerializationMap = (function () {\r\n        function SerializationMap() {\r\n            this.classNameMap = {};\r\n        }\r\n        SerializationMap.getMap = function () {\r\n            if (SerializationMap.instance == null) {\r\n                SerializationMap.instance = new SerializationMap();\r\n            }\r\n            return SerializationMap.instance;\r\n        };\r\n        SerializationMap.register = function (cls) {\r\n            SerializationMap.getMap().classNameMap[cls.className] =\r\n                [cls, cls.fromConfig];\r\n        };\r\n        return SerializationMap;\r\n    }());\r\n    function registerClass(cls) {\r\n        assert(cls.className != null, \"Class being registered does not have the static className property \" +\r\n            \"defined.\");\r\n        assert(typeof cls.className === 'string', \"className is required to be a string, but got type \" +\r\n            typeof cls.className);\r\n        assert(cls.className.length > 0, \"Class being registered has an empty-string as its className, which \" +\r\n            \"is disallowed.\");\r\n        SerializationMap.register(cls);\r\n    }\n\n    var serialization = /*#__PURE__*/Object.freeze({\n        Serializable: Serializable,\n        SerializationMap: SerializationMap,\n        registerClass: registerClass\n    });\n\n    var WEBGL_ENVS = {\r\n        'HAS_WEBGL': true\r\n    };\r\n    var PACKED_ENVS = {\r\n        'WEBGL_PACK': true\r\n    };\r\n    var NODE_ENVS = {\r\n        'IS_NODE': true\r\n    };\r\n    var CHROME_ENVS = {\r\n        'IS_CHROME': true\r\n    };\r\n    var BROWSER_ENVS = {\r\n        'IS_BROWSER': true\r\n    };\r\n    var CPU_ENVS = {\r\n        'HAS_WEBGL': false\r\n    };\r\n    var ALL_ENVS = {};\r\n    function expectArraysClose(actual, expected, epsilon) {\r\n        if (epsilon == null) {\r\n            epsilon = ENV.get('TEST_EPSILON');\r\n        }\r\n        return expectArraysPredicate(actual, expected, function (a, b) { return areClose(a, Number(b), epsilon); });\r\n    }\r\n    function expectArraysPredicate(actual, expected, predicate) {\r\n        if (!(actual instanceof Tensor) && !(expected instanceof Tensor)) {\r\n            var aType = actual.constructor.name;\r\n            var bType = expected.constructor.name;\r\n            if (aType !== bType) {\r\n                throw new Error(\"Arrays are of different type actual: \" + aType + \" \" +\r\n                    (\"vs expected: \" + bType));\r\n            }\r\n        }\r\n        else if (actual instanceof Tensor && expected instanceof Tensor) {\r\n            if (actual.dtype !== expected.dtype) {\r\n                throw new Error(\"Arrays are of different type actual: \" + actual.dtype + \" \" +\r\n                    (\"vs expected: \" + expected.dtype + \".\"));\r\n            }\r\n            if (!arraysEqual(actual.shape, expected.shape)) {\r\n                throw new Error(\"Arrays are of different shape actual: \" + actual.shape + \" \" +\r\n                    (\"vs expected: \" + expected.shape + \".\"));\r\n            }\r\n        }\r\n        var actualValues;\r\n        var expectedValues;\r\n        if (actual instanceof Tensor) {\r\n            actualValues = actual.dataSync();\r\n        }\r\n        else {\r\n            actualValues = actual;\r\n        }\r\n        if (expected instanceof Tensor) {\r\n            expectedValues = expected.dataSync();\r\n        }\r\n        else {\r\n            expectedValues = expected;\r\n        }\r\n        if (actualValues.length !== expectedValues.length) {\r\n            throw new Error(\"Arrays have different lengths actual: \" + actualValues.length + \" vs \" +\r\n                (\"expected: \" + expectedValues.length + \".\\n\") +\r\n                (\"Actual:   \" + actualValues + \".\\n\") +\r\n                (\"Expected: \" + expectedValues + \".\"));\r\n        }\r\n        for (var i = 0; i < expectedValues.length; ++i) {\r\n            var a = actualValues[i];\r\n            var e = expectedValues[i];\r\n            if (!predicate(a, e)) {\r\n                throw new Error(\"Arrays differ: actual[\" + i + \"] = \" + a + \", expected[\" + i + \"] = \" + e + \".\\n\" +\r\n                    (\"Actual:   \" + actualValues + \".\\n\") +\r\n                    (\"Expected: \" + expectedValues + \".\"));\r\n            }\r\n        }\r\n    }\r\n    function expectPromiseToFail(fn, done) {\r\n        fn().then(function () { return done.fail(); }, function () { return done(); });\r\n    }\r\n    function expectArraysEqual(actual, expected) {\r\n        if (actual instanceof Tensor && actual.dtype === 'string' ||\r\n            expected instanceof Tensor && expected.dtype === 'string' ||\r\n            Array.isArray(actual) && isString(actual[0]) ||\r\n            Array.isArray(expected) && isString(expected[0])) {\r\n            return expectArraysPredicate(actual, expected, function (a, b) { return a == b; });\r\n        }\r\n        return expectArraysClose(actual, expected, 0);\r\n    }\r\n    function expectNumbersClose(a, e, epsilon) {\r\n        if (epsilon == null) {\r\n            epsilon = ENV.get('TEST_EPSILON');\r\n        }\r\n        if (!areClose(a, e, epsilon)) {\r\n            throw new Error(\"Numbers differ: actual === \" + a + \", expected === \" + e);\r\n        }\r\n    }\r\n    function areClose(a, e, epsilon) {\r\n        if (isNaN(a) && isNaN(e)) {\r\n            return true;\r\n        }\r\n        if (isNaN(a) || isNaN(e) || Math.abs(a - e) > epsilon) {\r\n            return false;\r\n        }\r\n        return true;\r\n    }\r\n    function expectValuesInRange(actual, low, high) {\r\n        var actualVals;\r\n        if (actual instanceof Tensor) {\r\n            actualVals = actual.dataSync();\r\n        }\r\n        else {\r\n            actualVals = actual;\r\n        }\r\n        for (var i = 0; i < actualVals.length; i++) {\r\n            if (actualVals[i] < low || actualVals[i] > high) {\r\n                throw new Error(\"Value out of range:\" + actualVals[i] + \" low: \" + low + \", high: \" + high);\r\n            }\r\n        }\r\n    }\r\n    function expectArrayBuffersEqual(actual, expected) {\r\n        expect(new Float32Array(actual)).toEqual(new Float32Array(expected));\r\n    }\n\n    var test_util = /*#__PURE__*/Object.freeze({\n        WEBGL_ENVS: WEBGL_ENVS,\n        PACKED_ENVS: PACKED_ENVS,\n        NODE_ENVS: NODE_ENVS,\n        CHROME_ENVS: CHROME_ENVS,\n        BROWSER_ENVS: BROWSER_ENVS,\n        CPU_ENVS: CPU_ENVS,\n        ALL_ENVS: ALL_ENVS,\n        expectArraysClose: expectArraysClose,\n        expectPromiseToFail: expectPromiseToFail,\n        expectArraysEqual: expectArraysEqual,\n        expectNumbersClose: expectNumbersClose,\n        expectValuesInRange: expectValuesInRange,\n        expectArrayBuffersEqual: expectArrayBuffersEqual\n    });\n\n    var version = '0.14.5';\n\n\n\n    var webgl = /*#__PURE__*/Object.freeze({\n        gpgpu_util: gpgpu_util,\n        webgl_util: webgl_util,\n        MathBackendWebGL: MathBackendWebGL,\n        GPGPUContext: GPGPUContext\n    });\n\n    var Optimizer = (function (_super) {\r\n        __extends(Optimizer, _super);\r\n        function Optimizer() {\r\n            return _super !== null && _super.apply(this, arguments) || this;\r\n        }\r\n        Optimizer.prototype.minimize = function (f, returnCost, varList) {\r\n            if (returnCost === void 0) { returnCost = false; }\r\n            var _a = this.computeGradients(f, varList), value = _a.value, grads$$1 = _a.grads;\r\n            this.applyGradients(grads$$1);\r\n            var varNames = Object.keys(grads$$1);\r\n            varNames.forEach(function (varName) { return grads$$1[varName].dispose(); });\r\n            if (returnCost) {\r\n                return value;\r\n            }\r\n            else {\r\n                value.dispose();\r\n                return null;\r\n            }\r\n        };\r\n        Optimizer.prototype.computeGradients = function (f, varList) {\r\n            return variableGrads(f, varList);\r\n        };\r\n        return Optimizer;\r\n    }(Serializable));\r\n    Object.defineProperty(Optimizer, Symbol.hasInstance, {\r\n        value: function (instance) {\r\n            return instance.minimize != null && instance.computeGradients != null &&\r\n                instance.applyGradients != null;\r\n        }\r\n    });\n\n    var AdadeltaOptimizer = (function (_super) {\r\n        __extends(AdadeltaOptimizer, _super);\r\n        function AdadeltaOptimizer(learningRate, rho, epsilon) {\r\n            if (epsilon === void 0) { epsilon = null; }\r\n            var _this = _super.call(this) || this;\r\n            _this.learningRate = learningRate;\r\n            _this.rho = rho;\r\n            _this.epsilon = epsilon;\r\n            _this.accumulatedGrads = {};\r\n            _this.accumulatedUpdates = {};\r\n            _this.c = keep(scalar(-learningRate));\r\n            _this.rhoScalar = keep(scalar(rho));\r\n            _this.oneMinusRho = keep(scalar(1 - rho));\r\n            if (epsilon === null) {\r\n                epsilon = ENV.get('EPSILON');\r\n            }\r\n            _this.epsilonScalar = keep(scalar(epsilon));\r\n            return _this;\r\n        }\r\n        AdadeltaOptimizer.prototype.applyGradients = function (variableGradients) {\r\n            var _this = this;\r\n            var _loop_1 = function (variableName) {\r\n                var value = ENV.engine.registeredVariables[variableName];\r\n                if (this_1.accumulatedGrads[variableName] == null) {\r\n                    var trainable_1 = false;\r\n                    tidy(function () {\r\n                        _this.accumulatedGrads[variableName] =\r\n                            zerosLike(value).variable(trainable_1);\r\n                    });\r\n                }\r\n                if (this_1.accumulatedUpdates[variableName] == null) {\r\n                    var trainable_2 = false;\r\n                    tidy(function () {\r\n                        _this.accumulatedUpdates[variableName] =\r\n                            zerosLike(value).variable(trainable_2);\r\n                    });\r\n                }\r\n                var gradient = variableGradients[variableName];\r\n                var accumulatedGrad = this_1.accumulatedGrads[variableName];\r\n                var accumulatedUpdate = this_1.accumulatedUpdates[variableName];\r\n                tidy(function () {\r\n                    var newAccumulatedGrad = _this.rhoScalar.mul(accumulatedGrad)\r\n                        .add(_this.oneMinusRho.mul(gradient.square()));\r\n                    var updates = accumulatedUpdate.add(_this.epsilonScalar)\r\n                        .sqrt()\r\n                        .div(accumulatedGrad.add(_this.epsilonScalar).sqrt())\r\n                        .mul(gradient);\r\n                    var newAccumulatedUpdate = _this.rhoScalar.mul(accumulatedUpdate)\r\n                        .add(_this.oneMinusRho.mul(updates.square()));\r\n                    _this.accumulatedGrads[variableName].assign(newAccumulatedGrad);\r\n                    _this.accumulatedUpdates[variableName].assign(newAccumulatedUpdate);\r\n                    var newValue = _this.c.mul(updates).add(value);\r\n                    value.assign(newValue);\r\n                });\r\n            };\r\n            var this_1 = this;\r\n            for (var variableName in variableGradients) {\r\n                _loop_1(variableName);\r\n            }\r\n        };\r\n        AdadeltaOptimizer.prototype.dispose = function () {\r\n            var _this = this;\r\n            this.c.dispose();\r\n            this.epsilonScalar.dispose();\r\n            this.rhoScalar.dispose();\r\n            this.oneMinusRho.dispose();\r\n            if (this.accumulatedUpdates != null) {\r\n                Object.keys(this.accumulatedUpdates)\r\n                    .forEach(function (name) { return _this.accumulatedUpdates[name].dispose(); });\r\n                Object.keys(this.accumulatedGrads)\r\n                    .forEach(function (name) { return _this.accumulatedGrads[name].dispose(); });\r\n            }\r\n        };\r\n        AdadeltaOptimizer.prototype.getConfig = function () {\r\n            return {\r\n                learningRate: this.learningRate,\r\n                rho: this.rho,\r\n                epsilon: this.epsilon\r\n            };\r\n        };\r\n        AdadeltaOptimizer.fromConfig = function (cls, config) {\r\n            return new cls(config.learningRate, config.rho, config.epsilon);\r\n        };\r\n        AdadeltaOptimizer.className = 'AdadeltaOptimizer';\r\n        return AdadeltaOptimizer;\r\n    }(Optimizer));\r\n    registerClass(AdadeltaOptimizer);\n\n    var AdagradOptimizer = (function (_super) {\r\n        __extends(AdagradOptimizer, _super);\r\n        function AdagradOptimizer(learningRate, initialAccumulatorValue) {\r\n            if (initialAccumulatorValue === void 0) { initialAccumulatorValue = 0.1; }\r\n            var _this = _super.call(this) || this;\r\n            _this.learningRate = learningRate;\r\n            _this.initialAccumulatorValue = initialAccumulatorValue;\r\n            _this.accumulatedGrads = {};\r\n            _this.c = keep(scalar(-learningRate));\r\n            _this.epsilon = keep(scalar(ENV.get('EPSILON')));\r\n            return _this;\r\n        }\r\n        AdagradOptimizer.prototype.applyGradients = function (variableGradients) {\r\n            var _this = this;\r\n            var _loop_1 = function (variableName) {\r\n                var value = ENV.engine.registeredVariables[variableName];\r\n                if (this_1.accumulatedGrads[variableName] == null) {\r\n                    var trainable_1 = false;\r\n                    tidy(function () {\r\n                        _this.accumulatedGrads[variableName] =\r\n                            fill(value.shape, _this.initialAccumulatorValue)\r\n                                .variable(trainable_1);\r\n                    });\r\n                }\r\n                var gradient = variableGradients[variableName];\r\n                var accumulatedGrad = this_1.accumulatedGrads[variableName];\r\n                tidy(function () {\r\n                    var newAccumulatedGrad = accumulatedGrad.add(gradient.square());\r\n                    _this.accumulatedGrads[variableName].assign(newAccumulatedGrad);\r\n                    var newValue = _this.c\r\n                        .mul(gradient.div(newAccumulatedGrad.add(_this.epsilon).sqrt()))\r\n                        .add(value);\r\n                    value.assign(newValue);\r\n                });\r\n            };\r\n            var this_1 = this;\r\n            for (var variableName in variableGradients) {\r\n                _loop_1(variableName);\r\n            }\r\n        };\r\n        AdagradOptimizer.prototype.dispose = function () {\r\n            var _this = this;\r\n            this.epsilon.dispose();\r\n            this.c.dispose();\r\n            if (this.accumulatedGrads != null) {\r\n                Object.keys(this.accumulatedGrads)\r\n                    .forEach(function (name) { return _this.accumulatedGrads[name].dispose(); });\r\n            }\r\n        };\r\n        AdagradOptimizer.prototype.getConfig = function () {\r\n            return {\r\n                learningRate: this.learningRate,\r\n                initialAccumulatorValue: this.initialAccumulatorValue,\r\n            };\r\n        };\r\n        AdagradOptimizer.fromConfig = function (cls, config) {\r\n            return new cls(config.learningRate, config.initialAccumulatorValue);\r\n        };\r\n        AdagradOptimizer.className = 'AdagradOptimizer';\r\n        return AdagradOptimizer;\r\n    }(Optimizer));\r\n    registerClass(AdagradOptimizer);\n\n    var AdamOptimizer = (function (_super) {\r\n        __extends(AdamOptimizer, _super);\r\n        function AdamOptimizer(learningRate, beta1, beta2, epsilon) {\r\n            if (epsilon === void 0) { epsilon = null; }\r\n            var _this = _super.call(this) || this;\r\n            _this.learningRate = learningRate;\r\n            _this.beta1 = beta1;\r\n            _this.beta2 = beta2;\r\n            _this.epsilon = epsilon;\r\n            _this.accumulatedFirstMoment = {};\r\n            _this.accumulatedSecondMoment = {};\r\n            _this.c = keep(scalar(-learningRate));\r\n            _this.beta1Scalar = keep(scalar(beta1));\r\n            _this.beta2Scalar = keep(scalar(beta2));\r\n            tidy(function () {\r\n                _this.accBeta1 = scalar(beta1).variable();\r\n                _this.accBeta2 = scalar(beta2).variable();\r\n            });\r\n            _this.oneMinusBeta1 = keep(scalar(1 - beta1));\r\n            _this.oneMinusBeta2 = keep(scalar(1 - beta2));\r\n            _this.one = keep(scalar(1));\r\n            if (epsilon === null) {\r\n                epsilon = ENV.get('EPSILON');\r\n            }\r\n            _this.epsScalar = keep(scalar(epsilon));\r\n            return _this;\r\n        }\r\n        AdamOptimizer.prototype.applyGradients = function (variableGradients) {\r\n            var _this = this;\r\n            tidy(function () {\r\n                var oneMinusAccBeta1 = _this.one.sub(_this.accBeta1);\r\n                var oneMinusAccBeta2 = _this.one.sub(_this.accBeta2);\r\n                for (var variableName in variableGradients) {\r\n                    var value = ENV.engine.registeredVariables[variableName];\r\n                    if (_this.accumulatedFirstMoment[variableName] == null) {\r\n                        var trainable = false;\r\n                        _this.accumulatedFirstMoment[variableName] =\r\n                            zerosLike(value).variable(trainable);\r\n                    }\r\n                    if (_this.accumulatedSecondMoment[variableName] == null) {\r\n                        var trainable = false;\r\n                        _this.accumulatedSecondMoment[variableName] =\r\n                            zerosLike(value).variable(trainable);\r\n                    }\r\n                    var gradient = variableGradients[variableName];\r\n                    var firstMoment = _this.accumulatedFirstMoment[variableName];\r\n                    var secondMoment = _this.accumulatedSecondMoment[variableName];\r\n                    var newFirstMoment = _this.beta1Scalar.mul(firstMoment)\r\n                        .add(_this.oneMinusBeta1.mul(gradient));\r\n                    var newSecondMoment = _this.beta2Scalar.mul(secondMoment)\r\n                        .add(_this.oneMinusBeta2.mul(gradient.square()));\r\n                    var biasCorrectedFirstMoment = newFirstMoment.div(oneMinusAccBeta1);\r\n                    var biasCorrectedSecondMoment = newSecondMoment.div(oneMinusAccBeta2);\r\n                    _this.accumulatedFirstMoment[variableName].assign(newFirstMoment);\r\n                    _this.accumulatedSecondMoment[variableName].assign(newSecondMoment);\r\n                    var newValue = _this.c\r\n                        .mul(biasCorrectedFirstMoment.div(_this.epsScalar.add(biasCorrectedSecondMoment.sqrt())))\r\n                        .add(value);\r\n                    value.assign(newValue);\r\n                }\r\n                _this.accBeta1.assign(_this.accBeta1.mul(_this.beta1Scalar));\r\n                _this.accBeta2.assign(_this.accBeta2.mul(_this.beta2Scalar));\r\n            });\r\n        };\r\n        AdamOptimizer.prototype.dispose = function () {\r\n            var _this = this;\r\n            this.c.dispose();\r\n            this.epsScalar.dispose();\r\n            this.beta1Scalar.dispose();\r\n            this.beta2Scalar.dispose();\r\n            this.accBeta1.dispose();\r\n            this.accBeta2.dispose();\r\n            this.oneMinusBeta1.dispose();\r\n            this.oneMinusBeta2.dispose();\r\n            this.one.dispose();\r\n            if (this.accumulatedFirstMoment != null) {\r\n                Object.keys(this.accumulatedFirstMoment)\r\n                    .forEach(function (name) { return _this.accumulatedFirstMoment[name].dispose(); });\r\n            }\r\n            if (this.accumulatedSecondMoment != null) {\r\n                Object.keys(this.accumulatedSecondMoment)\r\n                    .forEach(function (name) { return _this.accumulatedSecondMoment[name].dispose(); });\r\n            }\r\n        };\r\n        AdamOptimizer.prototype.getConfig = function () {\r\n            return {\r\n                learningRate: this.learningRate,\r\n                beta1: this.beta1,\r\n                beta2: this.beta2,\r\n                epsilon: this.epsilon,\r\n            };\r\n        };\r\n        AdamOptimizer.fromConfig = function (cls, config) {\r\n            return new cls(config.learningRate, config.beta1, config.beta2, config.epsilon);\r\n        };\r\n        AdamOptimizer.className = 'AdamOptimizer';\r\n        return AdamOptimizer;\r\n    }(Optimizer));\r\n    registerClass(AdamOptimizer);\n\n    var AdamaxOptimizer = (function (_super) {\r\n        __extends(AdamaxOptimizer, _super);\r\n        function AdamaxOptimizer(learningRate, beta1, beta2, epsilon, decay) {\r\n            if (epsilon === void 0) { epsilon = null; }\r\n            if (decay === void 0) { decay = 0.0; }\r\n            var _this = _super.call(this) || this;\r\n            _this.learningRate = learningRate;\r\n            _this.beta1 = beta1;\r\n            _this.beta2 = beta2;\r\n            _this.epsilon = epsilon;\r\n            _this.decay = decay;\r\n            _this.accumulatedFirstMoment = {};\r\n            _this.accumulatedWeightedInfNorm = {};\r\n            _this.c = keep(scalar(-learningRate));\r\n            _this.beta1Scalar = keep(scalar(beta1));\r\n            _this.beta2Scalar = keep(scalar(beta2));\r\n            _this.decayScalar = keep(scalar(decay));\r\n            tidy(function () {\r\n                _this.iteration = scalar(0).variable();\r\n                _this.accBeta1 = scalar(beta1).variable();\r\n            });\r\n            _this.oneMinusBeta1 = keep(scalar(1 - beta1));\r\n            _this.one = keep(scalar(1));\r\n            if (epsilon === null) {\r\n                epsilon = ENV.get('EPSILON');\r\n            }\r\n            _this.epsScalar = keep(scalar(epsilon));\r\n            return _this;\r\n        }\r\n        AdamaxOptimizer.prototype.applyGradients = function (variableGradients) {\r\n            var _this = this;\r\n            tidy(function () {\r\n                var oneMinusAccBeta1 = _this.one.sub(_this.accBeta1);\r\n                var lr = _this.c.div(_this.one.add(_this.decayScalar.mul(_this.iteration)));\r\n                for (var variableName in variableGradients) {\r\n                    var value = ENV.engine.registeredVariables[variableName];\r\n                    if (_this.accumulatedFirstMoment[variableName] == null) {\r\n                        var trainable = false;\r\n                        _this.accumulatedFirstMoment[variableName] =\r\n                            zerosLike(value).variable(trainable);\r\n                    }\r\n                    if (_this.accumulatedWeightedInfNorm[variableName] == null) {\r\n                        var trainable = false;\r\n                        _this.accumulatedWeightedInfNorm[variableName] =\r\n                            zerosLike(value).variable(trainable);\r\n                    }\r\n                    var gradient = variableGradients[variableName];\r\n                    var firstMoment = _this.accumulatedFirstMoment[variableName];\r\n                    var weightedInfNorm = _this.accumulatedWeightedInfNorm[variableName];\r\n                    var newFirstMoment = _this.beta1Scalar.mul(firstMoment)\r\n                        .add(_this.oneMinusBeta1.mul(gradient));\r\n                    var ut0 = _this.beta2Scalar.mul(weightedInfNorm);\r\n                    var ut1 = gradient.abs();\r\n                    var newWeightedInfNorm = ut0.maximum(ut1);\r\n                    _this.accumulatedFirstMoment[variableName].assign(newFirstMoment);\r\n                    _this.accumulatedWeightedInfNorm[variableName].assign(newWeightedInfNorm);\r\n                    var newValue = lr.div(oneMinusAccBeta1)\r\n                        .mul(newFirstMoment.div(_this.epsScalar.add(newWeightedInfNorm)))\r\n                        .add(value);\r\n                    value.assign(newValue);\r\n                }\r\n                _this.iteration.assign(_this.iteration.add(_this.one));\r\n                _this.accBeta1.assign(_this.accBeta1.mul(_this.beta1Scalar));\r\n            });\r\n        };\r\n        AdamaxOptimizer.prototype.dispose = function () {\r\n            var _this = this;\r\n            this.c.dispose();\r\n            this.epsScalar.dispose();\r\n            this.accBeta1.dispose();\r\n            this.beta1Scalar.dispose();\r\n            this.beta2Scalar.dispose();\r\n            this.oneMinusBeta1.dispose();\r\n            this.decayScalar.dispose();\r\n            this.iteration.dispose();\r\n            this.one.dispose();\r\n            if (this.accumulatedFirstMoment != null) {\r\n                Object.keys(this.accumulatedFirstMoment)\r\n                    .forEach(function (name) { return _this.accumulatedFirstMoment[name].dispose(); });\r\n            }\r\n            if (this.accumulatedWeightedInfNorm != null) {\r\n                Object.keys(this.accumulatedWeightedInfNorm)\r\n                    .forEach(function (name) { return _this.accumulatedWeightedInfNorm[name].dispose(); });\r\n            }\r\n        };\r\n        AdamaxOptimizer.prototype.getConfig = function () {\r\n            return {\r\n                learningRate: this.learningRate,\r\n                beta1: this.beta1,\r\n                beta2: this.beta2,\r\n                epsilon: this.epsilon,\r\n                decay: this.decay\r\n            };\r\n        };\r\n        AdamaxOptimizer.fromConfig = function (cls, config) {\r\n            return new cls(config.learningRate, config.beta1, config.beta2, config.epsilon, config.decay);\r\n        };\r\n        AdamaxOptimizer.className = 'AdamaxOptimizer';\r\n        return AdamaxOptimizer;\r\n    }(Optimizer));\r\n    registerClass(AdamaxOptimizer);\n\n    var SGDOptimizer = (function (_super) {\r\n        __extends(SGDOptimizer, _super);\r\n        function SGDOptimizer(learningRate) {\r\n            var _this = _super.call(this) || this;\r\n            _this.learningRate = learningRate;\r\n            _this.setLearningRate(learningRate);\r\n            return _this;\r\n        }\r\n        SGDOptimizer.prototype.applyGradients = function (variableGradients) {\r\n            var _this = this;\r\n            var varNames = Object.keys(variableGradients);\r\n            varNames.forEach(function (varName) {\r\n                var gradient = variableGradients[varName];\r\n                var value = ENV.engine.registeredVariables[varName];\r\n                tidy(function () {\r\n                    var newValue = _this.c.mul(gradient).add(value);\r\n                    value.assign(newValue);\r\n                });\r\n            });\r\n        };\r\n        SGDOptimizer.prototype.setLearningRate = function (learningRate) {\r\n            this.learningRate = learningRate;\r\n            if (this.c != null) {\r\n                this.c.dispose();\r\n            }\r\n            this.c = keep(scalar(-learningRate));\r\n        };\r\n        SGDOptimizer.prototype.dispose = function () {\r\n            this.c.dispose();\r\n        };\r\n        SGDOptimizer.prototype.getConfig = function () {\r\n            return { learningRate: this.learningRate };\r\n        };\r\n        SGDOptimizer.fromConfig = function (cls, config) {\r\n            return new cls(config.learningRate);\r\n        };\r\n        SGDOptimizer.className = 'SGDOptimizer';\r\n        return SGDOptimizer;\r\n    }(Optimizer));\r\n    registerClass(SGDOptimizer);\n\n    var MomentumOptimizer = (function (_super) {\r\n        __extends(MomentumOptimizer, _super);\r\n        function MomentumOptimizer(learningRate, momentum, useNesterov) {\r\n            if (useNesterov === void 0) { useNesterov = false; }\r\n            var _this = _super.call(this, learningRate) || this;\r\n            _this.learningRate = learningRate;\r\n            _this.momentum = momentum;\r\n            _this.useNesterov = useNesterov;\r\n            _this.m = scalar(_this.momentum);\r\n            _this.accumulations = {};\r\n            return _this;\r\n        }\r\n        MomentumOptimizer.prototype.applyGradients = function (variableGradients) {\r\n            var _this = this;\r\n            var _loop_1 = function (variableName) {\r\n                var value = ENV.engine.registeredVariables[variableName];\r\n                if (this_1.accumulations[variableName] == null) {\r\n                    var trainable_1 = false;\r\n                    tidy(function () {\r\n                        _this.accumulations[variableName] =\r\n                            zerosLike(value).variable(trainable_1);\r\n                    });\r\n                }\r\n                var accumulation = this_1.accumulations[variableName];\r\n                var gradient = variableGradients[variableName];\r\n                tidy(function () {\r\n                    var newValue;\r\n                    var newAccumulation = _this.m.mul(accumulation).add(gradient);\r\n                    if (_this.useNesterov) {\r\n                        newValue =\r\n                            _this.c.mul(gradient.add(newAccumulation.mul(_this.m))).add(value);\r\n                    }\r\n                    else {\r\n                        newValue = _this.c.mul(newAccumulation).add(value);\r\n                    }\r\n                    _this.accumulations[variableName].assign(newAccumulation);\r\n                    value.assign(newValue);\r\n                });\r\n            };\r\n            var this_1 = this;\r\n            for (var variableName in variableGradients) {\r\n                _loop_1(variableName);\r\n            }\r\n        };\r\n        MomentumOptimizer.prototype.dispose = function () {\r\n            _super.prototype.dispose.call(this);\r\n            this.m.dispose();\r\n            if (this.accumulations != null) {\r\n                for (var variableName in this.accumulations) {\r\n                    this.accumulations[variableName].dispose();\r\n                }\r\n            }\r\n        };\r\n        MomentumOptimizer.prototype.setMomentum = function (momentum) {\r\n            this.momentum = momentum;\r\n        };\r\n        MomentumOptimizer.prototype.getConfig = function () {\r\n            return {\r\n                learningRate: this.learningRate,\r\n                momentum: this.momentum,\r\n                useNesterov: this.useNesterov\r\n            };\r\n        };\r\n        MomentumOptimizer.fromConfig = function (cls, config) {\r\n            return new cls(config.learningRate, config.momentum, config.useNesterov);\r\n        };\r\n        MomentumOptimizer.className = 'MomentumOptimizer';\r\n        return MomentumOptimizer;\r\n    }(SGDOptimizer));\r\n    registerClass(MomentumOptimizer);\n\n    var RMSPropOptimizer = (function (_super) {\r\n        __extends(RMSPropOptimizer, _super);\r\n        function RMSPropOptimizer(learningRate, decay, momentum, epsilon, centered) {\r\n            if (decay === void 0) { decay = 0.9; }\r\n            if (momentum === void 0) { momentum = 0.0; }\r\n            if (epsilon === void 0) { epsilon = null; }\r\n            if (centered === void 0) { centered = false; }\r\n            var _this = _super.call(this) || this;\r\n            _this.learningRate = learningRate;\r\n            _this.decay = decay;\r\n            _this.momentum = momentum;\r\n            _this.epsilon = epsilon;\r\n            _this.accumulatedMeanSquares = {};\r\n            _this.accumulatedMeanGrads = {};\r\n            _this.accumulatedMoments = {};\r\n            _this.c = keep(scalar(learningRate));\r\n            _this.decayScalar = keep(scalar(decay));\r\n            _this.momentumScalar = keep(scalar(momentum));\r\n            _this.oneMinusDecay = keep(scalar(1 - decay));\r\n            _this.centered = centered;\r\n            if (epsilon === null) {\r\n                epsilon = ENV.get('EPSILON');\r\n            }\r\n            _this.epsilonScalar = keep(scalar(epsilon));\r\n            return _this;\r\n        }\r\n        RMSPropOptimizer.prototype.applyGradients = function (variableGradients) {\r\n            var _this = this;\r\n            var _loop_1 = function (variableName) {\r\n                var value = ENV.engine.registeredVariables[variableName];\r\n                if (this_1.accumulatedMeanSquares[variableName] == null) {\r\n                    var trainable_1 = false;\r\n                    tidy(function () {\r\n                        _this.accumulatedMeanSquares[variableName] =\r\n                            zerosLike(value).variable(trainable_1);\r\n                    });\r\n                }\r\n                if (this_1.accumulatedMeanGrads[variableName] == null && this_1.centered) {\r\n                    var trainable_2 = false;\r\n                    tidy(function () {\r\n                        _this.accumulatedMeanGrads[variableName] =\r\n                            zerosLike(value).variable(trainable_2);\r\n                    });\r\n                }\r\n                if (this_1.accumulatedMoments[variableName] == null) {\r\n                    var trainable_3 = false;\r\n                    tidy(function () {\r\n                        _this.accumulatedMoments[variableName] =\r\n                            zerosLike(value).variable(trainable_3);\r\n                    });\r\n                }\r\n                var accumulatedMeanSquare = this_1.accumulatedMeanSquares[variableName];\r\n                var accumulatedMeanGrad = this_1.accumulatedMeanGrads[variableName];\r\n                var accumulatedMoments = this_1.accumulatedMoments[variableName];\r\n                var gradient = variableGradients[variableName];\r\n                tidy(function () {\r\n                    var newAccumulatedMeanSquare = _this.decayScalar.mul(accumulatedMeanSquare)\r\n                        .add(_this.oneMinusDecay.mul(gradient.square()));\r\n                    if (_this.centered) {\r\n                        var newAccumulatedMeanGrad = _this.decayScalar.mul(accumulatedMeanGrad)\r\n                            .add(_this.oneMinusDecay.mul(gradient));\r\n                        var newAccumulatedMoments = _this.momentumScalar.mul(accumulatedMoments)\r\n                            .add(_this.c.mul(gradient).div(newAccumulatedMeanSquare\r\n                            .sub(newAccumulatedMeanGrad.square().add(_this.epsilonScalar))\r\n                            .sqrt()));\r\n                        _this.accumulatedMeanSquares[variableName].assign(newAccumulatedMeanSquare);\r\n                        _this.accumulatedMeanGrads[variableName].assign(newAccumulatedMeanGrad);\r\n                        _this.accumulatedMoments[variableName].assign(newAccumulatedMoments);\r\n                        var newValue = value.sub(newAccumulatedMoments);\r\n                        value.assign(newValue);\r\n                    }\r\n                    else {\r\n                        var newAccumulatedMeanSquare_1 = _this.decayScalar.mul(accumulatedMeanSquare)\r\n                            .add(_this.oneMinusDecay.mul(gradient.square()));\r\n                        var newAccumulatedMoments = _this.momentumScalar.mul(accumulatedMoments)\r\n                            .add(_this.c.mul(gradient).div(newAccumulatedMeanSquare_1.add(_this.epsilonScalar).sqrt()));\r\n                        _this.accumulatedMeanSquares[variableName].assign(newAccumulatedMeanSquare_1);\r\n                        _this.accumulatedMoments[variableName].assign(newAccumulatedMoments);\r\n                        var newValue = value.sub(newAccumulatedMoments);\r\n                        value.assign(newValue);\r\n                    }\r\n                });\r\n            };\r\n            var this_1 = this;\r\n            for (var variableName in variableGradients) {\r\n                _loop_1(variableName);\r\n            }\r\n        };\r\n        RMSPropOptimizer.prototype.dispose = function () {\r\n            var _this = this;\r\n            this.c.dispose();\r\n            this.epsilonScalar.dispose();\r\n            this.decayScalar.dispose();\r\n            this.momentumScalar.dispose();\r\n            this.oneMinusDecay.dispose();\r\n            if (this.accumulatedMeanSquares != null) {\r\n                Object.keys(this.accumulatedMeanSquares)\r\n                    .forEach(function (name) { return _this.accumulatedMeanSquares[name].dispose(); });\r\n            }\r\n            if (this.accumulatedMeanGrads != null && this.centered) {\r\n                Object.keys(this.accumulatedMeanGrads)\r\n                    .forEach(function (name) { return _this.accumulatedMeanGrads[name].dispose(); });\r\n            }\r\n            if (this.accumulatedMoments != null) {\r\n                Object.keys(this.accumulatedMoments)\r\n                    .forEach(function (name) { return _this.accumulatedMoments[name].dispose(); });\r\n            }\r\n        };\r\n        RMSPropOptimizer.prototype.getConfig = function () {\r\n            return {\r\n                learningRate: this.learningRate,\r\n                decay: this.decay,\r\n                momentum: this.momentum,\r\n                epsilon: this.epsilon,\r\n                centered: this.centered\r\n            };\r\n        };\r\n        RMSPropOptimizer.fromConfig = function (cls, config) {\r\n            return new cls(config.learningRate, config.decay, config.momentum, config.epsilon, config.centered);\r\n        };\r\n        RMSPropOptimizer.className = 'RMSPropOptimizer';\r\n        return RMSPropOptimizer;\r\n    }(Optimizer));\r\n    registerClass(RMSPropOptimizer);\n\n    var OptimizerConstructors = (function () {\r\n        function OptimizerConstructors() {\r\n        }\r\n        OptimizerConstructors.sgd = function (learningRate) {\r\n            return new SGDOptimizer(learningRate);\r\n        };\r\n        OptimizerConstructors.momentum = function (learningRate, momentum, useNesterov) {\r\n            if (useNesterov === void 0) { useNesterov = false; }\r\n            return new MomentumOptimizer(learningRate, momentum, useNesterov);\r\n        };\r\n        OptimizerConstructors.rmsprop = function (learningRate, decay, momentum, epsilon, centered) {\r\n            if (decay === void 0) { decay = .9; }\r\n            if (momentum === void 0) { momentum = 0.0; }\r\n            if (epsilon === void 0) { epsilon = null; }\r\n            if (centered === void 0) { centered = false; }\r\n            return new RMSPropOptimizer(learningRate, decay, momentum, epsilon, centered);\r\n        };\r\n        OptimizerConstructors.adam = function (learningRate, beta1, beta2, epsilon) {\r\n            if (learningRate === void 0) { learningRate = 0.001; }\r\n            if (beta1 === void 0) { beta1 = 0.9; }\r\n            if (beta2 === void 0) { beta2 = 0.999; }\r\n            if (epsilon === void 0) { epsilon = null; }\r\n            return new AdamOptimizer(learningRate, beta1, beta2, epsilon);\r\n        };\r\n        OptimizerConstructors.adadelta = function (learningRate, rho, epsilon) {\r\n            if (learningRate === void 0) { learningRate = .001; }\r\n            if (rho === void 0) { rho = .95; }\r\n            if (epsilon === void 0) { epsilon = null; }\r\n            return new AdadeltaOptimizer(learningRate, rho, epsilon);\r\n        };\r\n        OptimizerConstructors.adamax = function (learningRate, beta1, beta2, epsilon, decay) {\r\n            if (learningRate === void 0) { learningRate = 0.002; }\r\n            if (beta1 === void 0) { beta1 = 0.9; }\r\n            if (beta2 === void 0) { beta2 = 0.999; }\r\n            if (epsilon === void 0) { epsilon = null; }\r\n            if (decay === void 0) { decay = 0.0; }\r\n            return new AdamaxOptimizer(learningRate, beta1, beta2, epsilon, decay);\r\n        };\r\n        OptimizerConstructors.adagrad = function (learningRate, initialAccumulatorValue) {\r\n            if (initialAccumulatorValue === void 0) { initialAccumulatorValue = 0.1; }\r\n            return new AdagradOptimizer(learningRate, initialAccumulatorValue);\r\n        };\r\n        return OptimizerConstructors;\r\n    }());\n\n    var train = {\r\n        sgd: OptimizerConstructors.sgd,\r\n        momentum: OptimizerConstructors.momentum,\r\n        adadelta: OptimizerConstructors.adadelta,\r\n        adagrad: OptimizerConstructors.adagrad,\r\n        rmsprop: OptimizerConstructors.rmsprop,\r\n        adamax: OptimizerConstructors.adamax,\r\n        adam: OptimizerConstructors.adam\r\n    };\n\n    var setBackend = Environment.setBackend;\r\n    var getBackend = Environment.getBackend;\r\n    var disposeVariables = Environment.disposeVariables;\r\n    var memory = Environment.memory;\r\n    setOpHandler(ops);\n\n    exports.setBackend = setBackend;\n    exports.getBackend = getBackend;\n    exports.disposeVariables = disposeVariables;\n    exports.memory = memory;\n    exports.version_core = version;\n    exports.nextFrame = nextFrame;\n    exports.environment = environment;\n    exports.io = io;\n    exports.math = math;\n    exports.serialization = serialization;\n    exports.test_util = test_util;\n    exports.util = util;\n    exports.webgl = webgl;\n    exports.enableProdMode = enableProdMode;\n    exports.AdadeltaOptimizer = AdadeltaOptimizer;\n    exports.AdagradOptimizer = AdagradOptimizer;\n    exports.AdamOptimizer = AdamOptimizer;\n    exports.AdamaxOptimizer = AdamaxOptimizer;\n    exports.MomentumOptimizer = MomentumOptimizer;\n    exports.Optimizer = Optimizer;\n    exports.RMSPropOptimizer = RMSPropOptimizer;\n    exports.SGDOptimizer = SGDOptimizer;\n    exports.Tensor = Tensor;\n    exports.TensorBuffer = TensorBuffer;\n    exports.variable = variable;\n    exports.Variable = Variable;\n    exports.ENV = ENV;\n    exports.Environment = Environment;\n    exports.KernelBackend = KernelBackend;\n    exports.DataStorage = DataStorage;\n    exports.image = image_ops;\n    exports.linalg = linalg_ops;\n    exports.losses = loss_ops;\n    exports.spectral = spectral_ops;\n    exports.fused = fused_ops;\n    exports.op = op;\n    exports.batchNormalization2d = batchNormalization2d;\n    exports.batchNormalization3d = batchNormalization3d;\n    exports.batchNormalization4d = batchNormalization4d;\n    exports.batchNormalization = batchNormalization;\n    exports.complex = complex;\n    exports.real = real;\n    exports.imag = imag;\n    exports.concat = concat;\n    exports.concat1d = concat1d;\n    exports.concat2d = concat2d;\n    exports.concat3d = concat3d;\n    exports.concat4d = concat4d;\n    exports.split = split$1;\n    exports.conv1d = conv1d;\n    exports.conv2d = conv2d;\n    exports.conv3d = conv3d;\n    exports.conv2dDerFilter = conv2dDerFilter;\n    exports.depthwiseConv2d = depthwiseConv2d;\n    exports.separableConv2d = separableConv2d;\n    exports.conv2dTranspose = conv2dTranspose;\n    exports.matMul = matMul;\n    exports.dot = dot;\n    exports.outerProduct = outerProduct;\n    exports.reverse = reverse;\n    exports.reverse1d = reverse1d;\n    exports.reverse2d = reverse2d;\n    exports.reverse3d = reverse3d;\n    exports.reverse4d = reverse4d;\n    exports.maxPool = maxPool;\n    exports.avgPool = avgPool;\n    exports.pool = pool;\n    exports.slice = slice;\n    exports.slice1d = slice1d;\n    exports.slice2d = slice2d;\n    exports.slice3d = slice3d;\n    exports.slice4d = slice4d;\n    exports.abs = abs;\n    exports.acos = acos;\n    exports.acosh = acosh;\n    exports.asin = asin;\n    exports.asinh = asinh;\n    exports.atan = atan;\n    exports.atanh = atanh;\n    exports.ceil = ceil;\n    exports.clipByValue = clipByValue;\n    exports.cos = cos;\n    exports.cosh = cosh;\n    exports.erf = erf;\n    exports.exp = exp;\n    exports.expm1 = expm1;\n    exports.floor = floor;\n    exports.log = log$1;\n    exports.log1p = log1p;\n    exports.logSigmoid = logSigmoid;\n    exports.neg = neg;\n    exports.reciprocal = reciprocal;\n    exports.round = round;\n    exports.rsqrt = rsqrt;\n    exports.sigmoid = sigmoid;\n    exports.sign = sign;\n    exports.sin = sin;\n    exports.sinh = sinh;\n    exports.softplus = softplus;\n    exports.sqrt = sqrt;\n    exports.square = square;\n    exports.step = step;\n    exports.tan = tan;\n    exports.tanh = tanh$1;\n    exports.all = all;\n    exports.any = any;\n    exports.argMax = argMax;\n    exports.argMin = argMin;\n    exports.logSumExp = logSumExp;\n    exports.max = max;\n    exports.mean = mean;\n    exports.min = min;\n    exports.moments = moments;\n    exports.sum = sum$1;\n    exports.prod = prod;\n    exports.equal = equal;\n    exports.equalStrict = equalStrict;\n    exports.greater = greater;\n    exports.greaterEqual = greaterEqual;\n    exports.greaterEqualStrict = greaterEqualStrict;\n    exports.greaterStrict = greaterStrict;\n    exports.less = less;\n    exports.lessEqual = lessEqual;\n    exports.lessEqualStrict = lessEqualStrict;\n    exports.lessStrict = lessStrict;\n    exports.notEqual = notEqual;\n    exports.notEqualStrict = notEqualStrict;\n    exports.add = add;\n    exports.addN = addN;\n    exports.addStrict = addStrict;\n    exports.atan2 = atan2;\n    exports.div = div;\n    exports.divStrict = divStrict;\n    exports.floorDiv = floorDiv;\n    exports.maximum = maximum;\n    exports.maximumStrict = maximumStrict;\n    exports.minimum = minimum;\n    exports.minimumStrict = minimumStrict;\n    exports.mod = mod;\n    exports.modStrict = modStrict;\n    exports.mul = mul;\n    exports.mulStrict = mulStrict;\n    exports.pow = pow;\n    exports.powStrict = powStrict;\n    exports.squaredDifference = squaredDifference;\n    exports.squaredDifferenceStrict = squaredDifferenceStrict;\n    exports.sub = sub;\n    exports.subStrict = subStrict;\n    exports.elu = elu;\n    exports.leakyRelu = leakyRelu;\n    exports.prelu = prelu;\n    exports.relu = relu;\n    exports.selu = selu;\n    exports.logicalAnd = logicalAnd;\n    exports.logicalNot = logicalNot;\n    exports.logicalOr = logicalOr;\n    exports.logicalXor = logicalXor;\n    exports.where = where;\n    exports.whereAsync = whereAsync;\n    exports.buffer = buffer;\n    exports.toPixels = toPixels;\n    exports.print = print;\n    exports.batchToSpaceND = batchToSpaceND;\n    exports.cast = cast;\n    exports.clone = clone;\n    exports.cumsum = cumsum;\n    exports.depthToSpace = depthToSpace;\n    exports.expandDims = expandDims;\n    exports.eye = eye;\n    exports.fromPixels = fromPixels;\n    exports.multinomial = multinomial;\n    exports.oneHot = oneHot;\n    exports.pad = pad;\n    exports.pad1d = pad1d;\n    exports.pad2d = pad2d;\n    exports.pad3d = pad3d;\n    exports.pad4d = pad4d;\n    exports.rand = rand;\n    exports.randomNormal = randomNormal;\n    exports.randomUniform = randomUniform;\n    exports.reshape = reshape;\n    exports.spaceToBatchND = spaceToBatchND;\n    exports.squeeze = squeeze;\n    exports.stack = stack;\n    exports.tile = tile;\n    exports.truncatedNormal = truncatedNormal;\n    exports.unstack = unstack;\n    exports.setdiff1dAsync = setdiff1dAsync;\n    exports.fill = fill;\n    exports.linspace = linspace;\n    exports.ones = ones$1;\n    exports.range = range;\n    exports.scalar = scalar;\n    exports.tensor = tensor;\n    exports.tensor1d = tensor1d;\n    exports.tensor2d = tensor2d;\n    exports.tensor3d = tensor3d;\n    exports.tensor4d = tensor4d;\n    exports.tensor5d = tensor5d;\n    exports.tensor6d = tensor6d;\n    exports.zeros = zeros;\n    exports.onesLike = onesLike;\n    exports.zerosLike = zerosLike;\n    exports.transpose = transpose;\n    exports.softmax = softmax;\n    exports.logSoftmax = logSoftmax;\n    exports.localResponseNormalization = localResponseNormalization;\n    exports.norm = norm;\n    exports.gather = gather;\n    exports.unsortedSegmentSum = unsortedSegmentSum;\n    exports.basicLSTMCell = basicLSTMCell;\n    exports.multiRNNCell = multiRNNCell;\n    exports.movingAverage = movingAverage;\n    exports.stridedSlice = stridedSlice;\n    exports.topk = topk;\n    exports.scatterND = scatterND;\n    exports.fft = fft;\n    exports.ifft = ifft;\n    exports.rfft = rfft;\n    exports.irfft = irfft;\n    exports.sparseToDense = sparseToDense;\n    exports.gatherND = gatherND;\n    exports.train = train;\n    exports.tidy = tidy;\n    exports.keep = keep;\n    exports.dispose = dispose;\n    exports.time = time;\n    exports.profile = profile;\n    exports.customGrad = customGrad;\n    exports.grad = grad;\n    exports.grads = grads;\n    exports.valueAndGrad = valueAndGrad;\n    exports.valueAndGrads = valueAndGrads;\n    exports.variableGrads = variableGrads;\n\n    Object.defineProperty(exports, '__esModule', { value: true });\n\n})));\n//# sourceMappingURL=tf-core.js.map\n"
  },
  {
    "path": "tools/generate_concentric_circles_indices.js",
    "content": "/*jshint esversion: 6 */\n\n\nfunction generateAllArrays() {\n  var xs = [];\n  var ys = [];\n  var towards_center = [];\n  var kernel = 60;\n  var index = 0;\n  var count_per_radius = [];\n  var radius_offset = [];\n  var all_indices = [];\n\n  function addElementIfOnDistance(i, j, distance) {\n    var d = Math.floor(Math.sqrt(i*i + j*j));\n    if (d == distance) {\n       xs.push(i);\n       ys.push(j);\n       all_indices[(kernel + j) * (2 * kernel + 1) + kernel + i] = index++;\n       var x_of_element_towards_center = i - Math.sign(i);\n       var y_of_element_towards_center = j - Math.sign(j);\n       // Get the index of element with towards center x and y.\n       var found = false;\n       for (var z = xs.length - 1; z >= 0; z--) {\n         if (xs[z] == x_of_element_towards_center && ys[z] == y_of_element_towards_center) {\n           towards_center.push(z);\n           found = true;\n           break;\n         }\n       }\n       if (!found)\n           console.error(\"DCHECK failed:\" + x_of_element_towards_center + \"x\" + y_of_element_towards_center);\n       return 1;\n    }\n    return 0;\n  }\n\n\nvar t0 = performance.now();\n  var offset = 0;\n  for (var k = 0; k < kernel; k++) {\n    var counter = 0;\n    // Generate elements in such way that all the points on the circle with\n    // radius k are pushed to the array in clockwise order. \n    // 12:00 -> 3:00\n    for (var j = -k; j <= 0; j++) {\n      for (var i = 0; i <= k; i++) {\n        counter += addElementIfOnDistance(i, j, k);\n      }\n    }\n    // 3:00 -> 6:00\n    for (var j = 1; j <= k; j++) {\n      for (var i = k; i >= 1; i--) {\n        counter += addElementIfOnDistance(i, j, k);\n      }\n    }\n    // 6:00 -> 9:00\n    for (var j = k; j >= 1; j--) {\n      for (var i = 0; i >= -k; i--) {\n        counter += addElementIfOnDistance(i, j, k);\n      }\n    }\n    // 9:00 -> 12:00\n    for (var j = 0; j >= -k; j--) {\n      for (var i = -k; i <= -1; i++) {\n        counter += addElementIfOnDistance(i, j, k);\n      }\n    }\n    radius_offset.push(offset);\n    offset += counter;\n    count_per_radius.push(counter);\n  }\n\nvar t1 = performance.now();\nconsole.log(\"Call to generateAllArrays took \" + (t1 - t0) + \" milliseconds.\");\n\n  console.log(\"var xs = [\" + xs.join() + \"];\");\n  console.log(\"var ys = [\" + ys.join() + \"];\");\n  console.log(\"var towards_center = [\" + towards_center.join() + \"];\");\n  console.log(\"var count_per_radius = [\" + count_per_radius.join() + \"];\");\n  console.log(\"var radius_offset = [\" + radius_offset.join() + \"];\");\n\n  // Test.\n  if (xs.length != towards_center.length)\n    console.error(\"DCHECK failed on length\");\n  for (var i = 0; i < towards_center.length; ++i) {\n    var ti = towards_center[i];\n    xdiff = xs[i] - xs[ti];\n    ydiff = ys[i] - ys[ti];\n    \n    if (xs[i] > 0) {\n      if (xdiff > 1 || xdiff < 0)\n        console.error(\"DCHECK failed on positive xdiff\");\n    }\n    if (xs[i] < 0) {\n      if (xdiff < -1 || xdiff > 0)\n        console.error(\"DCHECK failed on negative xdiff\");\n    }\n    if (ys[i] > 0) {\n      if (ydiff > 1 || ydiff < 0)\n        console.error(\"DCHECK failed on positive xdiff\");\n    }\n    if (ys[i] < 0) {\n      if (ydiff < -1 || ydiff > 0)\n        console.error(\"DCHECK failed on negative xdiff\");\n    }\n  }\n\n  for (var i = 0; i < radius_offset.length; i++) {\n    for (var l = radius_offset[i]; l < radius_offset[i] + count_per_radius[i]; l++) {\n      var d = Math.floor(Math.sqrt(xs[l]*xs[l] + ys[l]*ys[l]));\n      if (d != i)\n        console.error(\"DCHECK failed on distance\"); \n    }\n  }\n  \n  for (var i = 0; i < radius_offset.length; i++) {\n    for (var l = radius_offset[i]; l < radius_offset[i] + count_per_radius[i] - 1; l++) {\n      if (Math.abs(xs[l] - xs[l + 1]) > 1)\n        console.error(\"DCHECK failed on neigbouring xs:\" + xs[l] + \"-\" + xs[l + 1] + \", ys:\" + ys[l] + \"-\" + ys[l + 1] + \" on radius:\" + i); \n      if (Math.abs(ys[l] - ys[l + 1]) > 1)\n        console.error(\"DCHECK failed on neigbouring ys\"); \n    }\n  }\n}"
  },
  {
    "path": "typing_in_the_air/doc/tutorial.html",
    "content": "<html><head><meta content=\"text/html; charset=UTF-8\" http-equiv=\"content-type\"><style type=\"text/css\">@import url('https://themes.googleusercontent.com/fonts/css?kit=dB3GuSCq0f_LRNaO3opFPA');.lst-kix_mkjo0yq6ldhg-6>li:before{content:\"\\0025cf  \"}.lst-kix_mkjo0yq6ldhg-4>li:before{content:\"\\0025cb  \"}.lst-kix_mkjo0yq6ldhg-8>li:before{content:\"\\0025a0  \"}.lst-kix_mkjo0yq6ldhg-5>li:before{content:\"\\0025a0  \"}.lst-kix_mkjo0yq6ldhg-2>li:before{content:\"\\0025a0  \"}.lst-kix_mkjo0yq6ldhg-3>li:before{content:\"\\0025cf  \"}ul.lst-kix_mkjo0yq6ldhg-4{list-style-type:none}ul.lst-kix_mkjo0yq6ldhg-3{list-style-type:none}ul.lst-kix_mkjo0yq6ldhg-2{list-style-type:none}ul.lst-kix_mkjo0yq6ldhg-1{list-style-type:none}.lst-kix_mkjo0yq6ldhg-0>li:before{content:\"\\0025a0  \"}ul.lst-kix_mkjo0yq6ldhg-8{list-style-type:none}ul.lst-kix_mkjo0yq6ldhg-7{list-style-type:none}.lst-kix_mkjo0yq6ldhg-1>li:before{content:\"\\0025cb  \"}ul.lst-kix_mkjo0yq6ldhg-6{list-style-type:none}ul.lst-kix_mkjo0yq6ldhg-5{list-style-type:none}ul.lst-kix_mkjo0yq6ldhg-0{list-style-type:none}.lst-kix_mkjo0yq6ldhg-7>li:before{content:\"\\0025cb  \"}ol{margin:0;padding:0}table td,table th{padding:0}.c10{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:26pt;font-family:\"Open Sans\";font-style:normal}.c1{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:14pt;font-family:\"Open Sans\";font-style:normal}.c6{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:14pt;font-family:\"Arial\";font-style:normal}.c5{padding-top:0pt;padding-bottom:0pt;line-height:1.15;orphans:2;widows:2;text-align:center;height:11pt}.c17{padding-top:0pt;padding-bottom:0pt;line-height:1.15;orphans:2;widows:2;text-align:center}.c15{padding-top:10pt;padding-bottom:0pt;line-height:1.15;orphans:2;widows:2;text-align:left}.c4{padding-top:0pt;padding-bottom:0pt;line-height:1.15;orphans:2;widows:2;text-align:left}.c20{padding-top:0pt;padding-bottom:3pt;line-height:1.0;page-break-after:avoid;text-align:left}.c0{padding-top:0pt;padding-bottom:0pt;line-height:1.0;text-align:left;height:11pt}.c31{padding-top:20pt;padding-bottom:6pt;line-height:1.15;page-break-after:avoid;text-align:left}.c27{padding-top:20pt;padding-bottom:6pt;line-height:1.0;page-break-after:avoid;text-align:left}.c8{padding-top:0pt;padding-bottom:0pt;line-height:1.0;text-align:center;height:11pt}.c11{color:#000000;text-decoration:none;vertical-align:baseline;font-style:normal}.c2{padding-top:0pt;padding-bottom:0pt;line-height:1.0;text-align:left}.c7{padding-top:0pt;padding-bottom:0pt;line-height:1.15;text-align:left}.c26{padding-top:0pt;padding-bottom:0pt;line-height:1.0;text-align:center}.c24{color:#666666;text-decoration:none;vertical-align:baseline;font-style:normal}.c21{padding-top:10pt;padding-bottom:0pt;line-height:1.0;text-align:left}.c3{font-size:14pt;font-family:\"Courier New\";font-weight:400}.c13{font-weight:400;font-size:11pt;font-family:\"Arial\"}.c12{font-size:10pt;font-family:\"Courier New\";font-weight:400}.c29{font-weight:400;font-size:20pt;font-family:\"Arial\"}.c9{font-size:14pt;font-family:\"Open Sans\";font-weight:400}.c22{font-weight:400;font-size:11pt;font-family:\"Open Sans\"}.c30{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.c14{padding:0;margin:0}.c16{color:inherit;text-decoration:inherit}.c23{margin-left:45pt;padding-left:-9pt}.c19{color:#1155cc;text-decoration:underline}.c25{vertical-align:baseline;font-style:normal}.c28{background-color:#fff2cc}.c18{height:11pt}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:\"Arial\";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:\"Arial\";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:\"Arial\"}p{margin:0;color:#000000;font-size:11pt;font-family:\"Arial\"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:\"Arial\";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:\"Arial\";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:\"Arial\";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:\"Arial\";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:\"Arial\";line-height:1.15;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:\"Arial\";line-height:1.15;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class=\"c30\"><div><p class=\"c4 c18\"><span class=\"c11 c13\"></span></p></div><p class=\"c20 title\" id=\"h.4v9lfldn86u\"><span class=\"c10\">Tutorial: Typing in the air using Chrome, depth camera and WebGL transform feedback</span></p><p class=\"c4 c18\"><span class=\"c11 c13\"></span></p><p class=\"c2\"><span class=\"c9 c19\"><a class=\"c16\" href=\"mailto:aleksandar.stojiljkovic@intel.com\">aleksandar.stojiljkovic@intel.com</a></span></p><p class=\"c0\"><span class=\"c1\"></span></p><p class=\"c2\"><span class=\"c1 c28\">Note: this tutorial is work in progress and the final version is expected to be published on 01.org in following days.</span></p><p class=\"c0\"><span class=\"c1\"></span></p><h1 class=\"c27\" id=\"h.csfaz1ff6j0f\"><span class=\"c11 c29\">Introduction</span></h1><p class=\"c0\"><span class=\"c1\"></span></p><p class=\"c2\"><span class=\"c1\">When I showed this first to my friend Babu, he said something on the line of &ldquo;that&rsquo;s not convenient&rdquo;. Well, though I can type on it faster than scrolling through the character grid, it is correct - it is not convenient, but it is a good illustration for a tutorial.</span></p><p class=\"c0\"><span class=\"c1\"></span></p><p class=\"c2\"><span class=\"c9\">Few words about the setup first. Plug the</span><span class=\"c9\">&nbsp;</span><span class=\"c9 c19 c25\"><a class=\"c16\" href=\"https://www.google.com/url?q=https://www.google.fi/url?sa%3Dt%26rct%3Dj%26q%3D%26esrc%3Ds%26source%3Dweb%26cd%3D1%26cad%3Drja%26uact%3D8%26ved%3D0ahUKEwim6rSGq6vUAhVsKpoKHWMjC9gQFggmMAA%26url%3Dhttps%253A%252F%252Fwww.intel.com%252Fcontent%252Fwww%252Fus%252Fen%252Farchitecture-and-technology%252Frealsense-overview.html%26usg%3DAFQjCNHYWDdHfpJ3LVnCZy2TlGRFv3SU-A%26sig2%3DjZlei6KsQJDean6847JFwA&amp;sa=D&amp;ust=1496829842600000&amp;usg=AFQjCNE-5uCzt4UNWPur64sE-C3NR3yo_Q\">Intel&reg; RealSense&trade;</a></span></p><p class=\"c2\"><span class=\"c9\">&nbsp;</span><span class=\"c1\">SR300 to USB 3.0 port of your Linux/Windows or Chrome OS machine. As a near-range camera, SR300 fits well for the use case here. The camera should point towards you, like in the photo. Once you get the hands closer to the camera, you&rsquo;ll notice they become visible over keyboard and then the closest fingertip movement is analyzed; if there is down-up movement and what is the key pressed.</span></p><p class=\"c26\"><span class=\"c9\">&nbsp;</span><span style=\"overflow: hidden; display: inline-block; margin: 0.00px 0.00px; border: 0.00px solid #000000; transform: rotate(0.00rad) translateZ(0px); -webkit-transform: rotate(0.00rad) translateZ(0px); width: 558.67px; height: 419.00px;\"><img alt=\"\" src=\"images/image4.jpg\" style=\"width: 558.67px; height: 419.00px; margin-left: 0.00px; margin-top: 0.00px; transform: rotate(0.00rad) translateZ(0px); -webkit-transform: rotate(0.00rad) translateZ(0px);\" title=\"\"></span></p><p class=\"c0\"><span class=\"c1\"></span></p><p class=\"c2\"><span class=\"c9\">The approach could be improved, but that would be </span><span class=\"c9 c19\"><a class=\"c16\" href=\"#h.5nc1qzab4rr0\">out of scope</a></span><span class=\"c1\">&nbsp;of this tutorial.</span></p><p class=\"c0\"><span class=\"c1\"></span></p><p class=\"c2\"><span class=\"c1\">Eventually, you&rsquo;ll manage to type with not that many mistakes. Use the Delete key to fix them; this is the reason why I made it a bit larger and easier to hit. The captured screenshot animation shows how it works.</span></p><p class=\"c0\"><span class=\"c1\"></span></p><p class=\"c2\"><span style=\"overflow: hidden; display: inline-block; margin: 0.00px 0.00px; border: 0.00px solid #000000; transform: rotate(0.00rad) translateZ(0px); -webkit-transform: rotate(0.00rad) translateZ(0px); width: 624.00px; height: 356.00px;\"><img alt=\"\" src=\"images/image5.gif\" style=\"width: 624.00px; height: 356.00px; margin-left: 0.00px; margin-top: 0.00px; transform: rotate(0.00rad) translateZ(0px); -webkit-transform: rotate(0.00rad) translateZ(0px);\" title=\"\"></span></p><p class=\"c0\"><span class=\"c1\"></span></p><h1 class=\"c27\" id=\"h.e582kwj3ault\"><span class=\"c11 c29\">The algorithm and the API used</span></h1><p class=\"c0\"><span class=\"c1\"></span></p><p class=\"c2\"><span class=\"c1\">The approach has two steps; pre-process every pixel on GPU and identify potential candidates and then process them on CPU. The algorithms are expected to be highly tailored for the use cases. The algorithm split could be explained like this:</span></p><p class=\"c0\"><span class=\"c1\"></span></p><p class=\"c2\"><span class=\"c9\">GPU:</span></p><ul class=\"c14 lst-kix_mkjo0yq6ldhg-0 start\"><li class=\"c2 c23\"><span class=\"c9\">Process every pixel or tile.</span></li><li class=\"c2 c23\"><span class=\"c9\">Map depth to color.</span></li><li class=\"c2 c23\"><span class=\"c1\">Sample around both depth and color texture, try to recognize features in shader.</span></li><li class=\"c2 c23\"><span class=\"c9\">Prepare the output result, either as transform feedback output or render to texture followed by readPixels.</span></li></ul><p class=\"c21\"><span class=\"c9\">CPU: </span></p><ul class=\"c14 lst-kix_mkjo0yq6ldhg-0\"><li class=\"c7 c23\"><span class=\"c1\">After selecting interest area, handle the results.</span></li><li class=\"c2 c23\"><span class=\"c1\">It is essential that GPU (shader code) reduces number of candidates or the area to post-process on CPU, but that it is still robust enough to avoid missing the feature.</span></li></ul><p class=\"c15\"><span class=\"c9\">WebGL API used for this is presented on the picture.</span></p><p class=\"c17\"><span style=\"overflow: hidden; display: inline-block; margin: 0.00px 0.00px; border: 0.00px solid #000000; transform: rotate(0.00rad) translateZ(0px); -webkit-transform: rotate(0.00rad) translateZ(0px); width: 560.00px; height: 400.71px;\"><img alt=\"\" src=\"images/image2.png\" style=\"width: 560.00px; height: 400.71px; margin-left: 0.00px; margin-top: 0.00px; transform: rotate(0.00rad) translateZ(0px); -webkit-transform: rotate(0.00rad) translateZ(0px);\" title=\"\"></span></p><p class=\"c5\"><span class=\"c11 c22\"></span></p><p class=\"c4\"><span class=\"c9\">The part using video and texImage2D is described in </span><span class=\"c9 c19\"><a class=\"c16\" href=\"https://www.google.com/url?q=https://01.org/chromium/blogs/astojilj/2017/depth-camera-capture-html5&amp;sa=D&amp;ust=1496829842614000&amp;usg=AFQjCNHNdbtD9VU_64tSfprA4Vu7mmywzA\">previous tutorial</a></span><span class=\"c1\">. In short, we follow this steps:</span></p><p class=\"c15\"><span class=\"c9\">1. Create HTML </span><span class=\"c3\">&lt;video&gt;</span><span class=\"c1\">&nbsp;tag.</span></p><p class=\"c7\"><span class=\"c9\">2. Call </span><span class=\"c3\">getUserMedia(constraint_to_depth_stream)</span><span class=\"c1\">&nbsp;to get the depth stream. If algorithm requires it, get the color stream, too.</span></p><p class=\"c7\"><span class=\"c9\">3. Set the stream as video source, e.g. </span><span class=\"c3\">video</span><span class=\"c3 c11\">.srcObject = stream;</span></p><p class=\"c7\"><span class=\"c1\">4. Upload the latest captured depth video frame to texture, e.g.</span></p><p class=\"c7\"><span class=\"c24 c3\">gl.texImage2D(gl.TEXTURE_2D, 0, gl.R32F, gl.RED, gl.FLOAT, video);</span></p><p class=\"c0\"><span class=\"c1\"></span></p><h1 class=\"c27\" id=\"h.bekywhr9akga\"><span class=\"c11 c29\">Step 1: GPU part of algorithm</span></h1><p class=\"c2\"><span class=\"c1\">This tutorial is describing transform feedback path. In the example we follow here, vertex shader code detects the points that are the centers of the area, as described by the picture:</span></p><p class=\"c0\"><span class=\"c1\"></span></p><p class=\"c26\"><span style=\"overflow: hidden; display: inline-block; margin: 0.00px 0.00px; border: 0.00px solid #000000; transform: rotate(0.00rad) translateZ(0px); -webkit-transform: rotate(0.00rad) translateZ(0px); width: 376.00px; height: 286.00px;\"><img alt=\"\" src=\"images/image3.png\" style=\"width: 376.00px; height: 286.00px; margin-left: 0.00px; margin-top: 0.00px; transform: rotate(0.00rad) translateZ(0px); -webkit-transform: rotate(0.00rad) translateZ(0px);\" title=\"\"></span></p><p class=\"c8\"><span class=\"c1\"></span></p><p class=\"c2\"><span class=\"c9\">So, we sample around and increase the distance of samples to the point. The idea is that on distance D (the green dots on the picture), all of the samples are inside the finger area, but on the distance D + 3, three or four out of four samples (the red dots) are outside the area.</span></p><p class=\"c21\"><span class=\"c1\">The part of vertex shader code doing this is:</span></p><p class=\"c0\"><span class=\"c11 c12\"></span></p><p class=\"c2\"><span class=\"c11 c12\">// Vertex shader code; transform feedback returns |depth|.</span></p><p class=\"c2\"><span class=\"c12\">// We have previously checked that the point is at least 3</span></p><p class=\"c2\"><span class=\"c12\">// pixels away from the edge, so start from i = 4.0. </span></p><p class=\"c2\"><span class=\"c12\">float i = 4.0;</span></p><p class=\"c2\"><span class=\"c12\">float number_of_dots_inside = 4.0;</span></p><p class=\"c0\"><span class=\"c11 c12\"></span></p><p class=\"c2\"><span class=\"c12\">for (; i &lt; MAX_DISTANCE; i += 3.0) {</span></p><p class=\"c2\"><span class=\"c12\">&nbsp; // Sample the texels like on the picture on the left.</span></p><p class=\"c2\"><span class=\"c12\">&nbsp; d_0 = texture(s_depth, depth_tex_pos + vec2(i, 0.0) * step).r;</span></p><p class=\"c2\"><span class=\"c12\">&nbsp; d_90 = texture(s_depth, depth_tex_pos + vec2(0.0, i) * step).r;</span></p><p class=\"c2\"><span class=\"c12\">&nbsp; d_180 = texture(s_depth, depth_tex_pos - vec2(i, 0.0) * step).r;</span></p><p class=\"c2\"><span class=\"c12\">&nbsp; d_270 = texture(s_depth, depth_tex_pos - vec2(0.0, i) * step).r;</span></p><p class=\"c2\"><span class=\"c12\">&nbsp; if (d_0 * d_90 * d_180 * d_270 == 0.0) {</span></p><p class=\"c2\"><span class=\"c12\">&nbsp; &nbsp; number_of_dots_inside = sign(d_0) + sign(d_90) +</span></p><p class=\"c2\"><span class=\"c12\">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sign(d_180) + sign(d_270);</span></p><p class=\"c2\"><span class=\"c12\">&nbsp; &nbsp; break;</span></p><p class=\"c2\"><span class=\"c12\">&nbsp; }</span></p><p class=\"c2\"><span class=\"c12\">}</span></p><p class=\"c0\"><span class=\"c11 c12\"></span></p><p class=\"c2\"><span class=\"c11 c12\">// &gt; 7.0 serves to eliminate &quot;thin&quot; areas. We pass depth &gt; 1.0 through</span></p><p class=\"c2\"><span class=\"c11 c12\">// transform feedback, so that CPU side of algorithm would understands</span></p><p class=\"c2\"><span class=\"c12\">// that this point is &quot;center of fingertip&quot; point and process it further.</span></p><p class=\"c2\"><span class=\"c12\">if (number_of_dots_inside &lt;= 1.0 &amp;&amp; i &gt; MIN_DISTANCE) {</span></p><p class=\"c2\"><span class=\"c12\">&nbsp; // Found it! Pack also the distance in the returned value.</span></p><p class=\"c2\"><span class=\"c12\">&nbsp; depth = i + depth;</span></p><p class=\"c2\"><span class=\"c12\">}</span></p><p class=\"c0\"><span class=\"c24 c9\"></span></p><h1 class=\"c27\" id=\"h.sswzd2xz5yu\"><span>Step 2: CPU part of algorithm</span></h1><p class=\"c4\"><span class=\"c9\">We start this by getting the transform feedback buffer data. The code includes the calls issuing the </span><span class=\"c9 c19\"><a class=\"c16\" href=\"#h.bekywhr9akga\">Step 1</a></span><span class=\"c9\">&nbsp;</span><span class=\"c1\">and getting the buffer data, using getBufferSubData, and looks like:</span></p><p class=\"c4 c18\"><span class=\"c1\"></span></p><p class=\"c4\"><span class=\"c11 c12\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, gl.transform_feedback)</span></p><p class=\"c4\"><span class=\"c11 c12\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, gl.tf_bo)</span></p><p class=\"c4\"><span class=\"c11 c12\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gl.beginTransformFeedback(gl.POINTS);</span></p><p class=\"c4\"><span class=\"c11 c12\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gl.drawArrays(gl.POINTS, 0, tf_output.length);</span></p><p class=\"c4\"><span class=\"c11 c12\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gl.endTransformFeedback();</span></p><p class=\"c4\"><span class=\"c11 c12\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, null)</span></p><p class=\"c4\"><span class=\"c11 c12\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gl.disable(gl.RASTERIZER_DISCARD);</span></p><p class=\"c4\"><span class=\"c11 c12\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, gl.tf_bo);</span></p><p class=\"c4\"><span class=\"c11 c12\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gl.getBufferSubData(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tf_output, 0, tf_output.length);</span></p><p class=\"c4\"><span class=\"c12\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, null);</span></p><p class=\"c4 c18\"><span class=\"c1\"></span></p><p class=\"c4\"><span class=\"c1\">After that, on CPU side, we:</span></p><p class=\"c4\"><span class=\"c1\">1. attempt to compensate for the noise and identify the fingertip closest to the camera,</span></p><p class=\"c4\"><span class=\"c1\">2. pass the position of the fingertip to the shader rendering it,</span></p><p class=\"c4\"><span class=\"c1\">3. find the keyboard key under the fingertip and display it as hovered, </span></p><p class=\"c4\"><span class=\"c1\">4. detect press-down-and-up gesture of the single fingertip and</span></p><p class=\"c4\"><span class=\"c1\">5. issue a key click if detecting press-down-and-up gesture.</span></p><p class=\"c4 c18\"><span class=\"c1\"></span></p><p class=\"c4\"><span class=\"c9\">Let&rsquo;s start with the data we get from GPU (</span><span class=\"c9 c19\"><a class=\"c16\" href=\"#h.bekywhr9akga\">Step 1</a></span><span class=\"c1\">). White dots are identified as centers of the area, fingertip candidates. The red dot is the one among them that is the closest to the camera.</span></p><p class=\"c17\"><span class=\"c9\">&nbsp;</span><span style=\"overflow: hidden; display: inline-block; margin: 0.00px 0.00px; border: 0.00px solid #000000; transform: rotate(0.00rad) translateZ(0px); -webkit-transform: rotate(0.00rad) translateZ(0px); width: 418.67px; height: 397.01px;\"><img alt=\"\" src=\"images/image1.gif\" style=\"width: 418.67px; height: 397.01px; margin-left: 0.00px; margin-top: 0.00px; transform: rotate(0.00rad) translateZ(0px); -webkit-transform: rotate(0.00rad) translateZ(0px);\" title=\"\"></span></p><p class=\"c5\"><span class=\"c1\"></span></p><p class=\"c4\"><span class=\"c1\">In the CPU side step, we take only that one, the red dot, and try to further stabilize it by calculating the center of mass (this would be the yellow dot on the pictures) of the shape around it. This step helps in reducing the noise, that is intrinsic to the infrared based depth sensing camera technology. Roughly speaking, the yellow dot is then the calculated center of mass of all connected points to the red point. When the finger is not moving, the yellow dot is more stable than the red, like on the picture.</span></p><p class=\"c17\"><span style=\"overflow: hidden; display: inline-block; margin: 0.00px 0.00px; border: 0.00px solid #000000; transform: rotate(0.00rad) translateZ(0px); -webkit-transform: rotate(0.00rad) translateZ(0px); width: 374.67px; height: 343.26px;\"><img alt=\"\" src=\"images/image6.gif\" style=\"width: 374.67px; height: 343.26px; margin-left: 0.00px; margin-top: 0.00px; transform: rotate(0.00rad) translateZ(0px); -webkit-transform: rotate(0.00rad) translateZ(0px);\" title=\"\"></span></p><p class=\"c5\"><span class=\"c1\"></span></p><p class=\"c4\"><span class=\"c1\">The algorithm implementing this is given in extractMinumums() function. Starting from the red dot, we enumerate the surrounding points on the same distance, as if spreading the waves of concentrical circles. For each point of the circle, we access the elements that is towards the center (the red point) to check if the point is connected to the red point. This way, we enumerate all the connected points to the red and calculate the average coordinate (i.e. the center of mass).</span></p><p class=\"c4 c18\"><span class=\"c1\"></span></p><h1 class=\"c31\" id=\"h.5nc1qzab4rr0\"><span class=\"c11 c29\">Summary</span></h1><p class=\"c4\"><span class=\"c1\">The approach could be improved by tracking all of the fingers; not only that it would enable simultaneous key presses, but the click detection would be more robust as we would not only analyze the single closest point to to camera. Instead, it might make more sense to spend some time on different gesture recognition, e.g. low latency hand gesture click made of quick contact of thumb and pointing finger and try to incorporate it in a game. The next tutorial should be about it.</span></p><p class=\"c4 c18\"><span class=\"c1\"></span></p></body></html>"
  },
  {
    "path": "typing_in_the_air/front_capture_typing.html",
    "content": "<html>\n<head>\n</head>\n<style>\n.canvasgroup {\n  position: relative;\n  width: 685px;\n}\n.canvasgroup canvas {\n  position: absolute;\n  top: 0;\n  left: 0;\n}\n#canvasGL {\n  pointer-events: none;\n  z-index: 10;\n  width: 666px;\n  height: 350px;\n}\n.floatleft {\n  float: left;    \n}\n* {\n  margin: 0;\n  padding: 0;\n}\nbody {\n  font: 75% Verdana;\n  background: #999;\n}\n#editor {\n  margin: 0 0 5px;\n  padding: 5px;\n  width: 666px;\n  height: 150px;\n  -webkit-border-radius: 5px;\n}\n.keyrow {\n  list-style: none;\n  float: left;\n}\n.keyrowshort {\n  width: 593px;\n}\n.keyrowreturn {\n  width: 70px;\n}\n#keyboard li {\n  float: left;\n  margin: 0 4px 4px 0;\n  width: 41px;\n  height: 41px;\n  line-height: 41px;\n  text-align: center;\n  border: 1px solid #f9f9f9;\n  -webkit-border-radius: 4px;\n}\n#keyboard .side {\n  width: 70px;\n}\n#keyboard #space {\n  width: 664px;\n}\n.capslock {\n  text-transform: uppercase;\n}\n.off {\n  display: none;\n}\n#keyboard li:hover, .hovered {\n  position: relative;\n  top: 1px;\n  left: 1px;\n  border-color: #e5e5e5;\n  background: #eee;\n  user-select: none;\n  cursor: default;\n}\n#keyboard #return {\n  width: 70px;\n  height: 88px;\n  line-height: 88px;     \n}\n</style>\n\n<body onload=\"onLoad()\">\n  <div id=\"errormessages\" style=\"font-color: red\">\n  </div>\n  <div class=\"floatleft\">\n    <div class=\"canvasgroup\" id=\"canvasGroup\">\n      <canvas id=\"canvasGL\" width=\"688\"></canvas>\n      <div>\n        <textarea id=\"editor\" rows=\"6\" cols=\"60\" autofocus onkeydown=\"return false;\"></textarea>\n        <div id=\"keyboard\">\n          <div>\n            <ul class=\"keyrow\">\n              <li class = \"side\" id=\"tab\">Tab</li>\n              <li class=\"key\"><span>q</span><span class=\"off\">1</span></li>\n              <li class=\"key\"><span>w</span><span class=\"off\">2</span></li>\n              <li class=\"key\"><span>e</span><span class=\"off\">3</span></li>\n              <li class=\"key\"><span>r</span><span class=\"off\">4</span></li>\n              <li class=\"key\"><span>t</span><span class=\"off\">5</span></li>\n              <li class=\"key\"><span>y</span><span class=\"off\">6</span></li>\n              <li class=\"key\"><span>u</span><span class=\"off\">7</span></li>\n              <li class=\"key\"><span>i</span><span class=\"off\">8</span></li>\n              <li class=\"key\"><span>o</span><span class=\"off\">9</span></li>\n              <li class=\"key\"><span>p</span><span class=\"off\">0</span></li>\n              <li class=\"key\"><span>:</span><span class=\"off\">~</span></li>\n              <li class = \"side\" data-onclick=\"deleteKey\">Delete</li>\n            </ul>\n          </div>\n          <div class=\"floatleft\">\n            <ul class=\"keyrow keyrowshort\">\n              <li class = \"side\" data-onclick=\"toggleCapsLock\">CapsLock</li>\n              <li class=\"key\"><span>a</span><span class=\"off\">[</span></li>\n              <li class=\"key\"><span>s</span><span class=\"off\">]</span></li>\n              <li class=\"key\"><span>d</span><span class=\"off\">{</span></li>\n              <li class=\"key\"><span>f</span><span class=\"off\">}</span></li>\n              <li class=\"key\"><span>g</span><span class=\"off\">\\</span></li>\n              <li class=\"key\"><span>h</span><span class=\"off\">|</span></li>\n              <li class=\"key\"><span>j</span><span class=\"off\">!</span></li>\n              <li class=\"key\"><span>k</span><span class=\"off\">#</span></li>\n              <li class=\"key\"><span>l</span><span class=\"off\">$</span></li>\n              <li class=\"key\"><span>;</span><span class=\"off\">£</span></li>\n              <li class=\"key\"><span>@</span><span class=\"off\">^</span></li>\n              <li class = \"side\" data-onclick=\"toggleSymbols\">Shift</li>\n              <li class=\"key\"><span>z</span><span class=\"off\">(</span></li>\n              <li class=\"key\"><span>x</span><span class=\"off\">)</span></li>\n              <li class=\"key\"><span>c</span><span class=\"off\">*</span></li>\n              <li class=\"key\"><span>v</span><span class=\"off\">+</span></li>\n              <li class=\"key\"><span>b</span><span class=\"off\">%</span></li>\n              <li class=\"key\"><span>n</span><span class=\"off\">/</span></li>\n              <li class=\"key\"><span>m</span><span class=\"off\">?</span></li>\n              <li class=\"key\"><span>&quot;</span><span class=\"off\">&amp;</span></li>\n              <li class=\"key\"><span>-</span><span class=\"off\">_</span></li>\n              <li class=\"key\"><span>,</span><span class=\"off\">&lt;</span></li>\n              <li class=\"key\"><span>.</span><span class=\"off\">&gt;</span></li>\n            </ul>\n          </div>\n          <ul class=\"keyrow keyrowreturn\"> \n            <li id=\"return\">Return</li>\n          </ul>\n          <ul class=\"keyrow\"> \n            <li id=\"space\">&nbsp;</li>\n          </ul>\n        </div>\n    </div>\n  </div>\n</body>\n<script type=\"text/javascript\" src=\"../depth-camera.js\"></script>\n<script type=\"text/javascript\" src=\"front_capture_typing.js\"></script>\n<script type=\"text/javascript\">\n\"use strict\";\n\nvar video_loaded = false;\n\nfunction showErrorToUser(message) {\n  var div = document.getElementById(\"errormessages\");\n  div.innerHTML += message + \"</br>\";\n}\n\nfunction handleError(error) {\n  console.error(error);\n  showErrorToUser(\"Error:\" + (error.name ? (error.name + \": \" + error.message)\n                                         : error));\n}\n\nvar video = createOffscreenVideo();\nvar init_done = false;\nvideo.addEventListener(\"play\", frameLoop);\nvar video_last_upload_time = -1;\n\nvideo.oncanplay = function(){\n  video_loaded=true;\n  init_done = false;\n}\n\nfunction frameLoop() {\n  if (video && video.paused && !touch_listener_added) {\n    touch_listener_added = true;\n    window.addEventListener(\"touchstart\", onVideoTouchStart, true);\n  }\n  \n  if (video_loaded) {\n    if (video_last_upload_time == video.currentTime) {\n      window.requestAnimationFrame(frameLoop);\n      return;\n    }\n    video_last_upload_time = video.currentTime;\n    if (!init_done) {\n      gl.videoLoaded(video);\n      init_done = true;\n    }\n\n    gl.activeTexture(gl.TEXTURE0);\n    gl.bindTexture(gl.TEXTURE_2D, gl.depth_texture);\n\n    // Upload the video frame to texture.\n    if (gl.color_buffer_float_ext) {\n      gl.texImage2D(gl.TEXTURE_2D, 0, gl.R32F, gl.RED, gl.FLOAT, video);\n    } else {\n      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA32F, gl.RGBA, gl.FLOAT, video);\n    }\n    gl.enable(gl.RASTERIZER_DISCARD);\n    gl.useProgram(gl.compute_program);\n    gl.bindVertexArray(gl.process_vao);\n    gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, gl.transform_feedback)\n    gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, gl.tf_bo)\n    gl.beginTransformFeedback(gl.POINTS);\n    gl.drawArrays(gl.POINTS, 0, tf_output.length);\n    gl.endTransformFeedback();\n    gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, null)\n    gl.disable(gl.RASTERIZER_DISCARD);\n    gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, gl.tf_bo);\n    gl.getBufferSubData(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tf_output, 0, tf_output.length);\n    gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, null);\n    gl.useProgram(gl.render_program);\n    extractMinumums();\n    gl.bindVertexArray(gl.render_vao);\n  }\n  gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertex_buffer);\n  gl.vertexAttribPointer(gl.vertex_location, 2, gl.FLOAT, false, 0, 0);\n\n  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.index_buffer);\n  gl.clear(gl.COLOR_BUFFER_BIT);\n  gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);\n\n  processCurrentPos();\n  window.requestAnimationFrame(frameLoop);\n}\n\nfunction createOffscreenVideo() {\n  var video = document.createElement(\"video\");\n  video.autoplay = true;\n  video.loop = true;\n  video.crossOrigin = \"anonymous\";\n  video.width = 640;\n  video.height = 480;\n  return video;\n}\n\nvar canvasGL = document.getElementById(\"canvasGL\");\nvar hover_node;\nvar queue = [];\nfunction processCurrentPos() {\n  var selected_node;\n  if (current_pos) {\n    const rect = canvasGL.getBoundingClientRect();\n    const scaled_pos_x = current_pos.x * rect.width / video.videoWidth;\n    const scaled_pos_y = current_pos.y * rect.height / video.videoHeight;\n    selected_node = keyFromPoint(scaled_pos_x + rect.left, scaled_pos_y + rect.top);\n\n    if (processClick(rect)) {\n      queue = [];\n      if (hover_node)\n        hover_node.classList.remove(\"hovered\");\n      hover_node = null;\n      return;\n    }\n    // Limit the queue size.\n    if (queue.length > 15)\n      queue.shift();\n    queue.push(current_pos);\n  } else {\n    // Start again if there is no value.\n    queue = [];\n  }\n  if (selected_node != hover_node) {\n    if (hover_node)\n      hover_node.classList.remove(\"hovered\");\n    hover_node = selected_node;\n    if (hover_node) {\n      if (!hover_node.classList)\n        hover_node.class = \"\";\n      hover_node.classList.add(\"hovered\");\n    }\n  }\n}\n\nfunction keyFromPoint(abs_x, abs_y) {\n  var node = document.elementFromPoint(abs_x, abs_y);\n  if (!node)\n    return undefined;\n  while (node.parentNode && node.nodeName != \"LI\")\n    node = node.parentNode;\n  return (node.parentNode &&\n          node.parentNode.classList.contains(\"keyrow\")) ? node : undefined;\n}\n\nvar finger_down_treshold = Number.MAX_VALUE;\nfunction processClick(rect) {\n  if (queue.length < 4)\n    return false;\n  var pos2 = queue[queue.length - 2];\n  var pos1 = queue[queue.length - 1];\n  // pos2 should be a minimum.\n  if (current_pos.depth < pos2.depth || pos1.depth < pos2.depth)\n    return false;\n  if (!areFromTheSameFinger(pos1, pos2) && !areFromTheSameFinger(current_pos, pos2))\n    return false;\n  var pos3 = queue[queue.length - 3];\n  if (pos2.depth + finger_down_treshold / 2 > current_pos.depth &&\n      pos2.depth + finger_down_treshold / 2 > pos1.depth)\n    return false;\n  if (!areFromTheSameFinger(pos2, pos3)) {\n    // Some other finger might be detected when moving up/down so check around.\n    if (!areFromTheSameFinger(pos2, queue[queue.length - 4]))\n      return false;\n  }\n  const scaled_pos2_x = pos2.x * rect.width / video.videoWidth;\n  const scaled_pos2_y = pos2.y * rect.height / video.videoHeight;\n  const node2 = keyFromPoint(scaled_pos2_x + rect.left, scaled_pos2_y + rect.top);\n  const scaled_pos3_x = pos3.x * rect.width / video.videoWidth;\n  const scaled_pos3_y = pos3.y * rect.height / video.videoHeight;\n  const node3 = keyFromPoint(scaled_pos3_x + rect.left, scaled_pos3_y + rect.top);\n\n  const node1 = keyFromPoint(pos1.x * rect.width / video.videoWidth + rect.left,\n                                     pos3.y * rect.height / video.videoHeight + rect.top);\n  if (!node2 && !node3)\n    return false;\n\n  var node = node2;\n  if (!node)\n    node = node3;\n  var finger_down = false;\n  // Look for the finger down movement.\n  for (var i = queue.length - 2; i > 2; --i) {\n    if ((queue[i].depth < queue[i - 1].depth - finger_down_treshold &&\n         areFromTheSameFinger(queue[i], queue[i - 1])) ||\n        (queue[i].depth < queue[i - 2].depth - finger_down_treshold &&\n         areFromTheSameFinger(queue[i], queue[i - 2]))) {\n      if (!areFromTheSameFinger(queue[i - 1], queue[i - 2]) &&\n         // Using thumb on space key is special case; long horizontal move but\n         // the key should be the same.\n         (node2 != node3 && node1 != node2))\n        return false;\n      finger_down = true;\n      break;\n    }\n  }\n\n  if (!finger_down && queue[1].depth < queue[0].depth - finger_down_treshold\n      && areFromTheSameFinger(queue[1], queue[0]))\n    finger_down = true;\n  \n  if (!finger_down)\n    return false;\n\n  buttonClicked(node);\n  return true;\n}\n\nfunction areFromTheSameFinger(pos1, pos2) {\n  var x2 = pos1.x - pos2.x;\n  var y2 = pos1.y - pos2.y;\n  x2 = x2 * x2;\n  y2 = y2 * y2;\n  return (x2 + y2 < pos1.filtered_width * pos1.filtered_width * 2);\n}\n\n// If needed, tap to start video.\nvar touch_listener_added = false;\nfunction onVideoTouchStart() {\n  touch_listener_added = false;\n  window.removeEventListener(\"touchstart\", onVideoTouchStart, true);\n  video.play();\n}\n\nfunction streamOpened(stream) {\n  video.srcObject = stream;\n  const depth_scale = DepthCamera.getCameraCalibration(stream).depthScale;\n  // Take 1 cm (0.01) as the minimal depth change when detecting the click.\n  finger_down_treshold = 0.0085 / depth_scale;\n\n  video_loaded = false;\n  init_done = false;\n}\n\nfunction reload() {\n  if (window.stream) {\n    window.stream.getTracks().forEach(function(track) {\n      track.stop();\n    });\n  }\n\n  DepthCamera.getDepthStream().then(streamOpened).catch(handleError);\n}\n\nfunction onLoad() {\n  gl = GL(\"canvasGL\");\n  \n  reload();\n}\n\nconst keyboard = document.getElementById(\"keyboard\");\nconst editor = document.getElementById(\"editor\");\nkeyboard.addEventListener(\"click\", function( event ) {\n    var node = document.elementFromPoint(event.clientX, event.clientY);\n    if (node)\n      buttonClicked(node);\n  }, false);\nkeyboard[\"symbols_on\"] = false;\nkeyboard[\"capslock\"] = false;\n\nfunction toggleSymbols() {\n  keyboard.symbols_on = !keyboard.symbols_on;\n  const span_on = keyboard.symbols_on ? 1 : 0;\n  const span_off = keyboard.symbols_on ? 0 : 1;\n  Array.from(keyboard.getElementsByClassName(\"key\")).forEach(\n    function(element) {\n      element.children[span_on].classList.remove(\"off\");\n      element.children[span_off].classList.add(\"off\");\n    });\n}\n\nfunction toggleCapsLock() {\n  keyboard.capslock = !keyboard.capslock;\n  Array.from(keyboard.getElementsByClassName(\"key\")).forEach(\n    function(element) {\n      if (keyboard.capslock)\n        element.classList.add(\"capslock\");\n      else\n        element.classList.remove(\"capslock\");\n    });\n}\n\nfunction deleteKey() {\n  editor.defaultValue = editor.defaultValue.slice(0, -1);\n}\n\nfunction buttonClicked(button) {\n  if (button.nodeName != \"LI\")\n    return;\n\n  const onclick = button.getAttribute(\"data-onclick\");\n  if (onclick) {\n    window[onclick]();\n    return;\n  }\n\n  let key = button.innerText;\n  \n  switch (button.id) {\n    case \"space\":\n      key = \" \";\n      break;\n    case \"tab\":\n      key = \"\\t\";\n      break;\n    case \"return\":\n      key = \"\\n\";\n      break;\n    default:\n      break;\n  }\n\n  // TODO: double click should make symbols stay after first character.\n  if (keyboard.symbols_on)\n    toggleSymbols();\n  editor.defaultValue = editor.defaultValue + key;\n\n  if (key == '.' && !keyboard.capslock)\n    toggleCapsLock();\n  if (keyboard.capslock && key.toLowerCase() != key.toUpperCase())\n    toggleCapsLock();\n}\n\n</script>\n\n</html>\n\n"
  },
  {
    "path": "typing_in_the_air/front_capture_typing.js",
    "content": "/*jshint esversion: 6 */\n\nvar depth_x = 640;\nvar depth_y = 480;\nvar plane = 0.042; // On SR300 around 35 cm\n\n// Creates WebGL/WebGL2 context used to upload depth video to texture.\n// Algorithm is split to two steps:\n// On GPU (in vertex shader)\n//   1. Detect “fingertip points.”\n//   2. How thick the finger is around the fingertip points.\n//\n// On CPU:\n//   1. Retrieve the data from GPU using transform feedback.\n//   2. Select the closest \"fingertip point\" to camera.\n//   3. Calculate the “center of fingertip”, as a center of mass of all\n//      connected points to the fingertip.\n//   4. Detect down+up movement on the keyboard.\n//\nfunction GL(canvasId) {\n  var canvas = document.getElementById(canvasId);\n  canvas.addEventListener(\"click\", onVideoTouchStart, false);\n  var gl = canvas.getContext(\"webgl2\", { antialias: true });\n  if (gl) {\n    // EXT_color_buffer_float to use single component R32F texture format.\n    gl.color_buffer_float_ext = gl.getExtension('EXT_color_buffer_float');\n    gl.WEBGL_get_buffer_sub_data_async =\n        gl.getExtension(\"WEBGL_get_buffer_sub_data_async\");\n    gl.texture_float_linear = gl.getExtension(\"OES_texture_float_linear\");\n  }\n  if (!gl || !gl.color_buffer_float_ext) {\n    alert(\"The demo doesn't run because it requires WebGL2 support.\");\n    return;\n  }\n\n  gl.enable(gl.BLEND);\n  gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);\n\n  // Transform feedback vertex shader is used for detecting \"finger tip\"\n  // candidate points. Passes the result as \"depth\": if it is > 1.0 then the\n  // point is potential \"center of area\" to analyse further on CPU side of\n  // algorithm.  \n  var tf_vertex_shader = gl.createShader(gl.VERTEX_SHADER);\n  gl.shaderSource(tf_vertex_shader, `#version 300 es\n    uniform sampler2D s_depth;\n    uniform vec2 u_depth_size;\n    uniform float u_plane;\n    out float depth;\n\n    void main() {\n      vec2 depth_pixel;\n      depth_pixel.x = mod(float(gl_VertexID) + 0.5, u_depth_size.x);\n      depth_pixel.y = clamp(floor(float(gl_VertexID) / u_depth_size.x) + 0.5,\n                            0.0, u_depth_size.y);\n      vec2 tex_pos = depth_pixel / u_depth_size;\n\n      // As camera face towards user, mirror the display.\n      tex_pos.x = 1.0 - tex_pos.x;\n\n      depth = texture(s_depth, tex_pos).r;\n      if (depth <= u_plane * 0.1 || depth >= u_plane)\n      \treturn;\n\n      vec2 step = vec2(1.0, 1.0) / u_depth_size;\n\n      float d_0   = texture(s_depth, tex_pos + vec2( 2.0, 0.0) * step).r;\n      float d_90  = texture(s_depth, tex_pos + vec2( 0.0, 2.0) * step).r;\n      float d_180 = texture(s_depth, tex_pos - vec2( 2.0, 0.0) * step).r;\n      float d_270 = texture(s_depth, tex_pos - vec2( 0.0, 2.0) * step).r;\n      float d_45_1  = texture(s_depth, tex_pos + vec2( 1.0, 1.0) * step).r;\n      float d_135_1 = texture(s_depth, tex_pos + vec2( -1.0, 1.0) * step).r;\n      float d_225_1 = texture(s_depth, tex_pos + vec2( -1.0, -1.0) * step).r;\n      float d_315_1 = texture(s_depth, tex_pos + vec2( 1.0, -1.0) * step).r;\n\n      // if one these is 0, it means that the point is around the border. Skip\n      // as we want to get points in the center of the area.\n      if (d_0 * d_90 * d_180 * d_270 * d_45_1 * d_135_1 * d_225_1 * d_315_1 == 0.0) {\n        depth = 0.0;\n        return;\n      }\n\n      // Sample around and increase the distance of samples to the point.\n      // The idea is that on distance D all the samples are inside the area\n      // but on the distance D + 3, 3 or 4 out of 4 are outside the area. This\n      // would make the point \"fingertip point\" (e.g part of the skeleton) for\n      // the area.\n      float i = 4.0;\n      float inside_count = 4.0;\n\n      for (; i < 30.0; i += 3.0) {\n        d_0   =  texture(s_depth, tex_pos + vec2( i, 0.0) * step).r;\n        d_90  =  texture(s_depth, tex_pos + vec2( 0.0, i) * step).r;\n        d_180 =  texture(s_depth, tex_pos - vec2( i, 0.0) * step).r;\n        d_270 =  texture(s_depth, tex_pos - vec2( 0.0, i) * step).r;\n        if (d_0 * d_90 * d_180 * d_270 == 0.0) {\n          inside_count = sign(d_0) + sign(d_90) + sign(d_180) + sign(d_270);\n          break;\n        }\n      }\n\n      // > 7.0 serves to eliminate \"thin\" areas. We pass depth > 1.0 through\n      // transform feedback, so that CPU side of algorithm would understands\n      // that this point is \"center of fingertip\" point and process it further.\n      if (inside_count <= 1.0 && i > 7.0) {\n        depth = i + depth;\n      }\n    }`\n  );\n  gl.compileShader(tf_vertex_shader);\n\n  var tf_dummy_pixel_shader = gl.createShader(gl.FRAGMENT_SHADER);\n  gl.shaderSource(tf_dummy_pixel_shader, `#version 300 es\n  \tprecision mediump float;\n    in float depth;\n    void main() {\n    }`\n  );\n  gl.compileShader(tf_dummy_pixel_shader);\n\n  var compute_program = gl.createProgram();\n  gl.attachShader(compute_program, tf_vertex_shader);\n  gl.attachShader(compute_program, tf_dummy_pixel_shader);\n  gl.transformFeedbackVaryings(compute_program, [\"depth\"], gl.INTERLEAVED_ATTRIBS);\n  gl.linkProgram(compute_program);\n  console.log(gl.getShaderInfoLog(tf_vertex_shader));\n  gl.useProgram(compute_program);\n  var process_vao = gl.createVertexArray();\n  gl.bindVertexArray(process_vao);\n\n  var tf_bo = gl.createBuffer();\n  gl.bindBuffer(gl.ARRAY_BUFFER, tf_bo);\n  var transform_feedback = gl.createTransformFeedback();\n  gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, transform_feedback)\n\n  gl.uniform1i(gl.getUniformLocation(compute_program, \"s_depth\"), 0);\n  gl.uniform2f(gl.getUniformLocation(compute_program, \"u_depth_size\"), depth_x, depth_y);\n  gl.uniform1f(gl.getUniformLocation(compute_program, \"u_plane\"), plane);\n\n  // Rendering vertex and fragment shaders are simple. Fragment shader only\n  // needs to display position of calculated \"closest fingertip to the camera\".\n  var render_vao = gl.createVertexArray();\n  gl.bindVertexArray(render_vao);\n  var vertex_shader = gl.createShader(gl.VERTEX_SHADER);\n  gl.shaderSource(vertex_shader, `#version 300 es\n    in vec2 v;\n    uniform vec2 u_depth_size;\n    out vec2 t;\n    void main() {\n      gl_Position = vec4(1.0 - v.x * 2.0, 1.0 - v.y * 2.0, 0, 1);\n      t = v;\n    }`\n  );\n  gl.compileShader(vertex_shader);\n\n  var pixel_shader = gl.createShader(gl.FRAGMENT_SHADER);\n  gl.shaderSource(pixel_shader, `#version 300 es\n  \tprecision mediump float;\n    uniform sampler2D s_depth;\n    uniform vec2 u_pointer;\n    uniform float u_plane;\n    in vec2 t;\n    out vec4 fragColor;\n    void main() {\n      vec4 tex = texture(s_depth, t);\n\n      float a = sign(tex.r) * ((tex.r < u_plane) ? 0.5 :\n          clamp((1.0 / (tex.r - u_plane) * 0.003), 0.0, 0.25));\n      // TODO: render  \"closest fingertip to the camera\" using texture.\n      float d = distance(t, u_pointer);\n      if (u_pointer.x > -1.0 && d < 0.01) {\n        a = 1.0 - 50.0 * d;\n      }\n      fragColor = vec4(tex.r, tex.r, tex.r, a);\n    }`\n  );\n  gl.compileShader(pixel_shader);\n\n  var program  = gl.createProgram();\n  gl.attachShader(program, vertex_shader);\n  gl.attachShader(program, pixel_shader);\n  gl.linkProgram(program);\n  gl.useProgram(program);\n\n  var vertex_location = gl.getAttribLocation(program, \"v\");\n  gl.enableVertexAttribArray(vertex_location);\n  gl.uniform1i(gl.getUniformLocation(program, \"s_depth\"), 0);\n  gl.uniform2f(gl.getUniformLocation(program, \"u_depth_size\"), depth_x, depth_y);\n  gl.uniform1f(gl.getUniformLocation(program, \"u_plane\"), plane);\n  gl.uniform2f(gl.getUniformLocation(program, \"u_pointer\"), -1.0, -1.0);\n  \n  var vertex_buffer = gl.createBuffer();\n  gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);\n  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0,0,1,0,1,1,0,1]), gl.STATIC_DRAW);\n\n  var index_buffer= gl.createBuffer();\n  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);\n  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([0,1,2,0,2,3]), gl.STATIC_DRAW);\n  gl.bindVertexArray(null);\n\n  // Upload the latest depth frame to this texture.\n  var depth_texture = gl.createTexture();\n  gl.bindTexture(gl.TEXTURE_2D, depth_texture);\n  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n  const filtering = gl.texture_float_linear ? gl.LINEAR : gl.NEAREST;\n  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filtering);\n  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filtering);\n\n  // Framebuffer for reading back the texture.\n  var framebuffer = gl.createFramebuffer();\n  gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);\n  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D,\n                          depth_texture, 0);\n  gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\n  gl.vertex_buffer = vertex_buffer;\n  gl.vertex_location = vertex_location;\n  gl.index_buffer = index_buffer;\n  gl.depth_texture = depth_texture;\n  gl.framebuffer = framebuffer;\n  gl.render_program = program;\n  gl.compute_program = compute_program;\n  gl.process_vao = process_vao;\n  gl.render_vao = render_vao;\n  gl.transform_feedback = transform_feedback;\n  gl.tf_bo = tf_bo;\n  gl.videoLoaded = videoLoaded;\n  return gl;\n}\n\n\nvar gl;\nvar u_plane;\nvar tf_output;\n\nfunction videoLoaded(video) {\n  gl.bindBuffer(gl.ARRAY_BUFFER, gl.tf_bo);\n  tf_output = new Float32Array(video.videoWidth * video.videoHeight);\n  gl.bufferData(gl.ARRAY_BUFFER, tf_output.length * 4, gl.DYNAMIC_READ);\n  gl.bindBuffer(gl.ARRAY_BUFFER, null);\n}\n\nvar minimum;\nvar minimum_previous;\nvar distance_to_previous_minimum;\nvar current_pos;\n\n// For each element we keep the index of element in direction towards central\n// point. When computing if the element is connected to central point, we just\n// check the connectivity of element with towards_center.\n\nfunction extractMinumums() {\n  minimum_previous = minimum ? minimum : {\"x\": -65535, \"y\": -65535, \"depth\": 1.0};\n  minimum = {\"x\": -65535, \"y\": -65535, \"depth\": 1.0};\n  distance_to_previous_minimum = Number.MAX_VALUE;\n  // If with the same value and no break, we replace all mins in kernel x kernel\n  // square, that have the same value, with one. This is useful for the use case\n  // here (typing) - in some other cases (e.g. sculpting) we might want all of\n  // the values.\n  for(var i = 0; i < tf_output.length; ++i) {\n    if (tf_output[i] > 1.0)\n      addMinimum(i);\n  }\n\n\n  // Average minimum to compensate for the noise: go through all connected\n  // points and calculate the \"center of mass\" for the shape. In this\n  // calculation we disregard the depth values of the points but calculate \n  // the shape center only.\n  if (minimum.x >= 0) {\n    connected.fill(false);\n\n    var cx = minimum.x;\n    var cy = minimum.y;\n    var count = 1;\n    var xsum = cx;\n    var ysum = cy;\n    var dsum = minimum.depth;\n\n    connected[0] = true;\n    // Filtered width is the width of the area we get from GPU. If the change is\n    // < 9 we keep the original so that the results look smooth.\n    // TODO: calculate multiple minimum averages for different radius and\n    // incorporate constant radius in key press analysis.\n    const filtered_width = (current_pos && Math.abs(current_pos.filtered_width -\n                                                    minimum.width) < 9)\n                           ? Math.max(current_pos.filtered_width, minimum.width)\n                           : minimum.width;\n    const radius = Math.min(radius_offset.length, filtered_width * 1.3);\n\n    for (var j = 1; j < radius; j++) {\n      const r_start = radius_offset[j];\n      const r_end = r_start + count_per_radius[j];\n      for (var i = r_start; i < r_end; i++) {\n        const element_towards_center = towards_center[i];\n        // We get the index of element towards center. If the point is not\n        // connected to the center, don't bother analyzing it.\n        if (!connected[element_towards_center])\n          continue;\n        var x = cx + xs[i];\n        var y = cy + ys[i];\n        if (x < 0 || y < 0 || x >= depth_x || y >= depth_y)\n          continue;\n        const l = tf_output[x + y * depth_x];\n        if (l > 0.0) {\n          connected[i] = true;\n          xsum += x;\n          ysum += y;\n          dsum += l % 1.0;\n          count++;\n        }\n      }\n    }\n\n    current_pos = { \"x\": Math.round(xsum / count),\n                         \"y\": Math.round(ysum / count),\n                         \"depth\" : minimum.depth,\n                         \"width\": minimum.width,\n                         \"filtered_width\": filtered_width };\n    // Render the position.\n    gl.uniform2f(gl.getUniformLocation(gl.render_program, \"u_pointer\"),\n                 1.0 - current_pos.x / depth_x, current_pos.y / depth_y);\n  } else {\n    current_pos = undefined;\n    gl.uniform2f(gl.getUniformLocation(gl.render_program, \"u_pointer\"), -1.0, -1.0);\n  }\n}\n\nfunction addMinimum(index) {\n  var width_depth = tf_output[index];\n  var depth = width_depth % 1.0;\n  if (depth < minimum.depth) {\n    var x = index % depth_x;\n    var y = Math.floor(index / depth_x);\n    minimum = {\"x\": x, \"y\": y, \"depth\": depth, \"width\": Math.floor(width_depth)};\n  }\n}\n\n// Generated using generate_concentric_circles_indices.js for kernel 60.\n// This is used to enumerate through points on the same distance from the center,\n// similar to spreading of vawes of concentrical circles and for each point of\n// the circle, use towards_center to calculate if the point is connected to the\n// center.\nvar xs = [0,0,1,1,1,0,-1,-1,-1,0,1,2,2,2,2,2,1,0,-1,-2,-2,-2,-2,-2,-1,0,1,2,3,3,3,3,3,2,1,0,-1,-2,-3,-3,-3,-3,-3,-2,-1,0,1,2,3,4,4,4,4,4,3,2,1,0,-1,-2,-3,-4,-4,-4,-4,-4,-3,-2,-1,0,1,2,3,3,4,4,5,5,5,5,5,5,5,4,4,3,3,2,1,0,-1,-2,-3,-3,-4,-4,-5,-5,-5,-5,-5,-5,-5,-4,-4,-3,-3,-2,-1,0,1,2,3,4,5,6,6,6,6,6,6,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-6,-6,-6,-6,-6,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,5,6,6,7,7,7,7,7,7,7,6,6,5,5,4,3,2,1,0,-1,-2,-3,-4,-5,-5,-6,-6,-7,-7,-7,-7,-7,-7,-7,-6,-6,-5,-5,-4,-3,-2,-1,0,1,2,3,4,4,5,6,7,7,8,8,8,8,8,8,8,8,8,7,7,6,5,4,4,3,2,1,0,-1,-2,-3,-4,-4,-5,-6,-7,-7,-8,-8,-8,-8,-8,-8,-8,-8,-8,-7,-7,-6,-5,-4,-4,-3,-2,-1,0,1,2,3,4,5,6,7,7,8,9,9,9,9,9,9,9,9,9,8,7,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-7,-8,-9,-9,-9,-9,-9,-9,-9,-9,-9,-8,-7,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,6,7,8,8,9,9,10,10,10,10,10,10,10,10,10,9,9,8,8,7,6,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-6,-7,-8,-8,-9,-9,-10,-10,-10,-10,-10,-10,-10,-10,-10,-9,-9,-8,-8,-7,-6,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,10,11,11,11,11,11,11,11,11,11,10,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-10,-11,-11,-11,-11,-11,-11,-11,-11,-11,-10,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,8,9,9,10,10,11,11,12,12,12,12,12,12,12,12,12,11,11,10,10,9,9,8,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-8,-9,-9,-10,-10,-11,-11,-12,-12,-12,-12,-12,-12,-12,-12,-12,-11,-11,-10,-10,-9,-9,-8,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,5,6,7,7,8,9,10,11,11,12,12,12,13,13,13,13,13,13,13,13,13,13,13,12,12,12,11,11,10,9,8,7,7,6,5,5,4,3,2,1,0,-1,-2,-3,-4,-5,-5,-6,-7,-7,-8,-9,-10,-11,-11,-12,-12,-12,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-12,-12,-12,-11,-11,-10,-9,-8,-7,-7,-6,-5,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,10,11,11,12,13,13,14,14,14,14,14,14,14,14,14,14,14,13,13,12,11,11,10,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-10,-11,-11,-12,-13,-13,-14,-14,-14,-14,-14,-14,-14,-14,-14,-14,-14,-13,-13,-12,-11,-11,-10,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,9,10,11,12,12,13,13,14,14,15,15,15,15,15,15,15,15,15,15,15,14,14,13,13,12,12,11,10,9,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-9,-10,-11,-12,-12,-13,-13,-14,-14,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-14,-14,-13,-13,-12,-12,-11,-10,-9,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,12,13,14,14,15,15,16,16,16,16,16,16,16,16,16,16,16,15,15,14,14,13,12,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-12,-13,-14,-14,-15,-15,-16,-16,-16,-16,-16,-16,-16,-16,-16,-16,-16,-15,-15,-14,-14,-13,-12,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,8,9,10,11,11,12,13,13,14,14,15,15,16,16,16,17,17,17,17,17,17,17,17,17,17,17,16,16,16,15,15,14,14,13,13,12,11,11,10,9,8,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-8,-9,-10,-11,-11,-12,-13,-13,-14,-14,-15,-15,-16,-16,-16,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-16,-16,-16,-15,-15,-14,-14,-13,-13,-12,-11,-11,-10,-9,-8,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,6,7,8,9,10,10,11,12,13,14,15,15,16,16,17,17,17,18,18,18,18,18,18,18,18,18,18,18,18,18,17,17,17,16,16,15,15,14,13,12,11,10,10,9,8,7,6,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-6,-7,-8,-9,-10,-10,-11,-12,-13,-14,-15,-15,-16,-16,-17,-17,-17,-18,-18,-18,-18,-18,-18,-18,-18,-18,-18,-18,-18,-18,-17,-17,-17,-16,-16,-15,-15,-14,-13,-12,-11,-10,-10,-9,-8,-7,-6,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,13,14,14,15,15,16,17,17,18,18,19,19,19,19,19,19,19,19,19,19,19,19,19,18,18,17,17,16,15,15,14,14,13,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-13,-14,-14,-15,-15,-16,-17,-17,-18,-18,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-18,-18,-17,-17,-16,-15,-15,-14,-14,-13,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,12,13,14,15,16,16,17,17,18,18,19,19,20,20,20,20,20,20,20,20,20,20,20,20,20,19,19,18,18,17,17,16,16,15,14,13,12,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-12,-13,-14,-15,-16,-16,-17,-17,-18,-18,-19,-19,-20,-20,-20,-20,-20,-20,-20,-20,-20,-20,-20,-20,-20,-19,-19,-18,-18,-17,-17,-16,-16,-15,-14,-13,-12,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,9,10,11,11,12,13,14,15,15,16,16,17,18,18,19,19,19,20,20,20,21,21,21,21,21,21,21,21,21,21,21,21,21,20,20,20,19,19,19,18,18,17,16,16,15,15,14,13,12,11,11,10,9,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-9,-10,-11,-11,-12,-13,-14,-15,-15,-16,-16,-17,-18,-18,-19,-19,-19,-20,-20,-20,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-20,-20,-20,-19,-19,-19,-18,-18,-17,-16,-16,-15,-15,-14,-13,-12,-11,-11,-10,-9,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,14,15,16,17,17,18,18,19,20,20,21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,21,21,21,20,20,19,18,18,17,17,16,15,14,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-14,-15,-16,-17,-17,-18,-18,-19,-20,-20,-21,-21,-21,-22,-22,-22,-22,-22,-22,-22,-22,-22,-22,-22,-22,-22,-21,-21,-21,-20,-20,-19,-18,-18,-17,-17,-16,-15,-14,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,13,14,15,16,17,18,19,19,20,20,21,21,22,22,22,23,23,23,23,23,23,23,23,23,23,23,23,23,22,22,22,21,21,20,20,19,19,18,17,16,15,14,13,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-13,-14,-15,-16,-17,-18,-19,-19,-20,-20,-21,-21,-22,-22,-22,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-22,-22,-22,-21,-21,-20,-20,-19,-19,-18,-17,-16,-15,-14,-13,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,17,17,18,18,19,19,20,21,21,22,22,23,23,23,24,24,24,24,24,24,24,24,24,24,24,24,24,23,23,23,22,22,21,21,20,19,19,18,18,17,17,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-16,-17,-17,-18,-18,-19,-19,-20,-21,-21,-22,-22,-23,-23,-23,-24,-24,-24,-24,-24,-24,-24,-24,-24,-24,-24,-24,-24,-23,-23,-23,-22,-22,-21,-21,-20,-19,-19,-18,-18,-17,-17,-16,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,7,8,9,10,11,12,12,13,14,15,15,16,17,18,19,20,20,21,21,22,22,23,23,23,24,24,24,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,24,24,24,23,23,23,22,22,21,21,20,20,19,18,17,16,15,15,14,13,12,12,11,10,9,8,7,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-7,-8,-9,-10,-11,-12,-12,-13,-14,-15,-15,-16,-17,-18,-19,-20,-20,-21,-21,-22,-22,-23,-23,-23,-24,-24,-24,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-24,-24,-24,-23,-23,-23,-22,-22,-21,-21,-20,-20,-19,-18,-17,-16,-15,-15,-14,-13,-12,-12,-11,-10,-9,-8,-7,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,10,11,12,13,14,14,15,16,17,18,18,19,19,20,20,21,22,22,23,23,24,24,24,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,25,25,25,24,24,24,23,23,22,22,21,20,20,19,19,18,18,17,16,15,14,14,13,12,11,10,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-10,-11,-12,-13,-14,-14,-15,-16,-17,-18,-18,-19,-19,-20,-20,-21,-22,-22,-23,-23,-24,-24,-24,-25,-25,-25,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-24,-24,-24,-23,-23,-22,-22,-21,-20,-20,-19,-19,-18,-18,-17,-16,-15,-14,-14,-13,-12,-11,-10,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,17,18,19,20,21,21,22,22,23,24,24,25,25,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,26,26,26,25,25,24,24,23,22,22,21,21,20,19,18,17,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-17,-18,-19,-20,-21,-21,-22,-22,-23,-24,-24,-25,-25,-26,-26,-26,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-26,-26,-26,-25,-25,-24,-24,-23,-22,-22,-21,-21,-20,-19,-18,-17,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,17,18,19,20,21,22,23,23,24,24,25,25,26,26,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,27,27,27,26,26,25,25,24,24,23,23,22,21,20,19,18,17,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-16,-17,-18,-19,-20,-21,-22,-23,-23,-24,-24,-25,-25,-26,-26,-27,-27,-27,-28,-28,-28,-28,-28,-28,-28,-28,-28,-28,-28,-28,-28,-28,-28,-27,-27,-27,-26,-26,-25,-25,-24,-24,-23,-23,-22,-21,-20,-19,-18,-17,-16,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,13,14,15,16,17,18,19,19,20,20,21,21,22,22,23,23,24,25,25,26,26,27,27,27,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,28,28,28,27,27,27,26,26,25,25,24,23,23,22,22,21,21,20,20,19,19,18,17,16,15,14,13,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-13,-14,-15,-16,-17,-18,-19,-19,-20,-20,-21,-21,-22,-22,-23,-23,-24,-25,-25,-26,-26,-27,-27,-27,-28,-28,-28,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-28,-28,-28,-27,-27,-27,-26,-26,-25,-25,-24,-23,-23,-22,-22,-21,-21,-20,-20,-19,-19,-18,-17,-16,-15,-14,-13,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15,16,17,18,18,19,20,21,22,23,24,24,25,25,26,26,27,27,28,28,28,29,29,29,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,29,29,29,28,28,28,27,27,26,26,25,25,24,24,23,22,21,20,19,18,18,17,16,15,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-15,-16,-17,-18,-18,-19,-20,-21,-22,-23,-24,-24,-25,-25,-26,-26,-27,-27,-28,-28,-28,-29,-29,-29,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-29,-29,-29,-28,-28,-28,-27,-27,-26,-26,-25,-25,-24,-24,-23,-22,-21,-20,-19,-18,-18,-17,-16,-15,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,11,12,13,14,15,16,17,17,18,19,20,21,21,22,22,23,23,24,24,25,26,26,27,27,28,28,29,29,29,30,30,30,30,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,30,30,30,30,29,29,29,28,28,27,27,26,26,25,24,24,23,23,22,22,21,21,20,19,18,17,17,16,15,14,13,12,11,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-11,-12,-13,-14,-15,-16,-17,-17,-18,-19,-20,-21,-21,-22,-22,-23,-23,-24,-24,-25,-26,-26,-27,-27,-28,-28,-29,-29,-29,-30,-30,-30,-30,-31,-31,-31,-31,-31,-31,-31,-31,-31,-31,-31,-31,-31,-31,-31,-30,-30,-30,-30,-29,-29,-29,-28,-28,-27,-27,-26,-26,-25,-24,-24,-23,-23,-22,-22,-21,-21,-20,-19,-18,-17,-17,-16,-15,-14,-13,-12,-11,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,8,9,10,11,12,13,14,15,16,17,18,19,20,20,21,22,23,24,25,25,26,26,27,28,28,29,29,30,30,31,31,31,31,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,31,31,31,31,30,30,29,29,28,28,27,26,26,25,25,24,23,22,21,20,20,19,18,17,16,15,14,13,12,11,10,9,8,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-20,-21,-22,-23,-24,-25,-25,-26,-26,-27,-28,-28,-29,-29,-30,-30,-31,-31,-31,-31,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-31,-31,-31,-31,-30,-30,-29,-29,-28,-28,-27,-26,-26,-25,-25,-24,-23,-22,-21,-20,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,19,20,21,22,23,23,24,24,25,25,26,27,27,28,28,29,29,30,30,31,31,32,32,32,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,32,32,32,31,31,30,30,29,29,28,28,27,27,26,25,25,24,24,23,23,22,21,20,19,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-19,-20,-21,-22,-23,-23,-24,-24,-25,-25,-26,-27,-27,-28,-28,-29,-29,-30,-30,-31,-31,-32,-32,-32,-33,-33,-33,-33,-33,-33,-33,-33,-33,-33,-33,-33,-33,-33,-33,-33,-33,-32,-32,-32,-31,-31,-30,-30,-29,-29,-28,-28,-27,-27,-26,-25,-25,-24,-24,-23,-23,-22,-21,-20,-19,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,14,15,16,16,17,18,18,19,20,21,22,22,23,24,25,26,26,27,27,28,29,29,30,30,30,31,31,31,32,32,32,33,33,33,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,33,33,33,32,32,32,31,31,31,30,30,30,29,29,28,27,27,26,26,25,24,23,22,22,21,20,19,18,18,17,16,16,15,14,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-14,-15,-16,-16,-17,-18,-18,-19,-20,-21,-22,-22,-23,-24,-25,-26,-26,-27,-27,-28,-29,-29,-30,-30,-30,-31,-31,-31,-32,-32,-32,-33,-33,-33,-34,-34,-34,-34,-34,-34,-34,-34,-34,-34,-34,-34,-34,-34,-34,-34,-34,-33,-33,-33,-32,-32,-32,-31,-31,-31,-30,-30,-30,-29,-29,-28,-27,-27,-26,-26,-25,-24,-23,-22,-22,-21,-20,-19,-18,-18,-17,-16,-16,-15,-14,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,21,22,23,24,25,26,27,28,28,29,29,30,31,31,32,32,33,33,33,34,34,34,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,34,34,34,33,33,33,32,32,31,31,30,29,29,28,28,27,26,25,24,23,22,21,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-21,-22,-23,-24,-25,-26,-27,-28,-28,-29,-29,-30,-31,-31,-32,-32,-33,-33,-33,-34,-34,-34,-35,-35,-35,-35,-35,-35,-35,-35,-35,-35,-35,-35,-35,-35,-35,-35,-35,-34,-34,-34,-33,-33,-33,-32,-32,-31,-31,-30,-29,-29,-28,-28,-27,-26,-25,-24,-23,-22,-21,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,20,21,22,23,24,24,25,25,26,26,27,27,28,28,29,30,30,31,31,32,32,33,33,34,34,34,35,35,35,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,35,35,35,34,34,34,33,33,32,32,31,31,30,30,29,28,28,27,27,26,26,25,25,24,24,23,22,21,20,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-20,-21,-22,-23,-24,-24,-25,-25,-26,-26,-27,-27,-28,-28,-29,-30,-30,-31,-31,-32,-32,-33,-33,-34,-34,-34,-35,-35,-35,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-36,-35,-35,-35,-34,-34,-34,-33,-33,-32,-32,-31,-31,-30,-30,-29,-28,-28,-27,-27,-26,-26,-25,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,12,13,14,15,16,17,18,19,20,21,22,23,23,24,25,26,27,28,29,29,30,30,31,32,32,33,33,34,34,35,35,35,36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,36,36,36,35,35,35,34,34,33,33,32,32,31,30,30,29,29,28,27,26,25,24,23,23,22,21,20,19,18,17,16,15,14,13,12,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-23,-24,-25,-26,-27,-28,-29,-29,-30,-30,-31,-32,-32,-33,-33,-34,-34,-35,-35,-35,-36,-36,-36,-36,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-37,-36,-36,-36,-36,-35,-35,-35,-34,-34,-33,-33,-32,-32,-31,-30,-30,-29,-29,-28,-27,-26,-25,-24,-23,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,17,18,19,19,20,21,22,22,23,24,25,26,26,27,27,28,28,29,29,30,31,31,32,32,33,33,34,34,34,35,35,35,36,36,37,37,37,37,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,37,37,37,37,36,36,35,35,35,34,34,34,33,33,32,32,31,31,30,29,29,28,28,27,27,26,26,25,24,23,22,22,21,20,19,19,18,17,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-17,-18,-19,-19,-20,-21,-22,-22,-23,-24,-25,-26,-26,-27,-27,-28,-28,-29,-29,-30,-31,-31,-32,-32,-33,-33,-34,-34,-34,-35,-35,-35,-36,-36,-37,-37,-37,-37,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-38,-37,-37,-37,-37,-36,-36,-35,-35,-35,-34,-34,-34,-33,-33,-32,-32,-31,-31,-30,-29,-29,-28,-28,-27,-27,-26,-26,-25,-24,-23,-22,-22,-21,-20,-19,-19,-18,-17,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15,16,17,18,19,20,21,21,22,23,24,25,25,26,27,28,29,30,30,31,31,32,33,33,34,34,35,35,36,36,36,37,37,37,38,38,38,38,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,38,38,38,38,37,37,37,36,36,36,35,35,34,34,33,33,32,31,31,30,30,29,28,27,26,25,25,24,23,22,21,21,20,19,18,17,16,15,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-15,-16,-17,-18,-19,-20,-21,-21,-22,-23,-24,-25,-25,-26,-27,-28,-29,-30,-30,-31,-31,-32,-33,-33,-34,-34,-35,-35,-36,-36,-36,-37,-37,-37,-38,-38,-38,-38,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-39,-38,-38,-38,-38,-37,-37,-37,-36,-36,-36,-35,-35,-34,-34,-33,-33,-32,-31,-31,-30,-30,-29,-28,-27,-26,-25,-25,-24,-23,-22,-21,-21,-20,-19,-18,-17,-16,-15,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,24,25,26,27,28,29,30,31,32,32,33,33,34,35,35,36,36,37,37,38,38,38,39,39,39,39,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,39,39,39,39,38,38,38,37,37,36,36,35,35,34,33,33,32,32,31,30,29,28,27,26,25,24,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-24,-25,-26,-27,-28,-29,-30,-31,-32,-32,-33,-33,-34,-35,-35,-36,-36,-37,-37,-38,-38,-38,-39,-39,-39,-39,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-40,-39,-39,-39,-39,-38,-38,-38,-37,-37,-36,-36,-35,-35,-34,-33,-33,-32,-32,-31,-30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,23,24,25,26,27,27,28,28,29,29,30,30,31,31,32,32,33,34,34,35,35,36,36,37,37,38,38,39,39,39,40,40,40,40,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,40,40,40,40,39,39,39,38,38,37,37,36,36,35,35,34,34,33,32,32,31,31,30,30,29,29,28,28,27,27,26,25,24,23,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-23,-24,-25,-26,-27,-27,-28,-28,-29,-29,-30,-30,-31,-31,-32,-32,-33,-34,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-39,-39,-40,-40,-40,-40,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-40,-40,-40,-40,-39,-39,-39,-38,-38,-37,-37,-36,-36,-35,-35,-34,-34,-33,-32,-32,-31,-31,-30,-30,-29,-29,-28,-28,-27,-27,-26,-25,-24,-23,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,18,19,20,20,21,22,23,24,25,26,26,27,28,29,30,31,32,33,33,34,34,35,36,36,37,37,38,38,38,39,39,39,40,40,40,41,41,41,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,41,41,41,40,40,40,39,39,39,38,38,38,37,37,36,36,35,34,34,33,33,32,31,30,29,28,27,26,26,25,24,23,22,21,20,20,19,18,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-18,-19,-20,-20,-21,-22,-23,-24,-25,-26,-26,-27,-28,-29,-30,-31,-32,-33,-33,-34,-34,-35,-36,-36,-37,-37,-38,-38,-38,-39,-39,-39,-40,-40,-40,-41,-41,-41,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-41,-41,-41,-40,-40,-40,-39,-39,-39,-38,-38,-38,-37,-37,-36,-36,-35,-34,-34,-33,-33,-32,-31,-30,-29,-28,-27,-26,-26,-25,-24,-23,-22,-21,-20,-20,-19,-18,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,13,14,15,16,17,18,19,20,21,22,22,23,24,25,25,26,27,28,29,29,30,30,31,31,32,32,33,33,34,35,35,36,36,37,37,38,38,39,39,40,40,40,41,41,41,42,42,42,42,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,42,42,42,42,41,41,41,40,40,40,39,39,38,38,37,37,36,36,35,35,34,33,33,32,32,31,31,30,30,29,29,28,27,26,25,25,24,23,22,22,21,20,19,18,17,16,15,14,13,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-22,-23,-24,-25,-25,-26,-27,-28,-29,-29,-30,-30,-31,-31,-32,-32,-33,-33,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-39,-40,-40,-40,-41,-41,-41,-42,-42,-42,-42,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-42,-42,-42,-42,-41,-41,-41,-40,-40,-40,-39,-39,-38,-38,-37,-37,-36,-36,-35,-35,-34,-33,-33,-32,-32,-31,-31,-30,-30,-29,-29,-28,-27,-26,-25,-25,-24,-23,-22,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,17,18,19,20,21,22,23,24,24,25,26,27,28,28,29,30,31,32,33,34,34,35,35,36,37,37,38,38,39,39,40,40,41,41,41,42,42,42,43,43,43,43,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,43,43,43,43,42,42,42,41,41,41,40,40,39,39,38,38,37,37,36,35,35,34,34,33,32,31,30,29,28,28,27,26,25,24,24,23,22,21,20,19,18,17,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-16,-17,-18,-19,-20,-21,-22,-23,-24,-24,-25,-26,-27,-28,-28,-29,-30,-31,-32,-33,-34,-34,-35,-35,-36,-37,-37,-38,-38,-39,-39,-40,-40,-41,-41,-41,-42,-42,-42,-43,-43,-43,-43,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-43,-43,-43,-43,-42,-42,-42,-41,-41,-41,-40,-40,-39,-39,-38,-38,-37,-37,-36,-35,-35,-34,-34,-33,-32,-31,-30,-29,-28,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-19,-18,-17,-16,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,27,28,29,30,31,32,32,33,33,34,35,36,36,37,37,38,39,39,40,40,41,41,42,42,43,43,43,44,44,44,44,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,44,44,44,44,43,43,43,42,42,41,41,40,40,39,39,38,37,37,36,36,35,34,33,33,32,32,31,30,29,28,27,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-27,-28,-29,-30,-31,-32,-32,-33,-33,-34,-35,-36,-36,-37,-37,-38,-39,-39,-40,-40,-41,-41,-42,-42,-43,-43,-43,-44,-44,-44,-44,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-44,-44,-44,-44,-43,-43,-43,-42,-42,-41,-41,-40,-40,-39,-39,-38,-37,-37,-36,-36,-35,-34,-33,-33,-32,-32,-31,-30,-29,-28,-27,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,21,22,23,24,25,26,26,27,28,29,30,30,31,31,32,33,34,34,35,35,36,36,37,38,38,39,39,40,40,41,41,42,42,42,43,43,44,44,44,45,45,45,45,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,45,45,45,45,44,44,44,43,43,42,42,42,41,41,40,40,39,39,38,38,37,36,36,35,35,34,34,33,32,31,31,30,30,29,28,27,26,26,25,24,23,22,21,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-21,-22,-23,-24,-25,-26,-26,-27,-28,-29,-30,-30,-31,-31,-32,-33,-34,-34,-35,-35,-36,-36,-37,-38,-38,-39,-39,-40,-40,-41,-41,-42,-42,-42,-43,-43,-44,-44,-44,-45,-45,-45,-45,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-45,-45,-45,-45,-44,-44,-44,-43,-43,-42,-42,-42,-41,-41,-40,-40,-39,-39,-38,-38,-37,-36,-36,-35,-35,-34,-34,-33,-32,-31,-31,-30,-30,-29,-28,-27,-26,-26,-25,-24,-23,-22,-21,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,19,20,21,22,23,23,24,25,26,27,28,29,29,30,31,32,33,34,35,36,37,37,38,38,39,40,40,41,41,42,42,43,43,43,44,44,44,45,45,45,46,46,46,46,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,46,46,46,46,45,45,45,44,44,44,43,43,43,42,42,41,41,40,40,39,38,38,37,37,36,35,34,33,32,31,30,29,29,28,27,26,25,24,23,23,22,21,20,19,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-19,-20,-21,-22,-23,-23,-24,-25,-26,-27,-28,-29,-29,-30,-31,-32,-33,-34,-35,-36,-37,-37,-38,-38,-39,-40,-40,-41,-41,-42,-42,-43,-43,-43,-44,-44,-44,-45,-45,-45,-46,-46,-46,-46,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-46,-46,-46,-46,-45,-45,-45,-44,-44,-44,-43,-43,-43,-42,-42,-41,-41,-40,-40,-39,-38,-38,-37,-37,-36,-35,-34,-33,-32,-31,-30,-29,-29,-28,-27,-26,-25,-24,-23,-23,-22,-21,-20,-19,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,25,26,27,28,28,29,30,31,32,32,33,33,34,34,35,35,36,36,37,37,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,45,46,46,46,47,47,47,47,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,47,47,47,47,46,46,46,45,45,45,44,44,43,43,42,42,41,41,40,40,39,39,38,37,37,36,36,35,35,34,34,33,33,32,32,31,30,29,28,28,27,26,25,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-25,-26,-27,-28,-28,-29,-30,-31,-32,-32,-33,-33,-34,-34,-35,-35,-36,-36,-37,-37,-38,-39,-39,-40,-40,-41,-41,-42,-42,-43,-43,-44,-44,-45,-45,-45,-46,-46,-46,-47,-47,-47,-47,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-47,-47,-47,-47,-46,-46,-46,-45,-45,-45,-44,-44,-43,-43,-42,-42,-41,-41,-40,-40,-39,-39,-38,-37,-37,-36,-36,-35,-35,-34,-34,-33,-33,-32,-32,-31,-30,-29,-28,-28,-27,-26,-25,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,17,18,19,20,21,22,23,24,25,26,27,27,28,29,30,31,31,32,33,34,35,36,37,38,38,39,39,40,41,41,42,42,43,43,44,44,45,45,46,46,46,47,47,47,47,48,48,48,48,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,48,48,48,48,47,47,47,47,46,46,46,45,45,44,44,43,43,42,42,41,41,40,39,39,38,38,37,36,35,34,33,32,31,31,30,29,28,27,27,26,25,24,23,22,21,20,19,18,17,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-27,-28,-29,-30,-31,-31,-32,-33,-34,-35,-36,-37,-38,-38,-39,-39,-40,-41,-41,-42,-42,-43,-43,-44,-44,-45,-45,-46,-46,-46,-47,-47,-47,-47,-48,-48,-48,-48,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-48,-48,-48,-48,-47,-47,-47,-47,-46,-46,-46,-45,-45,-44,-44,-43,-43,-42,-42,-41,-41,-40,-39,-39,-38,-38,-37,-36,-35,-34,-33,-32,-31,-31,-30,-29,-28,-27,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,10,11,12,13,14,14,15,16,17,18,19,20,21,22,22,23,24,25,26,27,28,29,30,30,31,32,33,34,34,35,35,36,36,37,37,38,38,39,40,40,41,41,42,43,43,44,44,45,45,46,46,46,47,47,48,48,48,48,49,49,49,49,49,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,49,49,49,49,49,48,48,48,48,47,47,46,46,46,45,45,44,44,43,43,42,41,41,40,40,39,38,38,37,37,36,36,35,35,34,34,33,32,31,30,30,29,28,27,26,25,24,23,22,22,21,20,19,18,17,16,15,14,14,13,12,11,10,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-10,-11,-12,-13,-14,-14,-15,-16,-17,-18,-19,-20,-21,-22,-22,-23,-24,-25,-26,-27,-28,-29,-30,-30,-31,-32,-33,-34,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-40,-40,-41,-41,-42,-43,-43,-44,-44,-45,-45,-46,-46,-46,-47,-47,-48,-48,-48,-48,-49,-49,-49,-49,-49,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-49,-49,-49,-49,-49,-48,-48,-48,-48,-47,-47,-46,-46,-46,-45,-45,-44,-44,-43,-43,-42,-41,-41,-40,-40,-39,-38,-38,-37,-37,-36,-36,-35,-35,-34,-34,-33,-32,-31,-30,-30,-29,-28,-27,-26,-25,-24,-23,-22,-22,-21,-20,-19,-18,-17,-16,-15,-14,-14,-13,-12,-11,-10,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,24,25,26,26,27,28,29,29,30,31,32,33,33,34,35,36,37,38,39,39,40,40,41,42,42,43,43,44,44,45,45,45,46,46,47,47,47,48,48,49,49,49,50,50,50,50,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,50,50,50,50,49,49,49,48,48,47,47,47,46,46,45,45,45,44,44,43,43,42,42,41,40,40,39,39,38,37,36,35,34,33,33,32,31,30,29,29,28,27,26,26,25,24,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-24,-25,-26,-26,-27,-28,-29,-29,-30,-31,-32,-33,-33,-34,-35,-36,-37,-38,-39,-39,-40,-40,-41,-42,-42,-43,-43,-44,-44,-45,-45,-45,-46,-46,-47,-47,-47,-48,-48,-49,-49,-49,-50,-50,-50,-50,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-50,-50,-50,-50,-49,-49,-49,-48,-48,-47,-47,-47,-46,-46,-45,-45,-45,-44,-44,-43,-43,-42,-42,-41,-40,-40,-39,-39,-38,-37,-36,-35,-34,-33,-33,-32,-31,-30,-29,-29,-28,-27,-26,-26,-25,-24,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,20,21,22,23,24,25,26,27,28,29,30,31,32,32,33,34,35,36,37,38,39,40,41,41,42,42,43,44,44,45,46,46,47,47,48,48,48,49,49,49,50,50,50,51,51,51,51,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,51,51,51,51,50,50,50,49,49,49,48,48,48,47,47,46,46,45,44,44,43,42,42,41,41,40,39,38,37,36,35,34,33,32,32,31,30,29,28,27,26,25,24,23,22,21,20,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-20,-21,-22,-23,-24,-25,-26,-27,-28,-29,-30,-31,-32,-32,-33,-34,-35,-36,-37,-38,-39,-40,-41,-41,-42,-42,-43,-44,-44,-45,-46,-46,-47,-47,-48,-48,-48,-49,-49,-49,-50,-50,-50,-51,-51,-51,-51,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-51,-51,-51,-51,-50,-50,-50,-49,-49,-49,-48,-48,-48,-47,-47,-46,-46,-45,-44,-44,-43,-42,-42,-41,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,28,29,30,31,31,32,33,34,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,43,43,44,44,45,45,46,46,47,47,48,48,49,49,50,50,50,51,51,51,52,52,52,52,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,52,52,52,52,51,51,51,50,50,50,49,49,48,48,47,47,46,46,45,45,44,44,43,43,42,41,41,40,40,39,39,38,38,37,37,36,36,35,35,34,33,32,31,31,30,29,28,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-28,-28,-29,-30,-31,-31,-32,-33,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-39,-40,-40,-41,-41,-42,-43,-43,-44,-44,-45,-45,-46,-46,-47,-47,-48,-48,-49,-49,-50,-50,-50,-51,-51,-51,-52,-52,-52,-52,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-52,-52,-52,-52,-51,-51,-51,-50,-50,-50,-49,-49,-48,-48,-47,-47,-46,-46,-45,-45,-44,-44,-43,-43,-42,-41,-41,-40,-40,-39,-39,-38,-38,-37,-37,-36,-36,-35,-35,-34,-33,-32,-31,-31,-30,-29,-28,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,30,31,32,33,34,34,35,36,37,38,39,40,41,42,42,43,43,44,45,45,46,46,47,47,48,48,49,49,50,50,51,51,51,52,52,52,53,53,53,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,53,53,53,52,52,52,51,51,51,50,50,49,49,48,48,47,47,46,46,45,45,44,43,43,42,42,41,40,39,38,37,36,35,34,34,33,32,31,30,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-28,-29,-30,-30,-31,-32,-33,-34,-34,-35,-36,-37,-38,-39,-40,-41,-42,-42,-43,-43,-44,-45,-45,-46,-46,-47,-47,-48,-48,-49,-49,-50,-50,-51,-51,-51,-52,-52,-52,-53,-53,-53,-53,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-53,-53,-53,-53,-52,-52,-52,-51,-51,-51,-50,-50,-49,-49,-48,-48,-47,-47,-46,-46,-45,-45,-44,-43,-43,-42,-42,-41,-40,-39,-38,-37,-36,-35,-34,-34,-33,-32,-31,-30,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,18,19,20,21,22,23,23,24,25,25,26,27,27,28,29,30,31,32,33,33,34,35,36,37,37,38,38,39,39,40,40,41,41,42,42,43,44,44,45,45,46,47,47,48,48,49,49,49,50,50,50,51,51,51,52,52,52,53,53,53,53,54,54,54,54,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,54,54,54,54,53,53,53,53,52,52,52,51,51,51,50,50,50,49,49,49,48,48,47,47,46,45,45,44,44,43,42,42,41,41,40,40,39,39,38,38,37,37,36,35,34,33,33,32,31,30,29,28,27,27,26,25,25,24,23,23,22,21,20,19,18,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-18,-19,-20,-21,-22,-23,-23,-24,-25,-25,-26,-27,-27,-28,-29,-30,-31,-32,-33,-33,-34,-35,-36,-37,-37,-38,-38,-39,-39,-40,-40,-41,-41,-42,-42,-43,-44,-44,-45,-45,-46,-47,-47,-48,-48,-49,-49,-49,-50,-50,-50,-51,-51,-51,-52,-52,-52,-53,-53,-53,-53,-54,-54,-54,-54,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-54,-54,-54,-54,-53,-53,-53,-53,-52,-52,-52,-51,-51,-51,-50,-50,-50,-49,-49,-49,-48,-48,-47,-47,-46,-45,-45,-44,-44,-43,-42,-42,-41,-41,-40,-40,-39,-39,-38,-38,-37,-37,-36,-35,-34,-33,-33,-32,-31,-30,-29,-28,-27,-27,-26,-25,-25,-24,-23,-23,-22,-21,-20,-19,-18,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,29,30,31,32,32,33,34,35,36,36,37,38,39,40,41,42,43,43,44,44,45,46,46,47,47,48,48,49,49,50,50,51,51,52,52,52,53,53,54,54,54,54,55,55,55,55,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,55,55,55,55,54,54,54,54,53,53,52,52,52,51,51,50,50,49,49,48,48,47,47,46,46,45,44,44,43,43,42,41,40,39,38,37,36,36,35,34,33,32,32,31,30,29,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-28,-29,-29,-30,-31,-32,-32,-33,-34,-35,-36,-36,-37,-38,-39,-40,-41,-42,-43,-43,-44,-44,-45,-46,-46,-47,-47,-48,-48,-49,-49,-50,-50,-51,-51,-52,-52,-52,-53,-53,-54,-54,-54,-54,-55,-55,-55,-55,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-55,-55,-55,-55,-54,-54,-54,-54,-53,-53,-52,-52,-52,-51,-51,-50,-50,-49,-49,-48,-48,-47,-47,-46,-46,-45,-44,-44,-43,-43,-42,-41,-40,-39,-38,-37,-36,-36,-35,-34,-33,-32,-32,-31,-30,-29,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15,16,17,18,19,20,21,21,22,23,24,25,26,27,28,29,30,31,31,32,33,34,35,35,36,37,38,39,40,41,41,42,43,44,45,45,46,46,47,48,48,49,49,50,50,51,51,52,52,53,53,53,54,54,54,55,55,55,55,56,56,56,56,56,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,56,56,56,56,56,55,55,55,55,54,54,54,53,53,53,52,52,51,51,50,50,49,49,48,48,47,46,46,45,45,44,43,42,41,41,40,39,38,37,36,35,35,34,33,32,31,31,30,29,28,27,26,25,24,23,22,21,21,20,19,18,17,16,15,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-15,-16,-17,-18,-19,-20,-21,-21,-22,-23,-24,-25,-26,-27,-28,-29,-30,-31,-31,-32,-33,-34,-35,-35,-36,-37,-38,-39,-40,-41,-41,-42,-43,-44,-45,-45,-46,-46,-47,-48,-48,-49,-49,-50,-50,-51,-51,-52,-52,-53,-53,-53,-54,-54,-54,-55,-55,-55,-55,-56,-56,-56,-56,-56,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-56,-56,-56,-56,-56,-55,-55,-55,-55,-54,-54,-54,-53,-53,-53,-52,-52,-51,-51,-50,-50,-49,-49,-48,-48,-47,-46,-46,-45,-45,-44,-43,-42,-41,-41,-40,-39,-38,-37,-36,-35,-35,-34,-33,-32,-31,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-21,-20,-19,-18,-17,-16,-15,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,34,35,36,37,38,38,39,39,40,40,41,42,42,43,43,44,44,45,45,46,47,47,48,48,49,50,50,51,51,52,52,53,53,54,54,55,55,55,56,56,56,57,57,57,57,57,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,57,57,57,57,57,56,56,56,55,55,55,54,54,53,53,52,52,51,51,50,50,49,48,48,47,47,46,45,45,44,44,43,43,42,42,41,40,40,39,39,38,38,37,36,35,34,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-28,-29,-30,-31,-32,-33,-34,-34,-35,-36,-37,-38,-38,-39,-39,-40,-40,-41,-42,-42,-43,-43,-44,-44,-45,-45,-46,-47,-47,-48,-48,-49,-50,-50,-51,-51,-52,-52,-53,-53,-54,-54,-55,-55,-55,-56,-56,-56,-57,-57,-57,-57,-57,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-57,-57,-57,-57,-57,-56,-56,-56,-55,-55,-55,-54,-54,-53,-53,-52,-52,-51,-51,-50,-50,-49,-48,-48,-47,-47,-46,-45,-45,-44,-44,-43,-43,-42,-42,-41,-40,-40,-39,-39,-38,-38,-37,-36,-35,-34,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,26,27,28,28,29,30,31,32,33,33,34,35,36,37,37,38,39,40,41,42,43,44,45,46,46,47,47,48,49,49,50,50,51,51,52,52,53,53,53,54,54,54,55,55,56,56,56,57,57,57,58,58,58,58,58,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,58,58,58,58,58,57,57,57,56,56,56,55,55,54,54,54,53,53,53,52,52,51,51,50,50,49,49,48,47,47,46,46,45,44,43,42,41,40,39,38,37,37,36,35,34,33,33,32,31,30,29,28,28,27,26,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-26,-27,-28,-28,-29,-30,-31,-32,-33,-33,-34,-35,-36,-37,-37,-38,-39,-40,-41,-42,-43,-44,-45,-46,-46,-47,-47,-48,-49,-49,-50,-50,-51,-51,-52,-52,-53,-53,-53,-54,-54,-54,-55,-55,-56,-56,-56,-57,-57,-57,-58,-58,-58,-58,-58,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-58,-58,-58,-58,-58,-57,-57,-57,-56,-56,-56,-55,-55,-54,-54,-54,-53,-53,-53,-52,-52,-51,-51,-50,-50,-49,-49,-48,-47,-47,-46,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-37,-36,-35,-34,-33,-33,-32,-31,-30,-29,-28,-28,-27,-26,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1];\nvar ys = [0,-1,-1,0,1,1,1,0,-1,-2,-2,-2,-1,0,1,2,2,2,2,2,1,0,-1,-2,-2,-3,-3,-3,-2,-1,0,1,2,3,3,3,3,3,2,1,0,-1,-2,-3,-3,-4,-4,-4,-3,-2,-1,0,1,2,3,4,4,4,4,4,3,2,1,0,-1,-2,-3,-4,-4,-5,-5,-5,-5,-4,-4,-3,-3,-2,-1,0,1,2,3,3,4,4,5,5,5,5,5,5,5,4,4,3,3,2,1,0,-1,-2,-3,-3,-4,-4,-5,-5,-5,-6,-6,-6,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,6,6,6,6,6,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-6,-6,-7,-7,-7,-7,-6,-6,-5,-5,-4,-3,-2,-1,0,1,2,3,4,5,5,6,6,7,7,7,7,7,7,7,6,6,5,5,4,3,2,1,0,-1,-2,-3,-4,-5,-5,-6,-6,-7,-7,-7,-8,-8,-8,-8,-8,-7,-7,-6,-5,-4,-4,-3,-2,-1,0,1,2,3,4,4,5,6,7,7,8,8,8,8,8,8,8,8,8,7,7,6,5,4,4,3,2,1,0,-1,-2,-3,-4,-4,-5,-6,-7,-7,-8,-8,-8,-8,-9,-9,-9,-9,-9,-8,-7,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,7,8,9,9,9,9,9,9,9,9,9,8,7,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-7,-8,-9,-9,-9,-9,-10,-10,-10,-10,-10,-9,-9,-8,-8,-7,-6,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,6,7,8,8,9,9,10,10,10,10,10,10,10,10,10,9,9,8,8,7,6,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-6,-7,-8,-8,-9,-9,-10,-10,-10,-10,-11,-11,-11,-11,-11,-10,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,10,11,11,11,11,11,11,11,11,11,10,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-10,-11,-11,-11,-11,-12,-12,-12,-12,-12,-11,-11,-10,-10,-9,-9,-8,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,8,9,9,10,10,11,11,12,12,12,12,12,12,12,12,12,11,11,10,10,9,9,8,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-8,-9,-9,-10,-10,-11,-11,-12,-12,-12,-12,-13,-13,-13,-13,-13,-13,-12,-12,-12,-11,-11,-10,-9,-8,-7,-7,-6,-5,-5,-4,-3,-2,-1,0,1,2,3,4,5,5,6,7,7,8,9,10,11,11,12,12,12,13,13,13,13,13,13,13,13,13,13,13,12,12,12,11,11,10,9,8,7,7,6,5,5,4,3,2,1,0,-1,-2,-3,-4,-5,-5,-6,-7,-7,-8,-9,-10,-11,-11,-12,-12,-12,-13,-13,-13,-13,-13,-14,-14,-14,-14,-14,-14,-13,-13,-12,-11,-11,-10,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,10,11,11,12,13,13,14,14,14,14,14,14,14,14,14,14,14,13,13,12,11,11,10,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-10,-11,-11,-12,-13,-13,-14,-14,-14,-14,-14,-15,-15,-15,-15,-15,-15,-14,-14,-13,-13,-12,-12,-11,-10,-9,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,9,10,11,12,12,13,13,14,14,15,15,15,15,15,15,15,15,15,15,15,14,14,13,13,12,12,11,10,9,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-9,-10,-11,-12,-12,-13,-13,-14,-14,-15,-15,-15,-15,-15,-16,-16,-16,-16,-16,-16,-15,-15,-14,-14,-13,-12,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,12,13,14,14,15,15,16,16,16,16,16,16,16,16,16,16,16,15,15,14,14,13,12,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-12,-13,-14,-14,-15,-15,-16,-16,-16,-16,-16,-17,-17,-17,-17,-17,-17,-16,-16,-16,-15,-15,-14,-14,-13,-13,-12,-11,-11,-10,-9,-8,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,8,9,10,11,11,12,13,13,14,14,15,15,16,16,16,17,17,17,17,17,17,17,17,17,17,17,16,16,16,15,15,14,14,13,13,12,11,11,10,9,8,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-8,-9,-10,-11,-11,-12,-13,-13,-14,-14,-15,-15,-16,-16,-16,-17,-17,-17,-17,-17,-18,-18,-18,-18,-18,-18,-18,-17,-17,-17,-16,-16,-15,-15,-14,-13,-12,-11,-10,-10,-9,-8,-7,-6,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,6,7,8,9,10,10,11,12,13,14,15,15,16,16,17,17,17,18,18,18,18,18,18,18,18,18,18,18,18,18,17,17,17,16,16,15,15,14,13,12,11,10,10,9,8,7,6,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-6,-7,-8,-9,-10,-10,-11,-12,-13,-14,-15,-15,-16,-16,-17,-17,-17,-18,-18,-18,-18,-18,-18,-19,-19,-19,-19,-19,-19,-19,-18,-18,-17,-17,-16,-15,-15,-14,-14,-13,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,13,14,14,15,15,16,17,17,18,18,19,19,19,19,19,19,19,19,19,19,19,19,19,18,18,17,17,16,15,15,14,14,13,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-13,-14,-14,-15,-15,-16,-17,-17,-18,-18,-19,-19,-19,-19,-19,-19,-20,-20,-20,-20,-20,-20,-20,-19,-19,-18,-18,-17,-17,-16,-16,-15,-14,-13,-12,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,12,13,14,15,16,16,17,17,18,18,19,19,20,20,20,20,20,20,20,20,20,20,20,20,20,19,19,18,18,17,17,16,16,15,14,13,12,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-12,-13,-14,-15,-16,-16,-17,-17,-18,-18,-19,-19,-20,-20,-20,-20,-20,-20,-21,-21,-21,-21,-21,-21,-21,-20,-20,-20,-19,-19,-19,-18,-18,-17,-16,-16,-15,-15,-14,-13,-12,-11,-11,-10,-9,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,9,10,11,11,12,13,14,15,15,16,16,17,18,18,19,19,19,20,20,20,21,21,21,21,21,21,21,21,21,21,21,21,21,20,20,20,19,19,19,18,18,17,16,16,15,15,14,13,12,11,11,10,9,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-9,-10,-11,-11,-12,-13,-14,-15,-15,-16,-16,-17,-18,-18,-19,-19,-19,-20,-20,-20,-21,-21,-21,-21,-21,-21,-22,-22,-22,-22,-22,-22,-22,-21,-21,-21,-20,-20,-19,-18,-18,-17,-17,-16,-15,-14,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,14,15,16,17,17,18,18,19,20,20,21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,21,21,21,20,20,19,18,18,17,17,16,15,14,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-14,-15,-16,-17,-17,-18,-18,-19,-20,-20,-21,-21,-21,-22,-22,-22,-22,-22,-22,-23,-23,-23,-23,-23,-23,-23,-22,-22,-22,-21,-21,-20,-20,-19,-19,-18,-17,-16,-15,-14,-13,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,13,14,15,16,17,18,19,19,20,20,21,21,22,22,22,23,23,23,23,23,23,23,23,23,23,23,23,23,22,22,22,21,21,20,20,19,19,18,17,16,15,14,13,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-13,-14,-15,-16,-17,-18,-19,-19,-20,-20,-21,-21,-22,-22,-22,-23,-23,-23,-23,-23,-23,-24,-24,-24,-24,-24,-24,-24,-23,-23,-23,-22,-22,-21,-21,-20,-19,-19,-18,-18,-17,-17,-16,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,17,17,18,18,19,19,20,21,21,22,22,23,23,23,24,24,24,24,24,24,24,24,24,24,24,24,24,23,23,23,22,22,21,21,20,19,19,18,18,17,17,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-16,-17,-17,-18,-18,-19,-19,-20,-21,-21,-22,-22,-23,-23,-23,-24,-24,-24,-24,-24,-24,-25,-25,-25,-25,-25,-25,-25,-25,-24,-24,-24,-23,-23,-23,-22,-22,-21,-21,-20,-20,-19,-18,-17,-16,-15,-15,-14,-13,-12,-12,-11,-10,-9,-8,-7,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,7,8,9,10,11,12,12,13,14,15,15,16,17,18,19,20,20,21,21,22,22,23,23,23,24,24,24,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,24,24,24,23,23,23,22,22,21,21,20,20,19,18,17,16,15,15,14,13,12,12,11,10,9,8,7,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-7,-8,-9,-10,-11,-12,-12,-13,-14,-15,-15,-16,-17,-18,-19,-20,-20,-21,-21,-22,-22,-23,-23,-23,-24,-24,-24,-25,-25,-25,-25,-25,-25,-25,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-24,-24,-24,-23,-23,-22,-22,-21,-20,-20,-19,-19,-18,-18,-17,-16,-15,-14,-14,-13,-12,-11,-10,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,10,11,12,13,14,14,15,16,17,18,18,19,19,20,20,21,22,22,23,23,24,24,24,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,25,25,25,24,24,24,23,23,22,22,21,20,20,19,19,18,18,17,16,15,14,14,13,12,11,10,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-10,-11,-12,-13,-14,-14,-15,-16,-17,-18,-18,-19,-19,-20,-20,-21,-22,-22,-23,-23,-24,-24,-24,-25,-25,-25,-26,-26,-26,-26,-26,-26,-26,-27,-27,-27,-27,-27,-27,-27,-27,-26,-26,-26,-25,-25,-24,-24,-23,-22,-22,-21,-21,-20,-19,-18,-17,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,17,18,19,20,21,21,22,22,23,24,24,25,25,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,26,26,26,25,25,24,24,23,22,22,21,21,20,19,18,17,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-17,-18,-19,-20,-21,-21,-22,-22,-23,-24,-24,-25,-25,-26,-26,-26,-27,-27,-27,-27,-27,-27,-27,-28,-28,-28,-28,-28,-28,-28,-28,-27,-27,-27,-26,-26,-25,-25,-24,-24,-23,-23,-22,-21,-20,-19,-18,-17,-16,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,17,18,19,20,21,22,23,23,24,24,25,25,26,26,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,27,27,27,26,26,25,25,24,24,23,23,22,21,20,19,18,17,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-16,-17,-18,-19,-20,-21,-22,-23,-23,-24,-24,-25,-25,-26,-26,-27,-27,-27,-28,-28,-28,-28,-28,-28,-28,-29,-29,-29,-29,-29,-29,-29,-29,-28,-28,-28,-27,-27,-27,-26,-26,-25,-25,-24,-23,-23,-22,-22,-21,-21,-20,-20,-19,-19,-18,-17,-16,-15,-14,-13,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,13,14,15,16,17,18,19,19,20,20,21,21,22,22,23,23,24,25,25,26,26,27,27,27,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,28,28,28,27,27,27,26,26,25,25,24,23,23,22,22,21,21,20,20,19,19,18,17,16,15,14,13,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-13,-14,-15,-16,-17,-18,-19,-19,-20,-20,-21,-21,-22,-22,-23,-23,-24,-25,-25,-26,-26,-27,-27,-27,-28,-28,-28,-29,-29,-29,-29,-29,-29,-29,-30,-30,-30,-30,-30,-30,-30,-30,-29,-29,-29,-28,-28,-28,-27,-27,-26,-26,-25,-25,-24,-24,-23,-22,-21,-20,-19,-18,-18,-17,-16,-15,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15,16,17,18,18,19,20,21,22,23,24,24,25,25,26,26,27,27,28,28,28,29,29,29,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,29,29,29,28,28,28,27,27,26,26,25,25,24,24,23,22,21,20,19,18,18,17,16,15,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-15,-16,-17,-18,-18,-19,-20,-21,-22,-23,-24,-24,-25,-25,-26,-26,-27,-27,-28,-28,-28,-29,-29,-29,-30,-30,-30,-30,-30,-30,-30,-31,-31,-31,-31,-31,-31,-31,-31,-30,-30,-30,-30,-29,-29,-29,-28,-28,-27,-27,-26,-26,-25,-24,-24,-23,-23,-22,-22,-21,-21,-20,-19,-18,-17,-17,-16,-15,-14,-13,-12,-11,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,11,12,13,14,15,16,17,17,18,19,20,21,21,22,22,23,23,24,24,25,26,26,27,27,28,28,29,29,29,30,30,30,30,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,30,30,30,30,29,29,29,28,28,27,27,26,26,25,24,24,23,23,22,22,21,21,20,19,18,17,17,16,15,14,13,12,11,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-11,-12,-13,-14,-15,-16,-17,-17,-18,-19,-20,-21,-21,-22,-22,-23,-23,-24,-24,-25,-26,-26,-27,-27,-28,-28,-29,-29,-29,-30,-30,-30,-30,-31,-31,-31,-31,-31,-31,-31,-32,-32,-32,-32,-32,-32,-32,-32,-32,-31,-31,-31,-31,-30,-30,-29,-29,-28,-28,-27,-26,-26,-25,-25,-24,-23,-22,-21,-20,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,8,9,10,11,12,13,14,15,16,17,18,19,20,20,21,22,23,24,25,25,26,26,27,28,28,29,29,30,30,31,31,31,31,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,31,31,31,31,30,30,29,29,28,28,27,26,26,25,25,24,23,22,21,20,20,19,18,17,16,15,14,13,12,11,10,9,8,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-20,-21,-22,-23,-24,-25,-25,-26,-26,-27,-28,-28,-29,-29,-30,-30,-31,-31,-31,-31,-32,-32,-32,-32,-32,-32,-32,-32,-33,-33,-33,-33,-33,-33,-33,-33,-33,-32,-32,-32,-31,-31,-30,-30,-29,-29,-28,-28,-27,-27,-26,-25,-25,-24,-24,-23,-23,-22,-21,-20,-19,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,19,20,21,22,23,23,24,24,25,25,26,27,27,28,28,29,29,30,30,31,31,32,32,32,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,32,32,32,31,31,30,30,29,29,28,28,27,27,26,25,25,24,24,23,23,22,21,20,19,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-19,-20,-21,-22,-23,-23,-24,-24,-25,-25,-26,-27,-27,-28,-28,-29,-29,-30,-30,-31,-31,-32,-32,-32,-33,-33,-33,-33,-33,-33,-33,-33,-34,-34,-34,-34,-34,-34,-34,-34,-34,-33,-33,-33,-32,-32,-32,-31,-31,-31,-30,-30,-30,-29,-29,-28,-27,-27,-26,-26,-25,-24,-23,-22,-22,-21,-20,-19,-18,-18,-17,-16,-16,-15,-14,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,14,15,16,16,17,18,18,19,20,21,22,22,23,24,25,26,26,27,27,28,29,29,30,30,30,31,31,31,32,32,32,33,33,33,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,33,33,33,32,32,32,31,31,31,30,30,30,29,29,28,27,27,26,26,25,24,23,22,22,21,20,19,18,18,17,16,16,15,14,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-14,-15,-16,-16,-17,-18,-18,-19,-20,-21,-22,-22,-23,-24,-25,-26,-26,-27,-27,-28,-29,-29,-30,-30,-30,-31,-31,-31,-32,-32,-32,-33,-33,-33,-34,-34,-34,-34,-34,-34,-34,-34,-35,-35,-35,-35,-35,-35,-35,-35,-35,-34,-34,-34,-33,-33,-33,-32,-32,-31,-31,-30,-29,-29,-28,-28,-27,-26,-25,-24,-23,-22,-21,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,21,22,23,24,25,26,27,28,28,29,29,30,31,31,32,32,33,33,33,34,34,34,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,34,34,34,33,33,33,32,32,31,31,30,29,29,28,28,27,26,25,24,23,22,21,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-21,-22,-23,-24,-25,-26,-27,-28,-28,-29,-29,-30,-31,-31,-32,-32,-33,-33,-33,-34,-34,-34,-35,-35,-35,-35,-35,-35,-35,-35,-36,-36,-36,-36,-36,-36,-36,-36,-36,-35,-35,-35,-34,-34,-34,-33,-33,-32,-32,-31,-31,-30,-30,-29,-28,-28,-27,-27,-26,-26,-25,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,20,21,22,23,24,24,25,25,26,26,27,27,28,28,29,30,30,31,31,32,32,33,33,34,34,34,35,35,35,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,35,35,35,34,34,34,33,33,32,32,31,31,30,30,29,28,28,27,27,26,26,25,25,24,24,23,22,21,20,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-20,-21,-22,-23,-24,-24,-25,-25,-26,-26,-27,-27,-28,-28,-29,-30,-30,-31,-31,-32,-32,-33,-33,-34,-34,-34,-35,-35,-35,-36,-36,-36,-36,-36,-36,-36,-36,-37,-37,-37,-37,-37,-37,-37,-37,-37,-36,-36,-36,-36,-35,-35,-35,-34,-34,-33,-33,-32,-32,-31,-30,-30,-29,-29,-28,-27,-26,-25,-24,-23,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,12,13,14,15,16,17,18,19,20,21,22,23,23,24,25,26,27,28,29,29,30,30,31,32,32,33,33,34,34,35,35,35,36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,36,36,36,35,35,35,34,34,33,33,32,32,31,30,30,29,29,28,27,26,25,24,23,23,22,21,20,19,18,17,16,15,14,13,12,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-23,-24,-25,-26,-27,-28,-29,-29,-30,-30,-31,-32,-32,-33,-33,-34,-34,-35,-35,-35,-36,-36,-36,-36,-37,-37,-37,-37,-37,-37,-37,-37,-38,-38,-38,-38,-38,-38,-38,-38,-38,-37,-37,-37,-37,-36,-36,-35,-35,-35,-34,-34,-34,-33,-33,-32,-32,-31,-31,-30,-29,-29,-28,-28,-27,-27,-26,-26,-25,-24,-23,-22,-22,-21,-20,-19,-19,-18,-17,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,17,18,19,19,20,21,22,22,23,24,25,26,26,27,27,28,28,29,29,30,31,31,32,32,33,33,34,34,34,35,35,35,36,36,37,37,37,37,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,37,37,37,37,36,36,35,35,35,34,34,34,33,33,32,32,31,31,30,29,29,28,28,27,27,26,26,25,24,23,22,22,21,20,19,19,18,17,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-17,-18,-19,-19,-20,-21,-22,-22,-23,-24,-25,-26,-26,-27,-27,-28,-28,-29,-29,-30,-31,-31,-32,-32,-33,-33,-34,-34,-34,-35,-35,-35,-36,-36,-37,-37,-37,-37,-38,-38,-38,-38,-38,-38,-38,-38,-39,-39,-39,-39,-39,-39,-39,-39,-39,-38,-38,-38,-38,-37,-37,-37,-36,-36,-36,-35,-35,-34,-34,-33,-33,-32,-31,-31,-30,-30,-29,-28,-27,-26,-25,-25,-24,-23,-22,-21,-21,-20,-19,-18,-17,-16,-15,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15,16,17,18,19,20,21,21,22,23,24,25,25,26,27,28,29,30,30,31,31,32,33,33,34,34,35,35,36,36,36,37,37,37,38,38,38,38,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,38,38,38,38,37,37,37,36,36,36,35,35,34,34,33,33,32,31,31,30,30,29,28,27,26,25,25,24,23,22,21,21,20,19,18,17,16,15,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-15,-16,-17,-18,-19,-20,-21,-21,-22,-23,-24,-25,-25,-26,-27,-28,-29,-30,-30,-31,-31,-32,-33,-33,-34,-34,-35,-35,-36,-36,-36,-37,-37,-37,-38,-38,-38,-38,-39,-39,-39,-39,-39,-39,-39,-39,-40,-40,-40,-40,-40,-40,-40,-40,-40,-39,-39,-39,-39,-38,-38,-38,-37,-37,-36,-36,-35,-35,-34,-33,-33,-32,-32,-31,-30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,24,25,26,27,28,29,30,31,32,32,33,33,34,35,35,36,36,37,37,38,38,38,39,39,39,39,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,39,39,39,39,38,38,38,37,37,36,36,35,35,34,33,33,32,32,31,30,29,28,27,26,25,24,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-24,-25,-26,-27,-28,-29,-30,-31,-32,-32,-33,-33,-34,-35,-35,-36,-36,-37,-37,-38,-38,-38,-39,-39,-39,-39,-40,-40,-40,-40,-40,-40,-40,-40,-41,-41,-41,-41,-41,-41,-41,-41,-41,-41,-40,-40,-40,-40,-39,-39,-39,-38,-38,-37,-37,-36,-36,-35,-35,-34,-34,-33,-32,-32,-31,-31,-30,-30,-29,-29,-28,-28,-27,-27,-26,-25,-24,-23,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,23,24,25,26,27,27,28,28,29,29,30,30,31,31,32,32,33,34,34,35,35,36,36,37,37,38,38,39,39,39,40,40,40,40,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,40,40,40,40,39,39,39,38,38,37,37,36,36,35,35,34,34,33,32,32,31,31,30,30,29,29,28,28,27,27,26,25,24,23,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-23,-24,-25,-26,-27,-27,-28,-28,-29,-29,-30,-30,-31,-31,-32,-32,-33,-34,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-39,-39,-40,-40,-40,-40,-41,-41,-41,-41,-41,-41,-41,-41,-41,-42,-42,-42,-42,-42,-42,-42,-42,-42,-42,-41,-41,-41,-40,-40,-40,-39,-39,-39,-38,-38,-38,-37,-37,-36,-36,-35,-34,-34,-33,-33,-32,-31,-30,-29,-28,-27,-26,-26,-25,-24,-23,-22,-21,-20,-20,-19,-18,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,18,19,20,20,21,22,23,24,25,26,26,27,28,29,30,31,32,33,33,34,34,35,36,36,37,37,38,38,38,39,39,39,40,40,40,41,41,41,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,41,41,41,40,40,40,39,39,39,38,38,38,37,37,36,36,35,34,34,33,33,32,31,30,29,28,27,26,26,25,24,23,22,21,20,20,19,18,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-18,-19,-20,-20,-21,-22,-23,-24,-25,-26,-26,-27,-28,-29,-30,-31,-32,-33,-33,-34,-34,-35,-36,-36,-37,-37,-38,-38,-38,-39,-39,-39,-40,-40,-40,-41,-41,-41,-42,-42,-42,-42,-42,-42,-42,-42,-42,-43,-43,-43,-43,-43,-43,-43,-43,-43,-43,-42,-42,-42,-42,-41,-41,-41,-40,-40,-40,-39,-39,-38,-38,-37,-37,-36,-36,-35,-35,-34,-33,-33,-32,-32,-31,-31,-30,-30,-29,-29,-28,-27,-26,-25,-25,-24,-23,-22,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,13,14,15,16,17,18,19,20,21,22,22,23,24,25,25,26,27,28,29,29,30,30,31,31,32,32,33,33,34,35,35,36,36,37,37,38,38,39,39,40,40,40,41,41,41,42,42,42,42,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,42,42,42,42,41,41,41,40,40,40,39,39,38,38,37,37,36,36,35,35,34,33,33,32,32,31,31,30,30,29,29,28,27,26,25,25,24,23,22,22,21,20,19,18,17,16,15,14,13,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-22,-23,-24,-25,-25,-26,-27,-28,-29,-29,-30,-30,-31,-31,-32,-32,-33,-33,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-39,-40,-40,-40,-41,-41,-41,-42,-42,-42,-42,-43,-43,-43,-43,-43,-43,-43,-43,-43,-44,-44,-44,-44,-44,-44,-44,-44,-44,-44,-43,-43,-43,-43,-42,-42,-42,-41,-41,-41,-40,-40,-39,-39,-38,-38,-37,-37,-36,-35,-35,-34,-34,-33,-32,-31,-30,-29,-28,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-19,-18,-17,-16,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,17,18,19,20,21,22,23,24,24,25,26,27,28,28,29,30,31,32,33,34,34,35,35,36,37,37,38,38,39,39,40,40,41,41,41,42,42,42,43,43,43,43,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,43,43,43,43,42,42,42,41,41,41,40,40,39,39,38,38,37,37,36,35,35,34,34,33,32,31,30,29,28,28,27,26,25,24,24,23,22,21,20,19,18,17,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-16,-17,-18,-19,-20,-21,-22,-23,-24,-24,-25,-26,-27,-28,-28,-29,-30,-31,-32,-33,-34,-34,-35,-35,-36,-37,-37,-38,-38,-39,-39,-40,-40,-41,-41,-41,-42,-42,-42,-43,-43,-43,-43,-44,-44,-44,-44,-44,-44,-44,-44,-44,-45,-45,-45,-45,-45,-45,-45,-45,-45,-45,-44,-44,-44,-44,-43,-43,-43,-42,-42,-41,-41,-40,-40,-39,-39,-38,-37,-37,-36,-36,-35,-34,-33,-33,-32,-32,-31,-30,-29,-28,-27,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,27,28,29,30,31,32,32,33,33,34,35,36,36,37,37,38,39,39,40,40,41,41,42,42,43,43,43,44,44,44,44,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,44,44,44,44,43,43,43,42,42,41,41,40,40,39,39,38,37,37,36,36,35,34,33,33,32,32,31,30,29,28,27,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-27,-28,-29,-30,-31,-32,-32,-33,-33,-34,-35,-36,-36,-37,-37,-38,-39,-39,-40,-40,-41,-41,-42,-42,-43,-43,-43,-44,-44,-44,-44,-45,-45,-45,-45,-45,-45,-45,-45,-45,-46,-46,-46,-46,-46,-46,-46,-46,-46,-46,-45,-45,-45,-45,-44,-44,-44,-43,-43,-42,-42,-42,-41,-41,-40,-40,-39,-39,-38,-38,-37,-36,-36,-35,-35,-34,-34,-33,-32,-31,-31,-30,-30,-29,-28,-27,-26,-26,-25,-24,-23,-22,-21,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,21,22,23,24,25,26,26,27,28,29,30,30,31,31,32,33,34,34,35,35,36,36,37,38,38,39,39,40,40,41,41,42,42,42,43,43,44,44,44,45,45,45,45,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,45,45,45,45,44,44,44,43,43,42,42,42,41,41,40,40,39,39,38,38,37,36,36,35,35,34,34,33,32,31,31,30,30,29,28,27,26,26,25,24,23,22,21,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-21,-22,-23,-24,-25,-26,-26,-27,-28,-29,-30,-30,-31,-31,-32,-33,-34,-34,-35,-35,-36,-36,-37,-38,-38,-39,-39,-40,-40,-41,-41,-42,-42,-42,-43,-43,-44,-44,-44,-45,-45,-45,-45,-46,-46,-46,-46,-46,-46,-46,-46,-46,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-46,-46,-46,-46,-45,-45,-45,-44,-44,-44,-43,-43,-43,-42,-42,-41,-41,-40,-40,-39,-38,-38,-37,-37,-36,-35,-34,-33,-32,-31,-30,-29,-29,-28,-27,-26,-25,-24,-23,-23,-22,-21,-20,-19,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,19,20,21,22,23,23,24,25,26,27,28,29,29,30,31,32,33,34,35,36,37,37,38,38,39,40,40,41,41,42,42,43,43,43,44,44,44,45,45,45,46,46,46,46,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,46,46,46,46,45,45,45,44,44,44,43,43,43,42,42,41,41,40,40,39,38,38,37,37,36,35,34,33,32,31,30,29,29,28,27,26,25,24,23,23,22,21,20,19,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-19,-20,-21,-22,-23,-23,-24,-25,-26,-27,-28,-29,-29,-30,-31,-32,-33,-34,-35,-36,-37,-37,-38,-38,-39,-40,-40,-41,-41,-42,-42,-43,-43,-43,-44,-44,-44,-45,-45,-45,-46,-46,-46,-46,-47,-47,-47,-47,-47,-47,-47,-47,-47,-48,-48,-48,-48,-48,-48,-48,-48,-48,-48,-47,-47,-47,-47,-46,-46,-46,-45,-45,-45,-44,-44,-43,-43,-42,-42,-41,-41,-40,-40,-39,-39,-38,-37,-37,-36,-36,-35,-35,-34,-34,-33,-33,-32,-32,-31,-30,-29,-28,-28,-27,-26,-25,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,25,26,27,28,28,29,30,31,32,32,33,33,34,34,35,35,36,36,37,37,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,45,46,46,46,47,47,47,47,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,47,47,47,47,46,46,46,45,45,45,44,44,43,43,42,42,41,41,40,40,39,39,38,37,37,36,36,35,35,34,34,33,33,32,32,31,30,29,28,28,27,26,25,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-25,-26,-27,-28,-28,-29,-30,-31,-32,-32,-33,-33,-34,-34,-35,-35,-36,-36,-37,-37,-38,-39,-39,-40,-40,-41,-41,-42,-42,-43,-43,-44,-44,-45,-45,-45,-46,-46,-46,-47,-47,-47,-47,-48,-48,-48,-48,-48,-48,-48,-48,-48,-49,-49,-49,-49,-49,-49,-49,-49,-49,-49,-48,-48,-48,-48,-47,-47,-47,-47,-46,-46,-46,-45,-45,-44,-44,-43,-43,-42,-42,-41,-41,-40,-39,-39,-38,-38,-37,-36,-35,-34,-33,-32,-31,-31,-30,-29,-28,-27,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,17,18,19,20,21,22,23,24,25,26,27,27,28,29,30,31,31,32,33,34,35,36,37,38,38,39,39,40,41,41,42,42,43,43,44,44,45,45,46,46,46,47,47,47,47,48,48,48,48,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,48,48,48,48,47,47,47,47,46,46,46,45,45,44,44,43,43,42,42,41,41,40,39,39,38,38,37,36,35,34,33,32,31,31,30,29,28,27,27,26,25,24,23,22,21,20,19,18,17,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-27,-28,-29,-30,-31,-31,-32,-33,-34,-35,-36,-37,-38,-38,-39,-39,-40,-41,-41,-42,-42,-43,-43,-44,-44,-45,-45,-46,-46,-46,-47,-47,-47,-47,-48,-48,-48,-48,-49,-49,-49,-49,-49,-49,-49,-49,-49,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-49,-49,-49,-49,-49,-48,-48,-48,-48,-47,-47,-46,-46,-46,-45,-45,-44,-44,-43,-43,-42,-41,-41,-40,-40,-39,-38,-38,-37,-37,-36,-36,-35,-35,-34,-34,-33,-32,-31,-30,-30,-29,-28,-27,-26,-25,-24,-23,-22,-22,-21,-20,-19,-18,-17,-16,-15,-14,-14,-13,-12,-11,-10,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,10,11,12,13,14,14,15,16,17,18,19,20,21,22,22,23,24,25,26,27,28,29,30,30,31,32,33,34,34,35,35,36,36,37,37,38,38,39,40,40,41,41,42,43,43,44,44,45,45,46,46,46,47,47,48,48,48,48,49,49,49,49,49,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,49,49,49,49,49,48,48,48,48,47,47,46,46,46,45,45,44,44,43,43,42,41,41,40,40,39,38,38,37,37,36,36,35,35,34,34,33,32,31,30,30,29,28,27,26,25,24,23,22,22,21,20,19,18,17,16,15,14,14,13,12,11,10,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-10,-11,-12,-13,-14,-14,-15,-16,-17,-18,-19,-20,-21,-22,-22,-23,-24,-25,-26,-27,-28,-29,-30,-30,-31,-32,-33,-34,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-40,-40,-41,-41,-42,-43,-43,-44,-44,-45,-45,-46,-46,-46,-47,-47,-48,-48,-48,-48,-49,-49,-49,-49,-49,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-50,-50,-50,-50,-49,-49,-49,-48,-48,-47,-47,-47,-46,-46,-45,-45,-45,-44,-44,-43,-43,-42,-42,-41,-40,-40,-39,-39,-38,-37,-36,-35,-34,-33,-33,-32,-31,-30,-29,-29,-28,-27,-26,-26,-25,-24,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,24,25,26,26,27,28,29,29,30,31,32,33,33,34,35,36,37,38,39,39,40,40,41,42,42,43,43,44,44,45,45,45,46,46,47,47,47,48,48,49,49,49,50,50,50,50,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,50,50,50,50,49,49,49,48,48,47,47,47,46,46,45,45,45,44,44,43,43,42,42,41,40,40,39,39,38,37,36,35,34,33,33,32,31,30,29,29,28,27,26,26,25,24,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-24,-25,-26,-26,-27,-28,-29,-29,-30,-31,-32,-33,-33,-34,-35,-36,-37,-38,-39,-39,-40,-40,-41,-42,-42,-43,-43,-44,-44,-45,-45,-45,-46,-46,-47,-47,-47,-48,-48,-49,-49,-49,-50,-50,-50,-50,-51,-51,-51,-51,-51,-51,-51,-51,-51,-51,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-51,-51,-51,-51,-50,-50,-50,-49,-49,-49,-48,-48,-48,-47,-47,-46,-46,-45,-44,-44,-43,-42,-42,-41,-41,-40,-39,-38,-37,-36,-35,-34,-33,-32,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,20,21,22,23,24,25,26,27,28,29,30,31,32,32,33,34,35,36,37,38,39,40,41,41,42,42,43,44,44,45,46,46,47,47,48,48,48,49,49,49,50,50,50,51,51,51,51,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,51,51,51,51,50,50,50,49,49,49,48,48,48,47,47,46,46,45,44,44,43,42,42,41,41,40,39,38,37,36,35,34,33,32,32,31,30,29,28,27,26,25,24,23,22,21,20,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-20,-21,-22,-23,-24,-25,-26,-27,-28,-29,-30,-31,-32,-32,-33,-34,-35,-36,-37,-38,-39,-40,-41,-41,-42,-42,-43,-44,-44,-45,-46,-46,-47,-47,-48,-48,-48,-49,-49,-49,-50,-50,-50,-51,-51,-51,-51,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-52,-52,-52,-52,-51,-51,-51,-50,-50,-50,-49,-49,-48,-48,-47,-47,-46,-46,-45,-45,-44,-44,-43,-43,-42,-41,-41,-40,-40,-39,-39,-38,-38,-37,-37,-36,-36,-35,-35,-34,-33,-32,-31,-31,-30,-29,-28,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,28,29,30,31,31,32,33,34,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,43,43,44,44,45,45,46,46,47,47,48,48,49,49,50,50,50,51,51,51,52,52,52,52,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,52,52,52,52,51,51,51,50,50,50,49,49,48,48,47,47,46,46,45,45,44,44,43,43,42,41,41,40,40,39,39,38,38,37,37,36,36,35,35,34,33,32,31,31,30,29,28,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-28,-28,-29,-30,-31,-31,-32,-33,-34,-35,-35,-36,-36,-37,-37,-38,-38,-39,-39,-40,-40,-41,-41,-42,-43,-43,-44,-44,-45,-45,-46,-46,-47,-47,-48,-48,-49,-49,-50,-50,-50,-51,-51,-51,-52,-52,-52,-52,-53,-53,-53,-53,-53,-53,-53,-53,-53,-53,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-53,-53,-53,-53,-52,-52,-52,-51,-51,-51,-50,-50,-49,-49,-48,-48,-47,-47,-46,-46,-45,-45,-44,-43,-43,-42,-42,-41,-40,-39,-38,-37,-36,-35,-34,-34,-33,-32,-31,-30,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,30,31,32,33,34,34,35,36,37,38,39,40,41,42,42,43,43,44,45,45,46,46,47,47,48,48,49,49,50,50,51,51,51,52,52,52,53,53,53,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,53,53,53,52,52,52,51,51,51,50,50,49,49,48,48,47,47,46,46,45,45,44,43,43,42,42,41,40,39,38,37,36,35,34,34,33,32,31,30,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-28,-29,-30,-30,-31,-32,-33,-34,-34,-35,-36,-37,-38,-39,-40,-41,-42,-42,-43,-43,-44,-45,-45,-46,-46,-47,-47,-48,-48,-49,-49,-50,-50,-51,-51,-51,-52,-52,-52,-53,-53,-53,-53,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-54,-54,-54,-54,-53,-53,-53,-53,-52,-52,-52,-51,-51,-51,-50,-50,-50,-49,-49,-49,-48,-48,-47,-47,-46,-45,-45,-44,-44,-43,-42,-42,-41,-41,-40,-40,-39,-39,-38,-38,-37,-37,-36,-35,-34,-33,-33,-32,-31,-30,-29,-28,-27,-27,-26,-25,-25,-24,-23,-23,-22,-21,-20,-19,-18,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,18,19,20,21,22,23,23,24,25,25,26,27,27,28,29,30,31,32,33,33,34,35,36,37,37,38,38,39,39,40,40,41,41,42,42,43,44,44,45,45,46,47,47,48,48,49,49,49,50,50,50,51,51,51,52,52,52,53,53,53,53,54,54,54,54,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,54,54,54,54,53,53,53,53,52,52,52,51,51,51,50,50,50,49,49,49,48,48,47,47,46,45,45,44,44,43,42,42,41,41,40,40,39,39,38,38,37,37,36,35,34,33,33,32,31,30,29,28,27,27,26,25,25,24,23,23,22,21,20,19,18,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-18,-19,-20,-21,-22,-23,-23,-24,-25,-25,-26,-27,-27,-28,-29,-30,-31,-32,-33,-33,-34,-35,-36,-37,-37,-38,-38,-39,-39,-40,-40,-41,-41,-42,-42,-43,-44,-44,-45,-45,-46,-47,-47,-48,-48,-49,-49,-49,-50,-50,-50,-51,-51,-51,-52,-52,-52,-53,-53,-53,-53,-54,-54,-54,-54,-55,-55,-55,-55,-55,-55,-55,-55,-55,-55,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-55,-55,-55,-55,-54,-54,-54,-54,-53,-53,-52,-52,-52,-51,-51,-50,-50,-49,-49,-48,-48,-47,-47,-46,-46,-45,-44,-44,-43,-43,-42,-41,-40,-39,-38,-37,-36,-36,-35,-34,-33,-32,-32,-31,-30,-29,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,29,30,31,32,32,33,34,35,36,36,37,38,39,40,41,42,43,43,44,44,45,46,46,47,47,48,48,49,49,50,50,51,51,52,52,52,53,53,54,54,54,54,55,55,55,55,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,55,55,55,55,54,54,54,54,53,53,52,52,52,51,51,50,50,49,49,48,48,47,47,46,46,45,44,44,43,43,42,41,40,39,38,37,36,36,35,34,33,32,32,31,30,29,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-28,-29,-29,-30,-31,-32,-32,-33,-34,-35,-36,-36,-37,-38,-39,-40,-41,-42,-43,-43,-44,-44,-45,-46,-46,-47,-47,-48,-48,-49,-49,-50,-50,-51,-51,-52,-52,-52,-53,-53,-54,-54,-54,-54,-55,-55,-55,-55,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-56,-56,-56,-56,-56,-55,-55,-55,-55,-54,-54,-54,-53,-53,-53,-52,-52,-51,-51,-50,-50,-49,-49,-48,-48,-47,-46,-46,-45,-45,-44,-43,-42,-41,-41,-40,-39,-38,-37,-36,-35,-35,-34,-33,-32,-31,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-21,-20,-19,-18,-17,-16,-15,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15,16,17,18,19,20,21,21,22,23,24,25,26,27,28,29,30,31,31,32,33,34,35,35,36,37,38,39,40,41,41,42,43,44,45,45,46,46,47,48,48,49,49,50,50,51,51,52,52,53,53,53,54,54,54,55,55,55,55,56,56,56,56,56,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,56,56,56,56,56,55,55,55,55,54,54,54,53,53,53,52,52,51,51,50,50,49,49,48,48,47,46,46,45,45,44,43,42,41,41,40,39,38,37,36,35,35,34,33,32,31,31,30,29,28,27,26,25,24,23,22,21,21,20,19,18,17,16,15,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-15,-16,-17,-18,-19,-20,-21,-21,-22,-23,-24,-25,-26,-27,-28,-29,-30,-31,-31,-32,-33,-34,-35,-35,-36,-37,-38,-39,-40,-41,-41,-42,-43,-44,-45,-45,-46,-46,-47,-48,-48,-49,-49,-50,-50,-51,-51,-52,-52,-53,-53,-53,-54,-54,-54,-55,-55,-55,-55,-56,-56,-56,-56,-56,-57,-57,-57,-57,-57,-57,-57,-57,-57,-57,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-57,-57,-57,-57,-57,-56,-56,-56,-55,-55,-55,-54,-54,-53,-53,-52,-52,-51,-51,-50,-50,-49,-48,-48,-47,-47,-46,-45,-45,-44,-44,-43,-43,-42,-42,-41,-40,-40,-39,-39,-38,-38,-37,-36,-35,-34,-34,-33,-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,34,35,36,37,38,38,39,39,40,40,41,42,42,43,43,44,44,45,45,46,47,47,48,48,49,50,50,51,51,52,52,53,53,54,54,55,55,55,56,56,56,57,57,57,57,57,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,57,57,57,57,57,56,56,56,55,55,55,54,54,53,53,52,52,51,51,50,50,49,48,48,47,47,46,45,45,44,44,43,43,42,42,41,40,40,39,39,38,38,37,36,35,34,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-28,-29,-30,-31,-32,-33,-34,-34,-35,-36,-37,-38,-38,-39,-39,-40,-40,-41,-42,-42,-43,-43,-44,-44,-45,-45,-46,-47,-47,-48,-48,-49,-50,-50,-51,-51,-52,-52,-53,-53,-54,-54,-55,-55,-55,-56,-56,-56,-57,-57,-57,-57,-57,-58,-58,-58,-58,-58,-58,-58,-58,-58,-58,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59,-58,-58,-58,-58,-58,-57,-57,-57,-56,-56,-56,-55,-55,-54,-54,-54,-53,-53,-53,-52,-52,-51,-51,-50,-50,-49,-49,-48,-47,-47,-46,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-37,-36,-35,-34,-33,-33,-32,-31,-30,-29,-28,-28,-27,-26,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,26,27,28,28,29,30,31,32,33,33,34,35,36,37,37,38,39,40,41,42,43,44,45,46,46,47,47,48,49,49,50,50,51,51,52,52,53,53,53,54,54,54,55,55,56,56,56,57,57,57,58,58,58,58,58,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,58,58,58,58,58,57,57,57,56,56,56,55,55,54,54,54,53,53,53,52,52,51,51,50,50,49,49,48,47,47,46,46,45,44,43,42,41,40,39,38,37,37,36,35,34,33,33,32,31,30,29,28,28,27,26,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-26,-27,-28,-28,-29,-30,-31,-32,-33,-33,-34,-35,-36,-37,-37,-38,-39,-40,-41,-42,-43,-44,-45,-46,-46,-47,-47,-48,-49,-49,-50,-50,-51,-51,-52,-52,-53,-53,-53,-54,-54,-54,-55,-55,-56,-56,-56,-57,-57,-57,-58,-58,-58,-58,-58,-59,-59,-59,-59,-59,-59,-59,-59,-59,-59];\nvar towards_center = [0,0,0,0,0,0,0,0,0,1,1,2,3,3,3,4,5,5,5,6,7,7,7,8,1,9,9,10,12,13,13,13,14,16,17,17,17,18,20,21,21,21,22,24,9,25,25,26,11,29,30,30,30,31,15,34,35,35,35,36,19,39,40,40,40,41,23,44,25,45,45,46,47,27,48,28,49,50,51,51,51,52,53,32,54,33,55,56,57,57,57,58,59,37,60,38,61,62,63,63,63,64,65,42,66,43,67,68,45,69,69,70,71,73,75,77,78,79,79,79,80,81,83,85,87,88,89,89,89,90,91,93,95,97,98,99,99,99,100,101,103,105,107,108,69,109,109,110,111,72,113,74,114,76,116,117,118,118,118,119,120,82,122,84,123,86,125,126,127,127,127,128,129,92,131,94,132,96,134,135,136,136,136,137,138,102,140,104,141,106,143,144,109,145,145,146,147,148,112,149,151,153,115,154,155,156,157,157,157,158,159,160,121,161,163,165,124,166,167,168,169,169,169,170,171,172,130,173,175,177,133,178,179,180,181,181,181,182,183,184,139,185,187,189,142,190,191,192,145,193,193,194,195,196,198,150,200,152,202,204,205,206,207,207,207,208,209,210,212,162,214,164,216,218,219,220,221,221,221,222,223,224,226,174,228,176,230,232,233,234,235,235,235,236,237,238,240,186,242,188,244,246,247,248,193,249,249,250,251,252,197,254,199,255,257,201,258,203,260,261,262,263,263,263,264,265,266,211,268,213,269,271,215,272,217,274,275,276,277,277,277,278,279,280,225,282,227,283,285,229,286,231,288,289,290,291,291,291,292,293,294,239,296,241,297,299,243,300,245,302,303,304,249,305,305,306,307,308,253,310,312,256,315,317,259,319,320,321,322,322,322,323,324,325,267,327,329,270,332,334,273,336,337,338,339,339,339,340,341,342,281,344,346,284,349,351,287,353,354,355,356,356,356,357,358,359,295,361,363,298,366,368,301,370,371,372,305,373,373,374,375,376,309,378,311,380,313,381,314,382,316,384,318,386,387,388,389,389,389,390,391,392,326,394,328,396,330,397,331,398,333,400,335,402,403,404,405,405,405,406,407,408,343,410,345,412,347,413,348,414,350,416,352,418,419,420,421,421,421,422,423,424,360,426,362,428,364,429,365,430,367,432,369,434,435,436,373,437,437,438,439,440,441,377,442,443,379,444,446,448,450,383,451,452,385,453,454,455,456,457,457,457,458,459,460,461,393,462,463,395,464,466,468,470,399,471,472,401,473,474,475,476,477,477,477,478,479,480,481,409,482,483,411,484,486,488,490,415,491,492,417,493,494,495,496,497,497,497,498,499,500,501,425,502,503,427,504,506,508,510,431,511,512,433,513,514,515,516,437,517,517,518,519,520,521,523,524,526,445,528,447,529,449,531,533,534,536,537,538,539,540,540,540,541,542,543,544,546,547,549,465,551,467,552,469,554,556,557,559,560,561,562,563,563,563,564,565,566,567,569,570,572,485,574,487,575,489,577,579,580,582,583,584,585,586,586,586,587,588,589,590,592,593,595,505,597,507,598,509,600,602,603,605,606,607,608,517,609,609,610,611,612,613,522,615,525,617,527,618,620,622,530,623,532,625,535,627,628,629,630,631,631,631,632,633,634,635,545,637,548,639,550,640,642,644,553,645,555,647,558,649,650,651,652,653,653,653,654,655,656,657,568,659,571,661,573,662,664,666,576,667,578,669,581,671,672,673,674,675,675,675,676,677,678,679,591,681,594,683,596,684,686,688,599,689,601,691,604,693,694,695,696,609,697,697,698,699,700,701,614,703,616,705,707,619,709,621,711,713,624,715,626,717,718,719,720,721,721,721,722,723,724,725,636,727,638,729,731,641,733,643,735,737,646,739,648,741,742,743,744,745,745,745,746,747,748,749,658,751,660,753,755,663,757,665,759,761,668,763,670,765,766,767,768,769,769,769,770,771,772,773,680,775,682,777,779,685,781,687,783,785,690,787,692,789,790,791,792,697,793,793,794,795,796,797,702,799,800,704,801,706,803,708,804,806,710,807,712,809,714,810,811,716,813,814,815,816,817,817,817,818,819,820,821,726,823,824,728,825,730,827,732,828,830,734,831,736,833,738,834,835,740,837,838,839,840,841,841,841,842,843,844,845,750,847,848,752,849,754,851,756,852,854,758,855,760,857,762,858,859,764,861,862,863,864,865,865,865,866,867,868,869,774,871,872,776,873,778,875,780,876,878,782,879,784,881,786,882,883,788,885,886,887,888,793,889,889,890,891,892,893,894,798,895,896,898,899,802,900,902,805,905,907,808,908,909,911,912,812,913,914,915,916,917,918,918,918,919,920,921,922,923,822,924,925,927,928,826,929,931,829,934,936,832,937,938,940,941,836,942,943,944,945,946,947,947,947,948,949,950,951,952,846,953,954,956,957,850,958,960,853,963,965,856,966,967,969,970,860,971,972,973,974,975,976,976,976,977,978,979,980,981,870,982,983,985,986,874,987,989,877,992,994,880,995,996,998,999,884,1000,1001,1002,1003,1004,889,1005,1005,1006,1007,1008,1009,1010,1012,1013,897,1015,1017,901,1019,903,1020,904,1021,906,1023,1025,910,1027,1028,1030,1031,1032,1033,1034,1035,1035,1035,1036,1037,1038,1039,1040,1042,1043,926,1045,1047,930,1049,932,1050,933,1051,935,1053,1055,939,1057,1058,1060,1061,1062,1063,1064,1065,1065,1065,1066,1067,1068,1069,1070,1072,1073,955,1075,1077,959,1079,961,1080,962,1081,964,1083,1085,968,1087,1088,1090,1091,1092,1093,1094,1095,1095,1095,1096,1097,1098,1099,1100,1102,1103,984,1105,1107,988,1109,990,1110,991,1111,993,1113,1115,997,1117,1118,1120,1121,1122,1123,1124,1005,1125,1125,1126,1127,1128,1129,1130,1011,1132,1014,1134,1016,1136,1018,1137,1139,1141,1143,1022,1144,1024,1146,1026,1148,1029,1150,1151,1152,1153,1154,1155,1155,1155,1156,1157,1158,1159,1160,1041,1162,1044,1164,1046,1166,1048,1167,1169,1171,1173,1052,1174,1054,1176,1056,1178,1059,1180,1181,1182,1183,1184,1185,1185,1185,1186,1187,1188,1189,1190,1071,1192,1074,1194,1076,1196,1078,1197,1199,1201,1203,1082,1204,1084,1206,1086,1208,1089,1210,1211,1212,1213,1214,1215,1215,1215,1216,1217,1218,1219,1220,1101,1222,1104,1224,1106,1226,1108,1227,1229,1231,1233,1112,1234,1114,1236,1116,1238,1119,1240,1241,1242,1243,1244,1125,1245,1245,1246,1247,1248,1249,1250,1131,1252,1253,1133,1254,1255,1135,1256,1258,1138,1260,1140,1261,1142,1263,1265,1145,1266,1267,1147,1268,1269,1149,1271,1272,1273,1274,1275,1276,1276,1276,1277,1278,1279,1280,1281,1161,1283,1284,1163,1285,1286,1165,1287,1289,1168,1291,1170,1292,1172,1294,1296,1175,1297,1298,1177,1299,1300,1179,1302,1303,1304,1305,1306,1307,1307,1307,1308,1309,1310,1311,1312,1191,1314,1315,1193,1316,1317,1195,1318,1320,1198,1322,1200,1323,1202,1325,1327,1205,1328,1329,1207,1330,1331,1209,1333,1334,1335,1336,1337,1338,1338,1338,1339,1340,1341,1342,1343,1221,1345,1346,1223,1347,1348,1225,1349,1351,1228,1353,1230,1354,1232,1356,1358,1235,1359,1360,1237,1361,1362,1239,1364,1365,1366,1367,1368,1245,1369,1369,1370,1371,1372,1373,1374,1251,1376,1377,1379,1380,1382,1257,1384,1259,1385,1387,1389,1262,1390,1264,1392,1394,1395,1397,1398,1270,1400,1401,1402,1403,1404,1405,1405,1405,1406,1407,1408,1409,1410,1282,1412,1413,1415,1416,1418,1288,1420,1290,1421,1423,1425,1293,1426,1295,1428,1430,1431,1433,1434,1301,1436,1437,1438,1439,1440,1441,1441,1441,1442,1443,1444,1445,1446,1313,1448,1449,1451,1452,1454,1319,1456,1321,1457,1459,1461,1324,1462,1326,1464,1466,1467,1469,1470,1332,1472,1473,1474,1475,1476,1477,1477,1477,1478,1479,1480,1481,1482,1344,1484,1485,1487,1488,1490,1350,1492,1352,1493,1495,1497,1355,1498,1357,1500,1502,1503,1505,1506,1363,1508,1509,1510,1511,1512,1369,1513,1513,1514,1515,1516,1517,1518,1375,1520,1521,1378,1523,1381,1525,1383,1526,1528,1386,1388,1532,1534,1391,1535,1393,1537,1396,1539,1540,1399,1542,1543,1544,1545,1546,1547,1547,1547,1548,1549,1550,1551,1552,1411,1554,1555,1414,1557,1417,1559,1419,1560,1562,1422,1424,1566,1568,1427,1569,1429,1571,1432,1573,1574,1435,1576,1577,1578,1579,1580,1581,1581,1581,1582,1583,1584,1585,1586,1447,1588,1589,1450,1591,1453,1593,1455,1594,1596,1458,1460,1600,1602,1463,1603,1465,1605,1468,1607,1608,1471,1610,1611,1612,1613,1614,1615,1615,1615,1616,1617,1618,1619,1620,1483,1622,1623,1486,1625,1489,1627,1491,1628,1630,1494,1496,1634,1636,1499,1637,1501,1639,1504,1641,1642,1507,1644,1645,1646,1647,1648,1513,1649,1649,1650,1651,1652,1653,1654,1519,1656,1657,1522,1659,1524,1661,1663,1527,1665,1529,1666,1530,1667,1531,1668,1533,1670,1672,1536,1674,1538,1676,1677,1541,1679,1680,1681,1682,1683,1684,1684,1684,1685,1686,1687,1688,1689,1553,1691,1692,1556,1694,1558,1696,1698,1561,1700,1563,1701,1564,1702,1565,1703,1567,1705,1707,1570,1709,1572,1711,1712,1575,1714,1715,1716,1717,1718,1719,1719,1719,1720,1721,1722,1723,1724,1587,1726,1727,1590,1729,1592,1731,1733,1595,1735,1597,1736,1598,1737,1599,1738,1601,1740,1742,1604,1744,1606,1746,1747,1609,1749,1750,1751,1752,1753,1754,1754,1754,1755,1756,1757,1758,1759,1621,1761,1762,1624,1764,1626,1766,1768,1629,1770,1631,1771,1632,1772,1633,1773,1635,1775,1777,1638,1779,1640,1781,1782,1643,1784,1785,1786,1787,1788,1649,1789,1789,1790,1791,1792,1793,1794,1795,1655,1796,1797,1658,1799,1800,1660,1801,1662,1803,1664,1804,1806,1808,1810,1812,1669,1813,1671,1815,1673,1816,1817,1675,1819,1820,1678,1821,1822,1823,1824,1825,1826,1827,1827,1827,1828,1829,1830,1831,1832,1833,1690,1834,1835,1693,1837,1838,1695,1839,1697,1841,1699,1842,1844,1846,1848,1850,1704,1851,1706,1853,1708,1854,1855,1710,1857,1858,1713,1859,1860,1861,1862,1863,1864,1865,1865,1865,1866,1867,1868,1869,1870,1871,1725,1872,1873,1728,1875,1876,1730,1877,1732,1879,1734,1880,1882,1884,1886,1888,1739,1889,1741,1891,1743,1892,1893,1745,1895,1896,1748,1897,1898,1899,1900,1901,1902,1903,1903,1903,1904,1905,1906,1907,1908,1909,1760,1910,1911,1763,1913,1914,1765,1915,1767,1917,1769,1918,1920,1922,1924,1926,1774,1927,1776,1929,1778,1930,1931,1780,1933,1934,1783,1935,1936,1937,1938,1939,1940,1789,1941,1941,1942,1943,1944,1945,1946,1947,1949,1950,1951,1798,1952,1953,1955,1956,1802,1957,1959,1805,1961,1807,1962,1809,1963,1811,1965,1967,1814,1968,1969,1971,1972,1818,1973,1974,1975,1977,1978,1979,1980,1981,1982,1983,1983,1983,1984,1985,1986,1987,1988,1989,1991,1992,1993,1836,1994,1995,1997,1998,1840,1999,2001,1843,2003,1845,2004,1847,2005,1849,2007,2009,1852,2010,2011,2013,2014,1856,2015,2016,2017,2019,2020,2021,2022,2023,2024,2025,2025,2025,2026,2027,2028,2029,2030,2031,2033,2034,2035,1874,2036,2037,2039,2040,1878,2041,2043,1881,2045,1883,2046,1885,2047,1887,2049,2051,1890,2052,2053,2055,2056,1894,2057,2058,2059,2061,2062,2063,2064,2065,2066,2067,2067,2067,2068,2069,2070,2071,2072,2073,2075,2076,2077,1912,2078,2079,2081,2082,1916,2083,2085,1919,2087,1921,2088,1923,2089,1925,2091,2093,1928,2094,2095,2097,2098,1932,2099,2100,2101,2103,2104,2105,2106,2107,2108,1941,2109,2109,2110,2111,2112,2113,2114,2115,1948,2117,2118,2120,2121,1954,2123,2125,1958,2127,1960,2128,2130,2132,2134,1964,2135,1966,2137,2139,1970,2141,2142,2144,2145,1976,2147,2148,2149,2150,2151,2152,2153,2153,2153,2154,2155,2156,2157,2158,2159,1990,2161,2162,2164,2165,1996,2167,2169,2000,2171,2002,2172,2174,2176,2178,2006,2179,2008,2181,2183,2012,2185,2186,2188,2189,2018,2191,2192,2193,2194,2195,2196,2197,2197,2197,2198,2199,2200,2201,2202,2203,2032,2205,2206,2208,2209,2038,2211,2213,2042,2215,2044,2216,2218,2220,2222,2048,2223,2050,2225,2227,2054,2229,2230,2232,2233,2060,2235,2236,2237,2238,2239,2240,2241,2241,2241,2242,2243,2244,2245,2246,2247,2074,2249,2250,2252,2253,2080,2255,2257,2084,2259,2086,2260,2262,2264,2266,2090,2267,2092,2269,2271,2096,2273,2274,2276,2277,2102,2279,2280,2281,2282,2283,2284,2109,2285,2285,2286,2287,2288,2289,2290,2291,2116,2293,2294,2119,2296,2122,2298,2124,2300,2126,2301,2303,2129,2131,2133,2308,2310,2136,2311,2138,2313,2140,2315,2143,2317,2318,2146,2320,2321,2322,2323,2324,2325,2326,2326,2326,2327,2328,2329,2330,2331,2332,2160,2334,2335,2163,2337,2166,2339,2168,2341,2170,2342,2344,2173,2175,2177,2349,2351,2180,2352,2182,2354,2184,2356,2187,2358,2359,2190,2361,2362,2363,2364,2365,2366,2367,2367,2367,2368,2369,2370,2371,2372,2373,2204,2375,2376,2207,2378,2210,2380,2212,2382,2214,2383,2385,2217,2219,2221,2390,2392,2224,2393,2226,2395,2228,2397,2231,2399,2400,2234,2402,2403,2404,2405,2406,2407,2408,2408,2408,2409,2410,2411,2412,2413,2414,2248,2416,2417,2251,2419,2254,2421,2256,2423,2258,2424,2426,2261,2263,2265,2431,2433,2268,2434,2270,2436,2272,2438,2275,2440,2441,2278,2443,2444,2445,2446,2447,2448,2285,2449,2449,2450,2451,2452,2453,2454,2455,2292,2457,2458,2295,2460,2461,2297,2462,2299,2464,2466,2302,2468,2304,2469,2305,2470,2306,2471,2307,2472,2309,2474,2476,2312,2478,2314,2479,2480,2316,2482,2483,2319,2485,2486,2487,2488,2489,2490,2491,2491,2491,2492,2493,2494,2495,2496,2497,2333,2499,2500,2336,2502,2503,2338,2504,2340,2506,2508,2343,2510,2345,2511,2346,2512,2347,2513,2348,2514,2350,2516,2518,2353,2520,2355,2521,2522,2357,2524,2525,2360,2527,2528,2529,2530,2531,2532,2533,2533,2533,2534,2535,2536,2537,2538,2539,2374,2541,2542,2377,2544,2545,2379,2546,2381,2548,2550,2384,2552,2386,2553,2387,2554,2388,2555,2389,2556,2391,2558,2560,2394,2562,2396,2563,2564,2398,2566,2567,2401,2569,2570,2571,2572,2573,2574,2575,2575,2575,2576,2577,2578,2579,2580,2581,2415,2583,2584,2418,2586,2587,2420,2588,2422,2590,2592,2425,2594,2427,2595,2428,2596,2429,2597,2430,2598,2432,2600,2602,2435,2604,2437,2605,2606,2439,2608,2609,2442,2611,2612,2613,2614,2615,2616,2449,2617,2617,2618,2619,2620,2621,2622,2623,2456,2625,2626,2459,2628,2629,2631,2632,2463,2633,2465,2635,2467,2636,2638,2640,2642,2644,2646,2473,2647,2475,2649,2477,2650,2651,2653,2654,2481,2656,2657,2484,2659,2660,2661,2662,2663,2664,2665,2665,2665,2666,2667,2668,2669,2670,2671,2498,2673,2674,2501,2676,2677,2679,2680,2505,2681,2507,2683,2509,2684,2686,2688,2690,2692,2694,2515,2695,2517,2697,2519,2698,2699,2701,2702,2523,2704,2705,2526,2707,2708,2709,2710,2711,2712,2713,2713,2713,2714,2715,2716,2717,2718,2719,2540,2721,2722,2543,2724,2725,2727,2728,2547,2729,2549,2731,2551,2732,2734,2736,2738,2740,2742,2557,2743,2559,2745,2561,2746,2747,2749,2750,2565,2752,2753,2568,2755,2756,2757,2758,2759,2760,2761,2761,2761,2762,2763,2764,2765,2766,2767,2582,2769,2770,2585,2772,2773,2775,2776,2589,2777,2591,2779,2593,2780,2782,2784,2786,2788,2790,2599,2791,2601,2793,2603,2794,2795,2797,2798,2607,2800,2801,2610,2803,2804,2805,2806,2807,2808,2617,2809,2809,2810,2811,2812,2813,2814,2815,2624,2817,2818,2819,2627,2820,2821,2630,2823,2825,2826,2634,2827,2829,2637,2831,2639,2832,2641,2833,2643,2834,2645,2836,2838,2648,2839,2840,2842,2652,2844,2845,2655,2846,2847,2848,2658,2850,2851,2852,2853,2854,2855,2856,2856,2856,2857,2858,2859,2860,2861,2862,2672,2864,2865,2866,2675,2867,2868,2678,2870,2872,2873,2682,2874,2876,2685,2878,2687,2879,2689,2880,2691,2881,2693,2883,2885,2696,2886,2887,2889,2700,2891,2892,2703,2893,2894,2895,2706,2897,2898,2899,2900,2901,2902,2903,2903,2903,2904,2905,2906,2907,2908,2909,2720,2911,2912,2913,2723,2914,2915,2726,2917,2919,2920,2730,2921,2923,2733,2925,2735,2926,2737,2927,2739,2928,2741,2930,2932,2744,2933,2934,2936,2748,2938,2939,2751,2940,2941,2942,2754,2944,2945,2946,2947,2948,2949,2950,2950,2950,2951,2952,2953,2954,2955,2956,2768,2958,2959,2960,2771,2961,2962,2774,2964,2966,2967,2778,2968,2970,2781,2972,2783,2973,2785,2974,2787,2975,2789,2977,2979,2792,2980,2981,2983,2796,2985,2986,2799,2987,2988,2989,2802,2991,2992,2993,2994,2995,2996,2809,2997,2997,2998,2999,3000,3001,3002,3003,3004,2816,3005,3006,3007,3009,3010,2822,3012,2824,3014,3016,2828,3018,2830,3019,3021,3023,3025,3027,2835,3028,2837,3030,3032,2841,3034,2843,3036,3037,3039,3040,3041,2849,3042,3043,3044,3045,3046,3047,3048,3049,3049,3049,3050,3051,3052,3053,3054,3055,3056,2863,3057,3058,3059,3061,3062,2869,3064,2871,3066,3068,2875,3070,2877,3071,3073,3075,3077,3079,2882,3080,2884,3082,3084,2888,3086,2890,3088,3089,3091,3092,3093,2896,3094,3095,3096,3097,3098,3099,3100,3101,3101,3101,3102,3103,3104,3105,3106,3107,3108,2910,3109,3110,3111,3113,3114,2916,3116,2918,3118,3120,2922,3122,2924,3123,3125,3127,3129,3131,2929,3132,2931,3134,3136,2935,3138,2937,3140,3141,3143,3144,3145,2943,3146,3147,3148,3149,3150,3151,3152,3153,3153,3153,3154,3155,3156,3157,3158,3159,3160,2957,3161,3162,3163,3165,3166,2963,3168,2965,3170,3172,2969,3174,2971,3175,3177,3179,3181,3183,2976,3184,2978,3186,3188,2982,3190,2984,3192,3193,3195,3196,3197,2990,3198,3199,3200,3201,3202,3203,3204,2997,3205,3205,3206,3207,3208,3209,3210,3211,3212,3214,3215,3216,3008,3218,3011,3220,3013,3222,3015,3224,3017,3225,3227,3020,3229,3022,3230,3024,3231,3026,3233,3235,3029,3236,3031,3238,3033,3240,3035,3242,3038,3244,3245,3246,3248,3249,3250,3251,3252,3253,3254,3255,3255,3255,3256,3257,3258,3259,3260,3261,3262,3264,3265,3266,3060,3268,3063,3270,3065,3272,3067,3274,3069,3275,3277,3072,3279,3074,3280,3076,3281,3078,3283,3285,3081,3286,3083,3288,3085,3290,3087,3292,3090,3294,3295,3296,3298,3299,3300,3301,3302,3303,3304,3305,3305,3305,3306,3307,3308,3309,3310,3311,3312,3314,3315,3316,3112,3318,3115,3320,3117,3322,3119,3324,3121,3325,3327,3124,3329,3126,3330,3128,3331,3130,3333,3335,3133,3336,3135,3338,3137,3340,3139,3342,3142,3344,3345,3346,3348,3349,3350,3351,3352,3353,3354,3355,3355,3355,3356,3357,3358,3359,3360,3361,3362,3364,3365,3366,3164,3368,3167,3370,3169,3372,3171,3374,3173,3375,3377,3176,3379,3178,3380,3180,3381,3182,3383,3385,3185,3386,3187,3388,3189,3390,3191,3392,3194,3394,3395,3396,3398,3399,3400,3401,3402,3403,3404,3205,3405,3405,3406,3407,3408,3409,3410,3411,3412,3213,3414,3415,3217,3417,3418,3219,3419,3420,3221,3421,3422,3223,3423,3425,3226,3427,3228,3428,3430,3432,3434,3232,3435,3234,3437,3439,3237,3440,3441,3239,3442,3443,3241,3444,3445,3243,3447,3448,3247,3450,3451,3452,3453,3454,3455,3456,3457,3457,3457,3458,3459,3460,3461,3462,3463,3464,3263,3466,3467,3267,3469,3470,3269,3471,3472,3271,3473,3474,3273,3475,3477,3276,3479,3278,3480,3482,3484,3486,3282,3487,3284,3489,3491,3287,3492,3493,3289,3494,3495,3291,3496,3497,3293,3499,3500,3297,3502,3503,3504,3505,3506,3507,3508,3509,3509,3509,3510,3511,3512,3513,3514,3515,3516,3313,3518,3519,3317,3521,3522,3319,3523,3524,3321,3525,3526,3323,3527,3529,3326,3531,3328,3532,3534,3536,3538,3332,3539,3334,3541,3543,3337,3544,3545,3339,3546,3547,3341,3548,3549,3343,3551,3552,3347,3554,3555,3556,3557,3558,3559,3560,3561,3561,3561,3562,3563,3564,3565,3566,3567,3568,3363,3570,3571,3367,3573,3574,3369,3575,3576,3371,3577,3578,3373,3579,3581,3376,3583,3378,3584,3586,3588,3590,3382,3591,3384,3593,3595,3387,3596,3597,3389,3598,3599,3391,3600,3601,3393,3603,3604,3397,3606,3607,3608,3609,3610,3611,3612,3405,3613,3613,3614,3615,3616,3617,3618,3619,3620,3413,3622,3623,3416,3625,3626,3628,3629,3631,3632,3634,3424,3636,3426,3637,3639,3429,3431,3433,3644,3646,3436,3647,3438,3649,3651,3652,3654,3655,3657,3658,3446,3660,3661,3449,3663,3664,3665,3666,3667,3668,3669,3670,3670,3670,3671,3672,3673,3674,3675,3676,3677,3465,3679,3680,3468,3682,3683,3685,3686,3688,3689,3691,3476,3693,3478,3694,3696,3481,3483,3485,3701,3703,3488,3704,3490,3706,3708,3709,3711,3712,3714,3715,3498,3717,3718,3501,3720,3721,3722,3723,3724,3725,3726,3727,3727,3727,3728,3729,3730,3731,3732,3733,3734,3517,3736,3737,3520,3739,3740,3742,3743,3745,3746,3748,3528,3750,3530,3751,3753,3533,3535,3537,3758,3760,3540,3761,3542,3763,3765,3766,3768,3769,3771,3772,3550,3774,3775,3553,3777,3778,3779,3780,3781,3782,3783,3784,3784,3784,3785,3786,3787,3788,3789,3790,3791,3569,3793,3794,3572,3796,3797,3799,3800,3802,3803,3805,3580,3807,3582,3808,3810,3585,3587,3589,3815,3817,3592,3818,3594,3820,3822,3823,3825,3826,3828,3829,3602,3831,3832,3605,3834,3835,3836,3837,3838,3839,3840,3613,3841,3841,3842,3843,3844,3845,3846,3847,3848,3621,3850,3851,3624,3853,3854,3627,3856,3630,3858,3633,3860,3635,3861,3863,3638,3865,3640,3866,3641,3867,3642,3868,3643,3869,3645,3871,3873,3648,3874,3650,3876,3653,3878,3656,3880,3881,3659,3883,3884,3662,3886,3887,3888,3889,3890,3891,3892,3893,3893,3893,3894,3895,3896,3897,3898,3899,3900,3678,3902,3903,3681,3905,3906,3684,3908,3687,3910,3690,3912,3692,3913,3915,3695,3917,3697,3918,3698,3919,3699,3920,3700,3921,3702,3923,3925,3705,3926,3707,3928,3710,3930,3713,3932,3933,3716,3935,3936,3719,3938,3939,3940,3941,3942,3943,3944,3945,3945,3945,3946,3947,3948,3949,3950,3951,3952,3735,3954,3955,3738,3957,3958,3741,3960,3744,3962,3747,3964,3749,3965,3967,3752,3969,3754,3970,3755,3971,3756,3972,3757,3973,3759,3975,3977,3762,3978,3764,3980,3767,3982,3770,3984,3985,3773,3987,3988,3776,3990,3991,3992,3993,3994,3995,3996,3997,3997,3997,3998,3999,4000,4001,4002,4003,4004,3792,4006,4007,3795,4009,4010,3798,4012,3801,4014,3804,4016,3806,4017,4019,3809,4021,3811,4022,3812,4023,3813,4024,3814,4025,3816,4027,4029,3819,4030,3821,4032,3824,4034,3827,4036,4037,3830,4039,4040,3833,4042,4043,4044,4045,4046,4047,4048,3841,4049,4049,4050,4051,4052,4053,4054,4055,4056,3849,4058,4059,4060,3852,4061,4062,3855,4064,3857,4066,3859,4068,4070,3862,4072,3864,4073,4075,4077,4079,4081,4083,3870,4084,3872,4086,4088,3875,4090,3877,4092,3879,4094,4095,3882,4096,4097,4098,3885,4100,4101,4102,4103,4104,4105,4106,4107,4107,4107,4108,4109,4110,4111,4112,4113,4114,3901,4116,4117,4118,3904,4119,4120,3907,4122,3909,4124,3911,4126,4128,3914,4130,3916,4131,4133,4135,4137,4139,4141,3922,4142,3924,4144,4146,3927,4148,3929,4150,3931,4152,4153,3934,4154,4155,4156,3937,4158,4159,4160,4161,4162,4163,4164,4165,4165,4165,4166,4167,4168,4169,4170,4171,4172,3953,4174,4175,4176,3956,4177,4178,3959,4180,3961,4182,3963,4184,4186,3966,4188,3968,4189,4191,4193,4195,4197,4199,3974,4200,3976,4202,4204,3979,4206,3981,4208,3983,4210,4211,3986,4212,4213,4214,3989,4216,4217,4218,4219,4220,4221,4222,4223,4223,4223,4224,4225,4226,4227,4228,4229,4230,4005,4232,4233,4234,4008,4235,4236,4011,4238,4013,4240,4015,4242,4244,4018,4246,4020,4247,4249,4251,4253,4255,4257,4026,4258,4028,4260,4262,4031,4264,4033,4266,4035,4268,4269,4038,4270,4271,4272,4041,4274,4275,4276,4277,4278,4279,4280,4049,4281,4281,4282,4283,4284,4285,4286,4287,4288,4057,4290,4291,4292,4294,4295,4063,4297,4298,4065,4299,4300,4067,4301,4069,4303,4071,4304,4306,4074,4308,4076,4309,4078,4310,4080,4311,4082,4313,4315,4085,4316,4087,4318,4089,4319,4320,4091,4321,4322,4093,4324,4325,4327,4328,4329,4099,4331,4332,4333,4334,4335,4336,4337,4338,4338,4338,4339,4340,4341,4342,4343,4344,4345,4115,4347,4348,4349,4351,4352,4121,4354,4355,4123,4356,4357,4125,4358,4127,4360,4129,4361,4363,4132,4365,4134,4366,4136,4367,4138,4368,4140,4370,4372,4143,4373,4145,4375,4147,4376,4377,4149,4378,4379,4151,4381,4382,4384,4385,4386,4157,4388,4389,4390,4391,4392,4393,4394,4395,4395,4395,4396,4397,4398,4399,4400,4401,4402,4173,4404,4405,4406,4408,4409,4179,4411,4412,4181,4413,4414,4183,4415,4185,4417,4187,4418,4420,4190,4422,4192,4423,4194,4424,4196,4425,4198,4427,4429,4201,4430,4203,4432,4205,4433,4434,4207,4435,4436,4209,4438,4439,4441,4442,4443,4215,4445,4446,4447,4448,4449,4450,4451,4452,4452,4452,4453,4454,4455,4456,4457,4458,4459,4231,4461,4462,4463,4465,4466,4237,4468,4469,4239,4470,4471,4241,4472,4243,4474,4245,4475,4477,4248,4479,4250,4480,4252,4481,4254,4482,4256,4484,4486,4259,4487,4261,4489,4263,4490,4491,4265,4492,4493,4267,4495,4496,4498,4499,4500,4273,4502,4503,4504,4505,4506,4507,4508,4281,4509,4509,4510,4511,4512,4513,4514,4515,4516,4289,4518,4519,4520,4293,4522,4523,4296,4524,4525,4527,4528,4530,4531,4302,4532,4534,4305,4536,4307,4537,4539,4541,4543,4545,4312,4546,4314,4548,4550,4317,4551,4552,4554,4555,4557,4558,4323,4559,4560,4326,4562,4563,4564,4330,4566,4567,4568,4569,4570,4571,4572,4573,4573,4573,4574,4575,4576,4577,4578,4579,4580,4346,4582,4583,4584,4350,4586,4587,4353,4588,4589,4591,4592,4594,4595,4359,4596,4598,4362,4600,4364,4601,4603,4605,4607,4609,4369,4610,4371,4612,4614,4374,4615,4616,4618,4619,4621,4622,4380,4623,4624,4383,4626,4627,4628,4387,4630,4631,4632,4633,4634,4635,4636,4637,4637,4637,4638,4639,4640,4641,4642,4643,4644,4403,4646,4647,4648,4407,4650,4651,4410,4652,4653,4655,4656,4658,4659,4416,4660,4662,4419,4664,4421,4665,4667,4669,4671,4673,4426,4674,4428,4676,4678,4431,4679,4680,4682,4683,4685,4686,4437,4687,4688,4440,4690,4691,4692,4444,4694,4695,4696,4697,4698,4699,4700,4701,4701,4701,4702,4703,4704,4705,4706,4707,4708,4460,4710,4711,4712,4464,4714,4715,4467,4716,4717,4719,4720,4722,4723,4473,4724,4726,4476,4728,4478,4729,4731,4733,4735,4737,4483,4738,4485,4740,4742,4488,4743,4744,4746,4747,4749,4750,4494,4751,4752,4497,4754,4755,4756,4501,4758,4759,4760,4761,4762,4763,4764,4509,4765,4765,4766,4767,4768,4769,4770,4771,4772,4517,4774,4775,4776,4521,4778,4779,4781,4782,4526,4784,4529,4786,4788,4533,4790,4535,4791,4793,4538,4540,4542,4544,4799,4801,4547,4802,4549,4804,4806,4553,4808,4556,4810,4811,4813,4814,4561,4816,4817,4818,4565,4820,4821,4822,4823,4824,4825,4826,4827,4827,4827,4828,4829,4830,4831,4832,4833,4834,4581,4836,4837,4838,4585,4840,4841,4843,4844,4590,4846,4593,4848,4850,4597,4852,4599,4853,4855,4602,4604,4606,4608,4861,4863,4611,4864,4613,4866,4868,4617,4870,4620,4872,4873,4875,4876,4625,4878,4879,4880,4629,4882,4883,4884,4885,4886,4887,4888,4889,4889,4889,4890,4891,4892,4893,4894,4895,4896,4645,4898,4899,4900,4649,4902,4903,4905,4906,4654,4908,4657,4910,4912,4661,4914,4663,4915,4917,4666,4668,4670,4672,4923,4925,4675,4926,4677,4928,4930,4681,4932,4684,4934,4935,4937,4938,4689,4940,4941,4942,4693,4944,4945,4946,4947,4948,4949,4950,4951,4951,4951,4952,4953,4954,4955,4956,4957,4958,4709,4960,4961,4962,4713,4964,4965,4967,4968,4718,4970,4721,4972,4974,4725,4976,4727,4977,4979,4730,4732,4734,4736,4985,4987,4739,4988,4741,4990,4992,4745,4994,4748,4996,4997,4999,5000,4753,5002,5003,5004,4757,5006,5007,5008,5009,5010,5011,5012,4765,5013,5013,5014,5015,5016,5017,5018,5019,5020,5021,4773,5022,5023,5024,4777,5026,5027,4780,5029,4783,5031,4785,5033,4787,5035,4789,5036,5038,4792,5040,4794,5041,4795,5042,4796,5043,4797,5044,4798,5045,4800,5047,5049,4803,5050,4805,5052,4807,5054,4809,5056,4812,5058,5059,4815,5061,5062,5063,4819,5064,5065,5066,5067,5068,5069,5070,5071,5072,5072,5072,5073,5074,5075,5076,5077,5078,5079,5080,4835,5081,5082,5083,4839,5085,5086,4842,5088,4845,5090,4847,5092,4849,5094,4851,5095,5097,4854,5099,4856,5100,4857,5101,4858,5102,4859,5103,4860,5104,4862,5106,5108,4865,5109,4867,5111,4869,5113,4871,5115,4874,5117,5118,4877,5120,5121,5122,4881,5123,5124,5125,5126,5127,5128,5129,5130,5131,5131,5131,5132,5133,5134,5135,5136,5137,5138,5139,4897,5140,5141,5142,4901,5144,5145,4904,5147,4907,5149,4909,5151,4911,5153,4913,5154,5156,4916,5158,4918,5159,4919,5160,4920,5161,4921,5162,4922,5163,4924,5165,5167,4927,5168,4929,5170,4931,5172,4933,5174,4936,5176,5177,4939,5179,5180,5181,4943,5182,5183,5184,5185,5186,5187,5188,5189,5190,5190,5190,5191,5192,5193,5194,5195,5196,5197,5198,4959,5199,5200,5201,4963,5203,5204,4966,5206,4969,5208,4971,5210,4973,5212,4975,5213,5215,4978,5217,4980,5218,4981,5219,4982,5220,4983,5221,4984,5222,4986,5224,5226,4989,5227,4991,5229,4993,5231,4995,5233,4998,5235,5236,5001,5238,5239,5240,5005,5241,5242,5243,5244,5245,5246,5247,5248,5013,5249,5249,5250,5251,5252,5253,5254,5255,5256,5257,5259,5260,5261,5025,5263,5264,5028,5266,5267,5030,5268,5269,5032,5270,5034,5272,5274,5037,5276,5039,5277,5279,5281,5283,5285,5287,5289,5046,5290,5048,5292,5294,5051,5296,5053,5297,5298,5055,5299,5300,5057,5302,5303,5060,5305,5306,5307,5309,5310,5311,5312,5313,5314,5315,5316,5317,5317,5317,5318,5319,5320,5321,5322,5323,5324,5325,5327,5328,5329,5084,5331,5332,5087,5334,5335,5089,5336,5337,5091,5338,5093,5340,5342,5096,5344,5098,5345,5347,5349,5351,5353,5355,5357,5105,5358,5107,5360,5362,5110,5364,5112,5365,5366,5114,5367,5368,5116,5370,5371,5119,5373,5374,5375,5377,5378,5379,5380,5381,5382,5383,5384,5385,5385,5385,5386,5387,5388,5389,5390,5391,5392,5393,5395,5396,5397,5143,5399,5400,5146,5402,5403,5148,5404,5405,5150,5406,5152,5408,5410,5155,5412,5157,5413,5415,5417,5419,5421,5423,5425,5164,5426,5166,5428,5430,5169,5432,5171,5433,5434,5173,5435,5436,5175,5438,5439,5178,5441,5442,5443,5445,5446,5447,5448,5449,5450,5451,5452,5453,5453,5453,5454,5455,5456,5457,5458,5459,5460,5461,5463,5464,5465,5202,5467,5468,5205,5470,5471,5207,5472,5473,5209,5474,5211,5476,5478,5214,5480,5216,5481,5483,5485,5487,5489,5491,5493,5223,5494,5225,5496,5498,5228,5500,5230,5501,5502,5232,5503,5504,5234,5506,5507,5237,5509,5510,5511,5513,5514,5515,5516,5517,5518,5519,5520,5249,5521,5521,5522,5523,5524,5525,5526,5527,5528,5529,5258,5531,5532,5533,5262,5534,5535,5265,5537,5538,5540,5541,5543,5544,5271,5545,5273,5547,5275,5548,5550,5278,5552,5280,5553,5282,5554,5284,5555,5286,5556,5288,5558,5560,5291,5561,5293,5563,5295,5564,5565,5567,5568,5570,5571,5301,5573,5574,5304,5575,5576,5577,5308,5579,5580,5581,5582,5583,5584,5585,5586,5587,5587,5587,5588,5589,5590,5591,5592,5593,5594,5595,5326,5597,5598,5599,5330,5600,5601,5333,5603,5604,5606,5607,5609,5610,5339,5611,5341,5613,5343,5614,5616,5346,5618,5348,5619,5350,5620,5352,5621,5354,5622,5356,5624,5626,5359,5627,5361,5629,5363,5630,5631,5633,5634,5636,5637,5369,5639,5640,5372,5641,5642,5643,5376,5645,5646,5647,5648,5649,5650,5651,5652,5653,5653,5653,5654,5655,5656,5657,5658,5659,5660,5661,5394,5663,5664,5665,5398,5666,5667,5401,5669,5670,5672,5673,5675,5676,5407,5677,5409,5679,5411,5680,5682,5414,5684,5416,5685,5418,5686,5420,5687,5422,5688,5424,5690,5692,5427,5693,5429,5695,5431,5696,5697,5699,5700,5702,5703,5437,5705,5706,5440,5707,5708,5709,5444,5711,5712,5713,5714,5715,5716,5717,5718,5719,5719,5719,5720,5721,5722,5723,5724,5725,5726,5727,5462,5729,5730,5731,5466,5732,5733,5469,5735,5736,5738,5739,5741,5742,5475,5743,5477,5745,5479,5746,5748,5482,5750,5484,5751,5486,5752,5488,5753,5490,5754,5492,5756,5758,5495,5759,5497,5761,5499,5762,5763,5765,5766,5768,5769,5505,5771,5772,5508,5773,5774,5775,5512,5777,5778,5779,5780,5781,5782,5783,5784,5521,5785,5785,5786,5787,5788,5789,5790,5791,5792,5793,5530,5795,5796,5797,5799,5800,5801,5536,5802,5803,5539,5805,5542,5807,5809,5810,5546,5811,5813,5549,5815,5551,5816,5818,5820,5822,5824,5826,5557,5827,5559,5829,5831,5562,5832,5833,5835,5566,5837,5569,5839,5840,5572,5841,5842,5843,5845,5846,5847,5578,5849,5850,5851,5852,5853,5854,5855,5856,5857,5857,5857,5858,5859,5860,5861,5862,5863,5864,5865,5596,5867,5868,5869,5871,5872,5873,5602,5874,5875,5605,5877,5608,5879,5881,5882,5612,5883,5885,5615,5887,5617,5888,5890,5892,5894,5896,5898,5623,5899,5625,5901,5903,5628,5904,5905,5907,5632,5909,5635,5911,5912,5638,5913,5914,5915,5917,5918,5919,5644,5921,5922,5923,5924,5925,5926,5927,5928,5929,5929,5929,5930,5931,5932,5933,5934,5935,5936,5937,5662,5939,5940,5941,5943,5944,5945,5668,5946,5947,5671,5949,5674,5951,5953,5954,5678,5955,5957,5681,5959,5683,5960,5962,5964,5966,5968,5970,5689,5971,5691,5973,5975,5694,5976,5977,5979,5698,5981,5701,5983,5984,5704,5985,5986,5987,5989,5990,5991,5710,5993,5994,5995,5996,5997,5998,5999,6000,6001,6001,6001,6002,6003,6004,6005,6006,6007,6008,6009,5728,6011,6012,6013,6015,6016,6017,5734,6018,6019,5737,6021,5740,6023,6025,6026,5744,6027,6029,5747,6031,5749,6032,6034,6036,6038,6040,6042,5755,6043,5757,6045,6047,5760,6048,6049,6051,5764,6053,5767,6055,6056,5770,6057,6058,6059,6061,6062,6063,5776,6065,6066,6067,6068,6069,6070,6071,6072,5785,6073,6073,6074,6075,6076,6077,6078,6079,6080,6081,5794,6083,6084,6085,5798,6087,6088,6090,6091,5804,6093,5806,6095,5808,6097,6099,5812,6101,5814,6102,6104,5817,5819,6107,5821,6108,5823,5825,6111,6113,5828,6114,5830,6116,6118,5834,6120,5836,6122,5838,6124,6125,6127,6128,5844,6130,6131,6132,5848,6134,6135,6136,6137,6138,6139,6140,6141,6142,6142,6142,6143,6144,6145,6146,6147,6148,6149,6150,5866,6152,6153,6154,5870,6156,6157,6159,6160,5876,6162,5878,6164,5880,6166,6168,5884,6170,5886,6171,6173,5889,5891,6176,5893,6177,5895,5897,6180,6182,5900,6183,5902,6185,6187,5906,6189,5908,6191,5910,6193,6194,6196,6197,5916,6199,6200,6201,5920,6203,6204,6205,6206,6207,6208,6209,6210,6211,6211,6211,6212,6213,6214,6215,6216,6217,6218,6219,5938,6221,6222,6223,5942,6225,6226,6228,6229,5948,6231,5950,6233,5952,6235,6237,5956,6239,5958,6240,6242,5961,5963,6245,5965,6246,5967,5969,6249,6251,5972,6252,5974,6254,6256,5978,6258,5980,6260,5982,6262,6263,6265,6266,5988,6268,6269,6270,5992,6272,6273,6274,6275,6276,6277,6278,6279,6280,6280,6280,6281,6282,6283,6284,6285,6286,6287,6288,6010,6290,6291,6292,6014,6294,6295,6297,6298,6020,6300,6022,6302,6024,6304,6306,6028,6308,6030,6309,6311,6033,6035,6314,6037,6315,6039,6041,6318,6320,6044,6321,6046,6323,6325,6050,6327,6052,6329,6054,6331,6332,6334,6335,6060,6337,6338,6339,6064,6341,6342,6343,6344,6345,6346,6347,6348,6073,6349,6349,6350,6351,6352,6353,6354,6355,6356,6357,6082,6359,6360,6361,6086,6363,6364,6089,6366,6092,6368,6369,6094,6370,6096,6372,6098,6374,6100,6375,6377,6103,6379,6105,6380,6106,6381,6383,6385,6109,6386,6110,6387,6112,6389,6391,6115,6392,6117,6394,6119,6396,6121,6397,6398,6123,6400,6126,6402,6403,6129,6405,6406,6407,6133,6409,6410,6411,6412,6413,6414,6415,6416,6417,6417,6417,6418,6419,6420,6421,6422,6423,6424,6425,6151,6427,6428,6429,6155,6431,6432,6158,6434,6161,6436,6437,6163,6438,6165,6440,6167,6442,6169,6443,6445,6172,6447,6174,6448,6175,6449,6451,6453,6178,6454,6179,6455,6181,6457,6459,6184,6460,6186,6462,6188,6464,6190,6465,6466,6192,6468,6195,6470,6471,6198,6473,6474,6475,6202,6477,6478,6479,6480,6481,6482,6483,6484,6485,6485,6485,6486,6487,6488,6489,6490,6491,6492,6493,6220,6495,6496,6497,6224,6499,6500,6227,6502,6230,6504,6505,6232,6506,6234,6508,6236,6510,6238,6511,6513,6241,6515,6243,6516,6244,6517,6519,6521,6247,6522,6248,6523,6250,6525,6527,6253,6528,6255,6530,6257,6532,6259,6533,6534,6261,6536,6264,6538,6539,6267,6541,6542,6543,6271,6545,6546,6547,6548,6549,6550,6551,6552,6553,6553,6553,6554,6555,6556,6557,6558,6559,6560,6561,6289,6563,6564,6565,6293,6567,6568,6296,6570,6299,6572,6573,6301,6574,6303,6576,6305,6578,6307,6579,6581,6310,6583,6312,6584,6313,6585,6587,6589,6316,6590,6317,6591,6319,6593,6595,6322,6596,6324,6598,6326,6600,6328,6601,6602,6330,6604,6333,6606,6607,6336,6609,6610,6611,6340,6613,6614,6615,6616,6617,6618,6619,6620,6349,6621,6621,6622,6623,6624,6625,6626,6627,6628,6629,6358,6631,6632,6633,6362,6635,6636,6365,6638,6639,6367,6640,6641,6643,6644,6371,6645,6373,6647,6649,6376,6651,6378,6652,6654,6656,6382,6384,6660,6662,6664,6388,6665,6390,6667,6669,6393,6671,6395,6672,6673,6675,6676,6399,6677,6678,6401,6680,6681,6404,6683,6684,6685,6408,6687,6688,6689,6690,6691,6692,6693,6694,6695,6695,6695,6696,6697,6698,6699,6700,6701,6702,6703,6426,6705,6706,6707,6430,6709,6710,6433,6712,6713,6435,6714,6715,6717,6718,6439,6719,6441,6721,6723,6444,6725,6446,6726,6728,6730,6450,6452,6734,6736,6738,6456,6739,6458,6741,6743,6461,6745,6463,6746,6747,6749,6750,6467,6751,6752,6469,6754,6755,6472,6757,6758,6759,6476,6761,6762,6763,6764,6765,6766,6767,6768,6769,6769,6769,6770,6771,6772,6773,6774,6775,6776,6777,6494,6779,6780,6781,6498,6783,6784,6501,6786,6787,6503,6788,6789,6791,6792,6507,6793,6509,6795,6797,6512,6799,6514,6800,6802,6804,6518,6520,6808,6810,6812,6524,6813,6526,6815,6817,6529,6819,6531,6820,6821,6823,6824,6535,6825,6826,6537,6828,6829,6540,6831,6832,6833,6544,6835,6836,6837,6838,6839,6840,6841,6842,6843,6843,6843,6844,6845,6846,6847,6848,6849,6850,6851,6562,6853,6854,6855,6566,6857,6858,6569,6860,6861,6571,6862,6863,6865,6866,6575,6867,6577,6869,6871,6580,6873,6582,6874,6876,6878,6586,6588,6882,6884,6886,6592,6887,6594,6889,6891,6597,6893,6599,6894,6895,6897,6898,6603,6899,6900,6605,6902,6903,6608,6905,6906,6907,6612,6909,6910,6911,6912,6913,6914,6915,6916,6621,6917,6917,6918,6919,6920,6921,6922,6923,6924,6925,6630,6927,6928,6929,6634,6931,6932,6637,6934,6935,6937,6938,6642,6940,6942,6943,6646,6944,6648,6946,6650,6947,6949,6653,6951,6655,6952,6657,6953,6658,6954,6659,6955,6661,6956,6663,6958,6960,6666,6961,6668,6963,6670,6964,6965,6967,6674,6969,6970,6972,6973,6679,6975,6976,6682,6978,6979,6980,6686,6982,6983,6984,6985,6986,6987,6988,6989,6990,6990,6990,6991,6992,6993,6994,6995,6996,6997,6998,6704,7000,7001,7002,6708,7004,7005,6711,7007,7008,7010,7011,6716,7013,7015,7016,6720,7017,6722,7019,6724,7020,7022,6727,7024,6729,7025,6731,7026,6732,7027,6733,7028,6735,7029,6737,7031,7033,6740,7034,6742,7036,6744,7037,7038,7040,6748,7042,7043,7045,7046,6753,7048,7049,6756,7051,7052,7053,6760,7055,7056,7057,7058,7059,7060,7061,7062,7063,7063,7063,7064,7065,7066,7067,7068,7069,7070,7071,6778,7073,7074,7075,6782,7077,7078,6785,7080,7081,7083,7084,6790,7086,7088,7089,6794,7090,6796,7092,6798,7093,7095,6801,7097,6803,7098,6805,7099,6806,7100,6807,7101,6809,7102,6811,7104,7106,6814,7107,6816,7109,6818,7110,7111,7113,6822,7115,7116,7118,7119,6827,7121,7122,6830,7124,7125,7126,6834,7128,7129,7130,7131,7132,7133,7134,7135,7136,7136,7136,7137,7138,7139,7140,7141,7142,7143,7144,6852,7146,7147,7148,6856,7150,7151,6859,7153,7154,7156,7157,6864,7159,7161,7162,6868,7163,6870,7165,6872,7166,7168,6875,7170,6877,7171,6879,7172,6880,7173,6881,7174,6883,7175,6885,7177,7179,6888,7180,6890,7182,6892,7183,7184,7186,6896,7188,7189,7191,7192,6901,7194,7195,6904,7197,7198,7199,6908,7201,7202,7203,7204,7205,7206,7207,7208,6917,7209,7209,7210,7211,7212,7213,7214,7215,7216,7217,6926,7219,7220,7221,6930,7223,7224,7225,6933,7226,7227,6936,7229,6939,7231,6941,7233,7235,7236,6945,7237,7239,6948,7241,6950,7242,7244,7246,7248,7250,7252,7254,6957,7255,6959,7257,7259,6962,7260,7261,7263,6966,7265,6968,7267,6971,7269,7270,6974,7271,7272,7273,6977,7275,7276,7277,6981,7279,7280,7281,7282,7283,7284,7285,7286,7287,7287,7287,7288,7289,7290,7291,7292,7293,7294,7295,6999,7297,7298,7299,7003,7301,7302,7303,7006,7304,7305,7009,7307,7012,7309,7014,7311,7313,7314,7018,7315,7317,7021,7319,7023,7320,7322,7324,7326,7328,7330,7332,7030,7333,7032,7335,7337,7035,7338,7339,7341,7039,7343,7041,7345,7044,7347,7348,7047,7349,7350,7351,7050,7353,7354,7355,7054,7357,7358,7359,7360,7361,7362,7363,7364,7365,7365,7365,7366,7367,7368,7369,7370,7371,7372,7373,7072,7375,7376,7377,7076,7379,7380,7381,7079,7382,7383,7082,7385,7085,7387,7087,7389,7391,7392,7091,7393,7395,7094,7397,7096,7398,7400,7402,7404,7406,7408,7410,7103,7411,7105,7413,7415,7108,7416,7417,7419,7112,7421,7114,7423,7117,7425,7426,7120,7427,7428,7429,7123,7431,7432,7433,7127,7435,7436,7437,7438,7439,7440,7441,7442,7443,7443,7443,7444,7445,7446,7447,7448,7449,7450,7451,7145,7453,7454,7455,7149,7457,7458,7459,7152,7460,7461,7155,7463,7158,7465,7160,7467,7469,7470,7164,7471,7473,7167,7475,7169,7476,7478,7480,7482,7484,7486,7488,7176,7489,7178,7491,7493,7181,7494,7495,7497,7185,7499,7187,7501,7190,7503,7504,7193,7505,7506,7507,7196,7509,7510,7511,7200,7513,7514,7515,7516,7517,7518,7519,7520,7209,7521,7521,7522,7523,7524,7525,7526,7527,7528,7529,7530,7218,7531,7532,7533,7534,7222,7535,7536,7537,7539,7540,7228,7542,7543,7230,7544,7232,7546,7234,7548,7550,7238,7552,7240,7553,7555,7243,7557,7245,7558,7247,7559,7249,7560,7251,7561,7253,7563,7565,7256,7566,7258,7568,7570,7262,7572,7264,7574,7266,7575,7576,7268,7578,7579,7581,7582,7583,7274,7584,7585,7586,7587,7278,7588,7589,7590,7591,7592,7593,7594,7595,7596,7597,7597,7597,7598,7599,7600,7601,7602,7603,7604,7605,7606,7296,7607,7608,7609,7610,7300,7611,7612,7613,7615,7616,7306,7618,7619,7308,7620,7310,7622,7312,7624,7626,7316,7628,7318,7629,7631,7321,7633,7323,7634,7325,7635,7327,7636,7329,7637,7331,7639,7641,7334,7642,7336,7644,7646,7340,7648,7342,7650,7344,7651,7652,7346,7654,7655,7657,7658,7659,7352,7660,7661,7662,7663,7356,7664,7665,7666,7667,7668,7669,7670,7671,7672,7673,7673,7673,7674,7675,7676,7677,7678,7679,7680,7681,7682,7374,7683,7684,7685,7686,7378,7687,7688,7689,7691,7692,7384,7694,7695,7386,7696,7388,7698,7390,7700,7702,7394,7704,7396,7705,7707,7399,7709,7401,7710,7403,7711,7405,7712,7407,7713,7409,7715,7717,7412,7718,7414,7720,7722,7418,7724,7420,7726,7422,7727,7728,7424,7730,7731,7733,7734,7735,7430,7736,7737,7738,7739,7434,7740,7741,7742,7743,7744,7745,7746,7747,7748,7749,7749,7749,7750,7751,7752,7753,7754,7755,7756,7757,7758,7452,7759,7760,7761,7762,7456,7763,7764,7765,7767,7768,7462,7770,7771,7464,7772,7466,7774,7468,7776,7778,7472,7780,7474,7781,7783,7477,7785,7479,7786,7481,7787,7483,7788,7485,7789,7487,7791,7793,7490,7794,7492,7796,7798,7496,7800,7498,7802,7500,7803,7804,7502,7806,7807,7809,7810,7811,7508,7812,7813,7814,7815,7512,7816,7817,7818,7819,7820,7821,7822,7823,7824,7521,7825,7825,7826,7827,7828,7829,7830,7831,7832,7833,7834,7836,7837,7838,7839,7841,7842,7843,7538,7845,7541,7847,7848,7850,7851,7545,7852,7853,7547,7854,7549,7856,7551,7857,7859,7554,7861,7556,7862,7864,7866,7868,7870,7872,7562,7873,7564,7875,7877,7567,7878,7569,7880,7571,7881,7882,7573,7883,7884,7886,7887,7577,7889,7580,7891,7892,7893,7895,7896,7897,7898,7900,7901,7902,7903,7904,7905,7906,7907,7908,7909,7909,7909,7910,7911,7912,7913,7914,7915,7916,7917,7918,7920,7921,7922,7923,7925,7926,7927,7614,7929,7617,7931,7932,7934,7935,7621,7936,7937,7623,7938,7625,7940,7627,7941,7943,7630,7945,7632,7946,7948,7950,7952,7954,7956,7638,7957,7640,7959,7961,7643,7962,7645,7964,7647,7965,7966,7649,7967,7968,7970,7971,7653,7973,7656,7975,7976,7977,7979,7980,7981,7982,7984,7985,7986,7987,7988,7989,7990,7991,7992,7993,7993,7993,7994,7995,7996,7997,7998,7999,8000,8001,8002,8004,8005,8006,8007,8009,8010,8011,7690,8013,7693,8015,8016,8018,8019,7697,8020,8021,7699,8022,7701,8024,7703,8025,8027,7706,8029,7708,8030,8032,8034,8036,8038,8040,7714,8041,7716,8043,8045,7719,8046,7721,8048,7723,8049,8050,7725,8051,8052,8054,8055,7729,8057,7732,8059,8060,8061,8063,8064,8065,8066,8068,8069,8070,8071,8072,8073,8074,8075,8076,8077,8077,8077,8078,8079,8080,8081,8082,8083,8084,8085,8086,8088,8089,8090,8091,8093,8094,8095,7766,8097,7769,8099,8100,8102,8103,7773,8104,8105,7775,8106,7777,8108,7779,8109,8111,7782,8113,7784,8114,8116,8118,8120,8122,8124,7790,8125,7792,8127,8129,7795,8130,7797,8132,7799,8133,8134,7801,8135,8136,8138,8139,7805,8141,7808,8143,8144,8145,8147,8148,8149,8150,8152,8153,8154,8155,8156,8157,8158,8159,8160,7825,8161,8161,8162,8163,8164,8165,8166,8167,8168,8169,8170,7835,8172,8173,8174,7840,8176,8177,7844,8179,8180,7846,8181,8182,7849,8184,8186,8187,8189,7855,8191,8193,7858,8195,7860,8196,8198,7863,7865,7867,7869,7871,8205,8207,7874,8208,7876,8210,8212,7879,8214,8216,8217,8219,7885,8221,8222,7888,8223,8224,7890,8226,8227,7894,8229,8230,8231,7899,8233,8234,8235,8236,8237,8238,8239,8240,8241,8242,8242,8242,8243,8244,8245,8246,8247,8248,8249,8250,8251,7919,8253,8254,8255,7924,8257,8258,7928,8260,8261,7930,8262,8263,7933,8265,8267,8268,8270,7939,8272,8274,7942,8276,7944,8277,8279,7947,7949,7951,7953,7955,8286,8288,7958,8289,7960,8291,8293,7963,8295,8297,8298,8300,7969,8302,8303,7972,8304,8305,7974,8307,8308,7978,8310,8311,8312,7983,8314,8315,8316,8317,8318,8319,8320,8321,8322,8323,8323,8323,8324,8325,8326,8327,8328,8329,8330,8331,8332,8003,8334,8335,8336,8008,8338,8339,8012,8341,8342,8014,8343,8344,8017,8346,8348,8349,8351,8023,8353,8355,8026,8357,8028,8358,8360,8031,8033,8035,8037,8039,8367,8369,8042,8370,8044,8372,8374,8047,8376,8378,8379,8381,8053,8383,8384,8056,8385,8386,8058,8388,8389,8062,8391,8392,8393,8067,8395,8396,8397,8398,8399,8400,8401,8402,8403,8404,8404,8404,8405,8406,8407,8408,8409,8410,8411,8412,8413,8087,8415,8416,8417,8092,8419,8420,8096,8422,8423,8098,8424,8425,8101,8427,8429,8430,8432,8107,8434,8436,8110,8438,8112,8439,8441,8115,8117,8119,8121,8123,8448,8450,8126,8451,8128,8453,8455,8131,8457,8459,8460,8462,8137,8464,8465,8140,8466,8467,8142,8469,8470,8146,8472,8473,8474,8151,8476,8477,8478,8479,8480,8481,8482,8483,8484,8161,8485,8485,8486,8487,8488,8489,8490,8491,8492,8493,8494,8171,8496,8497,8498,8175,8500,8501,8178,8503,8504,8506,8507,8183,8509,8185,8511,8188,8513,8190,8514,8192,8516,8194,8517,8519,8197,8521,8199,8522,8200,8523,8201,8524,8202,8525,8203,8526,8204,8527,8206,8529,8531,8209,8532,8211,8534,8213,8535,8215,8537,8218,8539,8220,8541,8542,8544,8545,8225,8547,8548,8228,8550,8551,8552,8232,8554,8555,8556,8557,8558,8559,8560,8561,8562,8563,8563,8563,8564,8565,8566,8567,8568,8569,8570,8571,8572,8252,8574,8575,8576,8256,8578,8579,8259,8581,8582,8584,8585,8264,8587,8266,8589,8269,8591,8271,8592,8273,8594,8275,8595,8597,8278,8599,8280,8600,8281,8601,8282,8602,8283,8603,8284,8604,8285,8605,8287,8607,8609,8290,8610,8292,8612,8294,8613,8296,8615,8299,8617,8301,8619,8620,8622,8623,8306,8625,8626,8309,8628,8629,8630,8313,8632,8633,8634,8635,8636,8637,8638,8639,8640,8641,8641,8641,8642,8643,8644,8645,8646,8647,8648,8649,8650,8333,8652,8653,8654,8337,8656,8657,8340,8659,8660,8662,8663,8345,8665,8347,8667,8350,8669,8352,8670,8354,8672,8356,8673,8675,8359,8677,8361,8678,8362,8679,8363,8680,8364,8681,8365,8682,8366,8683,8368,8685,8687,8371,8688,8373,8690,8375,8691,8377,8693,8380,8695,8382,8697,8698,8700,8701,8387,8703,8704,8390,8706,8707,8708,8394,8710,8711,8712,8713,8714,8715,8716,8717,8718,8719,8719,8719,8720,8721,8722,8723,8724,8725,8726,8727,8728,8414,8730,8731,8732,8418,8734,8735,8421,8737,8738,8740,8741,8426,8743,8428,8745,8431,8747,8433,8748,8435,8750,8437,8751,8753,8440,8755,8442,8756,8443,8757,8444,8758,8445,8759,8446,8760,8447,8761,8449,8763,8765,8452,8766,8454,8768,8456,8769,8458,8771,8461,8773,8463,8775,8776,8778,8779,8468,8781,8782,8471,8784,8785,8786,8475,8788,8789,8790,8791,8792,8793,8794,8795,8796,8485,8797,8797,8798,8799,8800,8801,8802,8803,8804,8805,8806,8495,8808,8809,8810,8499,8812,8813,8502,8815,8816,8505,8818,8508,8820,8510,8822,8512,8824,8826,8827,8515,8828,8830,8518,8832,8520,8833,8835,8837,8839,8841,8843,8845,8847,8528,8848,8530,8850,8852,8533,8853,8854,8856,8536,8858,8538,8860,8540,8862,8543,8864,8865,8546,8867,8868,8549,8870,8871,8872,8553,8874,8875,8876,8877,8878,8879,8880,8881,8882,8883,8883,8883,8884,8885,8886,8887,8888,8889,8890,8891,8892,8573,8894,8895,8896,8577,8898,8899,8580,8901,8902,8583,8904,8586,8906,8588,8908,8590,8910,8912,8913,8593,8914,8916,8596,8918,8598,8919,8921,8923,8925,8927,8929,8931,8933,8606,8934,8608,8936,8938,8611,8939,8940,8942,8614,8944,8616,8946,8618,8948,8621,8950,8951,8624,8953,8954,8627,8956,8957,8958,8631,8960,8961,8962,8963,8964,8965,8966,8967,8968,8969,8969,8969,8970,8971,8972,8973,8974,8975,8976,8977,8978,8651,8980,8981,8982,8655,8984,8985,8658,8987,8988,8661,8990,8664,8992,8666,8994,8668,8996,8998,8999,8671,9000,9002,8674,9004,8676,9005,9007,9009,9011,9013,9015,9017,9019,8684,9020,8686,9022,9024,8689,9025,9026,9028,8692,9030,8694,9032,8696,9034,8699,9036,9037,8702,9039,9040,8705,9042,9043,9044,8709,9046,9047,9048,9049,9050,9051,9052,9053,9054,9055,9055,9055,9056,9057,9058,9059,9060,9061,9062,9063,9064,8729,9066,9067,9068,8733,9070,9071,8736,9073,9074,8739,9076,8742,9078,8744,9080,8746,9082,9084,9085,8749,9086,9088,8752,9090,8754,9091,9093,9095,9097,9099,9101,9103,9105,8762,9106,8764,9108,9110,8767,9111,9112,9114,8770,9116,8772,9118,8774,9120,8777,9122,9123,8780,9125,9126,8783,9128,9129,9130,8787,9132,9133,9134,9135,9136,9137,9138,9139,9140,8797,9141,9141,9142,9143,9144,9145,9146,9147,9148,9149,9150,8807,9152,9153,9154,8811,9156,9157,9158,8814,9159,9160,8817,9162,9163,8819,9164,9165,8821,9166,9167,8823,9168,8825,9170,9172,8829,9174,8831,9175,9177,8834,9179,8836,9180,8838,9181,8840,9182,8842,9183,8844,9184,8846,9186,9188,8849,9189,8851,9191,9193,8855,9195,8857,9196,9197,8859,9198,9199,8861,9200,9201,8863,9203,9204,8866,9205,9206,9207,8869,9209,9210,9211,8873,9213,9214,9215,9216,9217,9218,9219,9220,9221,9222,9222,9222,9223,9224,9225,9226,9227,9228,9229,9230,9231,8893,9233,9234,9235,8897,9237,9238,9239,8900,9240,9241,8903,9243,9244,8905,9245,9246,8907,9247,9248,8909,9249,8911,9251,9253,8915,9255,8917,9256,9258,8920,9260,8922,9261,8924,9262,8926,9263,8928,9264,8930,9265,8932,9267,9269,8935,9270,8937,9272,9274,8941,9276,8943,9277,9278,8945,9279,9280,8947,9281,9282,8949,9284,9285,8952,9286,9287,9288,8955,9290,9291,9292,8959,9294,9295,9296,9297,9298,9299,9300,9301,9302,9303,9303,9303,9304,9305,9306,9307,9308,9309,9310,9311,9312,8979,9314,9315,9316,8983,9318,9319,9320,8986,9321,9322,8989,9324,9325,8991,9326,9327,8993,9328,9329,8995,9330,8997,9332,9334,9001,9336,9003,9337,9339,9006,9341,9008,9342,9010,9343,9012,9344,9014,9345,9016,9346,9018,9348,9350,9021,9351,9023,9353,9355,9027,9357,9029,9358,9359,9031,9360,9361,9033,9362,9363,9035,9365,9366,9038,9367,9368,9369,9041,9371,9372,9373,9045,9375,9376,9377,9378,9379,9380,9381,9382,9383,9384,9384,9384,9385,9386,9387,9388,9389,9390,9391,9392,9393,9065,9395,9396,9397,9069,9399,9400,9401,9072,9402,9403,9075,9405,9406,9077,9407,9408,9079,9409,9410,9081,9411,9083,9413,9415,9087,9417,9089,9418,9420,9092,9422,9094,9423,9096,9424,9098,9425,9100,9426,9102,9427,9104,9429,9431,9107,9432,9109,9434,9436,9113,9438,9115,9439,9440,9117,9441,9442,9119,9443,9444,9121,9446,9447,9124,9448,9449,9450,9127,9452,9453,9454,9131,9456,9457,9458,9459,9460,9461,9462,9463,9464,9141,9465,9465,9466,9467,9468,9469,9470,9471,9472,9473,9474,9151,9476,9477,9478,9155,9480,9481,9482,9484,9485,9161,9487,9488,9490,9491,9493,9494,9496,9497,9169,9498,9171,9500,9173,9501,9503,9176,9505,9178,9506,9508,9510,9512,9514,9516,9518,9185,9519,9187,9521,9523,9190,9524,9192,9526,9194,9527,9528,9530,9531,9533,9534,9536,9537,9202,9539,9540,9542,9543,9544,9208,9546,9547,9548,9212,9550,9551,9552,9553,9554,9555,9556,9557,9558,9559,9559,9559,9560,9561,9562,9563,9564,9565,9566,9567,9568,9232,9570,9571,9572,9236,9574,9575,9576,9578,9579,9242,9581,9582,9584,9585,9587,9588,9590,9591,9250,9592,9252,9594,9254,9595,9597,9257,9599,9259,9600,9602,9604,9606,9608,9610,9612,9266,9613,9268,9615,9617,9271,9618,9273,9620,9275,9621,9622,9624,9625,9627,9628,9630,9631,9283,9633,9634,9636,9637,9638,9289,9640,9641,9642,9293,9644,9645,9646,9647,9648,9649,9650,9651,9652,9653,9653,9653,9654,9655,9656,9657,9658,9659,9660,9661,9662,9313,9664,9665,9666,9317,9668,9669,9670,9672,9673,9323,9675,9676,9678,9679,9681,9682,9684,9685,9331,9686,9333,9688,9335,9689,9691,9338,9693,9340,9694,9696,9698,9700,9702,9704,9706,9347,9707,9349,9709,9711,9352,9712,9354,9714,9356,9715,9716,9718,9719,9721,9722,9724,9725,9364,9727,9728,9730,9731,9732,9370,9734,9735,9736,9374,9738,9739,9740,9741,9742,9743,9744,9745,9746,9747,9747,9747,9748,9749,9750,9751,9752,9753,9754,9755,9756,9394,9758,9759,9760,9398,9762,9763,9764,9766,9767,9404,9769,9770,9772,9773,9775,9776,9778,9779,9412,9780,9414,9782,9416,9783,9785,9419,9787,9421,9788,9790,9792,9794,9796,9798,9800,9428,9801,9430,9803,9805,9433,9806,9435,9808,9437,9809,9810,9812,9813,9815,9816,9818,9819,9445,9821,9822,9824,9825,9826,9451,9828,9829,9830,9455,9832,9833,9834,9835,9836,9837,9838,9839,9840,9465,9841,9841,9842,9843,9844,9845,9846,9847,9848,9849,9850,9475,9852,9853,9854,9855,9479,9856,9857,9858,9483,9860,9861,9486,9862,9863,9489,9865,9492,9867,9495,9869,9871,9872,9499,9873,9875,9502,9877,9504,9878,9880,9507,9509,9511,9884,9513,9515,9517,9888,9890,9520,9891,9522,9893,9895,9525,9896,9897,9899,9529,9901,9532,9903,9535,9905,9906,9538,9907,9908,9541,9910,9911,9912,9545,9913,9914,9915,9916,9549,9918,9919,9920,9921,9922,9923,9924,9925,9926,9927,9927,9927,9928,9929,9930,9931,9932,9933,9934,9935,9936,9569,9938,9939,9940,9941,9573,9942,9943,9944,9577,9946,9947,9580,9948,9949,9583,9951,9586,9953,9589,9955,9957,9958,9593,9959,9961,9596,9963,9598,9964,9966,9601,9603,9605,9970,9607,9609,9611,9974,9976,9614,9977,9616,9979,9981,9619,9982,9983,9985,9623,9987,9626,9989,9629,9991,9992,9632,9993,9994,9635,9996,9997,9998,9639,9999,10000,10001,10002,9643,10004,10005,10006,10007,10008,10009,10010,10011,10012,10013,10013,10013,10014,10015,10016,10017,10018,10019,10020,10021,10022,9663,10024,10025,10026,10027,9667,10028,10029,10030,9671,10032,10033,9674,10034,10035,9677,10037,9680,10039,9683,10041,10043,10044,9687,10045,10047,9690,10049,9692,10050,10052,9695,9697,9699,10056,9701,9703,9705,10060,10062,9708,10063,9710,10065,10067,9713,10068,10069,10071,9717,10073,9720,10075,9723,10077,10078,9726,10079,10080,9729,10082,10083,10084,9733,10085,10086,10087,10088,9737,10090,10091,10092,10093,10094,10095,10096,10097,10098,10099,10099,10099,10100,10101,10102,10103,10104,10105,10106,10107,10108,9757,10110,10111,10112,10113,9761,10114,10115,10116,9765,10118,10119,9768,10120,10121,9771,10123,9774,10125,9777,10127,10129,10130,9781,10131,10133,9784,10135,9786,10136,10138,9789,9791,9793,10142,9795,9797,9799,10146,10148,9802,10149,9804,10151,10153,9807,10154,10155,10157,9811,10159,9814,10161,9817,10163,10164,9820,10165,10166,9823,10168,10169,10170,9827,10171,10172,10173,10174,9831,10176,10177,10178,10179,10180,10181,10182,10183,10184,9841,10185,10185,10186,10187,10188,10189,10190,10191,10192,10193,10194,9851,10196,10197,10198,10199,10201,10202,10203,9859,10205,10206,10208,10209,9864,10211,9866,10213,9868,10215,9870,10217,10219,9874,10221,9876,10222,10224,9879,10226,9881,10227,9882,10228,9883,10229,10231,9885,10232,9886,10233,9887,10234,9889,10236,10238,9892,10239,9894,10241,10243,9898,10245,9900,10247,9902,10249,9904,10251,10252,10254,10255,9909,10257,10258,10259,10261,10262,10263,10264,9917,10266,10267,10268,10269,10270,10271,10272,10273,10274,10275,10275,10275,10276,10277,10278,10279,10280,10281,10282,10283,10284,9937,10286,10287,10288,10289,10291,10292,10293,9945,10295,10296,10298,10299,9950,10301,9952,10303,9954,10305,9956,10307,10309,9960,10311,9962,10312,10314,9965,10316,9967,10317,9968,10318,9969,10319,10321,9971,10322,9972,10323,9973,10324,9975,10326,10328,9978,10329,9980,10331,10333,9984,10335,9986,10337,9988,10339,9990,10341,10342,10344,10345,9995,10347,10348,10349,10351,10352,10353,10354,10003,10356,10357,10358,10359,10360,10361,10362,10363,10364,10365,10365,10365,10366,10367,10368,10369,10370,10371,10372,10373,10374,10023,10376,10377,10378,10379,10381,10382,10383,10031,10385,10386,10388,10389,10036,10391,10038,10393,10040,10395,10042,10397,10399,10046,10401,10048,10402,10404,10051,10406,10053,10407,10054,10408,10055,10409,10411,10057,10412,10058,10413,10059,10414,10061,10416,10418,10064,10419,10066,10421,10423,10070,10425,10072,10427,10074,10429,10076,10431,10432,10434,10435,10081,10437,10438,10439,10441,10442,10443,10444,10089,10446,10447,10448,10449,10450,10451,10452,10453,10454,10455,10455,10455,10456,10457,10458,10459,10460,10461,10462,10463,10464,10109,10466,10467,10468,10469,10471,10472,10473,10117,10475,10476,10478,10479,10122,10481,10124,10483,10126,10485,10128,10487,10489,10132,10491,10134,10492,10494,10137,10496,10139,10497,10140,10498,10141,10499,10501,10143,10502,10144,10503,10145,10504,10147,10506,10508,10150,10509,10152,10511,10513,10156,10515,10158,10517,10160,10519,10162,10521,10522,10524,10525,10167,10527,10528,10529,10531,10532,10533,10534,10175,10536,10537,10538,10539,10540,10541,10542,10543,10544,10185,10545,10545,10546,10547,10548,10549,10550,10551,10552,10553,10554,10195,10556,10557,10558,10559,10200,10561,10562,10204,10564,10565,10207,10567,10210,10569,10570,10212,10571,10572,10214,10573,10216,10575,10218,10577,10220,10578,10580,10223,10582,10225,10583,10585,10587,10589,10230,10592,10594,10596,10598,10235,10599,10237,10601,10603,10240,10604,10242,10606,10244,10608,10246,10609,10610,10248,10611,10612,10250,10614,10253,10616,10617,10256,10619,10620,10260,10622,10623,10624,10625,10265,10627,10628,10629,10630,10631,10632,10633,10634,10635,10636,10636,10636,10637,10638,10639,10640,10641,10642,10643,10644,10645,10285,10647,10648,10649,10650,10290,10652,10653,10294,10655,10656,10297,10658,10300,10660,10661,10302,10662,10663,10304,10664,10306,10666,10308,10668,10310,10669,10671,10313,10673,10315,10674,10676,10678,10680,10320,10683,10685,10687,10689,10325,10690,10327,10692,10694,10330,10695,10332,10697,10334,10699,10336,10700,10701,10338,10702,10703,10340,10705,10343,10707,10708,10346,10710,10711,10350,10713,10714,10715,10716,10355,10718,10719,10720,10721,10722,10723,10724,10725,10726,10727,10727,10727,10728,10729,10730,10731,10732,10733,10734,10735,10736,10375,10738,10739,10740,10741,10380,10743,10744,10384,10746,10747,10387,10749,10390,10751,10752,10392,10753,10754,10394,10755,10396,10757,10398,10759,10400,10760,10762,10403,10764,10405,10765,10767,10769,10771,10410,10774,10776,10778,10780,10415,10781,10417,10783,10785,10420,10786,10422,10788,10424,10790,10426,10791,10792,10428,10793,10794,10430,10796,10433,10798,10799,10436,10801,10802,10440,10804,10805,10806,10807,10445,10809,10810,10811,10812,10813,10814,10815,10816,10817,10818,10818,10818,10819,10820,10821,10822,10823,10824,10825,10826,10827,10465,10829,10830,10831,10832,10470,10834,10835,10474,10837,10838,10477,10840,10480,10842,10843,10482,10844,10845,10484,10846,10486,10848,10488,10850,10490,10851,10853,10493,10855,10495,10856,10858,10860,10862,10500,10865,10867,10869,10871,10505,10872,10507,10874,10876,10510,10877,10512,10879,10514,10881,10516,10882,10883,10518,10884,10885,10520,10887,10523,10889,10890,10526,10892,10893,10530,10895,10896,10897,10898,10535,10900,10901,10902,10903,10904,10905,10906,10907,10908,10545];\nvar count_per_radius = [1,8,16,20,24,40,36,48,56,56,68,64,80,92,88,96,96,116,120,120,124,144,136,140,152,168,176,164,168,192,188,208,200,208,228,208,232,228,256,248,236,272,264,288,276,272,296,292,312,304,336,324,312,344,324,376,344,360,364,368];\nvar radius_offset = [0,1,9,25,45,69,109,145,193,249,305,373,437,517,609,697,793,889,1005,1125,1245,1369,1513,1649,1789,1941,2109,2285,2449,2617,2809,2997,3205,3405,3613,3841,4049,4281,4509,4765,5013,5249,5521,5785,6073,6349,6621,6917,7209,7521,7825,8161,8485,8797,9141,9465,9841,10185,10545,10909];\n// End of generated.\n\nvar connected = new Array(towards_center.length).fill(true);\n"
  }
]